diff options
29 files changed, 379 insertions, 119 deletions
diff --git a/docs/markdown/Build-options.md b/docs/markdown/Build-options.md index 8b29afd..2d53e28 100644 --- a/docs/markdown/Build-options.md +++ b/docs/markdown/Build-options.md @@ -83,9 +83,9 @@ Currently supported in - `disabled` do not look for the dependency and always return 'not-found'. When getting the value of this type of option using `get_option()`, a special -object is returned instead of the string representation of the option's value. -That object has three methods returning boolean and taking no argument: -`enabled()`, `disabled()`, and `auto()`. +[feature option object](Reference-manual.md#feature-option-object) +is returned instead of the string representation of the option's value. +This object can be passed to `required`: ```meson d = dependency('foo', required : get_option('myfeature')) @@ -94,6 +94,21 @@ if d.found() endif ``` +To check the value of the feature, the object has three methods +returning a boolean and taking no argument: + +- `.enabled()` +- `.disabled()` +- `.auto()` + +This is useful for custom code depending on the feature: + +```meson +if get_option('myfeature').enabled() + # ... +endif +``` + If the value of a `feature` option is set to `auto`, that value is overridden by the global `auto_features` option (which defaults to `auto`). This is intended to be used by packagers who want to have full control on which dependencies are diff --git a/docs/markdown/CMake-module.md b/docs/markdown/CMake-module.md index a021396..a15e3c2 100644 --- a/docs/markdown/CMake-module.md +++ b/docs/markdown/CMake-module.md @@ -99,6 +99,8 @@ and supports the following methods: - `get_variable(name)` fetches the specified variable from inside the subproject. Usually `dependency()` or `target()` should be preferred to extract build targets. + - `found` returns true if the subproject is available, otherwise false + *new in in 0.53.2* ## CMake configuration files 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-manual.md b/docs/markdown/Reference-manual.md index 510d443..475b711 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -846,8 +846,10 @@ configuration as-is, which may be absolute, or relative to `prefix`. if you need the absolute path to one of these e.g. to use in a define etc., you should use `get_option('prefix') / get_option('localstatedir')` -For options of type `feature` a special object is returned instead of -a string. See [`feature` options](Build-options.md#features) +For options of type `feature` a +[feature option object](#feature-option-object) +is returned instead of a string. +See [`feature` options](Build-options.md#features) documentation for more details. ### get_variable() @@ -1226,7 +1228,7 @@ This function is used to summarize build configuration at the end of the build process. This function provides a way for projects (and subprojects) to report this information in a clear way. -The content is a serie of key/value pairs grouped into sections. If the section +The content is a series of key/value pairs grouped into sections. If the section keyword argument is omitted, those key/value pairs are implicitly grouped into a section with no title. key/value pairs can optionally be grouped into a dictionary, but keep in mind that dictionaries does not guarantee ordering. `key` must be string, @@ -1285,7 +1287,7 @@ My Project 1.0 The first argument to this function must be a string defining the name of this project. It is followed by programming languages that the project uses. Supported values for languages are `c`, `cpp` (for -`C++`), `d`, `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`), +`C++`), `cuda`, `d`, `objc`, `objcpp`, `fortran`, `java`, `cs` (for `C#`), `vala` and `rust`. Since version `0.40.0` the list of languages is optional. @@ -1718,8 +1720,11 @@ the following methods. given as an argument to be run during the install step, this script will have the environment variables `MESON_SOURCE_ROOT`, `MESON_BUILD_ROOT`, `MESON_INSTALL_PREFIX`, - `MESON_INSTALL_DESTDIR_PREFIX`, and `MESONINTROSPECT` set. All - additional arguments are passed as parameters. + `MESON_INSTALL_DESTDIR_PREFIX`, and `MESONINTROSPECT` set. + All positional arguments are passed as parameters. + + *(added 0.54)* If `meson install` is called with the `--quiet` option, the + environment variable `MESON_INSTALL_QUIET` will be set. Meson uses the `DESTDIR` environment variable as set by the inherited environment to determine the (temporary) installation @@ -2469,6 +2474,16 @@ library. This object has the following methods: object will only inherit other attributes from its parent as controlled by keyword arguments. +### Feature option object + +The following methods are defined for all [`feature` options](Build-options.md#features): + +- `enabled()` returns whether the feature was set to `'enabled'` +- `disabled()` returns whether the feature was set to `'disabled'` +- `auto()` returns whether the feature was set to `'auto'` + +Feature options are available since 0.47.0. + ### `generator` object This object is returned by [`generator()`](#generator) and contains a 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/minstall_quiet.md b/docs/markdown/snippets/minstall_quiet.md new file mode 100644 index 0000000..3a7ff31 --- /dev/null +++ b/docs/markdown/snippets/minstall_quiet.md @@ -0,0 +1,11 @@ +## New option `--quiet` to `meson install` + +Now you can run `meson install --quiet` and meson will not verbosely print +every file as it is being installed. As before, the full log is always +available inside the builddir in `meson-logs/install-log.txt`. + +When this option is passed, install scripts will have the environment variable +`MESON_INSTALL_QUIET` set. + +Numerous speed-ups were also made for the install step, especially on Windows +where it is now 300% to 1200% faster than before depending on your workload. 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 81844a0..4d87705 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -399,7 +399,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 03b1a33..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] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 720d064..11b8deb 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -850,6 +850,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 +863,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 +872,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) 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 dbd90b2..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,17 +652,38 @@ 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. """ - pass + def __init__(self, *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')) + self.has_allow_shlib_undefined = not ('unknown argument: --allow-shlib-undefined' in e) + + def get_allow_undefined_args(self) -> T.List[str]: + if self.has_allow_shlib_undefined: + return self._apply_prefix('--allow-shlib-undefined') + return [] class CcrxDynamicLinker(DynamicLinker): @@ -668,7 +692,7 @@ class CcrxDynamicLinker(DynamicLinker): 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: @@ -701,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: @@ -733,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 [] @@ -846,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]: @@ -862,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) @@ -872,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 @@ -929,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/minstall.py b/mesonbuild/minstall.py index cc6ea0a..64bcca2 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -13,6 +13,7 @@ # limitations under the License. import sys, pickle, os, shutil, subprocess, errno +import argparse import shlex from glob import glob from .scripts import depfixer @@ -35,10 +36,14 @@ selinux_updates = [] def add_arguments(parser): parser.add_argument('-C', default='.', dest='wd', help='directory to cd into before running') + parser.add_argument('--profile-self', action='store_true', dest='profile', + help=argparse.SUPPRESS) parser.add_argument('--no-rebuild', default=False, action='store_true', help='Do not rebuild before installing.') parser.add_argument('--only-changed', default=False, action='store_true', help='Only overwrite files that are older than the copied file.') + parser.add_argument('--quiet', default=False, action='store_true', + help='Do not print every file that was installed.') class DirMaker: def __init__(self, lf): @@ -216,6 +221,10 @@ class Installer: self.lf = lf self.preserved_file_count = 0 + def log(self, msg): + if not self.options.quiet: + print(msg) + def should_preserve_existing_file(self, from_file, to_file): if not self.options.only_changed: return False @@ -226,7 +235,7 @@ class Installer: to_time = os.stat(to_file).st_mtime return from_time <= to_time - def do_copyfile(self, from_file, to_file): + def do_copyfile(self, from_file, to_file, makedirs=None): outdir = os.path.split(to_file)[0] if not os.path.isfile(from_file) and not os.path.islink(from_file): raise RuntimeError('Tried to install something that isn\'t a file:' @@ -243,7 +252,12 @@ class Installer: self.preserved_file_count += 1 return False os.remove(to_file) - print('Installing %s to %s' % (from_file, outdir)) + elif makedirs: + # Unpack tuple + dirmaker, outdir = makedirs + # Create dirs if needed + dirmaker.makedirs(outdir, exist_ok=True) + self.log('Installing %s to %s' % (from_file, outdir)) if os.path.islink(from_file): if not os.path.exists(from_file): # Dangling symlink. Replicate as is. @@ -318,6 +332,7 @@ class Installer: abs_dst = os.path.join(dst_dir, filepart) if os.path.isdir(abs_dst): print('Tried to copy file %s but a directory of that name already exists.' % abs_dst) + sys.exit(1) parent_dir = os.path.dirname(abs_dst) if not os.path.isdir(parent_dir): os.mkdir(parent_dir) @@ -347,10 +362,10 @@ class Installer: restore_selinux_contexts() self.run_install_script(d) if not self.did_install_something: - print('Nothing to install.') - if self.preserved_file_count > 0: - print('Preserved {} unchanged files, see {} for the full list' - .format(self.preserved_file_count, os.path.normpath(self.lf.name))) + self.log('Nothing to install.') + if not self.options.quiet and self.preserved_file_count > 0: + self.log('Preserved {} unchanged files, see {} for the full list' + .format(self.preserved_file_count, os.path.normpath(self.lf.name))) except PermissionError: if shutil.which('pkexec') is not None and 'PKEXEC_UID' not in os.environ: print('Installation failed due to insufficient permissions.') @@ -364,42 +379,39 @@ class Installer: for (src_dir, dst_dir, mode, exclude) in d.install_subdirs: self.did_install_something = True full_dst_dir = get_destdir_path(d, dst_dir) - print('Installing subdir %s to %s' % (src_dir, full_dst_dir)) + self.log('Installing subdir %s to %s' % (src_dir, full_dst_dir)) d.dirmaker.makedirs(full_dst_dir, exist_ok=True) self.do_copydir(d, src_dir, full_dst_dir, exclude, mode) def install_data(self, d): for i in d.data: - self.did_install_something = True fullfilename = i[0] outfilename = get_destdir_path(d, i[1]) mode = i[2] outdir = os.path.dirname(outfilename) - d.dirmaker.makedirs(outdir, exist_ok=True) - self.do_copyfile(fullfilename, outfilename) + if self.do_copyfile(fullfilename, outfilename, makedirs=(d.dirmaker, outdir)): + self.did_install_something = True set_mode(outfilename, mode, d.install_umask) def install_man(self, d): for m in d.man: - self.did_install_something = True full_source_filename = m[0] outfilename = get_destdir_path(d, m[1]) outdir = os.path.dirname(outfilename) - d.dirmaker.makedirs(outdir, exist_ok=True) install_mode = m[2] - self.do_copyfile(full_source_filename, outfilename) + if self.do_copyfile(full_source_filename, outfilename, makedirs=(d.dirmaker, outdir)): + self.did_install_something = True set_mode(outfilename, install_mode, d.install_umask) def install_headers(self, d): for t in d.headers: - self.did_install_something = True fullfilename = t[0] fname = os.path.basename(fullfilename) outdir = get_destdir_path(d, t[1]) outfilename = os.path.join(outdir, fname) install_mode = t[2] - d.dirmaker.makedirs(outdir, exist_ok=True) - self.do_copyfile(fullfilename, outfilename) + if self.do_copyfile(fullfilename, outfilename, makedirs=(d.dirmaker, outdir)): + self.did_install_something = True set_mode(outfilename, install_mode, d.install_umask) def run_install_script(self, d): @@ -409,6 +421,8 @@ class Installer: 'MESON_INSTALL_DESTDIR_PREFIX': d.fullprefix, 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in d.mesonintrospect]), } + if self.options.quiet: + env['MESON_INSTALL_QUIET'] = '1' child_env = os.environ.copy() child_env.update(env) @@ -418,7 +432,7 @@ class Installer: script = i['exe'] args = i['args'] name = ' '.join(script + args) - print('Running custom install script {!r}'.format(name)) + self.log('Running custom install script {!r}'.format(name)) try: rc = subprocess.call(script + args, env=child_env) if rc != 0: @@ -429,14 +443,14 @@ class Installer: def install_targets(self, d): for t in d.targets: - self.did_install_something = True if not os.path.exists(t.fname): # For example, import libraries of shared modules are optional if t.optional: - print('File {!r} not found, skipping'.format(t.fname)) + self.log('File {!r} not found, skipping'.format(t.fname)) continue else: raise RuntimeError('File {!r} could not be found'.format(t.fname)) + file_copied = False # not set when a directory is copied fname = check_for_stampfile(t.fname) outdir = get_destdir_path(d, t.outdir) outname = os.path.join(outdir, os.path.basename(fname)) @@ -446,17 +460,16 @@ class Installer: install_rpath = t.install_rpath install_name_mappings = t.install_name_mappings install_mode = t.install_mode - d.dirmaker.makedirs(outdir, exist_ok=True) if not os.path.exists(fname): raise RuntimeError('File {!r} could not be found'.format(fname)) elif os.path.isfile(fname): - self.do_copyfile(fname, outname) + file_copied = self.do_copyfile(fname, outname, makedirs=(d.dirmaker, outdir)) set_mode(outname, install_mode, d.install_umask) if should_strip and d.strip_bin is not None: if fname.endswith('.jar'): - print('Not stripping jar target:', os.path.basename(fname)) + self.log('Not stripping jar target:', os.path.basename(fname)) continue - print('Stripping target {!r} using {}.'.format(fname, d.strip_bin[0])) + self.log('Stripping target {!r} using {}.'.format(fname, d.strip_bin[0])) ps, stdo, stde = Popen_safe(d.strip_bin + [outname]) if ps.returncode != 0: print('Could not strip file.\n') @@ -469,10 +482,11 @@ class Installer: wasm_source = os.path.splitext(fname)[0] + '.wasm' if os.path.exists(wasm_source): wasm_output = os.path.splitext(outname)[0] + '.wasm' - self.do_copyfile(wasm_source, wasm_output) + file_copied = self.do_copyfile(wasm_source, wasm_output) elif os.path.isdir(fname): fname = os.path.join(d.build_dir, fname.rstrip('/')) outname = os.path.join(outdir, os.path.basename(fname)) + d.dirmaker.makedirs(outdir, exist_ok=True) self.do_copydir(d, fname, outname, None, install_mode) else: raise RuntimeError('Unknown file type for {!r}'.format(fname)) @@ -491,7 +505,8 @@ class Installer: print("Symlink creation does not work on this platform. " "Skipping all symlinking.") printed_symlink_error = True - if os.path.isfile(outname): + if file_copied: + self.did_install_something = True try: depfixer.fix_rpath(outname, install_rpath, final_path, install_name_mappings, verbose=False) @@ -515,5 +530,10 @@ def run(opts): installer = Installer(opts, lf) append_to_log(lf, '# List of files installed by Meson') append_to_log(lf, '# Does not contain files installed by custom scripts.') - installer.do_install(datafilename) + if opts.profile: + import cProfile as profile + fname = os.path.join(private_dir, 'profile-installer.log') + profile.runctx('installer.do_install(datafilename)', globals(), locals(), filename=fname) + else: + installer.do_install(datafilename) return 0 diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 21f144f..6c4098b 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -18,7 +18,7 @@ import shutil from . import ExtensionModule, ModuleReturnValue from .. import build, dependencies, mesonlib, mlog -from ..interpreterbase import permittedKwargs, FeatureNew, stringArgs, InterpreterObject, ObjectHolder +from ..interpreterbase import permittedKwargs, FeatureNew, stringArgs, InterpreterObject, ObjectHolder, noPosargs from ..interpreter import ConfigurationDataHolder, InterpreterException, SubprojectHolder @@ -66,6 +66,7 @@ class CMakeSubprojectHolder(InterpreterObject, ObjectHolder): 'target': self.target, 'target_type': self.target_type, 'target_list': self.target_list, + 'found': self.found_method, }) def _args_to_info(self, args): @@ -105,12 +106,18 @@ class CMakeSubprojectHolder(InterpreterObject, ObjectHolder): info = self._args_to_info(args) return info['func'] + @noPosargs @permittedKwargs({}) def target_list(self, args, kwargs): - if len(args) > 0: - raise InterpreterException('target_list does not take any parameters.') return self.held_object.cm_interpreter.target_list() + @noPosargs + @permittedKwargs({}) + @FeatureNew('CMakeSubproject.found()', '0.53.2') + def found_method(self, args, kwargs): + return self.held_object is not None + + class CmakeModule(ExtensionModule): cmake_detected = False cmake_root = None 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/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index 5be7d40..5ba3a97 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -26,6 +26,9 @@ DT_STRTAB = 5 DT_SONAME = 14 DT_MIPS_RLD_MAP_REL = 1879048245 +# Global cache for tools +INSTALL_NAME_TOOL = False + class DataSizes: def __init__(self, ptrsize, is_le): if is_le: @@ -428,11 +431,11 @@ def fix_jar(fname): subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF']) def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True): - # Static libraries never have rpaths - if fname.endswith('.a'): - return - # DLLs and EXE never have rpaths - if fname.endswith('.dll') or fname.endswith('.exe'): + global INSTALL_NAME_TOOL + # Static libraries, import libraries, debug information, headers, etc + # never have rpaths + # DLLs and EXE currently do not need runtime path fixing + if fname.endswith(('.a', '.lib', '.pdb', '.h', '.hpp', '.dll', '.exe')): return try: if fname.endswith('.jar'): @@ -445,5 +448,11 @@ def fix_rpath(fname, new_rpath, final_path, install_name_mappings, verbose=True) pass else: raise - if shutil.which('install_name_tool'): + # We don't look for this on import because it will do a useless PATH lookup + # on non-mac platforms. That can be expensive on some Windows machines + # (upto 30ms), which is significant with --only-changed. For details, see: + # https://github.com/mesonbuild/meson/pull/6612#discussion_r378581401 + if INSTALL_NAME_TOOL is False: + INSTALL_NAME_TOOL = shutil.which('install_name_tool') + if INSTALL_NAME_TOOL: fix_darwin(fname, new_rpath, final_path, install_name_mappings) diff --git a/run_unittests.py b/run_unittests.py index 56618df..033647c 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -4974,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 @@ -6060,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/cmake/1 basic/meson.build b/test cases/cmake/1 basic/meson.build index 8e1671a..19c87c4 100644 --- a/test cases/cmake/1 basic/meson.build +++ b/test cases/cmake/1 basic/meson.build @@ -5,6 +5,7 @@ cm = import('cmake') sub_pro = cm.subproject('cmMod') sub_dep = sub_pro.dependency('cmModLib++') +assert(sub_pro.found(), 'found() method reports not found, but should be found') assert(sub_pro.target_list() == ['cmModLib++'], 'There should be exactly one target') assert(sub_pro.target_type('cmModLib++') == 'shared_library', 'Target type should be shared_library') diff --git a/test cases/cmake/9 disabled subproject/meson.build b/test cases/cmake/9 disabled subproject/meson.build index ba38410..c153fa3 100644 --- a/test cases/cmake/9 disabled subproject/meson.build +++ b/test cases/cmake/9 disabled subproject/meson.build @@ -2,4 +2,5 @@ project('cmakeSubTest', ['c', 'cpp']) cm = import('cmake') -sub_pro = cm.subproject('nothinig', required: false)
\ No newline at end of file +sub_pro = cm.subproject('nothinig', required: false) +assert(not sub_pro.found(), 'subproject found() reports wrong value') 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; +}; |