diff options
21 files changed, 286 insertions, 92 deletions
diff --git a/docs/markdown/Custom-build-targets.md b/docs/markdown/Custom-build-targets.md index 9a0f2a1..f0b50d8 100644 --- a/docs/markdown/Custom-build-targets.md +++ b/docs/markdown/Custom-build-targets.md @@ -16,8 +16,8 @@ infile = 'source_code.txt' outfile = 'output.bin' mytarget = custom_target('targetname', - output : 'output.bin', - input : 'source_code.txt', + output : outfile, + input : infile, command : [comp, '@INPUT@', '@OUTPUT@'], install : true, install_dir : 'subdir') diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index 50ea92f..8cffba4 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -181,7 +181,7 @@ should only be used if the CMake files are not stored in the project itself. Additional CMake parameters can be specified with the `cmake_args` property. -### Some notes on Dub +## Dub Please understand that meson is only able to find dependencies that exist in the local Dub repository. You need to manually fetch and diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 678090b..13fc4e6 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -56,6 +56,8 @@ keyword arguments. D sources referred to by this pkg-config file - `uninstalled_variables` used instead of the `variables` keyword argument, when generating the uninstalled pkg-config file. Since *0.54.0* +- `dataonly` field. (*since 0.54.0*) this is used for architecture-independent + pkg-config files in projects which also have architecture-dependent outputs. Since 0.46 a `StaticLibrary` or `SharedLibrary` object can optionally be passed as first positional argument. If one is provided a default value will be diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 86524b7..9f432f0 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -33,16 +33,27 @@ These are return values of the `get_id` (Compiler family) and ## Linker ids -These are return values of the `get_linker_id` (Linker family) method in a compiler object. - -| Value | Linker family | -| ----- | --------------- | -| ld.bfd | GNU Compiler Collection | -| {ld.bfd,lld} | Clang non-Windows | -| link | MSVC, Clang-cl, clang Windows | -| pgi | Portland/Nvidia PGI | -| {ld.bfd,gold,xild} | Intel compiler non-Windows | -| xilink | Intel-cl Windows | +These are return values of the `get_linker_id` method in a compiler object. + +| Value | Linker family | +| ----- | --------------- | +| ld.bfd | The GNU linker | +| ld.gold | The GNU gold linker | +| ld.lld | The LLVM linker, with the GNU interface | +| ld.solaris | Solaris and illumos | +| ld64 | Apple ld64 | +| link | MSVC linker | +| lld-link | The LLVM linker, with the MSVC interface | +| xilink | Used with Intel-cl only, MSVC like | +| optlink | optlink (used with DMD) | +| rlink | The Renesas linker, used with CCrx only | +| armlink | The ARM linker (arm and armclang compilers) | +| pgi | Portland/Nvidia PGI | +| nvlink | Nvidia Linker used with cuda | + +For languages that don't have separate dynamic linkers such as C# and Java, the +`get_linker_id` will return the compiler name. + ## Script environment variables diff --git a/docs/markdown/snippets/pkgconfig_dataonly.md b/docs/markdown/snippets/pkgconfig_dataonly.md new file mode 100644 index 0000000..8a2564c --- /dev/null +++ b/docs/markdown/snippets/pkgconfig_dataonly.md @@ -0,0 +1,15 @@ +## Introduce dataonly for the pkgconfig module +This allows users to disable writing out the inbuilt variables to +the pkg-config file as they might actualy not be required. + +One reason to have this is for architecture-independent pkg-config +files in projects which also have architecture-dependent outputs. + +``` +pkgg.generate( + name : 'libhello_nolib', + description : 'A minimalistic pkgconfig file.', + version : libver, + dataonly: true +) +``` diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index 41999ba..941baed 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -400,7 +400,19 @@ class ConverterTarget: if not os.path.isabs(x): x = os.path.normpath(os.path.join(self.src_dir, x)) if not os.path.exists(x) and not any([x.endswith(y) for y in obj_suffixes]) and not is_generated: - mlog.warning('CMake: path', mlog.bold(x), 'does not exist. Ignoring. This can lead to build errors') + mlog.warning('CMake: path', mlog.bold(x), 'does not exist.') + mlog.warning(' --> Ignoring. This can lead to build errors.') + return None + if ( + os.path.isabs(x) + and os.path.commonpath([x, self.env.get_source_dir()]) == self.env.get_source_dir() + and not ( + os.path.commonpath([x, root_src_dir]) == root_src_dir or + os.path.commonpath([x, self.env.get_build_dir()]) == self.env.get_build_dir() + ) + ): + mlog.warning('CMake: path', mlog.bold(x), 'is inside the root project but', mlog.bold('not'), 'inside the subproject.') + mlog.warning(' --> Ignoring. This can lead to build errors.') return None if os.path.isabs(x) and os.path.commonpath([x, self.env.get_build_dir()]) == self.env.get_build_dir(): if is_header: diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index e8e72cf..2f1e104 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -724,7 +724,13 @@ class Compiler: return self.id def get_linker_id(self) -> str: - return self.linker.id + # There is not guarantee that we have a dynamic linker instance, as + # some languages don't have separate linkers and compilers. In those + # cases return the compiler id + try: + return self.linker.id + except AttributeError: + return self.id def get_version_string(self) -> str: details = [self.id, self.version] @@ -1059,7 +1065,25 @@ class Compiler: return self.linker.get_undefined_link_args() def remove_linkerlike_args(self, args): - return [x for x in args if not x.startswith('-Wl')] + rm_exact = ('-headerpad_max_install_names',) + rm_prefixes = ('-Wl,', '-L',) + rm_next = ('-L',) + ret = [] + iargs = iter(args) + for arg in iargs: + # Remove this argument + if arg in rm_exact: + continue + # If the argument starts with this, but is not *exactly* this + # f.ex., '-L' should match ['-Lfoo'] but not ['-L', 'foo'] + if arg.startswith(rm_prefixes) and arg not in rm_prefixes: + continue + # Ignore this argument and the one after it + if arg in rm_next: + next(iargs) + continue + ret.append(arg) + return ret def get_lto_compile_args(self) -> T.List[str]: return [] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 720d064..f1ce578 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -19,7 +19,7 @@ from itertools import chain from pathlib import PurePath from collections import OrderedDict from .mesonlib import ( - MesonException, MachineChoice, PerMachine, + MesonException, MachineChoice, PerMachine, OrderedSet, default_libdir, default_libexecdir, default_prefix, split_args ) from .wrap import WrapMode @@ -746,16 +746,20 @@ class CoreData: # Some options default to environment variables if they are # unset, set those now. These will either be overwritten # below, or they won't. These should only be set on the first run. - if env.first_invocation: - p_env = os.environ.get('PKG_CONFIG_PATH') - if p_env: - # PKG_CONFIG_PATH may contain duplicates, which must be - # removed, else a duplicates-in-array-option warning arises. - pkg_config_paths = [] - for k in p_env.split(':'): - if k not in pkg_config_paths: - pkg_config_paths.append(k) - options['pkg_config_path'] = pkg_config_paths + p_env = os.environ.get('PKG_CONFIG_PATH') + if p_env: + # PKG_CONFIG_PATH may contain duplicates, which must be + # removed, else a duplicates-in-array-option warning arises. + p_list = list(OrderedSet(p_env.split(':'))) + if env.first_invocation: + options['pkg_config_path'] = p_list + elif options.get('pkg_config_path', []) != p_list: + mlog.warning( + 'PKG_CONFIG_PATH environment variable has changed ' + 'between configurations, meson ignores this. ' + 'Use -Dpkg_config_path to change pkg-config search ' + 'path instead.' + ) for k, v in env.cmd_line_options.items(): if subproject: @@ -850,6 +854,9 @@ def read_cmd_line_file(build_dir, options): # literal_eval to get it into the list of strings. options.native_file = ast.literal_eval(properties.get('native_file', '[]')) +def cmd_line_options_to_string(options): + return {k: str(v) for k, v in options.cmd_line_options.items()} + def write_cmd_line_file(build_dir, options): filename = get_cmd_line_file(build_dir) config = CmdLineFileParser() @@ -860,7 +867,7 @@ def write_cmd_line_file(build_dir, options): if options.native_file: properties['native_file'] = options.native_file - config['options'] = options.cmd_line_options + config['options'] = cmd_line_options_to_string(options) config['properties'] = properties with open(filename, 'w') as f: config.write(f) @@ -869,7 +876,7 @@ def update_cmd_line_file(build_dir, options): filename = get_cmd_line_file(build_dir) config = CmdLineFileParser() config.read(filename) - config['options'].update(options.cmd_line_options) + config['options'].update(cmd_line_options_to_string(options)) with open(filename, 'w') as f: config.write(f) @@ -1074,8 +1081,8 @@ builtin_options = OrderedDict([ ]) builtin_options_per_machine = OrderedDict([ - ('pkg_config_path', BuiltinOption(UserArrayOption, 'T.List of additional paths for pkg-config to search', [])), - ('cmake_prefix_path', BuiltinOption(UserArrayOption, 'T.List of additional prefixes for cmake to search', [])), + ('pkg_config_path', BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [])), + ('cmake_prefix_path', BuiltinOption(UserArrayOption, 'List of additional prefixes for cmake to search', [])), ]) # Special prefix-dependent defaults for installation directories that reside in diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 554d79b..eb626b0 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -47,7 +47,8 @@ from .linkers import ( CcrxDynamicLinker, ClangClDynamicLinker, DynamicLinker, - GnuDynamicLinker, + GnuBFDDynamicLinker, + GnuGoldDynamicLinker, LLVMDynamicLinker, MSVCDynamicLinker, OptlinkDynamicLinker, @@ -767,7 +768,7 @@ class Environment: if o.startswith('LLD'): if '(compatible with GNU linkers)' in o: return LLVMDynamicLinker( - compiler, for_machine, 'lld', comp_class.LINKER_PREFIX, + compiler, for_machine, comp_class.LINKER_PREFIX, override, version=search_version(o)) if value is not None: @@ -830,7 +831,7 @@ class Environment: v = search_version(o) if o.startswith('LLD'): linker = LLVMDynamicLinker( - compiler, for_machine, 'lld', comp_class.LINKER_PREFIX, override, version=v) # type: DynamicLinker + compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) # type: DynamicLinker elif e.startswith('lld-link: '): # Toolchain wrapper got in the way; this happens with e.g. https://github.com/mstorsjo/llvm-mingw # Let's try to extract the linker invocation command to grab the version. @@ -846,30 +847,29 @@ class Environment: _, o, e = Popen_safe([linker_cmd, '--version']) v = search_version(o) - linker = LLVMDynamicLinker(compiler, for_machine, 'lld', comp_class.LINKER_PREFIX, override, version=v) + linker = LLVMDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) # first is for apple clang, second is for real gcc, the third is icc elif e.endswith('(use -v to see invocation)\n') or 'macosx_version' in e or 'ld: unknown option:' in e: if isinstance(comp_class.LINKER_PREFIX, str): _, _, e = Popen_safe(compiler + [comp_class.LINKER_PREFIX + '-v'] + extra_args) else: _, _, e = Popen_safe(compiler + comp_class.LINKER_PREFIX + ['-v'] + extra_args) - i = 'APPLE ld' for line in e.split('\n'): if 'PROJECT:ld' in line: v = line.split('-')[1] break else: v = 'unknown version' - linker = AppleDynamicLinker(compiler, for_machine, i, comp_class.LINKER_PREFIX, override, version=v) + linker = AppleDynamicLinker(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) elif 'GNU' in o: if 'gold' in o: - i = 'GNU ld.gold' + cls = GnuGoldDynamicLinker else: - i = 'GNU ld.bfd' - linker = GnuDynamicLinker(compiler, for_machine, i, comp_class.LINKER_PREFIX, override, version=v) + cls = GnuBFDDynamicLinker + linker = cls(compiler, for_machine, comp_class.LINKER_PREFIX, override, version=v) elif 'Solaris' in e or 'Solaris' in o: linker = SolarisDynamicLinker( - compiler, for_machine, 'solaris', comp_class.LINKER_PREFIX, override, + compiler, for_machine, comp_class.LINKER_PREFIX, override, version=search_version(e)) else: raise EnvironmentException('Unable to determine dynamic linker') @@ -1061,7 +1061,7 @@ class Environment: if 'PGI Compilers' in out: cls = PGICCompiler if lang == 'c' else PGICPPCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) - linker = PGIDynamicLinker(compiler, for_machine, 'pgi', cls.LINKER_PREFIX, [], version=version) + linker = PGIDynamicLinker(compiler, for_machine, cls.LINKER_PREFIX, [], version=version) return cls( ccache + compiler, version, for_machine, is_cross, info, exe_wrap, linker=linker) @@ -1214,7 +1214,7 @@ class Environment: if 'PGI Compilers' in out: cls = PGIFortranCompiler self.coredata.add_lang_args(cls.language, cls, for_machine, self) - linker = PGIDynamicLinker(compiler, for_machine, 'pgi', + linker = PGIDynamicLinker(compiler, for_machine, cls.LINKER_PREFIX, [], version=version) return cls( compiler, version, for_machine, is_cross, info, exe_wrap, @@ -1413,7 +1413,7 @@ class Environment: linker = type(cc.linker)(for_machine, always_args, exelist=cc.linker.exelist, version=cc.linker.version, **extra_args) else: - linker = type(cc.linker)(compiler, for_machine, cc.linker.id, cc.LINKER_PREFIX, + linker = type(cc.linker)(compiler, for_machine, cc.LINKER_PREFIX, always_args=always_args, version=cc.linker.version, **extra_args) elif 'link' in override[0]: diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 310223a..84eb359 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -257,8 +257,8 @@ class DynamicLinker(metaclass=abc.ABCMeta): ret += self.prefix_arg + [arg] return ret - def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice, - id_: str, prefix_arg: T.Union[str, T.List[str]], + def __init__(self, id_: str, exelist: T.List[str], + for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]], always_args: T.List[str], *, version: str = 'unknown version'): self.exelist = exelist self.for_machine = for_machine @@ -570,6 +570,9 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): """Apple's ld implementation.""" + def __init__(self, *args, **kwargs): + super().__init__('ld64', *args, **kwargs) + def get_asneeded_args(self) -> T.List[str]: return self._apply_prefix('-dead_strip_dylibs') @@ -649,18 +652,29 @@ class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dynam """Representation of GNU ld.bfd and ld.gold.""" - pass + +class GnuGoldDynamicLinker(GnuDynamicLinker): + + def __init__(self, *args, **kwargs): + super().__init__('ld.gold', *args, **kwargs) + + +class GnuBFDDynamicLinker(GnuDynamicLinker): + + def __init__(self, *args, **kwargs): + super().__init__('ld.bfd', *args, **kwargs) class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker): - """Representation of LLVM's lld (not lld-link) linker. + """Representation of LLVM's ld.lld linker. - This is only the posix-like linker. + This is only the gnu-like linker, not the apple like or link.exe like + linkers. """ def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + super().__init__('ld.lld', *args, **kwargs) # Some targets don't seem to support this argument (windows, wasm, ...) _, _, e = mesonlib.Popen_safe(self.exelist + self._apply_prefix('--allow-shlib-undefined')) @@ -672,14 +686,13 @@ class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dyna return [] - class CcrxDynamicLinker(DynamicLinker): """Linker for Renesis CCrx compiler.""" def __init__(self, for_machine: mesonlib.MachineChoice, *, version: str = 'unknown version'): - super().__init__(['rlink.exe'], for_machine, 'rlink', '', [], + super().__init__('rlink', ['rlink.exe'], for_machine, '', [], version=version) def get_accepts_rsp(self) -> bool: @@ -712,7 +725,7 @@ class ArmDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): def __init__(self, for_machine: mesonlib.MachineChoice, *, version: str = 'unknown version'): - super().__init__(['armlink'], for_machine, 'armlink', '', [], + super().__init__('armlink', ['armlink'], for_machine, '', [], version=version) def get_accepts_rsp(self) -> bool: @@ -744,6 +757,9 @@ class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): """PGI linker.""" + def __init__(self, *args, **kwargs): + super().__init__('pgi', *args, **kwargs) + def get_allow_undefined_args(self) -> T.List[str]: return [] @@ -857,7 +873,7 @@ class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): prefix: T.Union[str, T.List[str]] = '', machine: str = 'x86', version: str = 'unknown version', direct: bool = True): - super().__init__(exelist or ['link.exe'], for_machine, 'link', + super().__init__('link', exelist or ['link.exe'], for_machine, prefix, always_args, machine=machine, version=version, direct=direct) def get_always_args(self) -> T.List[str]: @@ -873,7 +889,7 @@ class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): prefix: T.Union[str, T.List[str]] = '', machine: str = 'x86', version: str = 'unknown version', direct: bool = True): - super().__init__(exelist or ['lld-link.exe'], for_machine, 'lld-link', + super().__init__('lld-link', exelist or ['lld-link.exe'], for_machine, prefix, always_args, machine=machine, version=version, direct=direct) @@ -883,13 +899,16 @@ class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *, version: str = 'unknown version'): - super().__init__(['xilink.exe'], for_machine, 'xilink', '', always_args, version=version) + super().__init__('xilink', ['xilink.exe'], for_machine, '', always_args, version=version) class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): """Sys-V derived linker used on Solaris and OpenSolaris.""" + def __init__(self, *args, **kwargs): + super().__init__('ld.solaris', *args, **kwargs) + def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: if not args: return args @@ -940,13 +959,18 @@ class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): *, version: str = 'unknown version'): # Use optlink instead of link so we don't interfer with other link.exe # implementations. - super().__init__(['optlink.exe'], for_machine, 'optlink', '', [], version=version) + super().__init__('optlink', ['optlink.exe'], for_machine, '', [], version=version) def get_allow_undefined_args(self) -> T.List[str]: return [] + class CudaLinker(PosixDynamicLinkerMixin, DynamicLinker): """Cuda linker (nvlink)""" + + def __init__(self, *args, **kwargs): + super().__init__('nvlink', *args, **kwargs) + @staticmethod def parse_version(): version_cmd = ['nvlink', '--version'] diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index da0a60e..cfdae4f 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -266,7 +266,7 @@ class PkgConfigModule(ExtensionModule): def generate_pkgconfig_file(self, state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, - uninstalled=False): + uninstalled=False, dataonly=False): deps.remove_dups() coredata = state.environment.get_coredata() if uninstalled: @@ -283,12 +283,13 @@ class PkgConfigModule(ExtensionModule): incdir = PurePath(coredata.get_builtin_option('includedir')) fname = os.path.join(outdir, pcfile) with open(fname, 'w', encoding='utf-8') as ofile: - ofile.write('prefix={}\n'.format(self._escape(prefix))) - if uninstalled: - ofile.write('srcdir={}\n'.format(self._escape(srcdir))) - else: - ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) - ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) + if not dataonly: + ofile.write('prefix={}\n'.format(self._escape(prefix))) + if uninstalled: + ofile.write('srcdir={}\n'.format(self._escape(srcdir))) + else: + ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) + ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) if variables: ofile.write('\n') for k, v in variables: @@ -370,27 +371,28 @@ class PkgConfigModule(ExtensionModule): ofile.write('Libs: {}\n'.format(' '.join(generate_libs_flags(deps.pub_libs)))) if len(deps.priv_libs) > 0: ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(deps.priv_libs)))) + + def generate_compiler_flags(): + cflags_buf = [] + for f in deps.cflags: + cflags_buf.append(self._escape(f)) + return cflags_buf + + cflags = generate_compiler_flags() ofile.write('Cflags:') if uninstalled: ofile.write(' '.join(generate_uninstalled_cflags(deps.pub_libs + deps.priv_libs))) - else: - for h in subdirs: - ofile.write(' ') - if h == '.': - ofile.write('-I${includedir}') - else: - ofile.write(self._escape(PurePath('-I${includedir}') / h)) - for f in deps.cflags: - ofile.write(' ') - ofile.write(self._escape(f)) - ofile.write('\n') + elif not dataonly and cflags: + ofile.write('{}\n'.format(' '.join(cflags))) @FeatureNewKwargs('pkgconfig.generate', '0.54.0', ['uninstalled_variables']) @FeatureNewKwargs('pkgconfig.generate', '0.42.0', ['extra_cflags']) @FeatureNewKwargs('pkgconfig.generate', '0.41.0', ['variables']) + @FeatureNewKwargs('pkgconfig.generate', '0.54.0', ['dataonly']) @permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase', 'subdirs', 'requires', 'requires_private', 'libraries_private', - 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions'}) + 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions', + 'dataonly'}) def generate(self, state, args, kwargs): if 'variables' in kwargs: FeatureNew('custom pkgconfig variables', '0.41.0').use(state.subproject) @@ -399,6 +401,7 @@ class PkgConfigModule(ExtensionModule): default_description = None default_name = None mainlib = None + default_subdirs = ['.'] if not args and 'version' not in kwargs: FeatureNew('pkgconfig.generate implicit version keyword', '0.46.0').use(state.subproject) elif len(args) == 1: @@ -414,7 +417,14 @@ class PkgConfigModule(ExtensionModule): elif len(args) > 1: raise mesonlib.MesonException('Too many positional arguments passed to Pkgconfig_gen.') - subdirs = mesonlib.stringlistify(kwargs.get('subdirs', ['.'])) + dataonly = kwargs.get('dataonly', False) + if dataonly: + default_subdirs = [] + blocked_vars = ['libraries', 'libraries_private', 'require_private', 'extra_cflags', 'subdirs'] + if len(set(kwargs) & set(blocked_vars)) > 0: + raise mesonlib.MesonException('Cannot combine dataonly with any of {}'.format(blocked_vars)) + + subdirs = mesonlib.stringlistify(kwargs.get('subdirs', default_subdirs)) version = kwargs.get('version', default_version) if not isinstance(version, str): raise mesonlib.MesonException('Version must be specified.') @@ -440,6 +450,11 @@ class PkgConfigModule(ExtensionModule): libraries = [mainlib] + libraries deps = DependenciesHelper(state, filebase) + for d in subdirs: + if d == '.': + deps.add_cflags(['-I${includedir}']) + else: + deps.add_cflags(self._escape(PurePath('-I${includedir}') / d)) deps.add_pub_libs(libraries) deps.add_priv_libs(kwargs.get('libraries_private', [])) deps.add_pub_reqs(kwargs.get('requires', [])) @@ -488,13 +503,14 @@ class PkgConfigModule(ExtensionModule): if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, - version, pcfile, conflicts, variables) + version, pcfile, conflicts, variables, + False, dataonly) res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot) variables = parse_variable_list(mesonlib.stringlistify(kwargs.get('uninstalled_variables', []))) pcfile = filebase + '-uninstalled.pc' self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, - uninstalled=True) + uninstalled=True, dataonly=dataonly) # Associate the main library with this generated pc file. If the library # is used in any subsequent call to the generated, it will generate a # 'Requires:' or 'Requires.private:'. diff --git a/mesonbuild/msubprojects.py b/mesonbuild/msubprojects.py index d6f0715..b1c79b8 100755 --- a/mesonbuild/msubprojects.py +++ b/mesonbuild/msubprojects.py @@ -60,7 +60,7 @@ def update_git(wrap, repo_dir, options): git_output(['fetch'], repo_dir) git_output(['checkout', revision], repo_dir) except subprocess.CalledProcessError as e: - out = e.output.decode().strip() + out = e.output.strip() mlog.log(' -> Could not checkout revision', mlog.cyan(revision)) mlog.log(mlog.red(out)) mlog.log(mlog.red(str(e))) @@ -70,7 +70,7 @@ def update_git(wrap, repo_dir, options): # We are in the same branch, pull latest commits git_output(['-c', 'rebase.autoStash=true', 'pull', '--rebase'], repo_dir) except subprocess.CalledProcessError as e: - out = e.output.decode().strip() + out = e.output.strip() mlog.log(' -> Could not rebase', mlog.bold(repo_dir), 'please fix and try again.') mlog.log(mlog.red(out)) mlog.log(mlog.red(str(e))) @@ -83,7 +83,7 @@ def update_git(wrap, repo_dir, options): git_output(['fetch'], repo_dir) git_output(['-c', 'rebase.autoStash=true', 'rebase', revision], repo_dir) except subprocess.CalledProcessError as e: - out = e.output.decode().strip() + out = e.output.strip() mlog.log(' -> Could not rebase', mlog.bold(repo_dir), 'please fix and try again.') mlog.log(mlog.red(out)) mlog.log(mlog.red(str(e))) @@ -153,7 +153,7 @@ def checkout(wrap, repo_dir, options): git_output(cmd, repo_dir) git_show(repo_dir) except subprocess.CalledProcessError as e: - out = e.output.decode().strip() + out = e.output.strip() mlog.log(' -> ', mlog.red(out)) def download(wrap, repo_dir, options): diff --git a/run_unittests.py b/run_unittests.py index 7c2ae05..033647c 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -4896,6 +4896,11 @@ class DarwinTests(BasePlatformTests): self.build() self.install() + def test_removing_unused_linker_args(self): + testdir = os.path.join(self.common_test_dir, '108 has arg') + env = {'CFLAGS': '-L/tmp -L /var/tmp -headerpad_max_install_names -Wl,-export_dynamic'} + self.init(testdir, override_envvars=env) + @unittest.skipUnless(not is_windows(), "requires something Unix-like") class LinuxlikeTests(BasePlatformTests): @@ -4969,6 +4974,11 @@ class LinuxlikeTests(BasePlatformTests): self.assertEqual(foo_dep.get_pkgconfig_variable('foo', {}), 'bar') self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir', {}), '/usr/data') + libhello_nolib = PkgConfigDependency('libhello_nolib', env, kwargs) + self.assertTrue(libhello_nolib.found()) + self.assertEqual(libhello_nolib.get_link_args(), []) + self.assertEqual(libhello_nolib.get_compile_args(), []) + def test_pkgconfig_gen_deps(self): ''' Test that generated pkg-config files correctly handle dependencies @@ -5939,7 +5949,6 @@ class LinuxlikeTests(BasePlatformTests): ''' testdir = os.path.join(self.common_test_dir, testdir) subdir = os.path.join(testdir, subdir_path) - curdir = os.getcwd() with chdir(subdir): # Can't distribute broken symlinks in the source tree because it breaks # the creation of zipapps. Create it dynamically and run the test by @@ -6056,30 +6065,30 @@ c = ['{0}'] self.assertEqual(comp.linker.id, expected) def test_ld_environment_variable_bfd(self): - self._check_ld('ld.bfd', 'bfd', 'c', 'GNU ld.bfd') + self._check_ld('ld.bfd', 'bfd', 'c', 'ld.bfd') def test_ld_environment_variable_gold(self): - self._check_ld('ld.gold', 'gold', 'c', 'GNU ld.gold') + self._check_ld('ld.gold', 'gold', 'c', 'ld.gold') def test_ld_environment_variable_lld(self): - self._check_ld('ld.lld', 'lld', 'c', 'lld') + self._check_ld('ld.lld', 'lld', 'c', 'ld.lld') @skipIfNoExecutable('rustc') def test_ld_environment_variable_rust(self): - self._check_ld('ld.gold', 'gold', 'rust', 'GNU ld.gold') + self._check_ld('ld.gold', 'gold', 'rust', 'ld.gold') def test_ld_environment_variable_cpp(self): - self._check_ld('ld.gold', 'gold', 'cpp', 'GNU ld.gold') + self._check_ld('ld.gold', 'gold', 'cpp', 'ld.gold') def test_ld_environment_variable_objc(self): - self._check_ld('ld.gold', 'gold', 'objc', 'GNU ld.gold') + self._check_ld('ld.gold', 'gold', 'objc', 'ld.gold') def test_ld_environment_variable_objcpp(self): - self._check_ld('ld.gold', 'gold', 'objcpp', 'GNU ld.gold') + self._check_ld('ld.gold', 'gold', 'objcpp', 'ld.gold') @skipIfNoExecutable('gfortran') def test_ld_environment_variable_fortran(self): - self._check_ld('ld.gold', 'gold', 'fortran', 'GNU ld.gold') + self._check_ld('ld.gold', 'gold', 'fortran', 'ld.gold') def compute_sha256(self, filename): with open(filename, 'rb') as f: diff --git a/test cases/common/47 pkgconfig-gen/installed_files.txt b/test cases/common/47 pkgconfig-gen/installed_files.txt index 94de704..9e1a40a 100644 --- a/test cases/common/47 pkgconfig-gen/installed_files.txt +++ b/test cases/common/47 pkgconfig-gen/installed_files.txt @@ -2,3 +2,4 @@ usr/include/simple.h usr/lib/pkgconfig/simple.pc usr/lib/pkgconfig/libfoo.pc usr/lib/pkgconfig/libhello.pc +usr/lib/pkgconfig/libhello_nolib.pc
\ No newline at end of file diff --git a/test cases/common/47 pkgconfig-gen/meson.build b/test cases/common/47 pkgconfig-gen/meson.build index 09c46c5..c251b9f 100644 --- a/test cases/common/47 pkgconfig-gen/meson.build +++ b/test cases/common/47 pkgconfig-gen/meson.build @@ -51,3 +51,10 @@ pkgg.generate( description : 'A minimalistic pkgconfig file.', version : libver, ) + +pkgg.generate( + name : 'libhello_nolib', + description : 'A minimalistic pkgconfig file.', + version : libver, + dataonly: true +) diff --git a/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp b/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp new file mode 100644 index 0000000..a5f09be --- /dev/null +++ b/test cases/failing build/4 cmake subproject isolation/incDir/fileA.hpp @@ -0,0 +1,3 @@ +#pragma once + +#define SOME_DEFINE " World" diff --git a/test cases/failing build/4 cmake subproject isolation/main.cpp b/test cases/failing build/4 cmake subproject isolation/main.cpp new file mode 100644 index 0000000..9507961 --- /dev/null +++ b/test cases/failing build/4 cmake subproject isolation/main.cpp @@ -0,0 +1,10 @@ +#include <iostream> +#include <cmMod.hpp> + +using namespace std; + +int main(void) { + cmModClass obj("Hello"); + cout << obj.getStr() << endl; + return 0; +} diff --git a/test cases/failing build/4 cmake subproject isolation/meson.build b/test cases/failing build/4 cmake subproject isolation/meson.build new file mode 100644 index 0000000..e606335 --- /dev/null +++ b/test cases/failing build/4 cmake subproject isolation/meson.build @@ -0,0 +1,17 @@ +project('subproject isolation', ['c', 'cpp']) + +if not find_program('cmake', required: false).found() + error('MESON_SKIP_TEST CMake is not installed') +endif + +incdir = meson.source_root() / 'incDir' + +cm = import('cmake') + +# This should generate a warning and the include dir should be skipped. +sub_pro = cm.subproject('cmMod', cmake_options : [ '-DMESON_INC_DIR=' + incdir ]) +sub_dep = sub_pro.dependency('cmModLib++') + +# Since the include dir is skipped, the compilation of this project should fail. +exe1 = executable('main', ['main.cpp'], dependencies: [sub_dep]) +test('test1', exe1) diff --git a/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt new file mode 100644 index 0000000..852dd09 --- /dev/null +++ b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.5) + +project(cmMod) +set (CMAKE_CXX_STANDARD 14) + +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${MESON_INC_DIR}) + +add_library(cmModLib++ SHARED cmMod.cpp) +include(GenerateExportHeader) +generate_export_header(cmModLib++) diff --git a/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp new file mode 100644 index 0000000..a668203 --- /dev/null +++ b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.cpp @@ -0,0 +1,12 @@ +#include "cmMod.hpp" +#include "fileA.hpp" + +using namespace std; + +cmModClass::cmModClass(string foo) { + str = foo + SOME_DEFINE; +} + +string cmModClass::getStr() const { + return str; +} diff --git a/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp new file mode 100644 index 0000000..0e6dc04 --- /dev/null +++ b/test cases/failing build/4 cmake subproject isolation/subprojects/cmMod/cmMod.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "cmmodlib++_export.h" +#include <string> + +class CMMODLIB___EXPORT cmModClass { +private: + std::string str; + +public: + cmModClass(std::string foo); + + std::string getStr() const; +}; |