diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 77e1b04db..462ea27fe 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -144,12 +144,13 @@ class TargetDependencyScannerInfo: :param private_dir: The private scratch directory for the target. :param source2object: A mapping of source file names to the objects that will be created from them. - :param sources: A list of all the sources in this target + :param sources: a list of sources mapping them to the language rules to use + to scan them. """ private_dir: str source2object: T.Dict[str, str] - sources: T.List[str] + sources: T.List[T.Tuple[str, Literal['cpp', 'fortran']]] @unique @@ -1098,7 +1099,7 @@ class NinjaBackend(backends.Backend): pickle_file = os.path.join(self.get_target_private_dir(target), pickle_base).replace('\\', '/') pickle_abs = os.path.join(self.get_target_private_dir_abs(target), pickle_base).replace('\\', '/') rule_name = 'depscan' - scan_sources = self.select_sources_to_scan(compiled_sources) + scan_sources = list(self.select_sources_to_scan(compiled_sources)) scaninfo = TargetDependencyScannerInfo( self.get_target_private_dir(target), source2object, scan_sources) @@ -1113,19 +1114,17 @@ class NinjaBackend(backends.Backend): elem.orderdeps.update(object_deps) self.add_build(elem) - def select_sources_to_scan(self, compiled_sources: T.List[str]) -> T.List[str]: + def select_sources_to_scan(self, compiled_sources: T.List[str] + ) -> T.Iterable[T.Tuple[str, Literal['cpp', 'fortran']]]: # in practice pick up C++ and Fortran files. If some other language # requires scanning (possibly Java to deal with inner class files) # then add them here. - all_suffixes = set(compilers.lang_suffixes['cpp']) | set(compilers.lang_suffixes['fortran']) - selected_sources = [] for source in compiled_sources: ext = os.path.splitext(source)[1][1:] - if ext != 'C': - ext = ext.lower() - if ext in all_suffixes: - selected_sources.append(source) - return selected_sources + if ext.lower() in compilers.lang_suffixes['cpp'] or ext == 'C': + yield source, 'cpp' + elif ext.lower() in compilers.lang_suffixes['fortran']: + yield source, 'fortran' def process_target_dependencies(self, target): for t in target.get_dependencies(): diff --git a/mesonbuild/scripts/depscan.py b/mesonbuild/scripts/depscan.py index c0ac09b52..79934fb5f 100644 --- a/mesonbuild/scripts/depscan.py +++ b/mesonbuild/scripts/depscan.py @@ -9,13 +9,12 @@ import os import pathlib import pickle import re -import sys import typing as T from ..backend.ninjabackend import ninja_quote -from ..compilers.compilers import lang_suffixes if T.TYPE_CHECKING: + from typing_extensions import Literal from ..backend.ninjabackend import TargetDependencyScannerInfo CPP_IMPORT_RE = re.compile(r'\w*import ([a-zA-Z0-9]+);') @@ -41,16 +40,11 @@ class DependencyScanner: self.needs: collections.defaultdict[str, T.List[str]] = collections.defaultdict(list) self.sources_with_exports: T.List[str] = [] - def scan_file(self, fname: str) -> None: - suffix = os.path.splitext(fname)[1][1:] - if suffix != 'C': - suffix = suffix.lower() - if suffix in lang_suffixes['fortran']: + def scan_file(self, fname: str, lang: Literal['cpp', 'fortran']) -> None: + if lang == 'fortran': self.scan_fortran_file(fname) - elif suffix in lang_suffixes['cpp']: - self.scan_cpp_file(fname) else: - sys.exit(f'Can not scan files with suffix .{suffix}.') + self.scan_cpp_file(fname) def scan_fortran_file(self, fname: str) -> None: fpath = pathlib.Path(fname) @@ -118,9 +112,8 @@ class DependencyScanner: assert isinstance(objname, str) return objname - def module_name_for(self, src: str) -> str: - suffix = os.path.splitext(src)[1][1:].lower() - if suffix in lang_suffixes['fortran']: + def module_name_for(self, src: str, lang: Literal['cpp', 'fortran']) -> str: + if lang == 'fortran': exported = self.exports[src] # Module foo:bar goes to a file name foo@bar.smod # Module Foo goes to a file name foo.mod @@ -130,23 +123,20 @@ class DependencyScanner: else: extension = 'mod' return os.path.join(self.target_data.private_dir, f'{namebase}.{extension}') - elif suffix in lang_suffixes['cpp']: - return '{}.ifc'.format(self.exports[src]) - else: - raise RuntimeError('Unreachable code.') + return '{}.ifc'.format(self.exports[src]) def scan(self) -> int: - for s in self.sources: - self.scan_file(s) + for s, lang in self.sources: + self.scan_file(s, lang) with open(self.outfile, 'w', encoding='utf-8') as ofile: ofile.write('ninja_dyndep_version = 1\n') - for src in self.sources: + for src, lang in self.sources: objfilename = self.objname_for(src) mods_and_submods_needed = [] module_files_generated = [] module_files_needed = [] if src in self.sources_with_exports: - module_files_generated.append(self.module_name_for(src)) + module_files_generated.append(self.module_name_for(src, lang)) if src in self.needs: for modname in self.needs[src]: if modname not in self.provided_by: @@ -159,7 +149,7 @@ class DependencyScanner: for modname in mods_and_submods_needed: provider_src = self.provided_by[modname] - provider_modfile = self.module_name_for(provider_src) + provider_modfile = self.module_name_for(provider_src, lang) # Prune self-dependencies if provider_src != src: module_files_needed.append(provider_modfile)