From 0efab591da210418e0d618449be2f9462d5d58e8 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 27 Aug 2019 14:50:10 -0700 Subject: compilers: Move the compiler argument to proxy linker flags to the compiler class Instead of the DynamicLinker returning a hardcoded value like `-Wl,-foo`, it now is passed a value that could be '-Wl,', or could be something '-Xlinker=' This makes a few things cleaner, and will make it possible to fix using clang (not clang-cl) on windows, where it invokes either link.exe or lld-link.exe instead of a gnu-ld compatible linker. --- mesonbuild/compilers/compilers.py | 2 + mesonbuild/compilers/cuda.py | 16 ++--- mesonbuild/compilers/d.py | 6 ++ mesonbuild/compilers/fortran.py | 6 ++ mesonbuild/compilers/mixins/gnu.py | 4 ++ mesonbuild/compilers/swift.py | 3 + mesonbuild/environment.py | 66 +++++++++++--------- mesonbuild/linkers.py | 122 ++++++++++++++++++++++--------------- 8 files changed, 137 insertions(+), 88 deletions(-) (limited to 'mesonbuild') diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index f16e447..4218775 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -650,6 +650,8 @@ class Compiler: # manually searched. internal_libs = () + LINKER_PREFIX = None # type: typing.Union[None, str, typing.List[str]] + def __init__(self, exelist, version, for_machine: MachineChoice, linker: typing.Optional['DynamicLinker'] = None, **kwargs): if isinstance(exelist, str): diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index b6bafe7..3bcabf5 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -25,6 +25,9 @@ if typing.TYPE_CHECKING: class CudaCompiler(Compiler): + + LINKER_PREFIX = '-Xlinker=' + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): if not hasattr(self, 'language'): self.language = 'cuda' @@ -162,17 +165,8 @@ class CudaCompiler(Compiler): @staticmethod def _cook_link_args(args: typing.List[str]) -> typing.List[str]: - """ - Converts GNU-style arguments -Wl,-arg,-arg - to NVCC-style arguments -Xlinker=-arg,-arg - """ - cooked = [] # type: typing.List[str] - for arg in args: - if arg.startswith('-Wl,'): - arg = arg.replace('-Wl,', '-Xlinker=', 1) - arg = arg.replace(' ', '\\') - cooked.append(arg) - return cooked + """Fixup arguments.""" + return [a.replace(' ', '\\') for a in args] def name_string(self): return ' '.join(self.exelist) diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 18e3bf9..5e0c173 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -67,6 +67,8 @@ dmd_optimization_args = {'0': [], class DmdLikeCompilerMixin: + LINKER_PREFIX = '-L' + def get_output_args(self, target): return ['-of=' + target] @@ -577,6 +579,10 @@ class DCompiler(Compiler): class GnuDCompiler(DCompiler, GnuCompiler): + + # we mostly want DCompiler, but that gives us the Compiler.LINKER_PREFIX instead + LINKER_PREFIX = GnuCompiler.LINKER_PREFIX + def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs): DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs) self.id = 'gcc' diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 30ec6fe..fd7b91a 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -185,6 +185,9 @@ class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler): ElbrusCompiler.__init__(self, compiler_type, defines) class G95FortranCompiler(FortranCompiler): + + LINKER_PREFIX = '-Wl,' + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) self.id = 'g95' @@ -203,6 +206,9 @@ class G95FortranCompiler(FortranCompiler): class SunFortranCompiler(FortranCompiler): + + LINKER_PREFIX = '-Wl,' + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) self.id = 'sun' diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index d4318b6..998b86c 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -128,6 +128,9 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta): and ICC. Certain functionality between them is different and requires that the actual concrete subclass define their own implementation. """ + + LINKER_PREFIX = '-Wl,' + def __init__(self, compiler_type: 'CompilerType'): self.compiler_type = compiler_type self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', @@ -298,6 +301,7 @@ class GnuCompiler(GnuLikeCompiler): GnuCompiler represents an actual GCC in its many incarnations. Compilers imitating GCC (Clang/Intel) should use the GnuLikeCompiler ABC. """ + def __init__(self, compiler_type: 'CompilerType', defines: typing.Dict[str, str]): super().__init__(compiler_type) self.id = 'gcc' diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index 6c639fd..e429056 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -27,6 +27,9 @@ swift_optimization_args = {'0': [], } class SwiftCompiler(Compiler): + + LINKER_PREFIX = ['-Xlinker'] + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, **kwargs): self.language = 'swift' super().__init__(exelist, version, for_machine, **kwargs) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 2675bca..71de41e 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -660,8 +660,8 @@ class Environment: raise EnvironmentException(errmsg) @staticmethod - def _guess_nix_linker(compiler: typing.List[str], for_machine: MachineChoice, *, - prefix: typing.Union[str, typing.List[str]] = '-Wl,', + def _guess_nix_linker(compiler: typing.List[str], for_machine: MachineChoice, + prefix: typing.Union[str, typing.List[str]], *, extra_args: typing.Optional[typing.List[str]] = None) -> 'DynamicLinker': """Helper for guessing what linker to use on Unix-Like OSes. @@ -682,7 +682,7 @@ class Environment: _, o, e = Popen_safe(compiler + check_args) v = search_version(o) if o.startswith('LLD'): - linker = LLVMDynamicLinker(compiler, for_machine, 'lld', version=v) # type: DynamicLinker + linker = LLVMDynamicLinker(compiler, for_machine, 'lld', prefix, version=v) # type: DynamicLinker # first is for apple clang, second is for real gcc elif e.endswith('(use -v to see invocation)\n') or 'macosx_version' in e: if isinstance(prefix, str): @@ -696,15 +696,17 @@ class Environment: break else: v = 'unknown version' - linker = AppleDynamicLinker(compiler, for_machine, i, version=v) + linker = AppleDynamicLinker(compiler, for_machine, i, prefix, version=v) elif 'GNU' in o: if 'gold' in 'o': i = 'GNU ld.gold' else: i = 'GNU ld.bfd' - linker = GnuDynamicLinker(compiler, for_machine, i, version=v) + linker = GnuDynamicLinker(compiler, for_machine, i, prefix, version=v) elif 'Solaris' in e: - linker = SolarisDynamicLinker(compiler, for_machine, 'solaris', version=search_version(e)) + linker = SolarisDynamicLinker( + compiler, for_machine, 'solaris', prefix, + version=search_version(e)) else: raise MesonException('Unable to determine dynamic linker.') return linker @@ -772,14 +774,14 @@ class Environment: continue compiler_type = self.get_gnu_compiler_type(defines) - linker = self._guess_nix_linker(compiler, for_machine) - if guess_gcc_or_lcc == 'lcc': version = self.get_lcc_version_from_defines(defines) cls = ElbrusCCompiler if lang == 'c' else ElbrusCPPCompiler else: version = self.get_gnu_version_from_defines(defines) cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler + + linker = self._guess_nix_linker(compiler, for_machine, cls.LINKER_PREFIX) return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version, linker=linker) @@ -833,7 +835,7 @@ class Environment: compiler_type = CompilerType.CLANG_STANDARD cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, cls.LINKER_PREFIX) return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) if 'Intel(R) C++ Intel(R)' in err: version = search_version(err) @@ -869,15 +871,15 @@ class Environment: else: compiler_type = CompilerType.PGI_STANDARD cls = PGICCompiler if lang == 'c' else PGICPPCompiler - linker = PGIDynamicLinker(compiler, for_machine, 'pgi', version=version) + linker = PGIDynamicLinker(compiler, for_machine, 'pgi', cls.LINKER_PREFIX, version=version) return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, linker=linker) if '(ICC)' in out: if self.machines[for_machine].is_darwin(): compiler_type = CompilerType.ICC_OSX - l = XildAppleDynamicLinker(compiler, for_machine, 'xild', version=version) + l = XildAppleDynamicLinker(compiler, for_machine, 'xild', '-Wl,', version=version) else: compiler_type = CompilerType.ICC_STANDARD - l = XildLinuxDynamicLinker(compiler, for_machine, 'xild', version=version) + l = XildLinuxDynamicLinker(compiler, for_machine, 'xild', '-Wl,', version=version) cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=l) if 'ARM' in out: @@ -929,7 +931,7 @@ class Environment: # Luckily, the "V" also makes it very simple to extract # the full version: version = out.strip().split('V')[-1] - linker = self._guess_nix_linker(compiler, for_machine, prefix='-Xlinker=') + linker = self._guess_nix_linker(compiler, for_machine, CudaCompiler.LINKER_PREFIX) return CudaCompiler(ccache + compiler, version, for_machine, exe_wrap, linker=linker) raise EnvironmentException('Could not find suitable CUDA compiler: "' + ' '.join(compilers) + '"') @@ -968,16 +970,16 @@ class Environment: else: version = self.get_gnu_version_from_defines(defines) cls = GnuFortranCompiler - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, cls.LINKER_PREFIX) return cls(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version, linker=linker) if 'G95' in out: - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, G95FortranCompiler.LINKER_PREFIX) return G95FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) if 'Sun Fortran' in err: version = search_version(err) - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, SunFortranCompiler.LINKER_PREFIX) return SunFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) if 'Intel(R) Visual Fortran' in err: @@ -987,7 +989,7 @@ class Environment: return IntelClFortranCompiler(compiler, version, for_machine, is_cross, target, exe_wrap, linker=linker) if 'ifort (IFORT)' in out: - linker = XildLinuxDynamicLinker(compiler, for_machine, 'xild', version=version) + linker = XildLinuxDynamicLinker(compiler, for_machine, 'xild', '-Wl,', version=version) return IntelFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) if 'PathScale EKOPath(tm)' in err: @@ -1000,19 +1002,19 @@ class Environment: compiler_type = CompilerType.PGI_WIN else: compiler_type = CompilerType.PGI_STANDARD - linker = PGIDynamicLinker(compiler, for_machine, 'pgi', version=version) + linker = PGIDynamicLinker(compiler, for_machine, 'pgi', PGIFortranCompiler.LINKER_PREFIX, version=version) return PGIFortranCompiler(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) if 'flang' in out or 'clang' in out: - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, FlangFortranCompiler.LINKER_PREFIX) return FlangFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) if 'Open64 Compiler Suite' in err: - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, Open64FortranCompiler.LINKER_PREFIX) return Open64FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) if 'NAG Fortran' in err: - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, NAGFortranCompiler.LINKER_PREFIX) return NAGFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker) self._handle_exceptions(popen_exceptions, compilers) @@ -1047,7 +1049,7 @@ class Environment: compiler_type = self.get_gnu_compiler_type(defines) version = self.get_gnu_version_from_defines(defines) comp = GnuObjCCompiler if objc else GnuObjCPPCompiler - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, comp.LINKER_PREFIX) return comp(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, linker=linker) if 'clang' in out: comp = ClangObjCCompiler if objc else ClangObjCPPCompiler @@ -1057,7 +1059,7 @@ class Environment: compiler_type = CompilerType.CLANG_MINGW else: compiler_type = CompilerType.CLANG_STANDARD - linker = self._guess_nix_linker(compiler, for_machine) + linker = self._guess_nix_linker(compiler, for_machine, comp.LINKER_PREFIX) return comp(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, linker=linker) self._handle_exceptions(popen_exceptions, compilers) @@ -1141,9 +1143,9 @@ class Environment: # default, and apple ld is used on mac. # TODO: find some better way to figure this out. if self.machines[for_machine].is_darwin(): - linker = AppleDynamicLinker([], for_machine, 'Apple ld') + linker = AppleDynamicLinker([], for_machine, 'Apple ld', '-Wl,') else: - linker = GnuDynamicLinker([], for_machine, 'GNU ld') + linker = GnuDynamicLinker([], for_machine, 'GNU ld', '-Wl,') return RustCompiler(compiler, version, for_machine, is_cross, exe_wrap, linker=linker) self._handle_exceptions(popen_exceptions, compilers) @@ -1196,10 +1198,13 @@ class Environment: linker = ClangClDynamicLinker(for_machine, version=search_version(o)) else: with tempfile.NamedTemporaryFile(suffix='.d') as f: - linker = self._guess_nix_linker(exelist, for_machine, prefix='-L', extra_args=[f.name]) + linker = self._guess_nix_linker( + exelist, for_machine, + compilers.LLVMDCompiler.LINKER_PREFIX, + extra_args=[f.name]) return compilers.LLVMDCompiler(exelist, version, for_machine, arch, full_version=full_version, linker=linker) elif 'gdc' in out: - linker = self._guess_nix_linker(exelist, for_machine) + linker = self._guess_nix_linker(exelist, for_machine, compilers.GnuDCompiler.LINKER_PREFIX) return compilers.GnuDCompiler(exelist, version, for_machine, arch, full_version=full_version, linker=linker) elif 'The D Language Foundation' in out or 'Digital Mars' in out: # DMD seems to require a file @@ -1208,7 +1213,10 @@ class Environment: linker = OptlinkDynamicLinker(for_machine, version=full_version) else: with tempfile.NamedTemporaryFile(suffix='.d') as f: - linker = self._guess_nix_linker(exelist, for_machine, prefix='-L', extra_args=[f.name]) + linker = self._guess_nix_linker( + exelist, for_machine, + compilers.LLVMDCompiler.LINKER_PREFIX, + extra_args=[f.name]) return compilers.DmdDCompiler(exelist, version, for_machine, arch, full_version=full_version, linker=linker) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') @@ -1228,7 +1236,7 @@ class Environment: # As for 5.0.1 swiftc *requires* a file to check the linker: with tempfile.NamedTemporaryFile(suffix='.swift') as f: linker = self._guess_nix_linker( - exelist, for_machine, prefix=['-Xlinker'], extra_args=[f.name]) + exelist, for_machine, compilers.SwiftCompiler.LINKER_PREFIX, extra_args=[f.name]) return compilers.SwiftCompiler(exelist, version, for_machine, is_cross, linker=linker) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index caf11f1..272f927 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -238,12 +238,18 @@ class DynamicLinker(metaclass=abc.ABCMeta): 'custom': [], } # type: typing.Dict[str, typing.List[str]] + def _apply_prefix(self, arg: str) -> typing.List[str]: + if isinstance(self.prefix_arg, str): + return [self.prefix_arg + arg] + return self.prefix_arg + [arg] + def __init__(self, exelist: typing.List[str], for_machine: mesonlib.MachineChoice, - id_: str, *, version: str = 'unknown version'): + id_: str, prefix_arg: str, *, version: str = 'unknown version'): self.exelist = exelist self.for_machine = for_machine self.version = version self.id = id_ + self.prefix_arg = prefix_arg def __repr__(self) -> str: return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist)) @@ -413,24 +419,29 @@ class GnuLikeDynamicLinkerMixin: 'plain': [], 'debug': [], 'debugoptimized': [], - 'release': ['-Wl,-O1'], + 'release': ['-O1'], 'minsize': [], 'custom': [], } # type: typing.Dict[str, typing.List[str]] + def get_buildtype_args(self, buildtype: str) -> typing.List[str]: + # We can override these in children by just overriding the + # _BUILDTYPE_ARGS value. + return mesonlib.listify([self._apply_prefix(a) for a in self._BUILDTYPE_ARGS[buildtype]]) + def get_pie_args(self) -> typing.List[str]: return ['-pie'] def get_asneeded_args(self) -> typing.List[str]: - return ['-Wl,--as-needed'] + return self._apply_prefix('--as-needed') def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]: if not args: return args - return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive'] + return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive') def get_allow_undefined_args(self) -> typing.List[str]: - return ['-Wl,--allow-shlib-undefined'] + return self._apply_prefix('--allow-shlib-undefined') def get_lto_args(self) -> typing.List[str]: return ['-flto'] @@ -450,11 +461,11 @@ class GnuLikeDynamicLinkerMixin: def export_dynamic_args(self, env: 'Environment') -> typing.List[str]: m = env.machines[self.for_machine] if m.is_windows() or m.is_cygwin(): - return ['-Wl,--export-all-symbols'] - return ['-Wl,-export-dynamic'] + return self._apply_prefix('--export-all-symbols') + return self._apply_prefix('-export-dynamic') def import_library_args(self, implibname: str) -> typing.List[str]: - return ['-Wl,--out-implib=' + implibname] + return self._apply_prefix('--out-implib=' + implibname) def thread_flags(self, env: 'Environment') -> typing.List[str]: if env.machines[self.for_machine].is_haiku(): @@ -462,10 +473,10 @@ class GnuLikeDynamicLinkerMixin: return ['-pthread'] def no_undefined_args(self) -> typing.List[str]: - return ['-Wl,--no-undefined'] + return self._apply_prefix('--no-undefined') def fatal_warnings(self) -> typing.List[str]: - return ['-Wl,--fatal-warnings'] + return self._apply_prefix('--fatal-warnings') def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: typing.Tuple[str, str], @@ -475,7 +486,7 @@ class GnuLikeDynamicLinkerMixin: # For PE/COFF the soname argument has no effect return [] sostr = '' if soversion is None else '.' + soversion - return ['-Wl,-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)] + return self._apply_prefix('-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)) def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, @@ -503,7 +514,7 @@ class GnuLikeDynamicLinkerMixin: # by default, but is not on dragonfly/openbsd for some reason. Without this # $ORIGIN in the runtime path will be undefined and any binaries # linked against local libraries will fail to resolve them. - args.append('-Wl,-z,origin') + args.extend(self._apply_prefix('-z,origin')) # In order to avoid relinking for RPATH removal, the binary needs to contain just # enough space in the ELF header to hold the final installation RPATH. @@ -514,7 +525,7 @@ class GnuLikeDynamicLinkerMixin: paths = padding else: paths = paths + ':' + padding - args.append('-Wl,-rpath,' + paths) + args.extend(self._apply_prefix('-rpath,' + paths)) # TODO: should this actually be "for solaris/sunos"? if mesonlib.is_sunos(): @@ -535,7 +546,8 @@ class GnuLikeDynamicLinkerMixin: # ...instead of just one single looooong option, like this: # # -Wl,-rpath-link,/path/to/folder1:/path/to/folder2:... - args.extend(['-Wl,-rpath-link,' + os.path.join(build_dir, p) for p in rpath_paths]) + for p in rpath_paths: + args.extend(self._apply_prefix('-rpath-link,' + os.path.join(build_dir, p))) return args @@ -545,31 +557,32 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): """Apple's ld implementation.""" def get_asneeded_args(self) -> typing.List[str]: - return ['-Wl,-dead_strip_dylibs'] + return self._apply_prefix('-dead_strip_dylibs') def get_allow_undefined_args(self) -> typing.List[str]: - return ['-Wl,-undefined,dynamic_lookup'] + return self._apply_prefix('-undefined,dynamic_lookup') def get_std_shared_module_args(self, options: 'OptionDictType') -> typing.List[str]: - return ['-bundle', '-Wl,-undefined,dynamic_lookup'] + return ['-bundle'] + self._apply_prefix('-undefined,dynamic_lookup') def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]: result = [] # type: typing.List[str] for a in args: - result.extend(['-Wl,-force_load', a]) + result.extend(self._apply_prefix('-force_load')) + result.append(a) return result def no_undefined_args(self) -> typing.List[str]: - return ['-Wl,-undefined,error'] + return self._apply_prefix('-undefined,error') def get_always_args(self) -> typing.List[str]: - return ['-Wl,-headerpad_max_install_names'] + return self._apply_prefix('-headerpad_max_install_names') def bitcode_args(self) -> typing.List[str]: - return ['-Wl,-bitcode_bundle'] + return self._apply_prefix('-bitcode_bundle') def fatal_warnings(self) -> typing.List[str]: - return ['-Wl,-fatal_warnings'] + return self._apply_prefix('-fatal_warnings') def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: typing.Tuple[str, str], @@ -593,7 +606,7 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): return [] # Ensure that there is enough space for install_name_tool in-place # editing of large RPATHs - args = ['-Wl,-headerpad_max_install_names'] + args = self._apply_prefix('-headerpad_max_install_names') # @loader_path is the equivalent of $ORIGIN on macOS # https://stackoverflow.com/q/26280738 origin_placeholder = '@loader_path' @@ -601,7 +614,8 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths]) if build_rpath != '': all_paths.add(build_rpath) - args.extend(['-Wl,-rpath,' + rp for rp in all_paths]) + for rp in all_paths: + args.extend(self._apply_prefix('-rpath,' + rp)) return args @@ -649,7 +663,7 @@ class CcrxDynamicLinker(DynamicLinker): def __init__(self, for_machine: mesonlib.MachineChoice, *, version: str = 'unknown version'): - super().__init__(['rlink.exe'], for_machine, 'rlink', + super().__init__(['rlink.exe'], for_machine, 'rlink', '', version=version) def get_accepts_rsp(self) -> bool: @@ -682,7 +696,7 @@ class ArmDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): def __init__(self, for_machine: mesonlib.MachineChoice, *, version: str = 'unknown version'): - super().__init__(['armlink'], for_machine, 'armlink', + super().__init__(['armlink'], for_machine, 'armlink', '', version=version) def get_accepts_rsp(self) -> bool: @@ -751,9 +765,13 @@ class VisualStudioLikeLinkerMixin: 'custom': [], } # type: typing.Dict[str, typing.List[str]] - def __init__(self, *args, **kwargs): + def __init__(self, *args, direct: bool = True, machine: str = 'x86', **kwargs): super().__init__(*args, **kwargs) - self.machine = 'x86' + self.direct = direct + self.machine = machine + + def invoked_by_compiler(self) -> bool: + return self.direct def get_debug_crt_args(self) -> typing.List[str]: """Arguments needed to select a debug crt for the linker. @@ -763,33 +781,36 @@ class VisualStudioLikeLinkerMixin: MSVC won't auto-select a CRT for us in that case and will error out asking us to select one. """ - return ['/MDd'] + return self._apply_prefix('/MDd') def get_output_args(self, outputname: str) -> typing.List[str]: - return ['/MACHINE:' + self.machine, '/OUT:' + outputname] + return self._apply_prefix('/MACHINE:' + self.machine) + self._apply_prefix('/OUT:' + outputname) def get_always_args(self) -> typing.List[str]: - return ['/nologo'] + return self._apply_prefix('/nologo') def get_search_args(self, dirname: str) -> typing.List[str]: - return ['/LIBPATH:' + dirname] + return self._apply_prefix('/LIBPATH:' + dirname) def get_std_shared_lib_args(self) -> typing.List[str]: - return ['/DLL'] + return self._apply_prefix('/DLL') def get_debugfile_args(self, targetfile: str) -> typing.List[str]: pdbarr = targetfile.split('.')[:-1] pdbarr += ['pdb'] - return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)] + return self._apply_prefix('/DEBUG') + self._apply_prefix('/PDB:' + '.'.join(pdbarr)) def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]: # Only since VS2015 args = mesonlib.listify(args) - return ['/WHOLEARCHIVE:' + x for x in args] + l = [] # typing.List[str] + for a in args: + l.extend(self._apply_prefix('/WHOLEARCHIVE:' + a)) + return l def get_allow_undefined_args(self) -> typing.List[str]: # link.exe - return ['/FORCE:UNRESOLVED'] + return self._apply_prefix('/FORCE:UNRESOLVED') def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: typing.Tuple[str, str], @@ -801,19 +822,24 @@ class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): """Microsoft's Link.exe.""" - def __init__(self, for_machine: mesonlib.MachineChoice, - *, version: str = 'unknown version'): - super().__init__(['link.exe'], for_machine, 'link', version=version) + def __init__(self, for_machine: mesonlib.MachineChoice, *, + exelist: typing.Optional[typing.List[str]] = None, + prefix: typing.Union[str, typing.List[str]] = '', + machine: str = 'x86', version: str = 'unknown version'): + super().__init__(exelist or ['link.exe'], for_machine, 'link', + prefix, machine=machine, version=version) class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): """Clang's lld-link.exe.""" - def __init__(self, for_machine: mesonlib.MachineChoice, - *, version: str = 'unknown version'): - super().__init__(['lld-link.exe'], for_machine, 'lld-link', - version=version) + def __init__(self, for_machine: mesonlib.MachineChoice, *, + exelist: typing.Optional[typing.List[str]] = None, + prefix: typing.Union[str, typing.List[str]] = '', + version: str = 'unknown version'): + super().__init__(exelist or ['lld-link.exe'], for_machine, + 'lld-link', prefix, version=version) class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): @@ -822,7 +848,7 @@ class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): def __init__(self, for_machine: mesonlib.MachineChoice, *, version: str = 'unknown version'): - super().__init__(['xilink.exe'], for_machine, 'xilink', version=version) + super().__init__(['xilink.exe'], for_machine, 'xilink', '', version=version) class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): @@ -832,7 +858,7 @@ class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]: if not args: return args - return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive'] + return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive') def no_undefined_args(self) -> typing.List[str]: return ['-z', 'defs'] @@ -862,13 +888,13 @@ class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): paths = padding else: paths = paths + ':' + padding - return ['-Wl,-rpath,{}'.format(paths)] + return self._apply_prefix('-rpath,{}'.format(paths)) def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, suffix: str, soversion: str, darwin_versions: typing.Tuple[str, str], is_shared_module: bool) -> typing.List[str]: sostr = '' if soversion is None else '.' + soversion - return ['-Wl,-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)] + return self._apply_prefix('-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)) class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): @@ -879,7 +905,7 @@ class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): *, version: str = 'unknown version'): # Use optlink instead of link so we don't interfer with other link.exe # implementations. - super().__init__(['optlink.exe'], for_machine, 'optlink', version=version) + super().__init__(['optlink.exe'], for_machine, 'optlink', prefix_arg='', version=version) def get_allow_undefined_args(self) -> typing.List[str]: return [] -- cgit v1.1