aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/linkers
diff options
context:
space:
mode:
authorDaniel Mensinger <daniel@mensinger-ka.de>2021-06-03 21:10:19 +0200
committerDaniel Mensinger <daniel@mensinger-ka.de>2021-06-25 19:34:48 +0200
commit0f237b8d1d84e4906c758bbef44d81e93207f8e4 (patch)
treedbcc035687e2a85bad3cbb3e2152edc22fdc5d88 /mesonbuild/linkers
parentd3d95d39beebb42894dbcf7cad58ef1fba4bbe2f (diff)
downloadmeson-0f237b8d1d84e4906c758bbef44d81e93207f8e4.zip
meson-0f237b8d1d84e4906c758bbef44d81e93207f8e4.tar.gz
meson-0f237b8d1d84e4906c758bbef44d81e93207f8e4.tar.bz2
linkers: move linkers.py into the linkers package
Diffstat (limited to 'mesonbuild/linkers')
-rw-r--r--mesonbuild/linkers/__init__.py115
-rw-r--r--mesonbuild/linkers/linkers.py1429
2 files changed, 1544 insertions, 0 deletions
diff --git a/mesonbuild/linkers/__init__.py b/mesonbuild/linkers/__init__.py
new file mode 100644
index 0000000..0d6fbc1
--- /dev/null
+++ b/mesonbuild/linkers/__init__.py
@@ -0,0 +1,115 @@
+# Copyright 2012-2021 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from .linkers import (
+ RSPFileSyntax,
+
+ StaticLinker,
+ VisualStudioLikeLinker,
+ VisualStudioLinker,
+ IntelVisualStudioLinker,
+ ArLinker,
+ ArmarLinker,
+ DLinker,
+ CcrxLinker,
+ Xc16Linker,
+ CompCertLinker,
+ C2000Linker,
+ AIXArLinker,
+ PGIStaticLinker,
+ NvidiaHPC_StaticLinker,
+
+ DynamicLinker,
+ PosixDynamicLinkerMixin,
+ GnuLikeDynamicLinkerMixin,
+ AppleDynamicLinker,
+ GnuDynamicLinker,
+ GnuGoldDynamicLinker,
+ GnuBFDDynamicLinker,
+ LLVMDynamicLinker,
+ WASMDynamicLinker,
+ CcrxDynamicLinker,
+ Xc16DynamicLinker,
+ CompCertDynamicLinker,
+ C2000DynamicLinker,
+ ArmDynamicLinker,
+ ArmClangDynamicLinker,
+ QualcommLLVMDynamicLinker,
+ PGIDynamicLinker,
+ NvidiaHPC_DynamicLinker,
+
+ VisualStudioLikeLinkerMixin,
+ MSVCDynamicLinker,
+ ClangClDynamicLinker,
+ XilinkDynamicLinker,
+ SolarisDynamicLinker,
+ AIXDynamicLinker,
+ OptlinkDynamicLinker,
+ CudaLinker,
+
+ prepare_rpaths,
+ order_rpaths,
+ evaluate_rpath,
+)
+
+__all__ = [
+ 'RSPFileSyntax',
+
+ 'StaticLinker',
+ 'VisualStudioLikeLinker',
+ 'VisualStudioLinker',
+ 'IntelVisualStudioLinker',
+ 'ArLinker',
+ 'ArmarLinker',
+ 'DLinker',
+ 'CcrxLinker',
+ 'Xc16Linker',
+ 'CompCertLinker',
+ 'C2000Linker',
+ 'AIXArLinker',
+ 'PGIStaticLinker',
+ 'NvidiaHPC_StaticLinker',
+
+ 'DynamicLinker',
+ 'PosixDynamicLinkerMixin',
+ 'GnuLikeDynamicLinkerMixin',
+ 'AppleDynamicLinker',
+ 'GnuDynamicLinker',
+ 'GnuGoldDynamicLinker',
+ 'GnuBFDDynamicLinker',
+ 'LLVMDynamicLinker',
+ 'WASMDynamicLinker',
+ 'CcrxDynamicLinker',
+ 'Xc16DynamicLinker',
+ 'CompCertDynamicLinker',
+ 'C2000DynamicLinker',
+ 'ArmDynamicLinker',
+ 'ArmClangDynamicLinker',
+ 'QualcommLLVMDynamicLinker',
+ 'PGIDynamicLinker',
+ 'NvidiaHPC_DynamicLinker',
+
+ 'VisualStudioLikeLinkerMixin',
+ 'MSVCDynamicLinker',
+ 'ClangClDynamicLinker',
+ 'XilinkDynamicLinker',
+ 'SolarisDynamicLinker',
+ 'AIXDynamicLinker',
+ 'OptlinkDynamicLinker',
+ 'CudaLinker',
+
+ 'prepare_rpaths',
+ 'order_rpaths',
+ 'evaluate_rpath',
+]
diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py
new file mode 100644
index 0000000..6ebdbcb
--- /dev/null
+++ b/mesonbuild/linkers/linkers.py
@@ -0,0 +1,1429 @@
+# Copyright 2012-2017 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import abc
+import enum
+import os
+import typing as T
+
+from .. import mesonlib
+from ..arglist import CompilerArgs
+
+if T.TYPE_CHECKING:
+ from ..coredata import KeyedOptionDictType
+ from ..environment import Environment
+ from ..mesonlib import MachineChoice
+
+
+@enum.unique
+class RSPFileSyntax(enum.Enum):
+
+ """Which RSP file syntax the compiler supports."""
+
+ MSVC = enum.auto()
+ GCC = enum.auto()
+
+
+class StaticLinker:
+
+ id: str
+
+ def __init__(self, exelist: T.List[str]):
+ self.exelist = exelist
+
+ def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs:
+ return CompilerArgs(self, args)
+
+ def can_linker_accept_rsp(self) -> bool:
+ """
+ Determines whether the linker can accept arguments using the @rsp syntax.
+ """
+ return mesonlib.is_windows()
+
+ def get_base_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
+ """Like compilers.get_base_link_args, but for the static linker."""
+ return []
+
+ def get_exelist(self) -> T.List[str]:
+ return self.exelist.copy()
+
+ def get_std_link_args(self) -> T.List[str]:
+ return []
+
+ def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]:
+ return []
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return[]
+
+ def get_coverage_link_args(self) -> T.List[str]:
+ return []
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
+
+ def thread_link_flags(self, env: 'Environment') -> T.List[str]:
+ return []
+
+ def openmp_flags(self) -> T.List[str]:
+ return []
+
+ def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
+ return []
+
+ @classmethod
+ def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]:
+ return args[:]
+
+ @classmethod
+ def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
+ return args[:]
+
+ def get_link_debugfile_name(self, targetfile: str) -> str:
+ return None
+
+ def get_link_debugfile_args(self, targetfile: str) -> T.List[str]:
+ # Static libraries do not have PDB files
+ return []
+
+ def get_always_args(self) -> T.List[str]:
+ return []
+
+ def get_linker_always_args(self) -> T.List[str]:
+ return []
+
+ def rsp_file_syntax(self) -> RSPFileSyntax:
+ """The format of the RSP file that this compiler supports.
+
+ If `self.can_linker_accept_rsp()` returns True, then this needs to
+ be implemented
+ """
+ assert not self.can_linker_accept_rsp(), f'{self.id} linker accepts RSP, but doesn\' provide a supported format, this is a bug'
+ raise mesonlib.EnvironmentException(f'{self.id} does not implemnt rsp format, this shouldn\'t be called')
+
+
+class VisualStudioLikeLinker:
+ always_args = ['/NOLOGO']
+
+ def __init__(self, machine: str):
+ self.machine = machine
+
+ def get_always_args(self) -> T.List[str]:
+ return self.always_args.copy()
+
+ def get_linker_always_args(self) -> T.List[str]:
+ return self.always_args.copy()
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ args = [] # type: T.List[str]
+ if self.machine:
+ args += ['/MACHINE:' + self.machine]
+ args += ['/OUT:' + target]
+ return args
+
+ @classmethod
+ def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]:
+ from ..compilers import VisualStudioCCompiler
+ return VisualStudioCCompiler.unix_args_to_native(args)
+
+ @classmethod
+ def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
+ from ..compilers import VisualStudioCCompiler
+ return VisualStudioCCompiler.native_args_to_unix(args)
+
+ def rsp_file_syntax(self) -> RSPFileSyntax:
+ return RSPFileSyntax.MSVC
+
+
+class VisualStudioLinker(VisualStudioLikeLinker, StaticLinker):
+
+ """Microsoft's lib static linker."""
+
+ def __init__(self, exelist: T.List[str], machine: str):
+ StaticLinker.__init__(self, exelist)
+ VisualStudioLikeLinker.__init__(self, machine)
+
+
+class IntelVisualStudioLinker(VisualStudioLikeLinker, StaticLinker):
+
+ """Intel's xilib static linker."""
+
+ def __init__(self, exelist: T.List[str], machine: str):
+ StaticLinker.__init__(self, exelist)
+ VisualStudioLikeLinker.__init__(self, machine)
+
+
+class ArLinker(StaticLinker):
+
+ def __init__(self, exelist: T.List[str]):
+ super().__init__(exelist)
+ self.id = 'ar'
+ pc, stdo = mesonlib.Popen_safe(self.exelist + ['-h'])[0:2]
+ # Enable deterministic builds if they are available.
+ if '[D]' in stdo:
+ self.std_args = ['csrD']
+ else:
+ self.std_args = ['csr']
+ self.can_rsp = '@<' in stdo
+
+ def can_linker_accept_rsp(self) -> bool:
+ return self.can_rsp
+
+ def get_std_link_args(self) -> T.List[str]:
+ return self.std_args
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return [target]
+
+ def rsp_file_syntax(self) -> RSPFileSyntax:
+ return RSPFileSyntax.GCC
+
+
+class ArmarLinker(ArLinker): # lgtm [py/missing-call-to-init]
+
+ def __init__(self, exelist: T.List[str]):
+ StaticLinker.__init__(self, exelist)
+ self.id = 'armar'
+ self.std_args = ['-csr']
+
+ def can_linker_accept_rsp(self) -> bool:
+ # armar can't accept arguments using the @rsp syntax
+ return False
+
+
+class DLinker(StaticLinker):
+ def __init__(self, exelist: T.List[str], arch: str, *, rsp_syntax: RSPFileSyntax = RSPFileSyntax.GCC):
+ super().__init__(exelist)
+ self.id = exelist[0]
+ self.arch = arch
+ self.__rsp_syntax = rsp_syntax
+
+ def get_std_link_args(self) -> T.List[str]:
+ return ['-lib']
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return ['-of=' + target]
+
+ def get_linker_always_args(self) -> T.List[str]:
+ if mesonlib.is_windows():
+ if self.arch == 'x86_64':
+ return ['-m64']
+ elif self.arch == 'x86_mscoff' and self.id == 'dmd':
+ return ['-m32mscoff']
+ return ['-m32']
+ return []
+
+ def rsp_file_syntax(self) -> RSPFileSyntax:
+ return self.__rsp_syntax
+
+
+class CcrxLinker(StaticLinker):
+
+ def __init__(self, exelist: T.List[str]):
+ super().__init__(exelist)
+ self.id = 'rlink'
+
+ def can_linker_accept_rsp(self) -> bool:
+ return False
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return [f'-output={target}']
+
+ def get_linker_always_args(self) -> T.List[str]:
+ return ['-nologo', '-form=library']
+
+
+class Xc16Linker(StaticLinker):
+
+ def __init__(self, exelist: T.List[str]):
+ super().__init__(exelist)
+ self.id = 'xc16-ar'
+
+ def can_linker_accept_rsp(self) -> bool:
+ return False
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return [f'{target}']
+
+ def get_linker_always_args(self) -> T.List[str]:
+ return ['rcs']
+
+class CompCertLinker(StaticLinker):
+
+ def __init__(self, exelist: T.List[str]):
+ super().__init__(exelist)
+ self.id = 'ccomp'
+
+ def can_linker_accept_rsp(self) -> bool:
+ return False
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return [f'-o{target}']
+
+
+class C2000Linker(StaticLinker):
+
+ def __init__(self, exelist: T.List[str]):
+ super().__init__(exelist)
+ self.id = 'ar2000'
+
+ def can_linker_accept_rsp(self) -> bool:
+ return False
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return [f'{target}']
+
+ def get_linker_always_args(self) -> T.List[str]:
+ return ['-r']
+
+
+class AIXArLinker(ArLinker):
+
+ def __init__(self, exelist: T.List[str]):
+ StaticLinker.__init__(self, exelist)
+ self.id = 'aixar'
+ self.std_args = ['-csr', '-Xany']
+
+ def can_linker_accept_rsp(self) -> bool:
+ # AIXAr can't accept arguments using the @rsp syntax
+ return False
+
+
+def prepare_rpaths(raw_rpaths: str, build_dir: str, from_dir: str) -> T.List[str]:
+ # The rpaths we write must be relative if they point to the build dir,
+ # because otherwise they have different length depending on the build
+ # directory. This breaks reproducible builds.
+ internal_format_rpaths = [evaluate_rpath(p, build_dir, from_dir) for p in raw_rpaths]
+ ordered_rpaths = order_rpaths(internal_format_rpaths)
+ return ordered_rpaths
+
+
+def order_rpaths(rpath_list: T.List[str]) -> T.List[str]:
+ # We want rpaths that point inside our build dir to always override
+ # those pointing to other places in the file system. This is so built
+ # binaries prefer our libraries to the ones that may lie somewhere
+ # in the file system, such as /lib/x86_64-linux-gnu.
+ #
+ # The correct thing to do here would be C++'s std::stable_partition.
+ # Python standard library does not have it, so replicate it with
+ # sort, which is guaranteed to be stable.
+ return sorted(rpath_list, key=os.path.isabs)
+
+
+def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str:
+ if p == from_dir:
+ return '' # relpath errors out in this case
+ elif os.path.isabs(p):
+ return p # These can be outside of build dir.
+ else:
+ return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir))
+
+class DynamicLinker(metaclass=abc.ABCMeta):
+
+ """Base class for dynamic linkers."""
+
+ _BUILDTYPE_ARGS = {
+ 'plain': [],
+ 'debug': [],
+ 'debugoptimized': [],
+ 'release': [],
+ 'minsize': [],
+ 'custom': [],
+ } # type: T.Dict[str, T.List[str]]
+
+ @abc.abstractproperty
+ def id(self) -> str:
+ pass
+
+ def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]:
+ args = [arg] if isinstance(arg, str) else arg
+ if self.prefix_arg is None:
+ return args
+ elif isinstance(self.prefix_arg, str):
+ return [self.prefix_arg + arg for arg in args]
+ ret = []
+ for arg in args:
+ ret += self.prefix_arg + [arg]
+ return ret
+
+ def __init__(self, exelist: T.List[str],
+ for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]],
+ always_args: T.List[str], *, version: str = 'unknown version'):
+ self.exelist = exelist
+ self.for_machine = for_machine
+ self.version = version
+ self.prefix_arg = prefix_arg
+ self.always_args = always_args
+ self.machine = None # type: T.Optional[str]
+
+ def __repr__(self) -> str:
+ return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist))
+
+ def get_id(self) -> str:
+ return self.id
+
+ def get_version_string(self) -> str:
+ return f'({self.id} {self.version})'
+
+ def get_exelist(self) -> T.List[str]:
+ return self.exelist.copy()
+
+ def get_accepts_rsp(self) -> bool:
+ # rsp files are only used when building on Windows because we want to
+ # avoid issues with quoting and max argument length
+ return mesonlib.is_windows()
+
+ def rsp_file_syntax(self) -> RSPFileSyntax:
+ """The format of the RSP file that this compiler supports.
+
+ If `self.can_linker_accept_rsp()` returns True, then this needs to
+ be implemented
+ """
+ return RSPFileSyntax.GCC
+
+ def get_always_args(self) -> T.List[str]:
+ return self.always_args.copy()
+
+ def get_lib_prefix(self) -> str:
+ return ''
+
+ # XXX: is use_ldflags a compiler or a linker attribute?
+
+ def get_option_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
+ return []
+
+ def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]:
+ m = 'Language {} does not support has_multi_link_arguments.'
+ raise mesonlib.EnvironmentException(m.format(self.id))
+
+ def get_debugfile_name(self, targetfile: str) -> str:
+ '''Name of debug file written out (see below)'''
+ return None
+
+ def get_debugfile_args(self, targetfile: str) -> T.List[str]:
+ """Some compilers (MSVC) write debug into a separate file.
+
+ This method takes the target object path and returns a list of
+ commands to append to the linker invocation to control where that
+ file is written.
+ """
+ return []
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ return []
+
+ def get_std_shared_module_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
+ return self.get_std_shared_lib_args()
+
+ def get_pie_args(self) -> T.List[str]:
+ # TODO: this really needs to take a boolean and return the args to
+ # disable pie, otherwise it only acts to enable pie if pie *isn't* the
+ # default.
+ m = 'Linker {} does not support position-independent executable'
+ raise mesonlib.EnvironmentException(m.format(self.id))
+
+ def get_lto_args(self) -> T.List[str]:
+ return []
+
+ def sanitizer_args(self, value: str) -> T.List[str]:
+ return []
+
+ def get_buildtype_args(self, buildtype: str) -> T.List[str]:
+ # We can override these in children by just overriding the
+ # _BUILDTYPE_ARGS value.
+ return self._BUILDTYPE_ARGS[buildtype]
+
+ def get_asneeded_args(self) -> T.List[str]:
+ return []
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ raise mesonlib.EnvironmentException(
+ f'Linker {self.id} does not support link_whole')
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ raise mesonlib.EnvironmentException(
+ f'Linker {self.id} does not support allow undefined')
+
+ @abc.abstractmethod
+ def get_output_args(self, outname: str) -> T.List[str]:
+ pass
+
+ def get_coverage_args(self) -> T.List[str]:
+ m = f"Linker {self.id} doesn't implement coverage data generation."
+ raise mesonlib.EnvironmentException(m)
+
+ @abc.abstractmethod
+ def get_search_args(self, dirname: str) -> T.List[str]:
+ pass
+
+ def export_dynamic_args(self, env: 'Environment') -> T.List[str]:
+ return []
+
+ def import_library_args(self, implibname: str) -> T.List[str]:
+ """The name of the outputted import library.
+
+ This implementation is used only on Windows by compilers that use GNU ld
+ """
+ return []
+
+ def thread_flags(self, env: 'Environment') -> T.List[str]:
+ return []
+
+ def no_undefined_args(self) -> T.List[str]:
+ """Arguments to error if there are any undefined symbols at link time.
+
+ This is the inverse of get_allow_undefined_args().
+
+ TODO: A future cleanup might merge this and
+ get_allow_undefined_args() into a single method taking a
+ boolean
+ """
+ return []
+
+ def fatal_warnings(self) -> T.List[str]:
+ """Arguments to make all warnings errors."""
+ return []
+
+ def headerpad_args(self) -> T.List[str]:
+ # Only used by the Apple linker
+ return []
+
+ def get_gui_app_args(self, value: bool) -> T.List[str]:
+ # Only used by VisualStudioLikeLinkers
+ return []
+
+ def get_win_subsystem_args(self, value: str) -> T.List[str]:
+ # Only used if supported by the dynamic linker and
+ # only when targeting Windows
+ return []
+
+ def bitcode_args(self) -> T.List[str]:
+ raise mesonlib.MesonException('This linker does not support bitcode bundles')
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ return []
+
+
+class PosixDynamicLinkerMixin:
+
+ """Mixin class for POSIX-ish linkers.
+
+ This is obviously a pretty small subset of the linker interface, but
+ enough dynamic linkers that meson supports are POSIX-like but not
+ GNU-like that it makes sense to split this out.
+ """
+
+ def get_output_args(self, outname: str) -> T.List[str]:
+ return ['-o', outname]
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ return ['-shared']
+
+ def get_search_args(self, dirname: str) -> T.List[str]:
+ return ['-L' + dirname]
+
+
+class GnuLikeDynamicLinkerMixin:
+
+ """Mixin class for dynamic linkers that provides gnu-like interface.
+
+ This acts as a base for the GNU linkers (bfd and gold), LLVM's lld, and
+ other linkers like GNU-ld.
+ """
+
+ if T.TYPE_CHECKING:
+ for_machine = MachineChoice.HOST
+ def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: ...
+
+ _BUILDTYPE_ARGS = {
+ 'plain': [],
+ 'debug': [],
+ 'debugoptimized': [],
+ 'release': ['-O1'],
+ 'minsize': [],
+ 'custom': [],
+ } # type: T.Dict[str, T.List[str]]
+
+ def get_buildtype_args(self, buildtype: str) -> T.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) -> T.List[str]:
+ return ['-pie']
+
+ def get_asneeded_args(self) -> T.List[str]:
+ return self._apply_prefix('--as-needed')
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ if not args:
+ return args
+ return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive')
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return self._apply_prefix('--allow-shlib-undefined')
+
+ def get_lto_args(self) -> T.List[str]:
+ return ['-flto']
+
+ def sanitizer_args(self, value: str) -> T.List[str]:
+ if value == 'none':
+ return []
+ return ['-fsanitize=' + value]
+
+ def get_coverage_args(self) -> T.List[str]:
+ return ['--coverage']
+
+ def export_dynamic_args(self, env: 'Environment') -> T.List[str]:
+ m = env.machines[self.for_machine]
+ if m.is_windows() or m.is_cygwin():
+ return self._apply_prefix('--export-all-symbols')
+ return self._apply_prefix('-export-dynamic')
+
+ def import_library_args(self, implibname: str) -> T.List[str]:
+ return self._apply_prefix('--out-implib=' + implibname)
+
+ def thread_flags(self, env: 'Environment') -> T.List[str]:
+ if env.machines[self.for_machine].is_haiku():
+ return []
+ return ['-pthread']
+
+ def no_undefined_args(self) -> T.List[str]:
+ return self._apply_prefix('--no-undefined')
+
+ def fatal_warnings(self) -> T.List[str]:
+ return self._apply_prefix('--fatal-warnings')
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ m = env.machines[self.for_machine]
+ if m.is_windows() or m.is_cygwin():
+ # For PE/COFF the soname argument has no effect
+ return []
+ sostr = '' if soversion is None else '.' + soversion
+ return self._apply_prefix(f'-soname,{prefix}{shlib_name}.{suffix}{sostr}')
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ m = env.machines[self.for_machine]
+ if m.is_windows() or m.is_cygwin():
+ return ([], set())
+ if not rpath_paths and not install_rpath and not build_rpath:
+ return ([], set())
+ args = []
+ origin_placeholder = '$ORIGIN'
+ processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
+ # Need to deduplicate rpaths, as macOS's install_name_tool
+ # is *very* allergic to duplicate -delete_rpath arguments
+ # when calling depfixer on installation.
+ all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
+ rpath_dirs_to_remove = set()
+ for p in all_paths:
+ rpath_dirs_to_remove.add(p.encode('utf8'))
+ # Build_rpath is used as-is (it is usually absolute).
+ if build_rpath != '':
+ all_paths.add(build_rpath)
+ for p in build_rpath.split(':'):
+ rpath_dirs_to_remove.add(p.encode('utf8'))
+
+ # TODO: should this actually be "for (dragonfly|open)bsd"?
+ if mesonlib.is_dragonflybsd() or mesonlib.is_openbsd():
+ # This argument instructs the compiler to record the value of
+ # ORIGIN in the .dynamic section of the elf. On Linux this is done
+ # 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.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.
+ paths = ':'.join(all_paths)
+ if len(paths) < len(install_rpath):
+ padding = 'X' * (len(install_rpath) - len(paths))
+ if not paths:
+ paths = padding
+ else:
+ paths = paths + ':' + padding
+ args.extend(self._apply_prefix('-rpath,' + paths))
+
+ # TODO: should this actually be "for solaris/sunos"?
+ if mesonlib.is_sunos():
+ return (args, rpath_dirs_to_remove)
+
+ # Rpaths to use while linking must be absolute. These are not
+ # written to the binary. Needed only with GNU ld:
+ # https://sourceware.org/bugzilla/show_bug.cgi?id=16936
+ # Not needed on Windows or other platforms that don't use RPATH
+ # https://github.com/mesonbuild/meson/issues/1897
+ #
+ # In addition, this linker option tends to be quite long and some
+ # compilers have trouble dealing with it. That's why we will include
+ # one option per folder, like this:
+ #
+ # -Wl,-rpath-link,/path/to/folder1 -Wl,-rpath,/path/to/folder2 ...
+ #
+ # ...instead of just one single looooong option, like this:
+ #
+ # -Wl,-rpath-link,/path/to/folder1:/path/to/folder2:...
+ for p in rpath_paths:
+ args.extend(self._apply_prefix('-rpath-link,' + os.path.join(build_dir, p)))
+
+ return (args, rpath_dirs_to_remove)
+
+ def get_win_subsystem_args(self, value: str) -> T.List[str]:
+ if 'windows' in value:
+ args = ['--subsystem,windows']
+ elif 'console' in value:
+ args = ['--subsystem,console']
+ else:
+ raise mesonlib.MesonException(f'Only "windows" and "console" are supported for win_subsystem with MinGW, not "{value}".')
+ if ',' in value:
+ args[-1] = args[-1] + ':' + value.split(',')[1]
+
+ return self._apply_prefix(args)
+
+
+class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
+
+ """Apple's ld implementation."""
+
+ id = 'ld64'
+
+ def get_asneeded_args(self) -> T.List[str]:
+ return self._apply_prefix('-dead_strip_dylibs')
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return self._apply_prefix('-undefined,dynamic_lookup')
+
+ def get_std_shared_module_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
+ return ['-bundle'] + self._apply_prefix('-undefined,dynamic_lookup')
+
+ def get_pie_args(self) -> T.List[str]:
+ return []
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ result = [] # type: T.List[str]
+ for a in args:
+ result.extend(self._apply_prefix('-force_load'))
+ result.append(a)
+ return result
+
+ def get_coverage_args(self) -> T.List[str]:
+ return ['--coverage']
+
+ def sanitizer_args(self, value: str) -> T.List[str]:
+ if value == 'none':
+ return []
+ return ['-fsanitize=' + value]
+
+ def no_undefined_args(self) -> T.List[str]:
+ return self._apply_prefix('-undefined,error')
+
+ def headerpad_args(self) -> T.List[str]:
+ return self._apply_prefix('-headerpad_max_install_names')
+
+ def bitcode_args(self) -> T.List[str]:
+ return self._apply_prefix('-bitcode_bundle')
+
+ def fatal_warnings(self) -> T.List[str]:
+ return self._apply_prefix('-fatal_warnings')
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ if is_shared_module:
+ return []
+ install_name = ['@rpath/', prefix, shlib_name]
+ if soversion is not None:
+ install_name.append('.' + soversion)
+ install_name.append('.dylib')
+ args = ['-install_name', ''.join(install_name)]
+ if darwin_versions:
+ args.extend(['-compatibility_version', darwin_versions[0],
+ '-current_version', darwin_versions[1]])
+ return args
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ if not rpath_paths and not install_rpath and not build_rpath:
+ return ([], set())
+ args = []
+ # @loader_path is the equivalent of $ORIGIN on macOS
+ # https://stackoverflow.com/q/26280738
+ origin_placeholder = '@loader_path'
+ processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
+ all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
+ if build_rpath != '':
+ all_paths.add(build_rpath)
+ for rp in all_paths:
+ args.extend(self._apply_prefix('-rpath,' + rp))
+
+ return (args, set())
+
+
+class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
+
+ """Representation of GNU ld.bfd and ld.gold."""
+
+ def get_accepts_rsp(self) -> bool:
+ return True
+
+
+class GnuGoldDynamicLinker(GnuDynamicLinker):
+
+ id = 'ld.gold'
+
+
+class GnuBFDDynamicLinker(GnuDynamicLinker):
+
+ id = 'ld.bfd'
+
+
+class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
+
+ """Representation of LLVM's ld.lld linker.
+
+ This is only the gnu-like linker, not the apple like or link.exe like
+ linkers.
+ """
+
+ id = 'ld.lld'
+
+ def __init__(self, exelist: T.List[str],
+ for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]],
+ always_args: T.List[str], *, version: str = 'unknown version'):
+ super().__init__(exelist, for_machine, prefix_arg, always_args, version=version)
+
+ # Some targets don't seem to support this argument (windows, wasm, ...)
+ _, _, e = mesonlib.Popen_safe(self.exelist + self._apply_prefix('--allow-shlib-undefined'))
+ self.has_allow_shlib_undefined = not ('unknown argument: --allow-shlib-undefined' in e)
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ if self.has_allow_shlib_undefined:
+ return self._apply_prefix('--allow-shlib-undefined')
+ return []
+
+
+class WASMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
+
+ """Emscripten's wasm-ld."""
+
+ id = 'ld.wasm'
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=0']
+
+ def no_undefined_args(self) -> T.List[str]:
+ return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1']
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ raise mesonlib.MesonException(f'{self.id} does not support shared libraries.')
+
+ def get_asneeded_args(self) -> T.List[str]:
+ return []
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
+
+
+class CcrxDynamicLinker(DynamicLinker):
+
+ """Linker for Renesis CCrx compiler."""
+
+ id = 'rlink'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice,
+ *, version: str = 'unknown version'):
+ super().__init__(['rlink.exe'], for_machine, '', [],
+ version=version)
+
+ def get_accepts_rsp(self) -> bool:
+ return False
+
+ def get_lib_prefix(self) -> str:
+ return '-lib='
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ return []
+
+ def get_output_args(self, outputname: str) -> T.List[str]:
+ return [f'-output={outputname}']
+
+ def get_search_args(self, dirname: str) -> 'T.NoReturn':
+ raise OSError('rlink.exe does not have a search dir argument')
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ return []
+
+
+class Xc16DynamicLinker(DynamicLinker):
+
+ """Linker for Microchip XC16 compiler."""
+
+ id = 'xc16-gcc'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice,
+ *, version: str = 'unknown version'):
+ super().__init__(['xc16-gcc.exe'], for_machine, '', [],
+ version=version)
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ if not args:
+ return args
+ return self._apply_prefix('--start-group') + args + self._apply_prefix('--end-group')
+
+ def get_accepts_rsp(self) -> bool:
+ return False
+
+ def get_lib_prefix(self) -> str:
+ return ''
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ return []
+
+ def get_output_args(self, outputname: str) -> T.List[str]:
+ return [f'-o{outputname}']
+
+ def get_search_args(self, dirname: str) -> 'T.NoReturn':
+ raise OSError('xc16-gcc.exe does not have a search dir argument')
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ return []
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
+
+class CompCertDynamicLinker(DynamicLinker):
+
+ """Linker for CompCert C compiler."""
+
+ id = 'ccomp'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice,
+ *, version: str = 'unknown version'):
+ super().__init__(['ccomp'], for_machine, '', [],
+ version=version)
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ if not args:
+ return args
+ return self._apply_prefix('-Wl,--whole-archive') + args + self._apply_prefix('-Wl,--no-whole-archive')
+
+ def get_accepts_rsp(self) -> bool:
+ return False
+
+ def get_lib_prefix(self) -> str:
+ return ''
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ return []
+
+ def get_output_args(self, outputname: str) -> T.List[str]:
+ return [f'-o{outputname}']
+
+ def get_search_args(self, dirname: str) -> T.List[str]:
+ return [f'-L{dirname}']
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ raise mesonlib.MesonException(f'{self.id} does not support shared libraries.')
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ return ([], set())
+
+class C2000DynamicLinker(DynamicLinker):
+
+ """Linker for Texas Instruments C2000 compiler."""
+
+ id = 'cl2000'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice,
+ *, version: str = 'unknown version'):
+ super().__init__(['cl2000.exe'], for_machine, '', [],
+ version=version)
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ if not args:
+ return args
+ return self._apply_prefix('--start-group') + args + self._apply_prefix('--end-group')
+
+ def get_accepts_rsp(self) -> bool:
+ return False
+
+ def get_lib_prefix(self) -> str:
+ return '-l='
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ return []
+
+ def get_output_args(self, outputname: str) -> T.List[str]:
+ return ['-z', f'--output_file={outputname}']
+
+ def get_search_args(self, dirname: str) -> 'T.NoReturn':
+ raise OSError('cl2000.exe does not have a search dir argument')
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_always_args(self) -> T.List[str]:
+ return []
+
+
+class ArmDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
+
+ """Linker for the ARM compiler."""
+
+ id = 'armlink'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice,
+ *, version: str = 'unknown version'):
+ super().__init__(['armlink'], for_machine, '', [],
+ version=version)
+
+ def get_accepts_rsp(self) -> bool:
+ return False
+
+ def get_std_shared_lib_args(self) -> 'T.NoReturn':
+ raise mesonlib.MesonException('The Arm Linkers do not support shared libraries')
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+
+class ArmClangDynamicLinker(ArmDynamicLinker):
+
+ """Linker used with ARM's clang fork.
+
+ The interface is similar enough to the old ARM ld that it inherits and
+ extends a few things as needed.
+ """
+
+ def export_dynamic_args(self, env: 'Environment') -> T.List[str]:
+ return ['--export_dynamic']
+
+ def import_library_args(self, implibname: str) -> T.List[str]:
+ return ['--symdefs=' + implibname]
+
+class QualcommLLVMDynamicLinker(LLVMDynamicLinker):
+
+ """ARM Linker from Snapdragon LLVM ARM Compiler."""
+
+ id = 'ld.qcld'
+
+
+class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
+
+ """PGI linker."""
+
+ id = 'pgi'
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ return []
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ # PGI -shared is Linux only.
+ if mesonlib.is_windows():
+ return ['-Bdynamic', '-Mmakedll']
+ elif mesonlib.is_linux():
+ return ['-shared']
+ return []
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ if not env.machines[self.for_machine].is_windows():
+ return (['-R' + os.path.join(build_dir, p) for p in rpath_paths], set())
+ return ([], set())
+
+NvidiaHPC_DynamicLinker = PGIDynamicLinker
+
+
+class PGIStaticLinker(StaticLinker):
+ def __init__(self, exelist: T.List[str]):
+ super().__init__(exelist)
+ self.id = 'ar'
+ self.std_args = ['-r']
+
+ def get_std_link_args(self) -> T.List[str]:
+ return self.std_args
+
+ def get_output_args(self, target: str) -> T.List[str]:
+ return [target]
+
+NvidiaHPC_StaticLinker = PGIStaticLinker
+
+
+class VisualStudioLikeLinkerMixin:
+
+ """Mixin class for for dynamic linkers that act like Microsoft's link.exe."""
+
+ if T.TYPE_CHECKING:
+ for_machine = MachineChoice.HOST
+ def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: ...
+
+ _BUILDTYPE_ARGS = {
+ 'plain': [],
+ 'debug': [],
+ 'debugoptimized': [],
+ # The otherwise implicit REF and ICF linker optimisations are disabled by
+ # /DEBUG. REF implies ICF.
+ 'release': ['/OPT:REF'],
+ 'minsize': ['/INCREMENTAL:NO', '/OPT:REF'],
+ 'custom': [],
+ } # type: T.Dict[str, T.List[str]]
+
+ def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice,
+ prefix_arg: T.Union[str, T.List[str]], always_args: T.List[str], *,
+ version: str = 'unknown version', direct: bool = True, machine: str = 'x86'):
+ # There's no way I can find to make mypy understand what's going on here
+ super().__init__(exelist, for_machine, prefix_arg, always_args, version=version) # type: ignore
+ self.machine = machine
+ self.direct = direct
+
+ def get_buildtype_args(self, buildtype: str) -> T.List[str]:
+ return mesonlib.listify([self._apply_prefix(a) for a in self._BUILDTYPE_ARGS[buildtype]])
+
+ def invoked_by_compiler(self) -> bool:
+ return not self.direct
+
+ def get_output_args(self, outputname: str) -> T.List[str]:
+ return self._apply_prefix(['/MACHINE:' + self.machine, '/OUT:' + outputname])
+
+ def get_always_args(self) -> T.List[str]:
+ parent = super().get_always_args() # type: ignore
+ return self._apply_prefix('/nologo') + T.cast(T.List[str], parent)
+
+ def get_search_args(self, dirname: str) -> T.List[str]:
+ return self._apply_prefix('/LIBPATH:' + dirname)
+
+ def get_std_shared_lib_args(self) -> T.List[str]:
+ return self._apply_prefix('/DLL')
+
+ def get_debugfile_name(self, targetfile: str) -> str:
+ basename = targetfile.rsplit('.', maxsplit=1)[0]
+ return basename + '.pdb'
+
+ def get_debugfile_args(self, targetfile: str) -> T.List[str]:
+ return self._apply_prefix(['/DEBUG', '/PDB:' + self.get_debugfile_name(targetfile)])
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ # Only since VS2015
+ args = mesonlib.listify(args)
+ l = [] # T.List[str]
+ for a in args:
+ l.extend(self._apply_prefix('/WHOLEARCHIVE:' + a))
+ return l
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ return []
+
+ def import_library_args(self, implibname: str) -> T.List[str]:
+ """The command to generate the import library."""
+ return self._apply_prefix(['/IMPLIB:' + implibname])
+
+ def rsp_file_syntax(self) -> RSPFileSyntax:
+ return RSPFileSyntax.MSVC
+
+
+class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
+
+ """Microsoft's Link.exe."""
+
+ id = 'link'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *,
+ exelist: T.Optional[T.List[str]] = None,
+ prefix: T.Union[str, T.List[str]] = '',
+ machine: str = 'x86', version: str = 'unknown version',
+ direct: bool = True):
+ super().__init__(exelist or ['link.exe'], for_machine,
+ prefix, always_args, machine=machine, version=version, direct=direct)
+
+ def get_always_args(self) -> T.List[str]:
+ return self._apply_prefix(['/nologo', '/release']) + super().get_always_args()
+
+ def get_gui_app_args(self, value: bool) -> T.List[str]:
+ return self.get_win_subsystem_args("windows" if value else "console")
+
+ def get_win_subsystem_args(self, value: str) -> T.List[str]:
+ return self._apply_prefix([f'/SUBSYSTEM:{value.upper()}'])
+
+
+class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
+
+ """Clang's lld-link.exe."""
+
+ id = 'lld-link'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *,
+ exelist: T.Optional[T.List[str]] = None,
+ prefix: T.Union[str, T.List[str]] = '',
+ machine: str = 'x86', version: str = 'unknown version',
+ direct: bool = True):
+ super().__init__(exelist or ['lld-link.exe'], for_machine,
+ prefix, always_args, machine=machine, version=version, direct=direct)
+
+ def get_output_args(self, outputname: str) -> T.List[str]:
+ # If we're being driven indirectly by clang just skip /MACHINE
+ # as clang's target triple will handle the machine selection
+ if self.machine is None:
+ return self._apply_prefix([f"/OUT:{outputname}"])
+
+ return super().get_output_args(outputname)
+
+ def get_gui_app_args(self, value: bool) -> T.List[str]:
+ return self.get_win_subsystem_args("windows" if value else "console")
+
+ def get_win_subsystem_args(self, value: str) -> T.List[str]:
+ return self._apply_prefix([f'/SUBSYSTEM:{value.upper()}'])
+
+
+class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
+
+ """Intel's Xilink.exe."""
+
+ id = 'xilink'
+
+ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *,
+ exelist: T.Optional[T.List[str]] = None,
+ prefix: T.Union[str, T.List[str]] = '',
+ machine: str = 'x86', version: str = 'unknown version',
+ direct: bool = True):
+ super().__init__(['xilink.exe'], for_machine, '', always_args, version=version)
+
+
+class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
+
+ """Sys-V derived linker used on Solaris and OpenSolaris."""
+
+ id = 'ld.solaris'
+
+ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
+ if not args:
+ return args
+ return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive')
+
+ def get_pie_args(self) -> T.List[str]:
+ # Available in Solaris 11.2 and later
+ pc, stdo, stde = mesonlib.Popen_safe(self.exelist + self._apply_prefix('-zhelp'))
+ for line in (stdo + stde).split('\n'):
+ if '-z type' in line:
+ if 'pie' in line:
+ return ['-z', 'type=pie']
+ break
+ return []
+
+ def get_asneeded_args(self) -> T.List[str]:
+ return self._apply_prefix(['-z', 'ignore'])
+
+ def no_undefined_args(self) -> T.List[str]:
+ return ['-z', 'defs']
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return ['-z', 'nodefs']
+
+ def fatal_warnings(self) -> T.List[str]:
+ return ['-z', 'fatal-warnings']
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ if not rpath_paths and not install_rpath and not build_rpath:
+ return ([], set())
+ processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
+ all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths])
+ rpath_dirs_to_remove = set()
+ for p in all_paths:
+ rpath_dirs_to_remove.add(p.encode('utf8'))
+ if build_rpath != '':
+ all_paths.add(build_rpath)
+ for p in build_rpath.split(':'):
+ rpath_dirs_to_remove.add(p.encode('utf8'))
+
+ # 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.
+ paths = ':'.join(all_paths)
+ if len(paths) < len(install_rpath):
+ padding = 'X' * (len(install_rpath) - len(paths))
+ if not paths:
+ paths = padding
+ else:
+ paths = paths + ':' + padding
+ return (self._apply_prefix(f'-rpath,{paths}'), rpath_dirs_to_remove)
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ sostr = '' if soversion is None else '.' + soversion
+ return self._apply_prefix(f'-soname,{prefix}{shlib_name}.{suffix}{sostr}')
+
+
+class AIXDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
+
+ """Sys-V derived linker used on AIX"""
+
+ id = 'ld.aix'
+
+ def get_always_args(self) -> T.List[str]:
+ return self._apply_prefix(['-bnoipath', '-bbigtoc']) + super().get_always_args()
+
+ def no_undefined_args(self) -> T.List[str]:
+ return self._apply_prefix(['-bernotok'])
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return self._apply_prefix(['-berok'])
+
+ def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
+ rpath_paths: str, build_rpath: str,
+ install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
+ all_paths = mesonlib.OrderedSet() # type: mesonlib.OrderedSet[str]
+ # install_rpath first, followed by other paths, and the system path last
+ if install_rpath != '':
+ all_paths.add(install_rpath)
+ if build_rpath != '':
+ all_paths.add(build_rpath)
+ for p in rpath_paths:
+ all_paths.add(os.path.join(build_dir, p))
+ # We should consider allowing the $LIBPATH environment variable
+ # to override sys_path.
+ sys_path = env.get_compiler_system_dirs(self.for_machine)
+ if len(sys_path) == 0:
+ # get_compiler_system_dirs doesn't support our compiler.
+ # Use the default system library path
+ all_paths.update(['/usr/lib','/lib'])
+ else:
+ # Include the compiler's default library paths, but filter out paths that don't exist
+ for p in sys_path:
+ if os.path.isdir(p):
+ all_paths.add(p)
+ return (self._apply_prefix('-blibpath:' + ':'.join(all_paths)), set())
+
+ def thread_flags(self, env: 'Environment') -> T.List[str]:
+ return ['-pthread']
+
+
+class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
+
+ """Digital Mars dynamic linker for windows."""
+
+ id = 'optlink'
+
+ def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice,
+ *, version: str = 'unknown version'):
+ # Use optlink instead of link so we don't interfer with other link.exe
+ # implementations.
+ super().__init__(exelist, for_machine, '', [], version=version)
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_debugfile_args(self, targetfile: str) -> T.List[str]:
+ # Optlink does not generate pdb files.
+ return []
+
+ def get_always_args(self) -> T.List[str]:
+ return []
+
+
+class CudaLinker(PosixDynamicLinkerMixin, DynamicLinker):
+ """Cuda linker (nvlink)"""
+
+ id = 'nvlink'
+
+ @staticmethod
+ def parse_version() -> str:
+ version_cmd = ['nvlink', '--version']
+ try:
+ _, out, _ = mesonlib.Popen_safe(version_cmd)
+ except OSError:
+ return 'unknown version'
+ # Output example:
+ # nvlink: NVIDIA (R) Cuda linker
+ # Copyright (c) 2005-2018 NVIDIA Corporation
+ # Built on Sun_Sep_30_21:09:22_CDT_2018
+ # Cuda compilation tools, release 10.0, V10.0.166
+ # we need the most verbose version output. Luckily starting with V
+ return out.strip().split('V')[-1]
+
+ def get_accepts_rsp(self) -> bool:
+ # nvcc does not support response files
+ return False
+
+ def get_lib_prefix(self) -> str:
+ if not mesonlib.is_windows():
+ return ''
+ # nvcc doesn't recognize Meson's default .a extension for static libraries on
+ # Windows and passes it to cl as an object file, resulting in 'warning D9024 :
+ # unrecognized source file type 'xxx.a', object file assumed'.
+ #
+ # nvcc's --library= option doesn't help: it takes the library name without the
+ # extension and assumes that the extension on Windows is .lib; prefixing the
+ # library with -Xlinker= seems to work.
+ from ..compilers import CudaCompiler
+ return CudaCompiler.LINKER_PREFIX
+
+ def fatal_warnings(self) -> T.List[str]:
+ return ['--warning-as-error']
+
+ def get_allow_undefined_args(self) -> T.List[str]:
+ return []
+
+ def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
+ suffix: str, soversion: str, darwin_versions: T.Tuple[str, str],
+ is_shared_module: bool) -> T.List[str]:
+ return []