aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--ci/azure-steps.yml3
-rw-r--r--docs/markdown/Cross-compilation.md7
-rw-r--r--docs/markdown/Native-environments.md1
-rw-r--r--docs/markdown/howtox.md25
-rw-r--r--docs/markdown/snippets/linker_override.md17
-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
-rwxr-xr-xrun_project_tests.py9
-rwxr-xr-xrun_unittests.py89
15 files changed, 334 insertions, 174 deletions
diff --git a/ci/azure-steps.yml b/ci/azure-steps.yml
index 34c658b..ff34c45 100644
--- a/ci/azure-steps.yml
+++ b/ci/azure-steps.yml
@@ -156,9 +156,10 @@ steps:
echo ""
- echo "Locating cl, rc:"
+ echo "Locating cl, rc, link:"
where.exe cl
where.exe rc
+ where.exe link
echo ""
echo "=== Start running tests ==="
diff --git a/docs/markdown/Cross-compilation.md b/docs/markdown/Cross-compilation.md
index beb9824..b3cdc81 100644
--- a/docs/markdown/Cross-compilation.md
+++ b/docs/markdown/Cross-compilation.md
@@ -97,6 +97,7 @@ this:
[binaries]
c = '/usr/bin/i586-mingw32msvc-gcc'
cpp = '/usr/bin/i586-mingw32msvc-g++'
+ld = 'gold'
ar = '/usr/i586-mingw32msvc/bin/ar'
strip = '/usr/i586-mingw32msvc/bin/strip'
pkgconfig = '/usr/bin/i586-mingw32msvc-pkg-config'
@@ -112,6 +113,12 @@ of a wrapper, these lines are all you need to write. Meson will
automatically use the given wrapper when it needs to run host
binaries. This happens e.g. when running the project's test suite.
+ld is special because it is compiler specific. For compilers like gcc and
+clang which are used to invoke the linker this is a value to pass to their
+"choose the linker" argument (-fuse-ld= in this case). For compilers like
+MSVC and Clang-Cl, this is the path to a linker for meson to invoke, such as
+`link.exe` or `lld-link.exe`. Support for ls is *new in 0.53.0*
+
The next section lists properties of the cross compiler and its target
system, and thus properties of host system of what we're building. It
looks like this:
diff --git a/docs/markdown/Native-environments.md b/docs/markdown/Native-environments.md
index 41e678e..677f067 100644
--- a/docs/markdown/Native-environments.md
+++ b/docs/markdown/Native-environments.md
@@ -40,6 +40,7 @@ like `llvm-config`
c = '/usr/local/bin/clang'
cpp = '/usr/local/bin/clang++'
rust = '/usr/local/bin/rust'
+ld = 'gold'
llvm-config = '/usr/local/llvm-svn/bin/llvm-config'
```
diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md
index 188f1f7..f73d6b9 100644
--- a/docs/markdown/howtox.md
+++ b/docs/markdown/howtox.md
@@ -23,8 +23,29 @@ compilation is done by setting `CC` to point to the cross compiler
that Meson supports natively the case where you compile helper tools
(such as code generators) and use the results during the
build. Because of this Meson needs to know both the native and the
-cross compiler. The former is set via the environment variables and
-the latter via the cross file only.
+cross compiler. The former is set via the environment variables or
+native-files and the latter via the cross file only.
+
+## Set dynamic linker
+
+```console
+$ CC=clang LD=lld meson <options>
+```
+
+or
+
+```console
+$ CC=clang-cl LD=link meson <options>
+```
+
+Like the compiler, the linker is selected via the LD environment variable, or
+through the `ld` entry in a native or cross file. You must be aware of
+whehter you're using a compiler that invokes the linker itself (most
+compilers including GCC and Clang) or a linker that is invoked directly (when
+using MSVC or compilers that act like it, including Clang-Cl). With the
+former `ld` or `LD` should be the value to pass to the compiler's special
+argument (such as `-fuse-ld` with clang and gcc), with the latter it should
+be an exectuable, such as `lld-link.exe`.
## Set default C/C++ language version
diff --git a/docs/markdown/snippets/linker_override.md b/docs/markdown/snippets/linker_override.md
new file mode 100644
index 0000000..21cb072
--- /dev/null
+++ b/docs/markdown/snippets/linker_override.md
@@ -0,0 +1,17 @@
+## Generic Overrider for Dynamic Linker selection
+
+Previous to meson 0.52.0 you set the dynamic linker using compiler specific
+flags passed via language flags and hoped things worked out. In meson 0.52.0
+meson started detecting the linker and making intelligent decisions about
+using it. Unfortunately this broke choosing a non-default linker.
+
+Now there is a generic mechanism for doing this, you may use the LD
+environment variable (with normal meson environment variable rules), or add
+the following to a cross or native file:
+
+```ini
+[binaries]
+ld = 'gold'
+```
+
+And meson will select the linker if possible.
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 []
diff --git a/run_project_tests.py b/run_project_tests.py
index b48b881..4f04fb2 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -621,14 +621,13 @@ def has_broken_rustc() -> bool:
mesonlib.windows_proof_rmtree(dirname)
return pc.returncode != 0
-def should_skip_rust() -> bool:
+def should_skip_rust(backend: Backend) -> bool:
if not shutil.which('rustc'):
return True
if backend is not Backend.ninja:
return True
- if mesonlib.is_windows():
- if has_broken_rustc():
- return True
+ if mesonlib.is_windows() and has_broken_rustc():
+ return True
return False
def detect_tests_to_run(only: typing.List[str]) -> typing.List[typing.Tuple[str, typing.List[Path], bool]]:
@@ -666,7 +665,7 @@ def detect_tests_to_run(only: typing.List[str]) -> typing.List[typing.Tuple[str,
('java', 'java', backend is not Backend.ninja or mesonlib.is_osx() or not have_java()),
('C#', 'csharp', skip_csharp(backend)),
('vala', 'vala', backend is not Backend.ninja or not shutil.which(os.environ.get('VALAC', 'valac'))),
- ('rust', 'rust', should_skip_rust()),
+ ('rust', 'rust', should_skip_rust(backend)),
('d', 'd', backend is not Backend.ninja or not have_d_compiler()),
('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or not have_objc_compiler()),
('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or not have_objcpp_compiler()),
diff --git a/run_unittests.py b/run_unittests.py
index 770d236..a7a0d26 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -291,26 +291,6 @@ def no_pkgconfig():
shutil.which = old_which
ExternalProgram._search = old_search
-class PatchModule:
- '''
- Fancy monkey-patching! Whee! Can't use mock.patch because it only
- patches in the local namespace.
- '''
-
- def __init__(self, func, name, impl):
- self.func = func
- assert(isinstance(name, str))
- self.func_name = name
- self.old_impl = None
- self.new_impl = impl
-
- def __enter__(self):
- self.old_impl = self.func
- exec('{} = self.new_impl'.format(self.func_name))
-
- def __exit__(self, *args):
- exec('{} = self.old_impl'.format(self.func_name))
-
class InternalTests(unittest.TestCase):
@@ -442,7 +422,7 @@ class InternalTests(unittest.TestCase):
def test_compiler_args_class_gnuld(self):
cargsfunc = mesonbuild.compilers.CompilerArgs
## Test --start/end-group
- linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,')
+ linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,', [])
gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock(), linker=linker)
## Ensure that the fake compiler is never called by overriding the relevant function
gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include']
@@ -471,7 +451,7 @@ class InternalTests(unittest.TestCase):
def test_compiler_args_remove_system(self):
cargsfunc = mesonbuild.compilers.CompilerArgs
## Test --start/end-group
- linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,')
+ linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake', '-Wl,', [])
gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', False, MachineChoice.HOST, mock.Mock(), linker=linker)
## Ensure that the fake compiler is never called by overriding the relevant function
gcc.get_default_include_dirs = lambda: ['/usr/include', '/usr/share/include', '/usr/local/include']
@@ -2316,11 +2296,11 @@ class AllPlatformTests(BasePlatformTests):
if isinstance(cc, intel):
self.assertIsInstance(linker, ar)
if is_osx():
- self.assertIsInstance(cc.linker, mesonbuild.linkers.XildAppleDynamicLinker)
+ self.assertIsInstance(cc.linker, mesonbuild.linkers.AppleDynamicLinker)
elif is_windows():
self.assertIsInstance(cc.linker, mesonbuild.linkers.XilinkDynamicLinker)
else:
- self.assertIsInstance(cc.linker, mesonbuild.linkers.XildLinuxDynamicLinker)
+ self.assertIsInstance(cc.linker, mesonbuild.linkers.GnuDynamicLinker)
if isinstance(cc, msvc):
self.assertTrue(is_windows())
self.assertIsInstance(linker, lib)
@@ -4558,6 +4538,29 @@ class WindowsTests(BasePlatformTests):
self.assertTrue('prog.pdb' in files)
+ def _check_ld(self, name: str, lang: str, expected: str) -> None:
+ if not shutil.which(name):
+ raise unittest.SkipTest('Could not find {}.'.format(name))
+ with mock.patch.dict(os.environ, {'LD': name}):
+ env = get_fake_env()
+ try:
+ comp = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
+ except EnvironmentException:
+ raise unittest.SkipTest('Could not find a compiler for {}'.format(lang))
+ self.assertEqual(comp.linker.id, expected)
+
+ def test_link_environment_variable_lld_link(self):
+ self._check_ld('lld-link', 'c', 'lld-link')
+
+ def test_link_environment_variable_link(self):
+ self._check_ld('link', 'c', 'link')
+
+ def test_link_environment_variable_optlink(self):
+ self._check_ld('optlink', 'c', 'optlink')
+
+ def test_link_environment_variable_rust(self):
+ self._check_ld('link', 'rust', 'link')
+
@unittest.skipUnless(is_osx(), "requires Darwin")
class DarwinTests(BasePlatformTests):
'''
@@ -5785,6 +5788,44 @@ c = ['{0}']
self.build()
self.run_tests()
+ def _check_ld(self, check: str, name: str, lang: str, expected: str) -> None:
+ if is_sunos():
+ raise unittest.SkipTest('Solaris currently cannot override the linker.')
+ if not shutil.which(check):
+ raise unittest.SkipTest('Could not find {}.'.format(check))
+ with mock.patch.dict(os.environ, {'LD': name}):
+ env = get_fake_env()
+ comp = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
+ if lang != 'rust' and comp.use_linker_args('foo') == []:
+ raise unittest.SkipTest(
+ 'Compiler {} does not support using alternative linkers'.format(comp.id))
+ self.assertEqual(comp.linker.id, expected)
+
+ def test_ld_environment_variable_bfd(self):
+ self._check_ld('ld.bfd', 'bfd', 'c', 'GNU ld.bfd')
+
+ def test_ld_environment_variable_gold(self):
+ self._check_ld('ld.gold', 'gold', 'c', 'GNU ld.gold')
+
+ def test_ld_environment_variable_lld(self):
+ self._check_ld('ld.lld', 'lld', 'c', 'lld')
+
+ def test_ld_environment_variable_rust(self):
+ self._check_ld('ld.gold', 'gold', 'rust', 'GNU ld.gold')
+
+ def test_ld_environment_variable_cpp(self):
+ self._check_ld('ld.gold', 'gold', 'cpp', 'GNU ld.gold')
+
+ def test_ld_environment_variable_objc(self):
+ self._check_ld('ld.gold', 'gold', 'objc', 'GNU ld.gold')
+
+ def test_ld_environment_variable_objcpp(self):
+ self._check_ld('ld.gold', 'gold', 'objcpp', 'GNU ld.gold')
+
+ def test_ld_environment_variable_fortran(self):
+ self._check_ld('ld.gold', 'gold', 'fortran', 'GNU ld.gold')
+
+
def should_run_cross_arm_tests():
return shutil.which('arm-linux-gnueabihf-gcc') and not platform.machine().lower().startswith('arm')