From f2d21bf8a98fe4eb528a077f3faf5d68cd35c244 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 21 Mar 2022 16:42:55 -0400 Subject: [PATCH] Make compilers list per subproject Previously subprojects inherited languages already added by main project, or any previous subproject. This change to have a list of compilers per interpreters, which means that if a subproject does not add 'c' language it won't be able to compile .c files any more, even if main project added the 'c' language. This delays processing list of compilers until the interpreter adds the BuildTarget into its list of targets. That way the interpreter can add missing languages instead of duplicating that logic into BuildTarget for the cython case. --- .../markdown/snippets/per_project_compiler.md | 6 + docs/yaml/functions/executable.yaml | 2 +- mesonbuild/ast/introspection.py | 5 +- mesonbuild/build.py | 201 +++++++++--------- mesonbuild/interpreter/interpreter.py | 37 ++-- mesonbuild/modules/unstable_rust.py | 3 +- test cases/failing/100 no lang/test.json | 2 +- .../failing/123 missing compiler/meson.build | 3 + .../subprojects/sub/main.c | 1 + .../subprojects/sub/meson.build | 4 + .../failing/123 missing compiler/test.json | 7 + .../54 wrong shared crate type/meson.build | 2 +- .../55 wrong static crate type/meson.build | 2 +- .../subprojects/sub/meson.build | 2 +- unittests/allplatformstests.py | 12 +- 15 files changed, 157 insertions(+), 132 deletions(-) create mode 100644 docs/markdown/snippets/per_project_compiler.md create mode 100644 test cases/failing/123 missing compiler/meson.build create mode 100644 test cases/failing/123 missing compiler/subprojects/sub/main.c create mode 100644 test cases/failing/123 missing compiler/subprojects/sub/meson.build create mode 100644 test cases/failing/123 missing compiler/test.json diff --git a/docs/markdown/snippets/per_project_compiler.md b/docs/markdown/snippets/per_project_compiler.md new file mode 100644 index 000000000..dcf47a1dc --- /dev/null +++ b/docs/markdown/snippets/per_project_compiler.md @@ -0,0 +1,6 @@ +## Per-subproject languages + +Subprojects does not inherit languages added by main project or other subprojects +any more. This could break subprojects that wants to compile e.g. `.c` files but +did not add `c` language, either in `project()` or `add_languages()`, and were +relying on the main project to do it for them. diff --git a/docs/yaml/functions/executable.yaml b/docs/yaml/functions/executable.yaml index 2e57bd4fb..cdf764a07 100644 --- a/docs/yaml/functions/executable.yaml +++ b/docs/yaml/functions/executable.yaml @@ -29,7 +29,7 @@ kwargs: the `implib` argument. implib: - type: bool + type: bool | str since: 0.42.0 description: | When set to true, an import library is generated for the diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 55c3bcc7a..f0a2a0c7d 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -258,7 +258,10 @@ class IntrospectionInterpreter(AstInterpreter): objects = [] # type: T.List[T.Any] empty_sources = [] # type: T.List[T.Any] # Passing the unresolved sources list causes errors - target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, [], objects, self.environment, kwargs_reduced) + target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, [], objects, + self.environment, self.coredata.compilers[for_machine], kwargs_reduced) + target.process_compilers() + target.process_compilers_late([]) new_target = { 'name': target.get_basename(), diff --git a/mesonbuild/build.py b/mesonbuild/build.py index f36648566..5c997e884 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -40,7 +40,7 @@ from .mesonlib import ( ) from .compilers import ( Compiler, is_object, clink_langs, sort_clink, lang_suffixes, all_languages, - is_known_suffix, detect_static_linker, detect_compiler_for + is_known_suffix, detect_static_linker ) from .linkers import StaticLinker from .interpreterbase import FeatureNew, FeatureDeprecated @@ -725,11 +725,12 @@ class BuildTarget(Target): def __init__(self, name: str, subdir: str, subproject: SubProject, for_machine: MachineChoice, sources: T.List['SourceOutputs'], structured_sources: T.Optional[StructuredSources], - objects, environment: environment.Environment, kwargs): + objects, environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], kwargs): super().__init__(name, subdir, subproject, True, for_machine) unity_opt = environment.coredata.get_option(OptionKey('unity')) self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '') self.environment = environment + self.all_compilers = compilers self.compilers = OrderedDict() # type: OrderedDict[str, Compiler] self.objects: T.List[T.Union[str, 'File', 'ExtractedObjects']] = [] self.structured_sources = structured_sources @@ -763,14 +764,15 @@ class BuildTarget(Target): self.process_objectlist(objects) self.process_kwargs(kwargs, environment) self.check_unknown_kwargs(kwargs) - self.process_compilers() if not any([self.sources, self.generated, self.objects, self.link_whole, self.structured_sources]): raise InvalidArguments(f'Build target {name} has no sources.') - self.process_compilers_late() - self.validate_sources() self.validate_install(environment) self.check_module_linking() + def post_init(self) -> None: + ''' Initialisations and checks requiring the final list of compilers to be known + ''' + self.validate_sources() if self.structured_sources and any([self.sources, self.generated]): raise MesonException('cannot mix structured sources and unstructured sources') if self.structured_sources and 'rust' not in self.compilers: @@ -844,15 +846,15 @@ class BuildTarget(Target): removed = True return removed - def process_compilers_late(self): + def process_compilers_late(self, extra_languages: T.List[str]): """Processes additional compilers after kwargs have been evaluated. This can add extra compilers that might be required by keyword arguments, such as link_with or dependencies. It will also try to guess which compiler to use if one hasn't been selected already. """ - # Populate list of compilers - compilers = self.environment.coredata.compilers[self.for_machine] + for lang in extra_languages: + self.compilers[lang] = self.all_compilers[lang] # did user override clink_langs for this target? link_langs = [self.link_language] if self.link_language else clink_langs @@ -860,36 +862,40 @@ class BuildTarget(Target): # If this library is linked against another library we need to consider # the languages of those libraries as well. if self.link_targets or self.link_whole_targets: - extra = set() for t in itertools.chain(self.link_targets, self.link_whole_targets): if isinstance(t, CustomTarget) or isinstance(t, CustomTargetIndex): continue # We can't know anything about these. for name, compiler in t.compilers.items(): - if name in link_langs: - extra.add((name, compiler)) - for name, compiler in sorted(extra, key=lambda p: sort_clink(p[0])): - self.compilers[name] = compiler + if name in link_langs and name not in self.compilers: + self.compilers[name] = compiler if not self.compilers: # No source files or parent targets, target consists of only object # files of unknown origin. Just add the first clink compiler # that we have and hope that it can link these objects for lang in link_langs: - if lang in compilers: - self.compilers[lang] = compilers[lang] + if lang in self.all_compilers: + self.compilers[lang] = self.all_compilers[lang] break - def process_compilers(self) -> None: + # Now that we have the final list of compilers we can sort it according + # to clink_langs and do sanity checks. + self.compilers = OrderedDict(sorted(self.compilers.items(), + key=lambda t: sort_clink(t[0]))) + self.post_init() + + def process_compilers(self) -> T.List[str]: ''' Populate self.compilers, which is the list of compilers that this target will use for compiling all its sources. We also add compilers that were used by extracted objects to simplify dynamic linker determination. + Returns a list of missing languages that we can add implicitly, such as + C/C++ compiler for cython. ''' + missing_languages: T.List[str] = [] if not any([self.sources, self.generated, self.objects, self.structured_sources]): - return - # Populate list of compilers - compilers = self.environment.coredata.compilers[self.for_machine] + return missing_languages # Pre-existing sources sources: T.List['FileOrString'] = list(self.sources) generated = self.generated.copy() @@ -936,56 +942,33 @@ class BuildTarget(Target): # are expected to be able to add arbitrary non-source files to the # sources list for s in sources: - for lang, compiler in compilers.items(): + for lang, compiler in self.all_compilers.items(): if compiler.can_compile(s): if lang not in self.compilers: self.compilers[lang] = compiler break else: if is_known_suffix(s): - raise MesonException('No {} machine compiler for "{}"'. - format(self.for_machine.get_lower_case_name(), s)) - - # Re-sort according to clink_langs - self.compilers = OrderedDict(sorted(self.compilers.items(), - key=lambda t: sort_clink(t[0]))) + path = pathlib.Path(str(s)).as_posix() + m = f'No {self.for_machine.get_lower_case_name()} machine compiler for {path!r}' + raise MesonException(m) # If all our sources are Vala, our target also needs the C compiler but # it won't get added above. if 'vala' in self.compilers and 'c' not in self.compilers: - self.compilers['c'] = compilers['c'] + self.compilers['c'] = self.all_compilers['c'] if 'cython' in self.compilers: key = OptionKey('language', machine=self.for_machine, lang='cython') if key in self.option_overrides: value = self.option_overrides[key] else: value = self.environment.coredata.options[key].value - try: - self.compilers[value] = compilers[value] + self.compilers[value] = self.all_compilers[value] except KeyError: - # TODO: it would be nice to not have to do this here, but we - # have two problems to work around: - # 1. If this is set via an override we have no way to know - # before now that we need a compiler for the non-default language - # 2. Because Cython itself initializes the `cython_language` - # option, we have no good place to insert that you need it - # before now, so we just have to do it here. - comp = detect_compiler_for(self.environment, value, self.for_machine) - - # This is copied verbatim from the interpreter - if self.for_machine == MachineChoice.HOST or self.environment.is_cross_build(): - logger_fun = mlog.log - else: - logger_fun = mlog.debug - logger_fun(comp.get_display_language(), 'compiler for the', self.for_machine.get_lower_case_name(), 'machine:', - mlog.bold(' '.join(comp.get_exelist())), comp.get_version_string()) - if comp.linker is not None: - logger_fun(comp.get_display_language(), 'linker for the', self.for_machine.get_lower_case_name(), 'machine:', - mlog.bold(' '.join(comp.linker.get_exelist())), comp.linker.id, comp.linker.version) - if comp is None: - raise MesonException(f'Cannot find required compiler {value}') - self.compilers[value] = comp + missing_languages.append(value) + + return missing_languages def validate_sources(self): if not self.sources: @@ -1553,14 +1536,13 @@ You probably should put it in link_with instead.''') return langs def get_prelinker(self): - all_compilers = self.environment.coredata.compilers[self.for_machine] if self.link_language: - comp = all_compilers[self.link_language] + comp = self.all_compilers[self.link_language] return comp for l in clink_langs: if l in self.compilers: try: - prelinker = all_compilers[l] + prelinker = self.all_compilers[l] except KeyError: raise MesonException( f'Could not get a prelinker linker for build target {self.name!r}. ' @@ -1579,15 +1561,16 @@ You probably should put it in link_with instead.''') that can link compiled C. We don't actually need to add an exception for Vala here because of that. ''' - # Populate list of all compilers, not just those being used to compile - # sources in this target - all_compilers = self.environment.coredata.compilers[self.for_machine] - # If the user set the link_language, just return that. if self.link_language: - comp = all_compilers[self.link_language] + comp = self.all_compilers[self.link_language] return comp, comp.language_stdlib_only_link_flags(self.environment) + # Since dependencies could come from subprojects, they could have + # languages we don't have in self.all_compilers. Use the global list of + # all compilers here. + all_compilers = self.environment.coredata.compilers[self.for_machine] + # Languages used by dependencies dep_langs = self.get_langs_used_by_deps() # Pick a compiler based on the language priority-order @@ -1601,11 +1584,9 @@ You probably should put it in link_with instead.''') f'Requires a linker for language "{l}", but that is not ' 'a project language.') stdlib_args: T.List[str] = [] - added_languages: T.Set[str] = set() for dl in itertools.chain(self.compilers, dep_langs): if dl != linker.language: stdlib_args += all_compilers[dl].language_stdlib_only_link_flags(self.environment) - added_languages.add(dl) # Type of var 'linker' is Compiler. # Pretty hard to fix because the return value is passed everywhere return linker, stdlib_args @@ -1653,7 +1634,7 @@ You probably should put it in link_with instead.''') ''' # Rustc can use msvc style linkers if self.uses_rust(): - compiler = self.environment.coredata.compilers[self.for_machine]['rust'] + compiler = self.all_compilers['rust'] else: compiler, _ = self.get_clink_dynamic_linker_and_stdlibs() # Mixing many languages with MSVC is not supported yet so ignore stdlibs. @@ -1833,18 +1814,38 @@ class Executable(BuildTarget): def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, sources: T.List[File], structured_sources: T.Optional['StructuredSources'], - objects, environment: environment.Environment, kwargs): + objects, environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], + kwargs): self.typename = 'executable' key = OptionKey('b_pie') if 'pie' not in kwargs and key in environment.coredata.options: kwargs['pie'] = environment.coredata.options[key].value - super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, kwargs) + super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, + environment, compilers, kwargs) + # Check for export_dynamic + self.export_dynamic = kwargs.get('export_dynamic', False) + if not isinstance(self.export_dynamic, bool): + raise InvalidArguments('"export_dynamic" keyword argument must be a boolean') + self.implib = kwargs.get('implib') + if not isinstance(self.implib, (bool, str, type(None))): + raise InvalidArguments('"export_dynamic" keyword argument must be a boolean or string') + if self.implib: + self.export_dynamic = True + if self.export_dynamic and self.implib is False: + raise InvalidArguments('"implib" keyword argument must not be false for if "export_dynamic" is true') + # Only linkwithable if using export_dynamic + self.is_linkwithable = self.export_dynamic + # Remember that this exe was returned by `find_program()` through an override + self.was_returned_by_find_program = False + + def post_init(self) -> None: + super().post_init() + machine = self.environment.machines[self.for_machine] # Unless overridden, executables have no suffix or prefix. Except on # Windows and with C#/Mono executables where the suffix is 'exe' if not hasattr(self, 'prefix'): self.prefix = '' if not hasattr(self, 'suffix'): - machine = environment.machines[for_machine] # Executable for Windows or C#/Mono if machine.is_windows() or machine.is_cygwin() or 'cs' in self.compilers: self.suffix = 'exe' @@ -1862,7 +1863,7 @@ class Executable(BuildTarget): 'cpp' in self.compilers and self.compilers['cpp'].get_id() in ('ti', 'c2000')): self.suffix = 'out' else: - self.suffix = environment.machines[for_machine].get_exe_suffix() + self.suffix = machine.get_exe_suffix() self.filename = self.name if self.suffix: self.filename += '.' + self.suffix @@ -1877,25 +1878,12 @@ class Executable(BuildTarget): # The debugging information file this target will generate self.debug_filename = None - # Check for export_dynamic - self.export_dynamic = False - if kwargs.get('export_dynamic'): - if not isinstance(kwargs['export_dynamic'], bool): - raise InvalidArguments('"export_dynamic" keyword argument must be a boolean') - self.export_dynamic = True - if kwargs.get('implib'): - self.export_dynamic = True - if self.export_dynamic and kwargs.get('implib') is False: - raise InvalidArguments('"implib" keyword argument must not be false for if "export_dynamic" is true') - - m = environment.machines[for_machine] - # If using export_dynamic, set the import library name if self.export_dynamic: implib_basename = self.name + '.exe' - if not isinstance(kwargs.get('implib', False), bool): - implib_basename = kwargs['implib'] - if m.is_windows() or m.is_cygwin(): + if isinstance(self.implib, str): + implib_basename = self.implib + if machine.is_windows() or machine.is_cygwin(): self.vs_import_filename = f'{implib_basename}.lib' self.gcc_import_filename = f'lib{implib_basename}.a' if self.get_using_msvc(): @@ -1903,17 +1891,11 @@ class Executable(BuildTarget): else: self.import_filename = self.gcc_import_filename - if m.is_windows() and ('cs' in self.compilers or - self.uses_rust() or - self.get_using_msvc()): + if machine.is_windows() and ('cs' in self.compilers or + self.uses_rust() or + self.get_using_msvc()): self.debug_filename = self.name + '.pdb' - # Only linkwithable if using export_dynamic - self.is_linkwithable = self.export_dynamic - - # Remember that this exe was returned by `find_program()` through an override - self.was_returned_by_find_program = False - def get_default_install_dir(self, environment: environment.Environment) -> T.Tuple[str, str]: return environment.get_bindir(), '{bindir}' @@ -1960,9 +1942,17 @@ class StaticLibrary(BuildTarget): def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, sources: T.List[File], structured_sources: T.Optional['StructuredSources'], - objects, environment: environment.Environment, kwargs): + objects, environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], + kwargs): self.typename = 'static library' - super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, kwargs) + self.prelink = kwargs.get('prelink', False) + if not isinstance(self.prelink, bool): + raise InvalidArguments('Prelink keyword argument must be a boolean.') + super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, + environment, compilers, kwargs) + + def post_init(self) -> None: + super().post_init() if 'cs' in self.compilers: raise InvalidArguments('Static libraries not supported for C#.') if 'rust' in self.compilers: @@ -1993,9 +1983,6 @@ class StaticLibrary(BuildTarget): self.suffix = 'a' self.filename = self.prefix + self.name + '.' + self.suffix self.outputs = [self.filename] - self.prelink = kwargs.get('prelink', False) - if not isinstance(self.prelink, bool): - raise InvalidArguments('Prelink keyword argument must be a boolean.') def get_link_deps_mapping(self, prefix: str, environment: environment.Environment) -> T.Mapping[str, str]: return {} @@ -2023,7 +2010,8 @@ class SharedLibrary(BuildTarget): def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, sources: T.List[File], structured_sources: T.Optional['StructuredSources'], - objects, environment: environment.Environment, kwargs): + objects, environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], + kwargs): self.typename = 'shared library' self.soversion = None self.ltversion = None @@ -2040,7 +2028,11 @@ class SharedLibrary(BuildTarget): self.debug_filename = None # Use by the pkgconfig module self.shared_library_only = False - super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, kwargs) + super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, + environment, compilers, kwargs) + + def post_init(self) -> None: + super().post_init() if 'rust' in self.compilers: # If no crate type is specified, or it's the generic lib type, use dylib if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib': @@ -2054,7 +2046,7 @@ class SharedLibrary(BuildTarget): if not hasattr(self, 'suffix'): self.suffix = None self.basic_filename_tpl = '{0.prefix}{0.name}.{0.suffix}' - self.determine_filenames(environment) + self.determine_filenames(self.environment) def get_link_deps_mapping(self, prefix: str, environment: environment.Environment) -> T.Mapping[str, str]: result: T.Dict[str, str] = {} @@ -2352,13 +2344,14 @@ class SharedModule(SharedLibrary): def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, sources: T.List[File], structured_sources: T.Optional['StructuredSources'], - objects, environment: environment.Environment, kwargs): + objects, environment: environment.Environment, + compilers: T.Dict[str, 'Compiler'], kwargs): if 'version' in kwargs: raise MesonException('Shared modules must not specify the version kwarg.') if 'soversion' in kwargs: raise MesonException('Shared modules must not specify the soversion kwarg.') super().__init__(name, subdir, subproject, for_machine, sources, - structured_sources, objects, environment, kwargs) + structured_sources, objects, environment, compilers, kwargs) self.typename = 'shared module' # We need to set the soname in cases where build files link the module # to build targets, see: https://github.com/mesonbuild/meson/issues/9492 @@ -2680,9 +2673,11 @@ class Jar(BuildTarget): def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice, sources: T.List[File], structured_sources: T.Optional['StructuredSources'], - objects, environment: environment.Environment, kwargs): + objects, environment: environment.Environment, compilers: T.Dict[str, 'Compiler'], + kwargs): self.typename = 'jar' - super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, environment, kwargs) + super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects, + environment, compilers, kwargs) for s in self.sources: if not s.endswith('.java'): raise InvalidArguments(f'Jar source {s} is not a java file.') diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 15d7d32b4..815737ce9 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -23,7 +23,8 @@ from .. import compilers from .. import envconfig from ..wrap import wrap, WrapMode from .. import mesonlib -from ..mesonlib import MesonBugException, HoldableObject, FileMode, MachineChoice, OptionKey, listify, extract_as_list, has_path_sep +from ..mesonlib import (MesonBugException, HoldableObject, FileMode, MachineChoice, OptionKey, + listify, extract_as_list, has_path_sep, PerMachine) from ..programs import ExternalProgram, NonExistingExternalProgram from ..dependencies import Dependency from ..depfile import DepFile @@ -304,6 +305,7 @@ class Interpreter(InterpreterBase, HoldableObject): self.build_func_dict() self.build_holder_map() self.user_defined_options = user_defined_options + self.compilers: PerMachine[T.Dict[str, 'Compiler']] = PerMachine({}, {}) # build_def_files needs to be defined before parse_project is called # @@ -1346,7 +1348,7 @@ external dependencies (including libraries) must go to "dependencies".''') def add_languages_for(self, args: T.List[str], required: bool, for_machine: MachineChoice) -> bool: args = [a.lower() for a in args] - langs = set(self.coredata.compilers[for_machine].keys()) + langs = set(self.compilers[for_machine].keys()) langs.update(args) # We'd really like to add cython's default language here, but it can't # actually be done because the cython compiler hasn't been initialized, @@ -1360,11 +1362,11 @@ external dependencies (including libraries) must go to "dependencies".''') success = True for lang in sorted(args, key=compilers.sort_clink): - clist = self.coredata.compilers[for_machine] + if lang in self.compilers[for_machine]: + continue machine_name = for_machine.get_lower_case_name() - if lang in clist: - comp = clist[lang] - else: + comp = self.coredata.compilers[for_machine].get(lang) + if not comp: try: comp = compilers.detect_compiler_for(self.environment, lang, for_machine) if comp is None: @@ -1402,6 +1404,7 @@ external dependencies (including libraries) must go to "dependencies".''') logger_fun(comp.get_display_language(), 'linker for the', machine_name, 'machine:', mlog.bold(' '.join(comp.linker.get_exelist())), comp.linker.id, comp.linker.version) self.build.ensure_static_linker(comp) + self.compilers[for_machine][lang] = comp return success @@ -2830,6 +2833,13 @@ Try setting b_lundef to false instead.'''.format(self.coredata.options[OptionKey idname = tobj.get_id() if idname in self.build.targets: raise InvalidCode(f'Tried to create target "{name}", but a target of that name already exists.') + + if isinstance(tobj, build.BuildTarget): + missing_languages = tobj.process_compilers() + self.add_languages(missing_languages, True, tobj.for_machine) + tobj.process_compilers_late(missing_languages) + self.add_stdlib_info(tobj) + self.build.targets[idname] = tobj if idname not in self.coredata.target_guids: self.coredata.target_guids[idname] = str(uuid.uuid4()).upper() @@ -2947,10 +2957,10 @@ Try setting b_lundef to false instead.'''.format(self.coredata.options[OptionKey outputs.update(o) kwargs['include_directories'] = self.extract_incdirs(kwargs) - target = targetclass(name, self.subdir, self.subproject, for_machine, srcs, struct, objs, self.environment, kwargs) + target = targetclass(name, self.subdir, self.subproject, for_machine, srcs, struct, objs, + self.environment, self.compilers[for_machine], kwargs) target.project_version = self.project_version - self.add_stdlib_info(target) self.add_target(name, target) self.project_args_frozen = True return target @@ -2972,17 +2982,8 @@ This will become a hard error in the future.''', location=self.current_node) cleaned_items.append(i) kwargs['d_import_dirs'] = cleaned_items - def get_used_languages(self, target): - result = set() - for i in target.sources: - for lang, c in self.coredata.compilers[target.for_machine].items(): - if c.can_compile(i): - result.add(lang) - break - return result - def add_stdlib_info(self, target): - for l in self.get_used_languages(target): + for l in target.compilers.keys(): dep = self.build.stdlibs[target.for_machine].get(l, None) if dep: target.add_deps(dep) diff --git a/mesonbuild/modules/unstable_rust.py b/mesonbuild/modules/unstable_rust.py index 85e49cf18..4e3dde28c 100644 --- a/mesonbuild/modules/unstable_rust.py +++ b/mesonbuild/modules/unstable_rust.py @@ -151,7 +151,8 @@ class RustModule(ExtensionModule): new_target = Executable( name, base_target.subdir, state.subproject, base_target.for_machine, base_target.sources, base_target.structured_sources, - base_target.objects, base_target.environment, new_target_kwargs + base_target.objects, base_target.environment, base_target.compilers, + new_target_kwargs ) test = self.interpreter.make_test( diff --git a/test cases/failing/100 no lang/test.json b/test cases/failing/100 no lang/test.json index 58dc1ac2e..a74adaf60 100644 --- a/test cases/failing/100 no lang/test.json +++ b/test cases/failing/100 no lang/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/100 no lang/meson.build:2:0: ERROR: No host machine compiler for \"main.c\"" + "line": "test cases/failing/100 no lang/meson.build:2:0: ERROR: No host machine compiler for 'main.c'" } ] } diff --git a/test cases/failing/123 missing compiler/meson.build b/test cases/failing/123 missing compiler/meson.build new file mode 100644 index 000000000..19bdd0c66 --- /dev/null +++ b/test cases/failing/123 missing compiler/meson.build @@ -0,0 +1,3 @@ +project('main project', 'c') + +subproject('sub') diff --git a/test cases/failing/123 missing compiler/subprojects/sub/main.c b/test cases/failing/123 missing compiler/subprojects/sub/main.c new file mode 100644 index 000000000..44e82e227 --- /dev/null +++ b/test cases/failing/123 missing compiler/subprojects/sub/main.c @@ -0,0 +1 @@ +int main(int argc, char *argv[]) { return 0; } diff --git a/test cases/failing/123 missing compiler/subprojects/sub/meson.build b/test cases/failing/123 missing compiler/subprojects/sub/meson.build new file mode 100644 index 000000000..b60850c9c --- /dev/null +++ b/test cases/failing/123 missing compiler/subprojects/sub/meson.build @@ -0,0 +1,4 @@ +project('sub') + +# Should fail because we did not add C language, even if parent project did. +executable('app', 'main.c') diff --git a/test cases/failing/123 missing compiler/test.json b/test cases/failing/123 missing compiler/test.json new file mode 100644 index 000000000..915df164c --- /dev/null +++ b/test cases/failing/123 missing compiler/test.json @@ -0,0 +1,7 @@ +{ + "stdout": [ + { + "line": "test cases/failing/123 missing compiler/subprojects/sub/meson.build:4:0: ERROR: No host machine compiler for 'subprojects/sub/main.c'" + } + ] +} diff --git a/test cases/failing/54 wrong shared crate type/meson.build b/test cases/failing/54 wrong shared crate type/meson.build index b9fcad4e5..90020faf8 100644 --- a/test cases/failing/54 wrong shared crate type/meson.build +++ b/test cases/failing/54 wrong shared crate type/meson.build @@ -4,4 +4,4 @@ if not add_languages('rust', required: false) error('MESON_SKIP_TEST test requires rust compiler') endif -shared_library('test', 'foo.rs', rust_crate_type : 'staticlib') +shared_library('mytest', 'foo.rs', rust_crate_type : 'staticlib') diff --git a/test cases/failing/55 wrong static crate type/meson.build b/test cases/failing/55 wrong static crate type/meson.build index 109907f96..179d7cd53 100644 --- a/test cases/failing/55 wrong static crate type/meson.build +++ b/test cases/failing/55 wrong static crate type/meson.build @@ -4,4 +4,4 @@ if not add_languages('rust', required: false) error('MESON_SKIP_TEST test requires rust compiler') endif -static_library('test', 'foo.rs', rust_crate_type : 'cdylib') +static_library('mytest', 'foo.rs', rust_crate_type : 'cdylib') diff --git a/test cases/unit/35 dist script/subprojects/sub/meson.build b/test cases/unit/35 dist script/subprojects/sub/meson.build index 612861310..a41a3b685 100644 --- a/test cases/unit/35 dist script/subprojects/sub/meson.build +++ b/test cases/unit/35 dist script/subprojects/sub/meson.build @@ -1,4 +1,4 @@ -project('sub') +project('sub', 'c') if get_option('broken_dist_script') # Make sure we can add a dist script in a subproject, but it won't be run diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 5a533a958..dd8fa661f 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -3998,10 +3998,14 @@ class AllPlatformTests(BasePlatformTests): env = get_fake_env(testdir, self.builddir, self.prefix) def output_name(name, type_): - return type_(name=name, subdir=None, subproject=None, - for_machine=MachineChoice.HOST, sources=[], - structured_sources=None, - objects=[], environment=env, kwargs={}).filename + target = type_(name=name, subdir=None, subproject=None, + for_machine=MachineChoice.HOST, sources=[], + structured_sources=None, + objects=[], environment=env, compilers=env.coredata.compilers[MachineChoice.HOST], + kwargs={}) + target.process_compilers() + target.process_compilers_late([]) + return target.filename shared_lib_name = lambda name: output_name(name, SharedLibrary) static_lib_name = lambda name: output_name(name, StaticLibrary)