aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2020-01-13 11:15:36 -0800
committerJussi Pakkanen <jpakkane@gmail.com>2020-01-22 23:39:33 +0200
commit730a7b296fdff8aca58e15829485b3b68262d3c0 (patch)
tree08d976f1a499520a520c09743904e268f5046d74
parent958df63dac810246e84c2b8eaa32d22d19ace0ef (diff)
downloadmeson-730a7b296fdff8aca58e15829485b3b68262d3c0.zip
meson-730a7b296fdff8aca58e15829485b3b68262d3c0.tar.gz
meson-730a7b296fdff8aca58e15829485b3b68262d3c0.tar.bz2
environment: Replace LD with <LANG>LD
The rust code is ugly, because rust is annoying. It doesn't invoke a linker directly (unless that linker is link.exe or lld-link.exe), instead it invokes the C compiler (gcc or clang usually) to do it's linking. Meson doesn't have good abstractions for this, though we probably should because some of the D compilers do the same thing. Either that or we should just call the c compiler directly, like vala does. This changes the public interface for meson, which we don't do unless we absolutely have to. In this case I think we need to do it. A fair number of projects have already been using 'ld' in their cross/native files to get the ld binary and call it directly in custom_targets or generators, and we broke that. While we could hit this problem again names like `c_ld` and `cpp_ld` are far less likely to cause collisions than `ld`. Additionally this gives a way to set the linker on a per-compiler basis, which is probably in itself very useful. Fixes #6442
-rw-r--r--docs/markdown/howtox.md34
-rw-r--r--mesonbuild/envconfig.py10
-rw-r--r--mesonbuild/environment.py66
-rwxr-xr-xrun_unittests.py7
4 files changed, 77 insertions, 40 deletions
diff --git a/docs/markdown/howtox.md b/docs/markdown/howtox.md
index f73d6b9..5deaa7e 100644
--- a/docs/markdown/howtox.md
+++ b/docs/markdown/howtox.md
@@ -28,24 +28,36 @@ native-files and the latter via the cross file only.
## Set dynamic linker
+Like the compiler, the linker is selected via the <compiler variable>_LD
+environment variable, or through the `<compiler entry>ld` entry in a native
+or cross file. You must be aware of whether 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 `cld` or `CC_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 executable, such as `lld-link.exe`.
+
+*NOTE* In meson 0.53.0 the `ld` entry in the cross/native file and the `LD`
+environment variable was used, this resulted in a large number of regressions
+and was changed.
+
```console
-$ CC=clang LD=lld meson <options>
+$ CC=clang CC_LD=lld meson <options>
```
or
```console
-$ CC=clang-cl LD=link meson <options>
+$ CC=clang-cl CC_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`.
+or in a cross or native file:
+
+```ini
+[binaries]
+c = 'clang'
+c_ld = 'lld'
+```
## Set default C/C++ language version
@@ -139,7 +151,7 @@ $ ninja coverage-html (or coverage-xml)
The coverage report can be found in the meson-logs subdirectory.
-Note: Currently, Meson does not support generating coverage reports
+Note: Currently, Meson does not support generating coverage reports
with Clang.
## Add some optimization to debug builds
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index c275ef2..1ebf067 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -313,11 +313,19 @@ class BinaryTable(HasEnvVarFallback):
'rust': 'RUSTC',
'vala': 'VALAC',
+ # Linkers
+ 'c_ld': 'CC_LD',
+ 'cpp_ld': 'CXX_LD',
+ 'd_ld': 'D_LD',
+ 'fortran_ld': 'F_LD',
+ 'objc_ld': 'OBJC_LD',
+ 'objcpp_ld': 'OBJCPP_LD',
+ 'rust_ld': 'RUST_LD',
+
# Binutils
'strip': 'STRIP',
'ar': 'AR',
'windres': 'WINDRES',
- 'ld': 'LD',
# Other tools
'cmake': 'CMAKE',
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 3d4f49a..122301f 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -749,7 +749,7 @@ class Environment:
check_args += self.coredata.compiler_options[for_machine][comp_class.language + '_args'].value
override = [] # type: T.List[str]
- value = self.binaries[for_machine].lookup_entry('ld')
+ value = self.binaries[for_machine].lookup_entry(comp_class.language + 'ld')
if value is not None:
override = comp_class.use_linker_args(value[0])
check_args += override
@@ -812,7 +812,7 @@ class Environment:
check_args = comp_class.LINKER_PREFIX + ['--version'] + extra_args
override = [] # type: T.List[str]
- value = self.binaries[for_machine].lookup_entry('ld')
+ value = self.binaries[for_machine].lookup_entry(comp_class.language + 'ld')
if value is not None:
override = comp_class.use_linker_args(value[0])
check_args += override
@@ -1355,6 +1355,7 @@ class Environment:
cc = self.detect_c_compiler(for_machine)
is_link_exe = isinstance(cc.linker, VisualStudioLikeLinkerMixin)
+ override = self.binaries[for_machine].lookup_entry('rustld')
for compiler in compilers:
if isinstance(compiler, str):
@@ -1378,32 +1379,45 @@ class Environment:
# 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)):
+ if override is None:
+ 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)])
+
+ # 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 = type(cc.linker)(compiler, for_machine, cc.linker.id, cc.LINKER_PREFIX,
+ always_args=always_args, version=cc.linker.version,
+ **extra_args)
+ elif 'link' in override[0]:
+ linker = self._guess_win_linker(
+ override, RustCompiler, for_machine, use_linker_prefix=False)
+ linker.direct = True
+ else:
+ # We're creating a new type of "C" compiler, that has rust
+ # as it's language. This is gross, but I can't figure out
+ # another way to handle this, because rustc is actually
+ # invoking the c compiler as it's linker.
+ b = type('b', (type(cc), ), {})
+ b.language = RustCompiler.language
+ linker = self._guess_nix_linker(cc.exelist, b, for_machine)
+
+ # Of course, we're not going to use any of that, we just
+ # need it to get the proper arguments to pass to rustc
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 = type(cc.linker)(compiler, for_machine, cc.linker.id, cc.LINKER_PREFIX,
- always_args=always_args, version=cc.linker.version,
- **extra_args)
+ compiler.extend(['-C', 'link-args={}'.format(' '.join(cc.use_linker_args(override[0])))])
return RustCompiler(
compiler, version, for_machine, is_cross, info, exe_wrap,
diff --git a/run_unittests.py b/run_unittests.py
index b034773..d8c3a1c 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -44,6 +44,7 @@ from distutils.dir_util import copy_tree
import mesonbuild.mlog
import mesonbuild.depfile
import mesonbuild.compilers
+import mesonbuild.envconfig
import mesonbuild.environment
import mesonbuild.mesonlib
import mesonbuild.coredata
@@ -4663,7 +4664,8 @@ class WindowsTests(BasePlatformTests):
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}):
+ envvar = mesonbuild.envconfig.BinaryTable.evarMap['{}ld'.format(lang)]
+ with mock.patch.dict(os.environ, {envvar: name}):
env = get_fake_env()
try:
comp = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
@@ -5943,7 +5945,8 @@ c = ['{0}']
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}):
+ envvar = mesonbuild.envconfig.BinaryTable.evarMap['{}ld'.format(lang)]
+ with mock.patch.dict(os.environ, {envvar: name}):
env = get_fake_env()
comp = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST)
if lang != 'rust' and comp.use_linker_args('foo') == []: