From 64c267c49c785a204730ca28141f1fe34bc1827a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 30 Jul 2021 11:07:03 -0700 Subject: [PATCH] compilers: Add default search path stdlib_only_link_flags This should be done in all cases of language_stdlib_only_link_flags, but I don't have access to all of the compilers to test it. This is required in cases where object files created by gfortran are linked using another compiler with a differen default search path, such as gfortran and clang together. --- mesonbuild/build.py | 4 +-- mesonbuild/compilers/compilers.py | 2 +- mesonbuild/compilers/cpp.py | 37 ++++++++++++++++++++++++---- mesonbuild/compilers/fortran.py | 33 ++++++++++++++++++++----- test cases/fortran/9 cpp/meson.build | 4 --- 5 files changed, 62 insertions(+), 18 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 2ee2d4a3e..98385dfbe 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1470,7 +1470,7 @@ You probably should put it in link_with instead.''') # If the user set the link_language, just return that. if self.link_language: comp = all_compilers[self.link_language] - return comp, comp.language_stdlib_only_link_flags() + return comp, comp.language_stdlib_only_link_flags(self.environment) # Languages used by dependencies dep_langs = self.get_langs_used_by_deps() @@ -1488,7 +1488,7 @@ You probably should put it in link_with instead.''') 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() + 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 diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index de5e4725d..6896b76d9 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -893,7 +893,7 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): def openmp_link_flags(self) -> T.List[str]: return self.openmp_flags() - def language_stdlib_only_link_flags(self) -> T.List[str]: + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: return [] def gnu_symbol_visibility_args(self, vistype: str) -> T.List[str]: diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index ecc911d72..6cbc26538 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -246,13 +246,31 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): return libs return [] - def language_stdlib_only_link_flags(self) -> T.List[str]: - return ['-lstdc++'] + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # We need to apply the search prefix here, as these link arguments may + # be passed to a differen compiler with a different set of default + # search paths, such as when using Clang for C/C++ and gfortran for + # fortran, + search_dir = self._get_search_dirs(env) + search_dirs: T.List[str] = [] + if search_dir is not None: + for d in search_dir.split()[-1][len('libraries: ='):].split(':'): + search_dirs.append(f'-L{d}') + return search_dirs + ['-lstdc++'] class AppleClangCPPCompiler(ClangCPPCompiler): - def language_stdlib_only_link_flags(self) -> T.List[str]: - return ['-lc++'] + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # We need to apply the search prefix here, as these link arguments may + # be passed to a differen compiler with a different set of default + # search paths, such as when using Clang for C/C++ and gfortran for + # fortran, + search_dir = self._get_search_dirs(env) + search_dirs: T.List[str] = [] + if search_dir is not None: + for d in search_dir.split()[-1][len('libraries: ='):].split(':'): + search_dirs.append(f'-L{d}') + return search_dirs + ['-lc++'] class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler): @@ -396,7 +414,16 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]: return ['-fpch-preprocess', '-include', os.path.basename(header)] - def language_stdlib_only_link_flags(self) -> T.List[str]: + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # We need to apply the search prefix here, as these link arguments may + # be passed to a differen compiler with a different set of default + # search paths, such as when using Clang for C/C++ and gfortran for + # fortran, + search_dir = self._get_search_dirs(env) + search_dirs: T.List[str] = [] + if search_dir is not None: + for d in search_dir.split()[-1][len('libraries: ='):].split(':'): + search_dirs.append(f'-L{d}') return ['-lstdc++'] diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 639c40fb4..5d72f4b0f 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -211,8 +211,17 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): def get_module_outdir_args(self, path: str) -> T.List[str]: return ['-J' + path] - def language_stdlib_only_link_flags(self) -> T.List[str]: - return ['-lgfortran', '-lm'] + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # We need to apply the search prefix here, as these link arguments may + # be passed to a differen compiler with a different set of default + # search paths, such as when using Clang for C/C++ and gfortran for + # fortran, + search_dir = self._get_search_dirs(env) + search_dirs: T.List[str] = [] + if search_dir is not None: + for d in search_dir.split()[-1][len('libraries: ='):].split(':'): + search_dirs.append(f'-L{d}') + return search_dirs + ['-lgfortran', '-lm'] def has_header(self, hname: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None, @@ -336,7 +345,8 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): def get_preprocess_only_args(self) -> T.List[str]: return ['-cpp', '-EP'] - def language_stdlib_only_link_flags(self) -> T.List[str]: + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # TODO: needs default search path added return ['-lifcore', '-limf'] def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]: @@ -420,7 +430,8 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler): '2': default_warn_args, '3': default_warn_args + ['-Mdclchk']} - def language_stdlib_only_link_flags(self) -> T.List[str]: + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # TODO: needs default search path added return ['-lpgf90rtl', '-lpgf90', '-lpgf90_rpm1', '-lpgf902', '-lpgf90rtl', '-lpgftnrtl', '-lrt'] @@ -461,8 +472,18 @@ class FlangFortranCompiler(ClangCompiler, FortranCompiler): '2': default_warn_args, '3': default_warn_args} - def language_stdlib_only_link_flags(self) -> T.List[str]: - return ['-lflang', '-lpgmath'] + def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]: + # We need to apply the search prefix here, as these link arguments may + # be passed to a differen compiler with a different set of default + # search paths, such as when using Clang for C/C++ and gfortran for + # fortran, + # XXX: Untested.... + search_dir = self._get_search_dirs(env) + search_dirs: T.List[str] = [] + if search_dir is not None: + for d in search_dir.split()[-1][len('libraries: ='):].split(':'): + search_dirs.append(f'-L{d}') + return search_dirs + ['-lflang', '-lpgmath'] class Open64FortranCompiler(FortranCompiler): diff --git a/test cases/fortran/9 cpp/meson.build b/test cases/fortran/9 cpp/meson.build index f96944b79..270fae5ef 100644 --- a/test cases/fortran/9 cpp/meson.build +++ b/test cases/fortran/9 cpp/meson.build @@ -3,10 +3,6 @@ project('C, C++ and Fortran', 'c', 'cpp', 'fortran') cpp = meson.get_compiler('cpp') fc = meson.get_compiler('fortran') -if cpp.get_id() == 'clang' - error('MESON_SKIP_TEST Clang C++ does not find -lgfortran for some reason.') -endif - if build_machine.system() == 'windows' and cpp.get_id() != fc.get_id() error('MESON_SKIP_TEST mixing gfortran with non-GNU C++ does not work.') endif