Skip to content

Commit

Permalink
Allow selecting the dynamic linker
Browse files Browse the repository at this point in the history
This uses the normal meson mechanisms, an LD environment variable or via
cross/native files.

Fixes: #6057
  • Loading branch information
dcbaker committed Dec 3, 2019
1 parent 7658e67 commit ef9aeb1
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 95 deletions.
17 changes: 17 additions & 0 deletions 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.
6 changes: 6 additions & 0 deletions mesonbuild/compilers/compilers.py
Expand Up @@ -1178,6 +1178,12 @@ def get_dependency_compile_args(self, dep):
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):
'''
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/compilers/mixins/gnu.py
Expand Up @@ -299,6 +299,10 @@ def get_include_args(self, path: str, is_system: bool) -> typing.List[str]:
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):
"""
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/compilers/mixins/visualstudio.py
Expand Up @@ -381,3 +381,7 @@ def has_func_attribute(self, name: str, env: 'Environment') -> typing.Tuple[bool

def get_argument_syntax(self) -> str:
return 'msvc'

@classmethod
def use_linker_args(cls, linker: str) -> typing.List[str]:
return []
6 changes: 5 additions & 1 deletion mesonbuild/compilers/rust.py
Expand Up @@ -32,7 +32,7 @@

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):
Expand Down Expand Up @@ -109,3 +109,7 @@ def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):

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.
2 changes: 2 additions & 0 deletions mesonbuild/envconfig.py
Expand Up @@ -309,7 +309,9 @@ def __init__(
'strip': 'STRIP',
'ar': 'AR',
'windres': 'WINDRES',
'ld': 'LD',

# Other tools
'cmake': 'CMAKE',
'qmake': 'QMAKE',
'pkgconfig': 'PKG_CONFIG',
Expand Down
206 changes: 126 additions & 80 deletions mesonbuild/environment.py

Large diffs are not rendered by default.

28 changes: 16 additions & 12 deletions mesonbuild/linkers.py
Expand Up @@ -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))
Expand All @@ -276,7 +280,7 @@ def get_accepts_rsp(self) -> bool:
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 ''
Expand Down Expand Up @@ -715,7 +719,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:
Expand Down Expand Up @@ -853,33 +857,33 @@ 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'):
super().__init__(exelist or ['link.exe'], for_machine, 'link',
prefix, machine=machine, version=version)
prefix, always_args, machine=machine, version=version)


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)
super().__init__(exelist or ['lld-link.exe'], for_machine, 'lld-link',
prefix, always_args, version=version)


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):
Expand Down Expand Up @@ -936,7 +940,7 @@ def __init__(self, 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__(['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 []
Expand Down
4 changes: 2 additions & 2 deletions run_unittests.py
Expand Up @@ -445,7 +445,7 @@ def test_compiler_args_class(self):
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']
Expand Down Expand Up @@ -474,7 +474,7 @@ def test_compiler_args_class_gnuld(self):
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']
Expand Down

0 comments on commit ef9aeb1

Please sign in to comment.