aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2019-12-11 23:29:33 +0200
committerGitHub <noreply@github.com>2019-12-11 23:29:33 +0200
commit17dd9e5bffd42c3ad6c2dff1f15639d6adf31e1c (patch)
tree88eb97cee03e8ecffbd18b7f15e06d8ba038c03d /mesonbuild
parentc3d0b95a58695257cc40cbc9a51dfa6c7f172ec4 (diff)
parentf8aa17d8e62e05ed264a00a5e948b3e42aa68b30 (diff)
downloadmeson-17dd9e5bffd42c3ad6c2dff1f15639d6adf31e1c.zip
meson-17dd9e5bffd42c3ad6c2dff1f15639d6adf31e1c.tar.gz
meson-17dd9e5bffd42c3ad6c2dff1f15639d6adf31e1c.tar.bz2
Merge pull request #6207 from dcbaker/linker-option
Add a way to select the dynamic linker meson uses
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/ninjabackend.py9
-rw-r--r--mesonbuild/compilers/compilers.py6
-rw-r--r--mesonbuild/compilers/mixins/gnu.py4
-rw-r--r--mesonbuild/compilers/mixins/visualstudio.py4
-rw-r--r--mesonbuild/compilers/rust.py6
-rw-r--r--mesonbuild/envconfig.py2
-rw-r--r--mesonbuild/environment.py257
-rw-r--r--mesonbuild/linkers.py69
8 files changed, 215 insertions, 142 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 8af692c..824b958 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -1291,6 +1291,15 @@ int dummy;
else:
raise InvalidArguments('Unknown target type for rustc.')
args.append(cratetype)
+
+ # If we're dynamically linking, add those arguments
+ #
+ # Rust is super annoying, calling -C link-arg foo does not work, it has
+ # to be -C link-arg=foo
+ if cratetype in {'bin', 'dylib'}:
+ for a in rustc.linker.get_always_args():
+ args += ['-C', 'link-arg={}'.format(a)]
+
args += ['--crate-name', target.name]
args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target))
args += rustc.get_debug_args(self.get_option_for_target('debug', target))
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 09c53ea..eedd4cf 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -1192,6 +1192,12 @@ class Compiler:
def get_dependency_link_args(self, dep):
return dep.get_link_args()
+ @classmethod
+ def use_linker_args(cls, linker: str) -> typing.List[str]:
+ """Get a list of arguments to pass to the compiler to set the linker.
+ """
+ return []
+
def get_largefile_args(compiler):
'''
diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py
index 64b0d3b..6683486 100644
--- a/mesonbuild/compilers/mixins/gnu.py
+++ b/mesonbuild/compilers/mixins/gnu.py
@@ -299,6 +299,10 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
return ['-isystem' + path]
return ['-I' + path]
+ @classmethod
+ def use_linker_args(cls, linker: str) -> typing.List[str]:
+ return ['-fuse-ld={}'.format(linker)]
+
class GnuCompiler(GnuLikeCompiler):
"""
diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py
index 60b07c4..4798bdc 100644
--- a/mesonbuild/compilers/mixins/visualstudio.py
+++ b/mesonbuild/compilers/mixins/visualstudio.py
@@ -381,3 +381,7 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
def get_argument_syntax(self) -> str:
return 'msvc'
+
+ @classmethod
+ def use_linker_args(cls, linker: str) -> typing.List[str]:
+ return []
diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py
index a17b697..405afea 100644
--- a/mesonbuild/compilers/rust.py
+++ b/mesonbuild/compilers/rust.py
@@ -32,7 +32,7 @@ rust_optimization_args = {'0': [],
class RustCompiler(Compiler):
- LINKER_PREFIX = '-Wl,'
+ # rustc doesn't invoke the compiler itself, it doesn't need a LINKER_PREFIX
def __init__(self, exelist, version, for_machine: MachineChoice,
is_cross, info: 'MachineInfo', exe_wrapper=None, **kwargs):
@@ -109,3 +109,7 @@ class RustCompiler(Compiler):
def get_std_exe_link_args(self):
return []
+
+ # Rust does not have a use_linker_args because it dispatches to a gcc-like
+ # C compiler for dynamic linking, as such we invoke the C compiler's
+ # use_linker_args method instead.
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index 1adb08d..0f277a7 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -309,7 +309,9 @@ class BinaryTable(HasEnvVarFallback):
'strip': 'STRIP',
'ar': 'AR',
'windres': 'WINDRES',
+ 'ld': 'LD',
+ # Other tools
'cmake': 'CMAKE',
'qmake': 'QMAKE',
'pkgconfig': 'PKG_CONFIG',
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 905a218..8443a47 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -53,10 +53,9 @@ from .linkers import (
PGIDynamicLinker,
PGIStaticLinker,
SolarisDynamicLinker,
- XildAppleDynamicLinker,
- XildLinuxDynamicLinker,
XilinkDynamicLinker,
CudaLinker,
+ VisualStudioLikeLinkerMixin,
)
from functools import lru_cache
from .compilers import (
@@ -733,55 +732,88 @@ class Environment:
errmsg += '\nRunning "{0}" gave "{1}"'.format(c, e)
raise EnvironmentException(errmsg)
- @staticmethod
- def _guess_win_linker(compiler: typing.List[str], for_machine: MachineChoice,
- prefix: typing.Union[str, typing.List[str]]) -> 'DynamicLinker':
+ def _guess_win_linker(self, compiler: typing.List[str], comp_class: Compiler,
+ for_machine: MachineChoice, *,
+ use_linker_prefix: bool = True) -> 'DynamicLinker':
# Explicitly pass logo here so that we can get the version of link.exe
- if isinstance(prefix, str):
- check_args = [prefix + '/logo', prefix + '--version']
- else:
- check_args = prefix + ['/logo'] + prefix + ['--version']
+ if not use_linker_prefix or comp_class.LINKER_PREFIX is None:
+ check_args = ['/logo', '--version']
+ elif isinstance(comp_class.LINKER_PREFIX, str):
+ check_args = [comp_class.LINKER_PREFIX + '/logo', comp_class.LINKER_PREFIX + '--version']
+ elif isinstance(comp_class.LINKER_PREFIX, list):
+ check_args = comp_class.LINKER_PREFIX + ['/logo'] + comp_class.LINKER_PREFIX + ['--version']
+
+ override = [] # type: typing.List[str]
+ value = self.binaries[for_machine].lookup_entry('ld')
+ if value is not None:
+ override = comp_class.use_linker_args(value[0])
+ check_args += override
+
p, o, _ = Popen_safe(compiler + check_args)
if o.startswith('LLD'):
if '(compatible with GNU linkers)' in o:
- return LLVMDynamicLinker(compiler, for_machine, 'lld', prefix, version=search_version(o))
- else:
- return ClangClDynamicLinker(for_machine, exelist=compiler, prefix=prefix, version=search_version(o))
- elif o.startswith('Microsoft'):
- match = re.search(r'.*(X86|X64|ARM|ARM64).*', o)
+ return LLVMDynamicLinker(
+ compiler, for_machine, 'lld', comp_class.LINKER_PREFIX,
+ override, version=search_version(o))
+
+ if value is not None:
+ compiler = value
+
+ p, o, e = Popen_safe(compiler + check_args)
+ if o.startswith('LLD'):
+ return ClangClDynamicLinker(
+ for_machine, [],
+ prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
+ exelist=compiler, version=search_version(o))
+ elif 'OPTLINK' in o:
+ # Opltink's stdout *may* beging with a \r character.
+ return OptlinkDynamicLinker(for_machine, version=search_version(o))
+ elif o.startswith('Microsoft') or e.startswith('Microsoft'):
+ out = o or e
+ match = re.search(r'.*(X86|X64|ARM|ARM64).*', out)
if match:
target = str(match.group(1))
else:
target = 'x86'
- return MSVCDynamicLinker(
- for_machine, machine=target, exelist=compiler, prefix=prefix,
- version=search_version(o))
- raise MesonException('Cannot guess dynamic linker')
- @staticmethod
- def _guess_nix_linker(compiler: typing.List[str], for_machine: MachineChoice,
- prefix: typing.Union[str, typing.List[str]], *,
+ return MSVCDynamicLinker(
+ for_machine, [], machine=target, exelist=compiler,
+ prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [],
+ version=search_version(out))
+ elif 'GNU coreutils' in o:
+ raise EnvironmentException(
+ "Found GNU link.exe instead of MSVC link.exe. This link.exe "
+ "is not a linker. You may need to reorder entries to your "
+ "%PATH% variable to resolve this.")
+ raise EnvironmentException('Unable to determine dynamic linker')
+
+ def _guess_nix_linker(self, compiler: typing.List[str], comp_class: typing.Type[Compiler],
+ for_machine: MachineChoice, *,
extra_args: typing.Optional[typing.List[str]] = None) -> 'DynamicLinker':
"""Helper for guessing what linker to use on Unix-Like OSes.
- :prefix: The prefix that the compiler uses to proxy arguments to the
- linker, if required. This can be passed as a string or a list of
- strings. If it is passed as a string then the arguments to be
- proxied to the linker will be concatenated, if it is a list they
- will be appended. This means that if a space is required (such as
- with swift which wants `-Xlinker --version` and *not*
- `-Xlinker=--version`) you must pass as a list.
+ :compiler: Invocation to use to get linker
+ :comp_class: The Compiler Type (uninstantiated)
+ :for_machine: which machine this linker targets
:extra_args: Any additional arguments required (such as a source file)
"""
extra_args = typing.cast(typing.List[str], extra_args or [])
- if isinstance(prefix, str):
- check_args = [prefix + '--version'] + extra_args
+
+ if isinstance(comp_class.LINKER_PREFIX, str):
+ check_args = [comp_class.LINKER_PREFIX + '--version'] + extra_args
else:
- check_args = prefix + ['--version'] + extra_args
+ check_args = comp_class.LINKER_PREFIX + ['--version'] + extra_args
+
+ override = [] # type: typing.List[str]
+ value = self.binaries[for_machine].lookup_entry('ld')
+ if value is not None:
+ override = comp_class.use_linker_args(value[0])
+ check_args += override
+
_, o, e = Popen_safe(compiler + check_args)
v = search_version(o)
if o.startswith('LLD'):
- linker = LLVMDynamicLinker(compiler, for_machine, 'lld', prefix, version=v) # type: DynamicLinker
+ linker = LLVMDynamicLinker(compiler, for_machine, 'lld', comp_class.LINKER_PREFIX, override, version=v) # type: DynamicLinker
elif e.startswith('lld-link: '):
# Toolchain wrapper got in the way; this happens with e.g. https://github.com/mstorsjo/llvm-mingw
# Let's try to extract the linker invocation command to grab the version.
@@ -797,13 +829,13 @@ class Environment:
_, o, e = Popen_safe([linker_cmd, '--version'])
v = search_version(o)
- linker = LLVMDynamicLinker(compiler, for_machine, 'lld', prefix, version=v)
+ linker = LLVMDynamicLinker(compiler, for_machine, 'lld', comp_class.LINKER_PREFIX, override, version=v)
# 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):
- _, _, e = Popen_safe(compiler + [prefix + '-v'] + extra_args)
+ if isinstance(comp_class.LINKER_PREFIX, str):
+ _, _, e = Popen_safe(compiler + [comp_class.LINKER_PREFIX + '-v'] + extra_args)
else:
- _, _, e = Popen_safe(compiler + prefix + ['-v'] + extra_args)
+ _, _, e = Popen_safe(compiler + comp_class.LINKER_PREFIX + ['-v'] + extra_args)
i = 'APPLE ld'
for line in e.split('\n'):
if 'PROJECT:ld' in line:
@@ -811,19 +843,19 @@ class Environment:
break
else:
v = 'unknown version'
- linker = AppleDynamicLinker(compiler, for_machine, i, prefix, version=v)
+ linker = AppleDynamicLinker(compiler, for_machine, i, comp_class.LINKER_PREFIX, override, 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, prefix, version=v)
+ linker = GnuDynamicLinker(compiler, for_machine, i, comp_class.LINKER_PREFIX, override, version=v)
elif 'Solaris' in e or 'Solaris' in o:
linker = SolarisDynamicLinker(
- compiler, for_machine, 'solaris', prefix,
+ compiler, for_machine, 'solaris', comp_class.LINKER_PREFIX, override,
version=search_version(e))
else:
- raise MesonException('Unable to determine dynamic linker.')
+ raise EnvironmentException('Unable to determine dynamic linker')
return linker
def _detect_c_or_cpp_compiler(self, lang: str, for_machine: MachineChoice) -> Compiler:
@@ -898,7 +930,7 @@ class Environment:
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)
+ linker = self._guess_nix_linker(compiler, cls, for_machine)
return cls(
ccache + compiler, version, for_machine, is_cross,
info, exe_wrap, defines, full_version=full_version,
@@ -925,7 +957,7 @@ class Environment:
version = search_version(arm_ver_str)
full_version = arm_ver_str
cls = ArmclangCCompiler if lang == 'c' else ArmclangCPPCompiler
- linker = ArmClangDynamicLinker(for_machine, version=version)
+ linker = ArmClangDynamicLinker(for_machine, [], version=version)
return cls(
ccache + compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
@@ -944,7 +976,7 @@ class Environment:
else:
target = 'unknown target'
cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler
- linker = ClangClDynamicLinker(for_machine, version=version)
+ linker = self._guess_win_linker(['lld-link'], cls, for_machine)
return cls(
compiler, version, for_machine, is_cross, info, exe_wrap,
target, linker=linker)
@@ -963,11 +995,11 @@ class Environment:
# style ld, but for clang on "real" windows we'll use
# either link.exe or lld-link.exe
try:
- linker = self._guess_win_linker(compiler, for_machine, cls.LINKER_PREFIX)
+ linker = self._guess_win_linker(compiler, cls, for_machine)
except MesonException:
pass
if linker is None:
- linker = self._guess_nix_linker(compiler, for_machine, cls.LINKER_PREFIX)
+ linker = self._guess_nix_linker(compiler, cls, for_machine)
return cls(
ccache + compiler, version, for_machine, is_cross, info,
@@ -999,23 +1031,23 @@ class Environment:
else:
m = 'Failed to detect MSVC compiler target architecture: \'cl /?\' output is\n{}'
raise EnvironmentException(m.format(cl_signature))
- linker = MSVCDynamicLinker(for_machine, version=version)
cls = VisualStudioCCompiler if lang == 'c' else VisualStudioCPPCompiler
+ linker = self._guess_win_linker(['link'], cls, for_machine)
return cls(
compiler, version, for_machine, is_cross, info, exe_wrap,
target, linker=linker)
if 'PGI Compilers' in out:
cls = PGICCompiler if lang == 'c' else PGICPPCompiler
- linker = PGIDynamicLinker(compiler, for_machine, 'pgi', cls.LINKER_PREFIX, version=version)
+ linker = PGIDynamicLinker(compiler, for_machine, 'pgi', cls.LINKER_PREFIX, [], version=version)
return cls(
ccache + compiler, version, for_machine, is_cross,
info, exe_wrap, linker=linker)
if '(ICC)' in out:
cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler
if self.machines[for_machine].is_darwin():
- l = XildAppleDynamicLinker(compiler, for_machine, 'xild', cls.LINKER_PREFIX, version=version)
+ l = AppleDynamicLinker(compiler, for_machine, 'APPLE ld', cls.LINKER_PREFIX, [], version=version)
else:
- l = XildLinuxDynamicLinker(compiler, for_machine, 'xild', cls.LINKER_PREFIX, version=version)
+ l = self._guess_nix_linker(compiler, cls, for_machine)
return cls(
ccache + compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=l)
@@ -1113,7 +1145,7 @@ class Environment:
version = self.get_gnu_version_from_defines(defines)
cls = GnuFortranCompiler
linker = self._guess_nix_linker(
- compiler, for_machine, cls.LINKER_PREFIX)
+ compiler, cls, for_machine)
return cls(
compiler, version, for_machine, is_cross, info,
exe_wrap, defines, full_version=full_version,
@@ -1121,7 +1153,7 @@ class Environment:
if 'G95' in out:
linker = self._guess_nix_linker(
- compiler, for_machine, cls.LINKER_PREFIX)
+ compiler, cls, for_machine)
return G95FortranCompiler(
compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
@@ -1129,7 +1161,7 @@ class Environment:
if 'Sun Fortran' in err:
version = search_version(err)
linker = self._guess_nix_linker(
- compiler, for_machine, cls.LINKER_PREFIX)
+ compiler, cls, for_machine)
return SunFortranCompiler(
compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
@@ -1137,14 +1169,13 @@ class Environment:
if 'Intel(R) Visual Fortran' in err:
version = search_version(err)
target = 'x86' if 'IA-32' in err else 'x86_64'
- linker = XilinkDynamicLinker(for_machine, version=version)
+ linker = XilinkDynamicLinker(for_machine, [], version=version)
return IntelClFortranCompiler(
compiler, version, for_machine, is_cross, target,
info, exe_wrap, linker=linker)
if 'ifort (IFORT)' in out:
- linker = XildLinuxDynamicLinker(
- compiler, for_machine, 'xild', IntelFortranCompiler.LINKER_PREFIX, version=version)
+ linker = self._guess_nix_linker(compiler, IntelFortranCompiler, for_machine)
return IntelFortranCompiler(
compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
@@ -1164,21 +1195,21 @@ class Environment:
if 'flang' in out or 'clang' in out:
linker = self._guess_nix_linker(
- compiler, for_machine, FlangFortranCompiler.LINKER_PREFIX)
+ compiler, FlangFortranCompiler, for_machine)
return FlangFortranCompiler(
compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
if 'Open64 Compiler Suite' in err:
linker = self._guess_nix_linker(
- compiler, for_machine, Open64FortranCompiler.LINKER_PREFIX)
+ compiler, Open64FortranCompiler, for_machine)
return Open64FortranCompiler(
compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
if 'NAG Fortran' in err:
linker = self._guess_nix_linker(
- compiler, for_machine, NAGFortranCompiler.LINKER_PREFIX)
+ compiler, NAGFortranCompiler, for_machine)
return NAGFortranCompiler(
compiler, version, for_machine, is_cross, info,
exe_wrap, full_version=full_version, linker=linker)
@@ -1217,7 +1248,7 @@ class Environment:
continue
version = self.get_gnu_version_from_defines(defines)
comp = GnuObjCCompiler if objc else GnuObjCPPCompiler
- linker = self._guess_nix_linker(compiler, for_machine, comp.LINKER_PREFIX)
+ linker = self._guess_nix_linker(compiler, comp, for_machine)
return comp(
ccache + compiler, version, for_machine, is_cross, info,
exe_wrap, defines, linker=linker)
@@ -1227,13 +1258,13 @@ class Environment:
if 'windows' in out or self.machines[for_machine].is_windows():
# If we're in a MINGW context this actually will use a gnu style ld
try:
- linker = self._guess_win_linker(compiler, for_machine, comp.LINKER_PREFIX)
+ linker = self._guess_win_linker(compiler, comp, for_machine)
except MesonException:
pass
if not linker:
linker = self._guess_nix_linker(
- compiler, for_machine, comp.LINKER_PREFIX)
+ compiler, comp, for_machine)
return comp(
ccache + compiler, version, for_machine,
is_cross, info, exe_wrap, linker=linker)
@@ -1303,6 +1334,10 @@ class Environment:
compilers, ccache, exe_wrap = self._get_compilers('rust', for_machine)
is_cross = not self.machines.matches_build_machine(for_machine)
info = self.machines[for_machine]
+
+ cc = self.detect_c_compiler(for_machine)
+ is_link_exe = isinstance(cc.linker, VisualStudioLikeLinkerMixin)
+
for compiler in compilers:
if isinstance(compiler, str):
compiler = [compiler]
@@ -1316,19 +1351,42 @@ class Environment:
version = search_version(out)
if 'rustc' in out:
- # Chalk up another quirk for rust. There is no way (AFAICT) to
- # figure out what linker rustc is using for a non-nightly compiler
- # (On nightly you can pass -Z print-link-args). So we're going to
- # hard code the linker based on the platform.
- # Currently gnu ld is used for everything except apple by
- # 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', RustCompiler.LINKER_PREFIX)
+ # On Linux and mac rustc will invoke gcc (clang for mac
+ # presumably) and it can do this windows, for dynamic linking.
+ # this means the easiest way to C compiler for dynamic linking.
+ # figure out what linker to use is to just get the value of the
+ # C compiler and use that as the basis of the rust linker.
+ # However, there are two things we need to change, if CC is not
+ # the default use that, and second add the necessary arguments
+ # to rust to use -fuse-ld
+
+ extra_args = {}
+ always_args = []
+ if is_link_exe:
+ compiler.extend(['-C', 'linker={}'.format(cc.linker.exelist[0])])
+ extra_args['direct'] = True
+ extra_args['machine'] = cc.linker.machine
+ elif not ((info.is_darwin() and isinstance(cc, AppleClangCCompiler)) or
+ isinstance(cc, GnuCCompiler)):
+ c = cc.exelist[1] if cc.exelist[0].endswith('ccache') else cc.exelist[0]
+ compiler.extend(['-C', 'linker={}'.format(c)])
+
+ value = self.binaries[for_machine].lookup_entry('ld')
+ if value is not None:
+ for a in cc.use_linker_args(value[0]):
+ always_args.extend(['-C', 'link-arg={}'.format(a)])
+
+ # This trickery with type() gets us the class of the linker
+ # so we can initialize a new copy for the Rust Compiler
+
+ if is_link_exe:
+ linker = type(cc.linker)(for_machine, always_args, exelist=cc.linker.exelist,
+ version=cc.linker.version, **extra_args)
else:
- linker = GnuDynamicLinker(
- [], for_machine, 'GNU ld', RustCompiler.LINKER_PREFIX)
+ linker = type(cc.linker)(compiler, for_machine, cc.linker.id, cc.LINKER_PREFIX,
+ always_args=always_args, version=cc.linker.version,
+ **extra_args)
+
return RustCompiler(
compiler, version, for_machine, is_cross, info, exe_wrap,
linker=linker)
@@ -1339,10 +1397,11 @@ class Environment:
info = self.machines[for_machine]
# Detect the target architecture, required for proper architecture handling on Windows.
- c_compiler = {}
- is_msvc = mesonlib.is_windows() and 'VCINSTALLDIR' in os.environ
- if is_msvc:
- c_compiler = {'c': self.detect_c_compiler(for_machine)} # MSVC compiler is required for correct platform detection.
+ # MSVC compiler is required for correct platform detection.
+ c_compiler = {'c': self.detect_c_compiler(for_machine)}
+ is_msvc = isinstance(c_compiler['c'], VisualStudioCCompiler)
+ if not is_msvc:
+ c_compiler = {}
arch = detect_cpu_family(c_compiler)
if is_msvc and arch == 'x86':
@@ -1372,25 +1431,22 @@ class Environment:
if 'LLVM D compiler' in out:
# LDC seems to require a file
- m = self.machines[for_machine]
- if m.is_windows() or m.is_cygwin():
- if is_msvc:
- linker = MSVCDynamicLinker(for_machine, version=version)
- else:
- # Getting LDC on windows to give useful linker output when not
- # doing real work is painfully hard. It ships with a version of
- # lld-link, so just assume that we're going to use lld-link
- # with it.
- _, o, _ = Popen_safe(['lld-link.exe', '--version'])
- linker = ClangClDynamicLinker(for_machine, version=search_version(o))
+ if info.is_windows() or info.is_cygwin():
+ # Getting LDC on windows to give useful linker output when
+ # not doing real work is painfully hard. It ships with a
+ # version of lld-link, so unless we think the user wants
+ # link.exe, just assume that we're going to use lld-link
+ # with it.
+ linker = self._guess_win_linker(
+ ['link' if is_msvc else 'lld-link'],
+ compilers.LLVMDCompiler, for_machine, use_linker_prefix=False)
else:
with tempfile.NamedTemporaryFile(suffix='.d') as f:
# LDC writes an object file to the current working directory.
# Clean it up.
objectfile = os.path.basename(f.name)[:-1] + 'o'
linker = self._guess_nix_linker(
- exelist, for_machine,
- compilers.LLVMDCompiler.LINKER_PREFIX,
+ exelist, compilers.LLVMDCompiler, for_machine,
extra_args=[f.name])
try:
os.unlink(objectfile)
@@ -1401,27 +1457,25 @@ class Environment:
exelist, version, for_machine, info, arch,
full_version=full_version, linker=linker)
elif 'gdc' in out:
- linker = self._guess_nix_linker(exelist, for_machine, compilers.GnuDCompiler.LINKER_PREFIX)
+ linker = self._guess_nix_linker(exelist, compilers.GnuDCompiler, for_machine)
return compilers.GnuDCompiler(
exelist, version, for_machine, info, arch, is_cross, exe_wrap,
full_version=full_version, linker=linker)
elif 'The D Language Foundation' in out or 'Digital Mars' in out:
# DMD seems to require a file
- m = self.machines[for_machine]
- if m.is_windows() or m.is_cygwin():
+ if info.is_windows() or info.is_cygwin():
if is_msvc:
- linker = MSVCDynamicLinker(for_machine, version=version)
+ linker_cmd = ['link']
elif arch == 'x86':
- linker = OptlinkDynamicLinker(for_machine, version=full_version)
+ linker_cmd = ['optlink']
else:
- # DMD ships with lld-link
- _, o, _ = Popen_safe(['lld-link.exe', '--version'])
- linker = ClangClDynamicLinker(for_machine, version=search_version(o))
+ linker_cmd = ['lld-link']
+ linker = self._guess_win_linker(linker_cmd, compilers.DmdDCompiler, for_machine,
+ use_linker_prefix=False)
else:
with tempfile.NamedTemporaryFile(suffix='.d') as f:
linker = self._guess_nix_linker(
- exelist, for_machine,
- compilers.LLVMDCompiler.LINKER_PREFIX,
+ exelist, compilers.DmdDCompiler, for_machine,
extra_args=[f.name])
return compilers.DmdDCompiler(
exelist, version, for_machine, info, arch,
@@ -1447,8 +1501,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,
- compilers.SwiftCompiler.LINKER_PREFIX,
+ exelist, compilers.SwiftCompiler, for_machine,
extra_args=[f.name])
return compilers.SwiftCompiler(
exelist, version, for_machine, info, is_cross, linker=linker)
diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py
index 41dd929..ab532a4 100644
--- a/mesonbuild/linkers.py
+++ b/mesonbuild/linkers.py
@@ -247,17 +247,21 @@ class DynamicLinker(metaclass=abc.ABCMeta):
} # type: typing.Dict[str, typing.List[str]]
def _apply_prefix(self, arg: str) -> typing.List[str]:
- if isinstance(self.prefix_arg, str):
+ if self.prefix_arg is None:
+ return [arg]
+ elif 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, prefix_arg: typing.Union[str, typing.List[str]], *, version: str = 'unknown version'):
+ id_: str, prefix_arg: typing.Union[str, typing.List[str]],
+ always_args: typing.List[str], *, version: str = 'unknown version'):
self.exelist = exelist
self.for_machine = for_machine
self.version = version
self.id = id_
self.prefix_arg = prefix_arg
+ self.always_args = always_args
def __repr__(self) -> str:
return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist))
@@ -276,7 +280,7 @@ class DynamicLinker(metaclass=abc.ABCMeta):
return mesonlib.is_windows()
def get_always_args(self) -> typing.List[str]:
- return []
+ return self.always_args.copy()
def get_lib_prefix(self) -> str:
return ''
@@ -395,6 +399,11 @@ class DynamicLinker(metaclass=abc.ABCMeta):
install_rpath: str) -> typing.List[str]:
return []
+ 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]:
+ return []
+
class PosixDynamicLinkerMixin:
@@ -419,8 +428,8 @@ class GnuLikeDynamicLinkerMixin:
"""Mixin class for dynamic linkers that provides gnu-like interface.
- This acts as a base for the GNU linkers (bfd and gold), the Intel Xild
- (which comes with ICC), LLVM's lld, and other linkers like GNU-ld.
+ This acts as a base for the GNU linkers (bfd and gold), LLVM's lld, and
+ other linkers like GNU-ld.
"""
_BUILDTYPE_ARGS = {
@@ -595,7 +604,7 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
return self._apply_prefix('-undefined,error')
def get_always_args(self) -> typing.List[str]:
- return self._apply_prefix('-headerpad_max_install_names')
+ return self._apply_prefix('-headerpad_max_install_names') + super().get_always_args()
def bitcode_args(self) -> typing.List[str]:
return self._apply_prefix('-bitcode_bundle')
@@ -656,26 +665,6 @@ class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, Dyna
pass
-class XildLinuxDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
-
- """Representation of Intel's Xild linker.
-
- This is only the linux-like linker which dispatches to Gnu ld.
- """
-
- pass
-
-
-class XildAppleDynamicLinker(AppleDynamicLinker):
-
- """Representation of Intel's Xild linker.
-
- This is the apple linker, which dispatches to Apple's ld.
- """
-
- pass
-
-
class CcrxDynamicLinker(DynamicLinker):
"""Linker for Renesis CCrx compiler."""
@@ -715,7 +704,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:
@@ -802,7 +791,7 @@ class VisualStudioLikeLinkerMixin:
self.machine = machine
def invoked_by_compiler(self) -> bool:
- return self.direct
+ return not self.direct
def get_debug_crt_args(self) -> typing.List[str]:
"""Arguments needed to select a debug crt for the linker.
@@ -818,7 +807,7 @@ class VisualStudioLikeLinkerMixin:
return self._apply_prefix('/MACHINE:' + self.machine) + self._apply_prefix('/OUT:' + outputname)
def get_always_args(self) -> typing.List[str]:
- return self._apply_prefix('/nologo')
+ return self._apply_prefix('/nologo') + super().get_always_args()
def get_search_args(self, dirname: str) -> typing.List[str]:
return self._apply_prefix('/LIBPATH:' + dirname)
@@ -853,33 +842,35 @@ class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
"""Microsoft's Link.exe."""
- def __init__(self, for_machine: mesonlib.MachineChoice, *,
+ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: typing.List[str], *,
exelist: typing.Optional[typing.List[str]] = None,
prefix: typing.Union[str, typing.List[str]] = '',
- machine: str = 'x86', version: str = 'unknown version'):
+ machine: str = 'x86', version: str = 'unknown version',
+ direct: bool = True):
super().__init__(exelist or ['link.exe'], for_machine, 'link',
- prefix, machine=machine, version=version)
+ prefix, always_args, machine=machine, version=version, direct=direct)
class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
"""Clang's lld-link.exe."""
- def __init__(self, for_machine: mesonlib.MachineChoice, *,
+ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: typing.List[str], *,
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)
+ machine: str = 'x86', version: str = 'unknown version',
+ direct: bool = True):
+ super().__init__(exelist or ['lld-link.exe'], for_machine, 'lld-link',
+ prefix, always_args, machine=machine, version=version, direct=direct)
class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
"""Intel's Xilink.exe."""
- def __init__(self, for_machine: mesonlib.MachineChoice,
+ def __init__(self, for_machine: mesonlib.MachineChoice, always_args: typing.List[str],
*, version: str = 'unknown version'):
- super().__init__(['xilink.exe'], for_machine, 'xilink', '', version=version)
+ super().__init__(['xilink.exe'], for_machine, 'xilink', '', always_args, version=version)
class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
@@ -936,7 +927,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', prefix_arg='', version=version)
+ super().__init__(['optlink.exe'], for_machine, 'optlink', '', [], version=version)
def get_allow_undefined_args(self) -> typing.List[str]:
return []