diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 0e6311a41..656ae5217 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1824,6 +1824,7 @@ rule FORTRAN_DEP_HACK%s modre = re.compile(r"\s*\bmodule\b\s+(\w+)\s*$", re.IGNORECASE) submodre = re.compile(r"\s*\bsubmodule\b\s+\((\w+:?\w+)\)\s+(\w+)\s*$", re.IGNORECASE) module_files = {} + submodule_files = {} for s in target.get_sources(): # FIXME, does not work for Fortran sources generated by # custom_target() and generator() as those are run after @@ -1847,15 +1848,16 @@ rule FORTRAN_DEP_HACK%s else: submodmatch = submodre.match(line) if submodmatch is not None: - submodname = submodmatch.group(2).lower() - if submodname in module_files: + # '_' is arbitrarily used to distinguish submod from mod. + submodname = '_' + submodmatch.group(2).lower() + if submodname in submodule_files: raise InvalidArguments( 'Namespace collision: submodule %s defined in ' 'two files %s and %s.' % - (submodname, module_files[submodname], s)) - module_files[submodname] = s + (submodname, submodule_files[submodname], s)) + submodule_files[submodname] = s - self.fortran_deps[target.get_basename()] = module_files + self.fortran_deps[target.get_basename()] = {**module_files, **submodule_files} def get_fortran_deps(self, compiler: FortranCompiler, src: str, target) -> List[str]: """ @@ -1865,6 +1867,63 @@ rule FORTRAN_DEP_HACK%s dirname = Path(self.get_target_private_dir(target)) tdeps = self.fortran_deps[target.get_basename()] srcdir = Path(self.source_dir) +<<<<<<< HEAD +======= + with src.open(encoding='ascii', errors='ignore') as f: + for line in f: + usematch = usere.match(line) + if usematch is not None: + usename = usematch.group(1).lower() + if usename == 'intrinsic': # this keeps the regex simpler + continue + if usename not in tdeps: + # The module is not provided by any source file. This + # is due to: + # a) missing file/typo/etc + # b) using a module provided by the compiler, such as + # OpenMP + # There's no easy way to tell which is which (that I + # know of) so just ignore this and go on. Ideally we + # would print a warning message to the user but this is + # a common occurrence, which would lead to lots of + # distracting noise. + continue + srcfile = srcdir / tdeps[usename].fname + if not srcfile.is_file(): + if srcfile.name != src.name: # generated source file + pass + else: # subproject + continue + elif srcfile.samefile(src): # self-reference + continue + + mod_name = compiler.module_name_to_filename(usename) + mod_files.append(str(dirname / mod_name)) + else: + submodmatch = submodre.match(line) + if submodmatch is not None: + parents = submodmatch.group(1).lower().split(':') + assert len(parents) in (1, 2), ( + 'submodule ancestry must be specified as' + ' ancestor:parent but Meson found {}'.parents) + + if len(parents) == 2: + parents[1] = '_' + parents[1] + + for parent in parents: + if parent not in tdeps: + raise MesonException("submodule {} relies on parent module {} that was not found.".format(submodmatch.group(2).lower(), parent)) + submodsrcfile = srcdir / tdeps[parent].fname + if not submodsrcfile.is_file(): + if submodsrcfile.name != src.name: # generated source file + pass + else: # subproject + continue + elif submodsrcfile.samefile(src): # self-reference + continue + mod_name = compiler.module_name_to_filename(parent) + mod_files.append(str(dirname / mod_name)) +>>>>>>> allow fortran submodule to have same name as module mod_files = _scan_fortran_file_deps(src, srcdir, dirname, tdeps, compiler) return mod_files