diff options
21 files changed, 284 insertions, 126 deletions
diff --git a/docs/markdown/FAQ.md b/docs/markdown/FAQ.md index 7a41443..4ea4d8d 100644 --- a/docs/markdown/FAQ.md +++ b/docs/markdown/FAQ.md @@ -500,3 +500,36 @@ meson -Dcpp_eh=none -Dcpp_rtti=false <other options> ``` The RTTI option is only available since Meson version 0.53.0. + +## Should I check for `buildtype` or individual options like `debug` in my build files? + +This depends highly on what you actually need to happen. The +´buildtype` option is meant do describe the current build's +_intent_. That is, what it will be used for. Individual options are +for determining what the exact state is. This becomes clearer with a +few examples. + +Suppose you have a source file that is known to miscompile when using +`-O3` and requires a workaround. Then you'd write something like this: + +```meson +if get_option('optimization') == '3' + add_project_arguments('-DOPTIMIZATION_WORKAROUND', ...) +endif +``` + +On the other hand if your project has extra logging and sanity checks +that you would like to be enabled during the day to day development +work (which uses the `debug` buildtype), you'd do this instead: + +```meson +if get_option('buildtype') == 'debug' + add_project_arguments('-DENABLE_EXTRA_CHECKS', ...) +endif +``` + +In this way the extra options are automatically used during +development but are not compiled in release builds. Note that (since +Meson 0.57.0) you can set optimization to, say, 2 in your debug builds +if you want to. If you tried to set this flag based on optimization +level, it would fail in this case. diff --git a/docs/markdown/snippets/buildtyperemains.md b/docs/markdown/snippets/buildtyperemains.md new file mode 100644 index 0000000..4eb6243 --- /dev/null +++ b/docs/markdown/snippets/buildtyperemains.md @@ -0,0 +1,10 @@ +## Buildtype remains even if dependent options are changed + +Setting the `buildtype' option to a value sets the `debug` and +`optimization` options to predefined values. Traditionally setting the +options to other values would then change the buildtype to `custom`. +This is confusing and means that you can't use, for example, debug +level `g` in `debug` buildtype even though it would make sense under +many circumstances. Starting with the buildtype is only changed when +the user explicitly sets it. Setting the build type sets the other +options to their default values as before.
\ No newline at end of file diff --git a/docs/markdown/snippets/msvc_no_zi.md b/docs/markdown/snippets/msvc_no_zi.md new file mode 100644 index 0000000..711598d --- /dev/null +++ b/docs/markdown/snippets/msvc_no_zi.md @@ -0,0 +1,14 @@ +## "Edit and continue" (/ZI) is no longer used by default for Visual Studio + +Meson was adding the `/ZI` compiler argument as an argument for Visual Studio +in debug mode. This enables the `edit-and-continue` debugging in +Visual Studio IDE's. + +Unfortunately, it is also extremely expensive and breaks certain use cases such +as link time code generation. Edit and continue can be enabled by manually by +adding `/ZI` to compiler arguments. + +The `/ZI` argument has now been replaced by the `/Zi` argument for debug builds. + +If this is an important issue for you and would like a builtin toggle option, +please file an issue in the Meson bug tracker.
\ No newline at end of file diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 92e6c15..ced1d7d 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -717,15 +717,16 @@ class Backend: commands += compiler.get_buildtype_args(self.get_option_for_target(OptionKey('buildtype'), target)) commands += compiler.get_optimization_args(self.get_option_for_target(OptionKey('optimization'), target)) commands += compiler.get_debug_args(self.get_option_for_target(OptionKey('debug'), target)) - # MSVC debug builds have /ZI argument by default and /Zi is added with debug flag - # /ZI needs to be removed in that case to avoid cl's warning to that effect (D9025 : overriding '/ZI' with '/Zi') - if ('/ZI' in commands) and ('/Zi' in commands): - commands.remove('/Zi') # Add compile args added using add_project_arguments() commands += self.build.get_project_args(compiler, target.subproject, target.for_machine) # Add compile args added using add_global_arguments() # These override per-project arguments commands += self.build.get_global_args(compiler, target.for_machine) + # Using both /ZI and /Zi at the same times produces a compiler warning. + # We do not add /ZI by default. If it is being used it is because the user has explicitly enabled it. + # /ZI needs to be removed in that case to avoid cl's warning to that effect (D9025 : overriding '/ZI' with '/Zi') + if ('/ZI' in commands) and ('/Zi' in commands): + commands.remove('/Zi') # Compile args added from the env: CFLAGS/CXXFLAGS, etc, or the cross # file. We want these to override all the defaults, but not the # per-target compile args. diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index d66708c..400433f 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -45,7 +45,7 @@ from ..mesonlib import ( ) from ..mesonlib import get_compiler_for_source, has_path_sep, OptionKey from .backends import CleanTrees -from ..build import InvalidArguments +from ..build import GeneratedList, InvalidArguments from ..interpreter import Interpreter if T.TYPE_CHECKING: @@ -691,13 +691,6 @@ int dummy; src_block['sources'] += sources src_block['generated_sources'] += generated_sources - def is_rust_target(self, target): - if len(target.sources) > 0: - first_file = target.sources[0] - if first_file.fname.endswith('.rs'): - return True - return False - def generate_target(self, target): try: if isinstance(target, build.BuildTarget): @@ -723,7 +716,7 @@ int dummy; if isinstance(target, build.Jar): self.generate_jar_target(target) return - if self.is_rust_target(target): + if target.uses_rust(): self.generate_rust_target(target) return if 'cs' in target.compilers: @@ -1588,12 +1581,27 @@ int dummy; args = rustc.compiler_args() # Compiler args for compiling this target args += compilers.get_base_compile_args(base_proxy, rustc) + self.generate_generator_list_rules(target) + + orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] + main_rust_file = None for i in target.get_sources(): if not rustc.can_compile(i): raise InvalidArguments('Rust target {} contains a non-rust source file.'.format(target.get_basename())) if main_rust_file is None: main_rust_file = i.rel_to_builddir(self.build_to_src) + for g in target.get_generated_sources(): + for i in g.get_outputs(): + if not rustc.can_compile(i): + raise InvalidArguments('Rust target {} contains a non-rust source file.'.format(target.get_basename())) + if isinstance(g, GeneratedList): + fname = os.path.join(self.get_target_private_dir(target), i) + else: + fname = i + if main_rust_file is None: + main_rust_file = fname + orderdeps.append(fname) if main_rust_file is None: raise RuntimeError('A Rust target has no Rust sources. This is weird. Also a bug. Please report') target_name = os.path.join(target.subdir, target.get_filename()) @@ -1631,7 +1639,6 @@ int dummy; args += target.get_extra_args('rust') args += rustc.get_output_args(os.path.join(target.subdir, target.get_filename())) args += self.environment.coredata.get_external_args(target.for_machine, rustc.language) - orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets] linkdirs = OrderedDict() for d in target.link_targets: linkdirs[d.subdir] = True @@ -1678,7 +1685,7 @@ int dummy; args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')] compiler_name = self.get_compiler_rule_name('rust', target.for_machine) element = NinjaBuildElement(self.all_outputs, target_name, compiler_name, main_rust_file) - if len(orderdeps) > 0: + if orderdeps: element.add_orderdep(orderdeps) element.add_item('ARGS', args) element.add_item('targetdep', depfile) @@ -2897,6 +2904,26 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) # Now we will add libraries and library paths from various sources + # Set runtime-paths so we can run executables without needing to set + # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows. + if has_path_sep(target.name): + # Target names really should not have slashes in them, but + # unfortunately we did not check for that and some downstream projects + # now have them. Once slashes are forbidden, remove this bit. + target_slashname_workaround_dir = os.path.join( + os.path.dirname(target.name), + self.get_target_dir(target)) + else: + target_slashname_workaround_dir = self.get_target_dir(target) + (rpath_args, target.rpath_dirs_to_remove) = ( + linker.build_rpath_args(self.environment, + self.environment.get_build_dir(), + target_slashname_workaround_dir, + self.determine_rpath_dirs(target), + target.build_rpath, + target.install_rpath)) + commands += rpath_args + # Add link args to link to all internal libraries (link_with:) and # internal dependencies needed by this target. if linker_base == 'STATIC': @@ -2944,25 +2971,6 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) dep_targets = [] dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal)) - # Set runtime-paths so we can run executables without needing to set - # LD_LIBRARY_PATH, etc in the environment. Doesn't work on Windows. - if has_path_sep(target.name): - # Target names really should not have slashes in them, but - # unfortunately we did not check for that and some downstream projects - # now have them. Once slashes are forbidden, remove this bit. - target_slashname_workaround_dir = os.path.join( - os.path.dirname(target.name), - self.get_target_dir(target)) - else: - target_slashname_workaround_dir = self.get_target_dir(target) - (rpath_args, target.rpath_dirs_to_remove) = ( - linker.build_rpath_args(self.environment, - self.environment.get_build_dir(), - target_slashname_workaround_dir, - self.determine_rpath_dirs(target), - target.build_rpath, - target.install_rpath)) - commands += rpath_args # Add libraries generated by custom targets custom_target_libraries = self.get_custom_target_provided_libraries(target) commands += extra_args diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 017b0f0..13783d1 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -569,7 +569,7 @@ class BuildTarget(Target): unity_opt = environment.coredata.get_option(OptionKey('unity')) self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '') self.environment = environment - self.sources = [] + self.sources: T.List[File] = [] self.compilers = OrderedDict() # type: OrderedDict[str, Compiler] self.objects = [] self.external_deps = [] @@ -588,7 +588,7 @@ class BuildTarget(Target): self.need_install = False self.pch = {} self.extra_args: T.Dict[str, T.List['FileOrString']] = {} - self.generated = [] + self.generated: T.Sequence[T.Union[GeneratedList, CustomTarget, CustomTargetIndex]] = [] self.d_features = {} self.pic = False self.pie = False @@ -1412,9 +1412,16 @@ You probably should put it in link_with instead.''') m = 'Could not get a dynamic linker for build target {!r}' raise AssertionError(m.format(self.name)) - def get_using_rustc(self) -> bool: + def uses_rust(self) -> bool: """Is this target a rust target.""" - return self.sources and self.sources[0].fname.endswith('.rs') + if self.sources: + first_file = self.sources[0] + if first_file.fname.endswith('.rs'): + return True + elif self.generated: + if self.generated[0].get_outputs()[0].endswith('.rs'): + return True + return False def get_using_msvc(self): ''' @@ -1434,11 +1441,13 @@ You probably should put it in link_with instead.''') 2. If the target contains only objects, process_compilers guesses and picks the first compiler that smells right. ''' - compiler, _ = self.get_clink_dynamic_linker_and_stdlibs() + # Rustc can use msvc style linkers + if self.uses_rust(): + compiler = self.environment.coredata.compilers[self.for_machine]['rust'] + else: + compiler, _ = self.get_clink_dynamic_linker_and_stdlibs() # Mixing many languages with MSVC is not supported yet so ignore stdlibs. - if compiler and compiler.get_linker_id() in {'link', 'lld-link', 'xilink', 'optlink'}: - return True - return False + return compiler and compiler.get_linker_id() in {'link', 'lld-link', 'xilink', 'optlink'} def check_module_linking(self): ''' @@ -1687,7 +1696,7 @@ class Executable(BuildTarget): self.import_filename = self.gcc_import_filename if m.is_windows() and ('cs' in self.compilers or - self.get_using_rustc() or + self.uses_rust() or self.get_using_msvc()): self.debug_filename = self.name + '.pdb' @@ -1877,7 +1886,7 @@ class SharedLibrary(BuildTarget): suffix = 'dll' self.vs_import_filename = '{0}{1}.lib'.format(self.prefix if self.prefix is not None else '', self.name) self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name) - if self.get_using_rustc(): + if self.uses_rust(): # Shared library is of the form foo.dll prefix = '' # Import library is called foo.dll.lib diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index 92f4fcd..61ee7cf 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -62,14 +62,14 @@ vs64_instruction_set_args = { msvc_buildtype_args = { 'plain': [], - 'debug': ["/ZI", "/RTC1"], + 'debug': ["/RTC1"], 'debugoptimized': [], 'release': [], 'minsize': [], 'custom': [], } # type: T.Dict[str, T.List[str]] -# Clang-cl doesn't have /ZI, and /Zi and /Z7 do the same thing +# Clang-cl /Zi and /Z7 do the same thing # quoting the docs (https://clang.llvm.org/docs/MSVCCompatibility.html): # # Clang emits relatively complete CodeView debug information if /Z7 or /Zi is diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 39da863..211efec 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -582,8 +582,35 @@ class CoreData: if key.name == 'buildtype': self._set_others_from_buildtype(value) - elif key.name in {'debug', 'optimization'}: - self._set_buildtype_from_others() + + def get_nondefault_buildtype_args(self): + result= [] + value = self.options[OptionKey('buildtype')].value + if value == 'plain': + opt = '0' + debug = False + elif value == 'debug': + opt = '0' + debug = True + elif value == 'debugoptimized': + opt = '2' + debug = True + elif value == 'release': + opt = '3' + debug = False + elif value == 'minsize': + opt = 's' + debug = True + else: + assert(value == 'custom') + return [] + actual_opt = self.options[OptionKey('optimization')].value + actual_debug = self.options[OptionKey('debug')].value + if actual_opt != opt: + result.append(('optimization', actual_opt, opt)) + if actual_debug != debug: + result.append(('debug', actual_debug, debug)) + return result def _set_others_from_buildtype(self, value: str) -> None: if value == 'plain': @@ -607,23 +634,6 @@ class CoreData: self.options[OptionKey('optimization')].set_value(opt) self.options[OptionKey('debug')].set_value(debug) - def _set_buildtype_from_others(self) -> None: - opt = self.options[OptionKey('optimization')].value - debug = self.options[OptionKey('debug')].value - if opt == '0' and not debug: - mode = 'plain' - elif opt == '0' and debug: - mode = 'debug' - elif opt == '2' and debug: - mode = 'debugoptimized' - elif opt == '3' and not debug: - mode = 'release' - elif opt == 's' and debug: - mode = 'minsize' - else: - mode = 'custom' - self.options[OptionKey('buildtype')].set_value(mode) - @staticmethod def is_per_machine_option(optname: OptionKey) -> bool: if optname.name in BUILTIN_OPTIONS_PER_MACHINE: diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index 686a336..5233d88 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -243,6 +243,17 @@ class Conf: print('') print_default_values_warning() + self.print_nondefault_buildtype_options() + + def print_nondefault_buildtype_options(self): + mismatching = self.coredata.get_nondefault_buildtype_args() + if not mismatching: + return + print("\nThe following option(s) have a different value than the build type default\n") + print(f' current default') + for m in mismatching: + print(f'{m[0]:21}{m[1]:10}{m[2]:10}') + def run(options): coredata.parse_cmd_line_options(options) builddir = os.path.abspath(os.path.realpath(options.builddir)) diff --git a/mesonbuild/modules/unstable_external_project.py b/mesonbuild/modules/unstable_external_project.py index 1604e25..e2205e5 100644 --- a/mesonbuild/modules/unstable_external_project.py +++ b/mesonbuild/modules/unstable_external_project.py @@ -162,12 +162,17 @@ class ExternalProject(InterpreterObject): def _run(self, step: str, command: T.List[str]): mlog.log('External project {}:'.format(self.name), mlog.bold(step)) - output = None if self.verbose else subprocess.DEVNULL + log_filename = Path(mlog.log_dir, '{}-{}.log'.format(self.name, step)) + output = None + if not self.verbose: + output = open(log_filename, 'w') p, o, e = Popen_safe(command, cwd=str(self.build_dir), env=self.run_env, stderr=subprocess.STDOUT, stdout=output) if p.returncode != 0: - m = '{} step failed:\n{}'.format(step, e) + m = '{} step returned error code {}.'.format(step, p.returncode) + if not self.verbose: + m += '\nSee logs: ' + str(log_filename) raise MesonException(m) def _create_targets(self): diff --git a/mesonbuild/modules/unstable_rust.py b/mesonbuild/modules/unstable_rust.py index 02369b6..d215376 100644 --- a/mesonbuild/modules/unstable_rust.py +++ b/mesonbuild/modules/unstable_rust.py @@ -85,7 +85,7 @@ class RustModule(ExtensionModule): base_target: BuildTarget = unholder(args[1]) if not isinstance(base_target, BuildTarget): raise InterpreterException('Second positional argument to rustmod.test() must be a library or executable') - if not base_target.get_using_rustc(): + if not base_target.uses_rust(): raise InterpreterException('Second positional argument to rustmod.test() must be a rust based target') extra_args = stringlistify(kwargs.get('args', [])) diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index bb153c5..34e58e3 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -114,11 +114,11 @@ class PackageDefinition: def parse_wrap(self) -> None: try: - self.config = configparser.ConfigParser(interpolation=None) - self.config.read(self.filename) + config = configparser.ConfigParser(interpolation=None) + config.read(self.filename) except configparser.Error as e: raise WrapException('Failed to parse {}: {}'.format(self.basename, str(e))) - self.parse_wrap_section() + self.parse_wrap_section(config) if self.type == 'redirect': # [wrap-redirect] have a `filename` value pointing to the real wrap # file we should parse instead. It must be relative to the current @@ -140,21 +140,21 @@ class PackageDefinition: self.filename = str(fname) self.parse_wrap() return - self.parse_provide_section() + self.parse_provide_section(config) - def parse_wrap_section(self) -> None: - if len(self.config.sections()) < 1: + def parse_wrap_section(self, config: configparser.ConfigParser) -> None: + if len(config.sections()) < 1: raise WrapException('Missing sections in {}'.format(self.basename)) - self.wrap_section = self.config.sections()[0] + self.wrap_section = config.sections()[0] if not self.wrap_section.startswith('wrap-'): m = '{!r} is not a valid first section in {}' raise WrapException(m.format(self.wrap_section, self.basename)) self.type = self.wrap_section[5:] - self.values = dict(self.config[self.wrap_section]) + self.values = dict(config[self.wrap_section]) - def parse_provide_section(self) -> None: - if self.config.has_section('provide'): - for k, v in self.config['provide'].items(): + def parse_provide_section(self, config: configparser.ConfigParser) -> None: + if config.has_section('provide'): + for k, v in config['provide'].items(): if k == 'dependency_names': # A comma separated list of dependency names that does not # need a variable name diff --git a/run_unittests.py b/run_unittests.py index e40ebc4..da6d329 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -3378,7 +3378,7 @@ class AllPlatformTests(BasePlatformTests): self.assertFalse(os.path.isdir(scommondir)) self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'scommon'], cwd=workdir, - stdout=subprocess.DEVNULL), 0) + stderr=subprocess.DEVNULL), 0) self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'invalid/path/to/scommon'], cwd=workdir, stderr=subprocess.DEVNULL), 0) @@ -3401,7 +3401,7 @@ class AllPlatformTests(BasePlatformTests): ambiguous_wrap = os.path.join(spdir, 'ambiguous.wrap') self.assertNotEqual(subprocess.call(self.wrap_command + ['promote', 'ambiguous'], cwd=workdir, - stdout=subprocess.DEVNULL), 0) + stderr=subprocess.DEVNULL), 0) self.assertFalse(os.path.isfile(ambiguous_wrap)) subprocess.check_call(self.wrap_command + ['promote', 'subprojects/s2/subprojects/ambiguous.wrap'], cwd=workdir) self.assertTrue(os.path.isfile(ambiguous_wrap)) @@ -3929,51 +3929,13 @@ class AllPlatformTests(BasePlatformTests): self.setconf('-Ddebug=false') opts = self.get_opts_as_dict() self.assertEqual(opts['debug'], False) - self.assertEqual(opts['buildtype'], 'plain') + self.assertEqual(opts['buildtype'], 'debug') self.assertEqual(opts['optimization'], '0') - - # Setting optimizations to 3 should cause buildtype - # to go to release mode. - self.setconf('-Doptimization=3') + self.setconf('-Doptimization=g') opts = self.get_opts_as_dict() - self.assertEqual(opts['buildtype'], 'release') self.assertEqual(opts['debug'], False) - self.assertEqual(opts['optimization'], '3') - - # Going to debug build type should reset debugging - # and optimization - self.setconf('-Dbuildtype=debug') - opts = self.get_opts_as_dict() self.assertEqual(opts['buildtype'], 'debug') - self.assertEqual(opts['debug'], True) - self.assertEqual(opts['optimization'], '0') - - # Command-line parsing of buildtype settings should be the same as - # setting with `meson configure`. - # - # Setting buildtype should set optimization/debug - self.new_builddir() - self.init(testdir, extra_args=['-Dbuildtype=debugoptimized']) - opts = self.get_opts_as_dict() - self.assertEqual(opts['debug'], True) - self.assertEqual(opts['optimization'], '2') - self.assertEqual(opts['buildtype'], 'debugoptimized') - # Setting optimization/debug should set buildtype - self.new_builddir() - self.init(testdir, extra_args=['-Doptimization=2', '-Ddebug=true']) - opts = self.get_opts_as_dict() - self.assertEqual(opts['debug'], True) - self.assertEqual(opts['optimization'], '2') - self.assertEqual(opts['buildtype'], 'debugoptimized') - # Setting both buildtype and debug on the command-line should work, and - # should warn not to do that. Also test that --debug is parsed as -Ddebug=true - self.new_builddir() - out = self.init(testdir, extra_args=['-Dbuildtype=debugoptimized', '--debug']) - self.assertRegex(out, 'Recommend using either.*buildtype.*debug.*redundant') - opts = self.get_opts_as_dict() - self.assertEqual(opts['debug'], True) - self.assertEqual(opts['optimization'], '2') - self.assertEqual(opts['buildtype'], 'debugoptimized') + self.assertEqual(opts['optimization'], 'g') @skipIfNoPkgconfig @unittest.skipIf(is_windows(), 'Help needed with fixing this test on windows') @@ -6720,18 +6682,37 @@ class LinuxlikeTests(BasePlatformTests): testdir = os.path.join(self.unit_test_dir, '10 build_rpath') self.init(testdir) self.build() - # C program RPATH build_rpath = get_rpath(os.path.join(self.builddir, 'prog')) self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar') + build_rpath = get_rpath(os.path.join(self.builddir, 'progcxx')) + self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar') self.install() install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/prog')) self.assertEqual(install_rpath, '/baz') - # C++ program RPATH + install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/progcxx')) + self.assertEqual(install_rpath, 'baz') + + @skipIfNoPkgconfig + def test_build_rpath_pkgconfig(self): + ''' + Test that current build artefacts (libs) are found first on the rpath, + manually specified rpath comes second and additional rpath elements (from + pkg-config files) come last + ''' + if is_cygwin(): + raise unittest.SkipTest('Windows PE/COFF binaries do not use RPATH') + testdir = os.path.join(self.unit_test_dir, '89 pkgconfig build rpath order') + self.init(testdir, override_envvars={'PKG_CONFIG_PATH': testdir}) + self.build() + build_rpath = get_rpath(os.path.join(self.builddir, 'prog')) + self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar:/foo/dummy') build_rpath = get_rpath(os.path.join(self.builddir, 'progcxx')) - self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar') + self.assertEqual(build_rpath, '$ORIGIN/sub:/foo/bar:/foo/dummy') self.install() + install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/prog')) + self.assertEqual(install_rpath, '/baz:/foo/dummy') install_rpath = get_rpath(os.path.join(self.installdir, 'usr/bin/progcxx')) - self.assertEqual(install_rpath, 'baz') + self.assertEqual(install_rpath, 'baz:/foo/dummy') def test_global_rpath(self): if is_cygwin(): diff --git a/test cases/rust/11 generated main/gen.py b/test cases/rust/11 generated main/gen.py new file mode 100644 index 0000000..ebbc2a7 --- /dev/null +++ b/test cases/rust/11 generated main/gen.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import argparse + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('out') + args = parser.parse_args() + + with open(args.out, 'w') as f: + f.write('fn main() { println!("I prefer tarnish, actually.") }') + + +if __name__ == "__main__": + main() diff --git a/test cases/rust/11 generated main/meson.build b/test cases/rust/11 generated main/meson.build new file mode 100644 index 0000000..4749816 --- /dev/null +++ b/test cases/rust/11 generated main/meson.build @@ -0,0 +1,16 @@ +project('generated rust main', 'rust') + +gen = find_program('gen.py') + +c = custom_target( + 'custom_target', + command : [gen, '@OUTPUT@'], + output : ['main.rs'], +) + +executable('custom_target_main', c) +executable('custom_target_index_main', c[0]) + +gen = generator(gen, arguments : ['@OUTPUT@'], output : '@BASENAME@.rs') +# Doesn't actually use gen.py as input, just a limitation of generators +executable('generator_main', gen.process(['gen.py'])) diff --git a/test cases/unit/89 pkgconfig build rpath order/dummy.pc b/test cases/unit/89 pkgconfig build rpath order/dummy.pc new file mode 100644 index 0000000..9e3048b --- /dev/null +++ b/test cases/unit/89 pkgconfig build rpath order/dummy.pc @@ -0,0 +1,7 @@ +prefix=/foo +libdir=${prefix}/dummy + +Name: dummy +Description: Nonexisting lib but add an rpath +Version: 1.0.0 +Libs: -Wl,-rpath,${libdir} diff --git a/test cases/unit/89 pkgconfig build rpath order/meson.build b/test cases/unit/89 pkgconfig build rpath order/meson.build new file mode 100644 index 0000000..76ed8de --- /dev/null +++ b/test cases/unit/89 pkgconfig build rpath order/meson.build @@ -0,0 +1,20 @@ +project('build rpath', 'c', 'cpp') + +subdir('sub') +pkgconf_dep = dependency('dummy') + +executable('prog', 'prog.c', + dependencies : pkgconf_dep, + link_with : l, + build_rpath : '/foo/bar', + install_rpath : '/baz', + install : true, + ) + +executable('progcxx', 'prog.cc', + dependencies : pkgconf_dep, + link_with : l, + build_rpath : '/foo/bar', + install_rpath : 'baz', + install : true, + ) diff --git a/test cases/unit/89 pkgconfig build rpath order/prog.c b/test cases/unit/89 pkgconfig build rpath order/prog.c new file mode 100644 index 0000000..45b2fa3 --- /dev/null +++ b/test cases/unit/89 pkgconfig build rpath order/prog.c @@ -0,0 +1,5 @@ +int get_stuff(); + +int main(int argc, char **argv) { + return get_stuff(); +} diff --git a/test cases/unit/89 pkgconfig build rpath order/prog.cc b/test cases/unit/89 pkgconfig build rpath order/prog.cc new file mode 100644 index 0000000..c7c2123 --- /dev/null +++ b/test cases/unit/89 pkgconfig build rpath order/prog.cc @@ -0,0 +1,8 @@ +#include <string> +#include <iostream> + +int main(int argc, char **argv) { + std::string* s = new std::string("Hello"); + delete s; + return 0; +} diff --git a/test cases/unit/89 pkgconfig build rpath order/sub/meson.build b/test cases/unit/89 pkgconfig build rpath order/sub/meson.build new file mode 100644 index 0000000..6879ec6 --- /dev/null +++ b/test cases/unit/89 pkgconfig build rpath order/sub/meson.build @@ -0,0 +1 @@ +l = shared_library('stuff', 'stuff.c') diff --git a/test cases/unit/89 pkgconfig build rpath order/sub/stuff.c b/test cases/unit/89 pkgconfig build rpath order/sub/stuff.c new file mode 100644 index 0000000..d56d8b0 --- /dev/null +++ b/test cases/unit/89 pkgconfig build rpath order/sub/stuff.c @@ -0,0 +1,3 @@ +int get_stuff() { + return 0; +} |