From 1c403e20e70ac523216a31f977901fb815166b7a Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 30 Jul 2020 09:21:53 -0400 Subject: [PATCH] Interpreter: Fix c_stdlib usage - Exceptions raised during subproject setup were ignored. - Allow c_stdlib in native file, was already half supported. - Eliminate usage of subproject variable name by overriding '_stdlib' dependency name. --- cross/ownstdlib.txt | 2 +- docs/markdown/Cross-compilation.md | 14 +++++- docs/markdown/snippets/stdlib.md | 6 +++ mesonbuild/backend/backends.py | 2 +- mesonbuild/backend/ninjabackend.py | 25 ++++------ mesonbuild/dependencies/base.py | 2 +- mesonbuild/interpreter.py | 49 ++++++++++--------- run_unittests.py | 22 +++++++++ .../unit/79 nostdlib}/meson.build | 0 .../unit/79 nostdlib}/prog.c | 0 .../79 nostdlib}/subprojects/mylibc/libc.c | 0 .../subprojects/mylibc/meson.build | 2 + .../79 nostdlib}/subprojects/mylibc/stdio.h | 0 .../subprojects/mylibc/stubstart.s | 0 14 files changed, 81 insertions(+), 43 deletions(-) create mode 100644 docs/markdown/snippets/stdlib.md rename {manual tests/9 nostdlib => test cases/unit/79 nostdlib}/meson.build (100%) rename {manual tests/9 nostdlib => test cases/unit/79 nostdlib}/prog.c (100%) rename {manual tests/9 nostdlib => test cases/unit/79 nostdlib}/subprojects/mylibc/libc.c (100%) rename {manual tests/9 nostdlib => test cases/unit/79 nostdlib}/subprojects/mylibc/meson.build (84%) rename {manual tests/9 nostdlib => test cases/unit/79 nostdlib}/subprojects/mylibc/stdio.h (100%) rename {manual tests/9 nostdlib => test cases/unit/79 nostdlib}/subprojects/mylibc/stubstart.s (100%) diff --git a/cross/ownstdlib.txt b/cross/ownstdlib.txt index 46e99f7a6..bdff6f44d 100644 --- a/cross/ownstdlib.txt +++ b/cross/ownstdlib.txt @@ -10,4 +10,4 @@ endian = 'little' [properties] -c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, dependency name +c_stdlib = 'mylibc' # Subproject name diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md index d86d417ab..c8cd72867 100644 --- a/docs/markdown/Cross-compilation.md +++ b/docs/markdown/Cross-compilation.md @@ -268,7 +268,7 @@ invocation to use in your cross file is the following: ```ini [properties] -c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, dependency name +c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, variable name ``` This specifies that C standard library is provided in the Meson @@ -277,6 +277,18 @@ is used on every cross built C target in the entire source tree (including subprojects) and the standard library is disabled. The build definitions of these targets do not need any modification. +Note that it is supported for any language, not only `c`, using `_stdlib` +property. + +Since *0.56.0* the variable name parameter is no longer required as long as the +subproject calls `meson.override_dependency('c_stdlib', mylibc_dep)`. +The above example becomes: + +```ini +[properties] +c_stdlib = 'mylibc' +``` + ## Changing cross file settings Cross file settings are only read when the build directory is set up diff --git a/docs/markdown/snippets/stdlib.md b/docs/markdown/snippets/stdlib.md new file mode 100644 index 000000000..5e80dd5a8 --- /dev/null +++ b/docs/markdown/snippets/stdlib.md @@ -0,0 +1,6 @@ +## Custom standard library + +- It is not limited to cross builds any more, `_stdlib` property can be + set in native files. +- The variable name parameter is no longer required as long as the subproject + calls `meson.override_dependency('c_stdlib', mylibc_dep)`. diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index c84bb7534..c6a48d36d 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -657,7 +657,7 @@ class Backend: # First, the trivial ones that are impossible to override. # # Add -nostdinc/-nostdinc++ if needed; can't be overridden - commands += self.get_cross_stdlib_args(target, compiler) + commands += self.get_no_stdlib_args(target, compiler) # Add things like /NOLOGO or -pipe; usually can't be overridden commands += compiler.get_always_args() # Only add warning-flags by default if the buildtype enables it, and if diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b4ebdc389..46886cecd 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2088,12 +2088,15 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) mod_files = _scan_fortran_file_deps(src, srcdir, dirname, tdeps, compiler) return mod_files - def get_cross_stdlib_args(self, target, compiler): - if self.environment.machines.matches_build_machine(target.for_machine): - return [] - if not self.environment.properties.host.has_stdlib(compiler.language): - return [] - return compiler.get_no_stdinc_args() + def get_no_stdlib_args(self, target, compiler): + if compiler.language in self.build.stdlibs[target.for_machine]: + return compiler.get_no_stdinc_args() + return [] + + def get_no_stdlib_link_args(self, target, linker): + if hasattr(linker, 'language') and linker.language in self.build.stdlibs[target.for_machine]: + return linker.get_no_stdlib_link_args() + return [] def get_compile_debugfile_args(self, compiler, target, objfile): # The way MSVC uses PDB files is documented exactly nowhere so @@ -2520,14 +2523,6 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) elem.add_item('CROSS', '--cross-host=' + self.environment.machines[target.for_machine].system) self.add_build(elem) - def get_cross_stdlib_link_args(self, target, linker): - if isinstance(target, build.StaticLibrary) or \ - self.environment.machines.matches_build_machine(target.for_machine): - return [] - if not self.environment.properties.host.has_stdlib(linker.language): - return [] - return linker.get_no_stdlib_link_args() - def get_import_filename(self, target): return os.path.join(self.get_target_dir(target), target.import_filename) @@ -2689,7 +2684,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) linker, isinstance(target, build.SharedModule)) # Add -nostdlib if needed; can't be overridden - commands += self.get_cross_stdlib_link_args(target, linker) + commands += self.get_no_stdlib_link_args(target, linker) # Add things like /NOLOGO; usually can't be overridden commands += linker.get_linker_always_args() # Add buildtype linker args: optimization level, etc. diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 368a4bc6b..f581c0604 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -2301,7 +2301,7 @@ def get_dep_identifier(name, kwargs) -> T.Tuple: # 'required' is irrelevant for caching; the caller handles it separately # 'fallback' subprojects cannot be cached -- they must be initialized # 'default_options' is only used in fallback case - if key in ('version', 'native', 'required', 'fallback', 'default_options'): + if key in ('version', 'native', 'required', 'fallback', 'default_options', 'force_fallback'): continue # All keyword arguments are strings, ints, or lists (or lists of lists) if isinstance(value, list): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index b547bbf3e..dc231cc05 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2572,21 +2572,25 @@ class Interpreter(InterpreterBase): return self.variables def check_stdlibs(self): - for for_machine in MachineChoice: + machine_choices = [MachineChoice.HOST] + if self.coredata.is_cross_build(): + machine_choices.append(MachineChoice.BUILD) + for for_machine in machine_choices: props = self.build.environment.properties[for_machine] for l in self.coredata.compilers[for_machine].keys(): try: di = mesonlib.stringlistify(props.get_stdlib(l)) - if len(di) != 2: - raise InterpreterException('Stdlib definition for %s should have exactly two elements.' - % l) - projname, depname = di - subproj = self.do_subproject(projname, 'meson', {}) - self.build.stdlibs.host[l] = subproj.get_variable_method([depname], {}) except KeyError: - pass - except InvalidArguments: - pass + continue + if len(di) == 1: + FeatureNew.single_use('stdlib without variable name', '0.56.0', self.subproject) + kwargs = {'fallback': di, + 'native': for_machine is MachineChoice.BUILD, + 'force_fallback': True, + } + name = display_name = l + '_stdlib' + dep = self.dependency_impl(name, display_name, kwargs) + self.build.stdlibs[for_machine][l] = dep def import_module(self, modname): if modname in self.modules: @@ -3682,9 +3686,11 @@ external dependencies (including libraries) must go to "dependencies".''') wrap_mode = self.coredata.get_builtin_option('wrap_mode') force_fallback_for = self.coredata.get_builtin_option('force_fallback_for') + force_fallback = kwargs.get('force_fallback', False) forcefallback = has_fallback and (wrap_mode == WrapMode.forcefallback or \ name in force_fallback_for or \ - dirname in force_fallback_for) + dirname in force_fallback_for or \ + force_fallback) if name != '' and not forcefallback: self._handle_featurenew_dependencies(name) kwargs['required'] = required and not has_fallback @@ -4786,8 +4792,7 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s target = targetclass(name, self.subdir, self.subproject, for_machine, sources, objs, self.environment, kwargs) target.project_version = self.project_version - if not self.environment.machines.matches_build_machine(for_machine): - self.add_cross_stdlib_info(target) + self.add_stdlib_info(target) l = targetholder(target, self) self.add_target(name, l.held_object) self.project_args_frozen = True @@ -4811,23 +4816,19 @@ This will become a hard error in the future.''', location=self.current_node) kwargs['d_import_dirs'] = cleaned_items def get_used_languages(self, target): - result = {} + result = set() for i in target.sources: - # TODO other platforms - for lang, c in self.coredata.compilers.host.items(): + for lang, c in self.coredata.compilers[target.for_machine].items(): if c.can_compile(i): - result[lang] = True + result.add(lang) break return result - def add_cross_stdlib_info(self, target): - if target.for_machine != MachineChoice.HOST: - return + def add_stdlib_info(self, target): for l in self.get_used_languages(target): - props = self.environment.properties.host - if props.has_stdlib(l) \ - and self.subproject != props.get_stdlib(l)[0]: - target.add_deps(self.build.stdlibs.host[l]) + dep = self.build.stdlibs[target.for_machine].get(l, None) + if dep: + target.add_deps(dep) def check_sources_exist(self, subdir, sources): for s in sources: diff --git a/run_unittests.py b/run_unittests.py index 95a60897a..f876d0637 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -5054,6 +5054,28 @@ recommended as it is not supported on some platforms''') self.build() self.run_tests() + @unittest.skipUnless(is_linux(), 'Requires ASM compiler currently only available on Linux CI runners') + def test_nostdlib(self): + testdir = os.path.join(self.unit_test_dir, '79 nostdlib') + machinefile = os.path.join(self.builddir, 'machine.txt') + with open(machinefile, 'w') as f: + f.write(textwrap.dedent(''' + [properties] + c_stdlib = 'mylibc' + ''')) + + # Test native C stdlib + self.meson_native_file = machinefile + self.init(testdir) + self.build() + + # Test cross C stdlib + self.new_builddir() + self.meson_native_file = None + self.meson_cross_file = machinefile + self.init(testdir) + self.build() + class FailureTests(BasePlatformTests): ''' Tests that test failure conditions. Build files here should be dynamically diff --git a/manual tests/9 nostdlib/meson.build b/test cases/unit/79 nostdlib/meson.build similarity index 100% rename from manual tests/9 nostdlib/meson.build rename to test cases/unit/79 nostdlib/meson.build diff --git a/manual tests/9 nostdlib/prog.c b/test cases/unit/79 nostdlib/prog.c similarity index 100% rename from manual tests/9 nostdlib/prog.c rename to test cases/unit/79 nostdlib/prog.c diff --git a/manual tests/9 nostdlib/subprojects/mylibc/libc.c b/test cases/unit/79 nostdlib/subprojects/mylibc/libc.c similarity index 100% rename from manual tests/9 nostdlib/subprojects/mylibc/libc.c rename to test cases/unit/79 nostdlib/subprojects/mylibc/libc.c diff --git a/manual tests/9 nostdlib/subprojects/mylibc/meson.build b/test cases/unit/79 nostdlib/subprojects/mylibc/meson.build similarity index 84% rename from manual tests/9 nostdlib/subprojects/mylibc/meson.build rename to test cases/unit/79 nostdlib/subprojects/mylibc/meson.build index aa0184e11..ff4bdb20f 100644 --- a/manual tests/9 nostdlib/subprojects/mylibc/meson.build +++ b/test cases/unit/79 nostdlib/subprojects/mylibc/meson.build @@ -9,3 +9,5 @@ libc = static_library('c', 'libc.c', 'stubstart.s') mylibc_dep = declare_dependency(link_with : libc, include_directories : include_directories('.') ) + +meson.override_dependency('c_stdlib', mylibc_dep) diff --git a/manual tests/9 nostdlib/subprojects/mylibc/stdio.h b/test cases/unit/79 nostdlib/subprojects/mylibc/stdio.h similarity index 100% rename from manual tests/9 nostdlib/subprojects/mylibc/stdio.h rename to test cases/unit/79 nostdlib/subprojects/mylibc/stdio.h diff --git a/manual tests/9 nostdlib/subprojects/mylibc/stubstart.s b/test cases/unit/79 nostdlib/subprojects/mylibc/stubstart.s similarity index 100% rename from manual tests/9 nostdlib/subprojects/mylibc/stubstart.s rename to test cases/unit/79 nostdlib/subprojects/mylibc/stubstart.s