Merge pull request #5681 from dcbaker/dynamic-linker-split

split dynamic linker representations from compilers
pull/5824/head
Jussi Pakkanen 6 years ago committed by GitHub
commit 1ea3ddc6ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      docs/markdown/snippets/b_lundef_on_apple.md
  2. 6
      docs/markdown/snippets/split-compiler-and-linker-representations.md
  3. 13
      mesonbuild/backend/ninjabackend.py
  4. 10
      mesonbuild/build.py
  5. 3
      mesonbuild/compilers/__init__.py
  6. 36
      mesonbuild/compilers/c.py
  7. 264
      mesonbuild/compilers/compilers.py
  8. 30
      mesonbuild/compilers/cpp.py
  9. 16
      mesonbuild/compilers/cs.py
  10. 65
      mesonbuild/compilers/cuda.py
  11. 335
      mesonbuild/compilers/d.py
  12. 20
      mesonbuild/compilers/fortran.py
  13. 18
      mesonbuild/compilers/java.py
  14. 60
      mesonbuild/compilers/mixins/arm.py
  15. 43
      mesonbuild/compilers/mixins/ccrx.py
  16. 72
      mesonbuild/compilers/mixins/clike.py
  17. 123
      mesonbuild/compilers/mixins/gnu.py
  18. 3
      mesonbuild/compilers/mixins/intel.py
  19. 124
      mesonbuild/compilers/mixins/islinker.py
  20. 32
      mesonbuild/compilers/mixins/pgi.py
  21. 69
      mesonbuild/compilers/mixins/visualstudio.py
  22. 12
      mesonbuild/compilers/objc.py
  23. 12
      mesonbuild/compilers/objcpp.py
  24. 15
      mesonbuild/compilers/rust.py
  25. 16
      mesonbuild/compilers/swift.py
  26. 246
      mesonbuild/environment.py
  27. 4
      mesonbuild/interpreter.py
  28. 698
      mesonbuild/linkers.py
  29. 1
      run_project_tests.py
  30. 15
      run_unittests.py
  31. 5
      test cases/common/152 shared module resolving symbol in executable/meson.build
  32. 15
      test cases/common/185 has link arg/meson.build
  33. 4
      test cases/common/203 function attributes/meson.build

@ -0,0 +1,5 @@
## Meson's builtin b_lundef is now supported on macOS
This has always been possible, but there are some addtional restrictions on
macOS (mainly do to Apple only features). With the linker internal
re-architecture this has become possible

@ -0,0 +1,6 @@
## Compiler and dynamic linker representation split
0.52.0 inclues a massive refactor of the representaitons of compilers to
tease apart the representations of compilers and dynamic linkers (ld). This
fixes a number of compiler/linker combinations. In particular this fixes
use GCC and vanilla clang on macOS.

@ -1328,7 +1328,8 @@ int dummy;
self.get_target_dir(target))
else:
target_slashname_workaround_dir = self.get_target_dir(target)
rpath_args = rustc.build_rpath_args(self.environment.get_build_dir(),
rpath_args = rustc.build_rpath_args(self.environment,
self.environment.get_build_dir(),
target_slashname_workaround_dir,
self.determine_rpath_dirs(target),
target.build_rpath,
@ -2325,9 +2326,10 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
# All shared libraries are PIC
commands += linker.get_pic_args()
# Add -Wl,-soname arguments on Linux, -install_name on OS X
commands += linker.get_soname_args(target.prefix, target.name, target.suffix,
target.soversion, target.darwin_versions,
isinstance(target, build.SharedModule))
commands += linker.get_soname_args(
self.environment, target.prefix, target.name, target.suffix,
target.soversion, target.darwin_versions,
isinstance(target, build.SharedModule))
# This is only visited when building for Windows using either GCC or Visual Studio
if target.vs_module_defs and hasattr(linker, 'gen_vs_module_defs_args'):
commands += linker.gen_vs_module_defs_args(target.vs_module_defs.rel_to_builddir(self.build_to_src))
@ -2538,7 +2540,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
self.get_target_dir(target))
else:
target_slashname_workaround_dir = self.get_target_dir(target)
commands += linker.build_rpath_args(self.environment.get_build_dir(),
commands += linker.build_rpath_args(self.environment,
self.environment.get_build_dir(),
target_slashname_workaround_dir,
self.determine_rpath_dirs(target),
target.build_rpath,

@ -28,7 +28,7 @@ from .mesonlib import (
extract_as_list, typeslistify, stringlistify, classify_unity_sources,
get_filenames_templates_dict, substitute_values, has_path_sep,
)
from .compilers import Compiler, is_object, clink_langs, sort_clink, lang_suffixes, get_macos_dylib_install_name
from .compilers import Compiler, is_object, clink_langs, sort_clink, lang_suffixes
from .linkers import StaticLinker
from .interpreterbase import FeatureNew
@ -96,8 +96,12 @@ known_stlib_kwargs = known_build_target_kwargs | {'pic'}
known_jar_kwargs = known_exe_kwargs | {'main_class'}
@lru_cache(maxsize=None)
def get_target_macos_dylib_install_name(ld):
return get_macos_dylib_install_name(ld.prefix, ld.name, ld.suffix, ld.soversion)
def get_target_macos_dylib_install_name(ld) -> str:
name = ['@rpath/', ld.prefix, ld.name]
if ld.soversion is not None:
name.append('.' + ld.soversion)
name.append('.dylib')
return ''.join(name)
class InvalidArguments(MesonException):
pass

@ -23,7 +23,6 @@ __all__ = [
'clink_langs',
'c_suffixes',
'cpp_suffixes',
'get_macos_dylib_install_name',
'get_base_compile_args',
'get_base_link_args',
'is_assembly',
@ -185,6 +184,6 @@ from .rust import RustCompiler
from .swift import SwiftCompiler
from .vala import ValaCompiler
from .mixins.visualstudio import VisualStudioLikeCompiler
from .mixins.gnu import GnuCompiler, get_macos_dylib_install_name
from .mixins.gnu import GnuCompiler
from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
from .mixins.clang import ClangCompiler

@ -27,6 +27,7 @@ from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
from .mixins.clang import ClangCompiler
from .mixins.elbrus import ElbrusCompiler
from .mixins.pgi import PGICompiler
from .mixins.islinker import BasicLinkerIsCompilerMixin, LinkerEnvVarsMixin
from .compilers import (
gnu_winlibs,
msvc_winlibs,
@ -112,14 +113,8 @@ class ClangCCompiler(ClangCompiler, CCompiler):
def get_option_link_args(self, options):
return []
def get_linker_always_args(self):
basic = super().get_linker_always_args()
if self.compiler_type.is_osx_compiler:
return basic + ['-Wl,-headerpad_max_install_names']
return basic
class EmscriptenCCompiler(ClangCCompiler):
class EmscriptenCCompiler(LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, ClangCCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs):
if not is_cross:
raise MesonException('Emscripten compiler can only be used for cross compilation.')
@ -129,18 +124,6 @@ class EmscriptenCCompiler(ClangCCompiler):
def get_option_link_args(self, options):
return []
def get_linker_always_args(self):
return []
def get_asneeded_args(self):
return []
def get_lundef_args(self):
return []
def build_rpath_args(self, *args, **kwargs):
return []
def get_soname_args(self, *args, **kwargs):
raise MesonException('Emscripten does not support shared libraries.')
@ -293,14 +276,14 @@ class VisualStudioLikeCCompilerMixin:
class VisualStudioCCompiler(VisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target: str):
CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap)
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target: str, **kwargs):
CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs)
VisualStudioLikeCompiler.__init__(self, target)
self.id = 'msvc'
class ClangClCCompiler(VisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target):
CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap)
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target, **kwargs):
CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs)
VisualStudioLikeCompiler.__init__(self, target)
self.id = 'clang-cl'
@ -311,8 +294,8 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM
__have_warned = False
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target):
CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap)
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target, **kwargs):
CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs)
IntelVisualStudioLikeCompiler.__init__(self, target)
def get_options(self):
@ -388,9 +371,6 @@ class CcrxCCompiler(CcrxCompiler, CCompiler):
def get_output_args(self, target):
return ['-output=obj=%s' % target]
def get_linker_output_args(self, outputname):
return ['-output=%s' % outputname]
def get_werror_args(self):
return ['-change_message=error']

@ -13,9 +13,10 @@
# limitations under the License.
import contextlib, enum, os.path, re, tempfile, shlex
from typing import Optional, Tuple, List
import typing
from typing import List, Optional, Tuple
from ..linkers import StaticLinker
from ..linkers import StaticLinker, GnuLikeDynamicLinkerMixin
from .. import coredata
from .. import mlog
from .. import mesonlib
@ -27,6 +28,11 @@ from ..envconfig import (
Properties,
)
if typing.TYPE_CHECKING:
from ..coredata import OptionDictType
from ..environment import Environment
from ..linkers import DynamicLinker # noqa: F401
"""This file contains the data files of all compilers Meson knows
about. To support a new compiler, add its information below.
Also add corresponding autodetection code in environment.py."""
@ -335,18 +341,26 @@ def get_base_link_args(options, linker, is_shared_module):
args += linker.get_coverage_link_args()
except KeyError:
pass
# These do not need a try...except
if not is_shared_module and option_enabled(linker.base_options, options, 'b_lundef'):
args.append('-Wl,--no-undefined')
as_needed = option_enabled(linker.base_options, options, 'b_asneeded')
bitcode = option_enabled(linker.base_options, options, 'b_bitcode')
# Shared modules cannot be built with bitcode_bundle because
# -bitcode_bundle is incompatible with -undefined and -bundle
if bitcode and not is_shared_module:
args.append('-Wl,-bitcode_bundle')
args.extend(linker.bitcode_args())
elif as_needed:
# -Wl,-dead_strip_dylibs is incompatible with bitcode
args.extend(linker.get_asneeded_args())
# Apple's ld (the only one that supports bitcode) does not like any
# -undefined arguments at all, so don't pass these when using bitcode
if not bitcode:
if (not is_shared_module and
option_enabled(linker.base_options, options, 'b_lundef')):
args.extend(linker.no_undefined_link_args())
else:
args.extend(linker.get_allow_undefined_link_args())
try:
crt_val = options['b_vscrt'].value
buildtype = options['buildtype'].value
@ -358,30 +372,6 @@ def get_base_link_args(options, linker, is_shared_module):
pass
return args
def prepare_rpaths(raw_rpaths, build_dir, from_dir):
internal_format_rpaths = [evaluate_rpath(p, build_dir, from_dir) for p in raw_rpaths]
ordered_rpaths = order_rpaths(internal_format_rpaths)
return ordered_rpaths
def order_rpaths(rpath_list):
# We want rpaths that point inside our build dir to always override
# those pointing to other places in the file system. This is so built
# binaries prefer our libraries to the ones that may lie somewhere
# in the file system, such as /lib/x86_64-linux-gnu.
#
# The correct thing to do here would be C++'s std::stable_partition.
# Python standard library does not have it, so replicate it with
# sort, which is guaranteed to be stable.
return sorted(rpath_list, key=os.path.isabs)
def evaluate_rpath(p, build_dir, from_dir):
if p == from_dir:
return '' # relpath errors out in this case
elif os.path.isabs(p):
return p # These can be outside of build dir.
else:
return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir))
class CrossNoRunException(MesonException):
pass
@ -529,7 +519,7 @@ class CompilerArgs(list):
return True
return False
def to_native(self, copy=False):
def to_native(self, copy: bool = False) -> typing.List[str]:
# Check if we need to add --start/end-group for circular dependencies
# between static libraries, and for recursively searching for symbols
# needed by static libraries that are provided by object files or
@ -538,8 +528,12 @@ class CompilerArgs(list):
new = self.copy()
else:
new = self
if get_compiler_uses_gnuld(self.compiler):
global soregex
# This covers all ld.bfd, ld.gold, ld.gold, and xild on Linux, which
# all act like (or are) gnu ld
# TODO: this could probably be added to the DynamicLinker instead
if (hasattr(self.compiler, 'linker') and
self.compiler.linker is not None and
isinstance(self.compiler.linker, GnuLikeDynamicLinkerMixin)):
group_start = -1
group_end = -1
for i, each in enumerate(new):
@ -656,7 +650,8 @@ class Compiler:
# manually searched.
internal_libs = ()
def __init__(self, exelist, version, for_machine: MachineChoice, **kwargs):
def __init__(self, exelist, version, for_machine: MachineChoice,
linker: typing.Optional['DynamicLinker'] = None, **kwargs):
if isinstance(exelist, str):
self.exelist = [exelist]
elif isinstance(exelist, list):
@ -676,6 +671,7 @@ class Compiler:
self.full_version = None
self.for_machine = for_machine
self.base_options = []
self.linker = linker
def __repr__(self):
repr_str = "<{0}: v{1} `{2}`>"
@ -729,6 +725,12 @@ class Compiler:
def get_exelist(self):
return self.exelist[:]
def get_linker_exelist(self) -> typing.List[str]:
return self.linker.get_exelist()
def get_linker_output_args(self, outputname: str) -> typing.List[str]:
return self.linker.get_output_args(outputname)
def get_builtin_define(self, *args, **kwargs):
raise EnvironmentException('%s does not support get_builtin_define.' % self.id)
@ -738,17 +740,17 @@ class Compiler:
def get_always_args(self):
return []
def can_linker_accept_rsp(self):
def can_linker_accept_rsp(self) -> bool:
"""
Determines whether the linker can accept arguments using the @rsp syntax.
"""
return mesonlib.is_windows()
return self.linker.get_accepts_rsp()
def get_linker_always_args(self):
return []
return self.linker.get_always_args()
def get_linker_lib_prefix(self):
return ''
return self.linker.get_lib_prefix()
def gen_import_library_args(self, implibname):
"""
@ -769,7 +771,10 @@ class Compiler:
"""
return self.get_language() in languages_using_ldflags
def get_args_from_envvars(self):
def get_linker_args_from_envvars(self) -> typing.List[str]:
return self.linker.get_args_from_envvars()
def get_args_from_envvars(self) -> typing.Tuple[typing.List[str], typing.List[str]]:
"""
Returns a tuple of (compile_flags, link_flags) for the specified language
from the inherited environment
@ -781,15 +786,13 @@ class Compiler:
mlog.debug('No {} in the environment, not changing global flags.'.format(var))
lang = self.get_language()
compiler_is_linker = False
if hasattr(self, 'get_linker_exelist'):
compiler_is_linker = (self.get_exelist() == self.get_linker_exelist())
compiler_is_linker = self.linker is not None and self.linker.invoked_by_compiler()
if lang not in cflags_mapping:
return [], []
compile_flags = []
link_flags = []
compile_flags = [] # type: typing.List[str]
link_flags = [] # type: typing.List[str]
env_compile_flags = os.environ.get(cflags_mapping[lang])
log_var(cflags_mapping[lang], env_compile_flags)
@ -798,12 +801,11 @@ class Compiler:
# Link flags (same for all languages)
if self.use_ldflags():
env_link_flags = os.environ.get('LDFLAGS')
env_link_flags = self.get_linker_args_from_envvars()
else:
env_link_flags = None
env_link_flags = []
log_var('LDFLAGS', env_link_flags)
if env_link_flags is not None:
link_flags += shlex.split(env_link_flags)
link_flags += env_link_flags
if compiler_is_linker:
# When the compiler is used as a wrapper around the linker (such as
# with GCC and Clang), the compile flags can be needed while linking
@ -861,8 +863,8 @@ class Compiler:
def get_option_compile_args(self, options):
return []
def get_option_link_args(self, options):
return []
def get_option_link_args(self, options: 'OptionDictType') -> typing.List[str]:
return self.linker.get_option_args(options)
def check_header(self, *args, **kwargs) -> Tuple[bool, bool]:
raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language())
@ -910,10 +912,8 @@ class Compiler:
'Language {} does not support has_multi_arguments.'.format(
self.get_display_language()))
def has_multi_link_arguments(self, args, env) -> Tuple[bool, bool]:
raise EnvironmentException(
'Language {} does not support has_multi_link_arguments.'.format(
self.get_display_language()))
def has_multi_link_arguments(self, args: typing.List[str], env: 'Environment') -> Tuple[bool, bool]:
return self.linker.has_multi_arguments(args, env)
def _get_compile_output(self, dirname, mode):
# In pre-processor mode, the output is sent to stdout and discarded
@ -1026,19 +1026,23 @@ class Compiler:
def get_compile_debugfile_args(self, rel_obj, **kwargs):
return []
def get_link_debugfile_args(self, rel_obj):
return []
def get_link_debugfile_args(self, targetfile: str) -> typing.List[str]:
return self.linker.get_debugfile_args(targetfile)
def get_std_shared_lib_link_args(self):
return []
def get_std_shared_lib_link_args(self) -> typing.List[str]:
return self.linker.get_std_shared_lib_args()
def get_std_shared_module_link_args(self, options: 'OptionDictType') -> typing.List[str]:
return self.linker.get_std_shared_module_args(options)
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
return self.linker.get_link_whole_for(args)
def get_std_shared_module_link_args(self, options):
return self.get_std_shared_lib_link_args()
def get_allow_undefined_link_args(self) -> typing.List[str]:
return self.linker.get_allow_undefined_args()
def get_link_whole_for(self, args):
if isinstance(args, list) and not args:
return []
raise EnvironmentException('Language %s does not support linking whole archives.' % self.get_display_language())
def no_undefined_link_args(self) -> typing.List[str]:
return self.linker.no_undefined_args()
# Compiler arguments needed to enable the given instruction set.
# May be [] meaning nothing needed or None meaning the given set
@ -1046,77 +1050,11 @@ class Compiler:
def get_instruction_set_args(self, instruction_set):
return None
def build_unix_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
if not rpath_paths and not install_rpath and not build_rpath:
return []
args = []
if get_compiler_is_osx_compiler(self):
# Ensure that there is enough space for install_name_tool in-place editing of large RPATHs
args.append('-Wl,-headerpad_max_install_names')
# @loader_path is the equivalent of $ORIGIN on macOS
# https://stackoverflow.com/q/26280738
origin_placeholder = '@loader_path'
else:
origin_placeholder = '$ORIGIN'
# The rpaths we write must be relative if they point to the build dir,
# because otherwise they have different length depending on the build
# directory. This breaks reproducible builds.
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
# Need to deduplicate rpaths, as macOS's install_name_tool
# is *very* allergic to duplicate -delete_rpath arguments
# when calling depfixer on installation.
all_paths = OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
# Build_rpath is used as-is (it is usually absolute).
if build_rpath != '':
all_paths.add(build_rpath)
if mesonlib.is_dragonflybsd() or mesonlib.is_openbsd():
# This argument instructs the compiler to record the value of
# ORIGIN in the .dynamic section of the elf. On Linux this is done
# by default, but is not on dragonfly/openbsd for some reason. Without this
# $ORIGIN in the runtime path will be undefined and any binaries
# linked against local libraries will fail to resolve them.
args.append('-Wl,-z,origin')
if get_compiler_is_osx_compiler(self):
# macOS does not support colon-separated strings in LC_RPATH,
# hence we have to pass each path component individually
args += ['-Wl,-rpath,' + rp for rp in all_paths]
else:
# In order to avoid relinking for RPATH removal, the binary needs to contain just
# enough space in the ELF header to hold the final installation RPATH.
paths = ':'.join(all_paths)
if len(paths) < len(install_rpath):
padding = 'X' * (len(install_rpath) - len(paths))
if not paths:
paths = padding
else:
paths = paths + ':' + padding
args.append('-Wl,-rpath,' + paths)
if mesonlib.is_sunos():
return args
if get_compiler_is_linuxlike(self):
# Rpaths to use while linking must be absolute. These are not
# written to the binary. Needed only with GNU ld:
# https://sourceware.org/bugzilla/show_bug.cgi?id=16936
# Not needed on Windows or other platforms that don't use RPATH
# https://github.com/mesonbuild/meson/issues/1897
#
# In addition, this linker option tends to be quite long and some
# compilers have trouble dealing with it. That's why we will include
# one option per folder, like this:
#
# -Wl,-rpath-link,/path/to/folder1 -Wl,-rpath,/path/to/folder2 ...
#
# ...instead of just one single looooong option, like this:
#
# -Wl,-rpath-link,/path/to/folder1:/path/to/folder2:...
args += ['-Wl,-rpath-link,' + os.path.join(build_dir, p) for p in rpath_paths]
return args
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
return self.linker.build_rpath_args(
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
def thread_flags(self, env):
return []
@ -1125,10 +1063,6 @@ class Compiler:
raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language())
def language_stdlib_only_link_flags(self):
# The linker flags needed to link the standard library of the current
# language in. This is needed in cases where you e.g. combine D and C++
# and both of which need to link their runtime library in or otherwise
# building fails with undefined symbols.
return []
def gnu_symbol_visibility_args(self, vistype):
@ -1149,9 +1083,8 @@ class Compiler:
m = 'Language {} does not support position-independent executable'
raise EnvironmentException(m.format(self.get_display_language()))
def get_pie_link_args(self):
m = 'Language {} does not support position-independent executable'
raise EnvironmentException(m.format(self.get_display_language()))
def get_pie_link_args(self) -> typing.List[str]:
return self.linker.get_pie_args()
def get_argument_syntax(self):
"""Returns the argument family type.
@ -1172,11 +1105,8 @@ class Compiler:
raise EnvironmentException(
'%s does not support get_profile_use_args ' % self.get_id())
def get_undefined_link_args(self):
'''
Get args for allowing undefined symbols when linking to a shared library
'''
return []
def get_undefined_link_args(self) -> typing.List[str]:
return self.linker.get_undefined_link_args()
def remove_linkerlike_args(self, args):
return [x for x in args if not x.startswith('-Wl')]
@ -1185,13 +1115,32 @@ class Compiler:
return []
def get_lto_link_args(self) -> List[str]:
return []
return self.linker.get_lto_args()
def sanitizer_compile_args(self, value: str) -> List[str]:
return []
def sanitizer_link_args(self, value: str) -> List[str]:
return []
return self.linker.sanitizer_args(value)
def get_asneeded_args(self) -> typing.List[str]:
return self.linker.get_asneeded_args()
def bitcode_args(self) -> typing.List[str]:
return self.linker.bitcode_args()
def get_linker_debug_crt_args(self) -> typing.List[str]:
return self.linker.get_debug_crt_args()
def get_buildtype_linker_args(self, buildtype: str) -> typing.List[str]:
return self.linker.get_buildtype_args(buildtype)
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 self.linker.get_soname_args(
env, prefix, shlib_name, suffix, soversion,
darwin_versions, is_shared_module)
@enum.unique
@ -1235,23 +1184,6 @@ def get_compiler_is_linuxlike(compiler):
compiler_type = getattr(compiler, 'compiler_type', None)
return compiler_type and compiler_type.is_standard_compiler
def get_compiler_is_osx_compiler(compiler):
compiler_type = getattr(compiler, 'compiler_type', None)
return compiler_type and compiler_type.is_osx_compiler
def get_compiler_uses_gnuld(c):
# FIXME: Perhaps we should detect the linker in the environment?
# FIXME: Assumes that *BSD use GNU ld, but they might start using lld soon
compiler_type = getattr(c, 'compiler_type', None)
return compiler_type in {
CompilerType.GCC_STANDARD,
CompilerType.GCC_MINGW,
CompilerType.GCC_CYGWIN,
CompilerType.CLANG_STANDARD,
CompilerType.CLANG_MINGW,
CompilerType.ICC_STANDARD,
}
def get_largefile_args(compiler):
'''
Enable transparent large-file-support for 32-bit UNIX systems

@ -36,6 +36,7 @@ from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
from .mixins.clang import ClangCompiler
from .mixins.elbrus import ElbrusCompiler
from .mixins.pgi import PGICompiler
from .mixins.islinker import BasicLinkerIsCompilerMixin, LinkerEnvVarsMixin
def non_msvc_eh_options(eh, args):
@ -183,7 +184,7 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
return ['-lstdc++']
class EmscriptenCPPCompiler(ClangCPPCompiler):
class EmscriptenCPPCompiler(LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, ClangCPPCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs):
if not is_cross:
raise MesonException('Emscripten compiler can only be used for cross compilation.')
@ -200,18 +201,6 @@ class EmscriptenCPPCompiler(ClangCPPCompiler):
def get_option_link_args(self, options):
return []
def get_linker_always_args(self):
return []
def get_asneeded_args(self):
return []
def get_lundef_args(self):
return []
def build_rpath_args(self, *args, **kwargs):
return []
def get_soname_args(self, *args, **kwargs):
raise MesonException('Emscripten does not support shared libraries.')
@ -473,8 +462,8 @@ class CPP11AsCPP14Mixin:
class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap, target):
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap)
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap, target, **kwargs):
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs)
VisualStudioLikeCompiler.__init__(self, target)
self.base_options = ['b_pch', 'b_vscrt'] # FIXME add lto, pgo and the like
self.id = 'msvc'
@ -506,8 +495,8 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi
return args
class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target):
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap)
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target, **kwargs):
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs)
VisualStudioLikeCompiler.__init__(self, target)
self.id = 'clang-cl'
@ -518,8 +507,8 @@ class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, Vi
class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLikeCompiler, CPPCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target):
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap)
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target, **kwargs):
CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs)
IntelVisualStudioLikeCompiler.__init__(self, target)
def get_options(self):
@ -574,9 +563,6 @@ class CcrxCPPCompiler(CcrxCompiler, CPPCompiler):
def get_output_args(self, target):
return ['-output=obj=%s' % target]
def get_linker_output_args(self, outputname):
return ['-output=%s' % outputname]
def get_option_link_args(self, options):
return []

@ -18,6 +18,7 @@ from ..mesonlib import EnvironmentException
from ..mesonlib import is_windows
from .compilers import Compiler, MachineChoice, mono_buildtype_args
from .mixins.islinker import BasicLinkerIsCompilerMixin
cs_optimization_args = {'0': [],
'g': [],
@ -27,7 +28,7 @@ cs_optimization_args = {'0': [],
's': ['-optimize+'],
}
class CsCompiler(Compiler):
class CsCompiler(BasicLinkerIsCompilerMixin, Compiler):
def __init__(self, exelist, version, for_machine: MachineChoice, comp_id, runner=None):
self.language = 'cs'
super().__init__(exelist, version, for_machine)
@ -50,18 +51,12 @@ class CsCompiler(Compiler):
def get_link_args(self, fname):
return ['-r:' + fname]
def get_soname_args(self, *args):
return []
def get_werror_args(self):
return ['-warnaserror']
def split_shlib_to_parts(self, fname):
return None, fname
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return []
def get_dependency_gen_args(self, outtarget, outfile):
return []
@ -71,15 +66,9 @@ class CsCompiler(Compiler):
def get_compile_only_args(self):
return []
def get_linker_output_args(self, outputname):
return []
def get_coverage_args(self):
return []
def get_coverage_link_args(self):
return []
def get_std_exe_link_args(self):
return []
@ -142,6 +131,7 @@ class CsCompiler(Compiler):
def get_optimization_args(self, optimization_level):
return cs_optimization_args[optimization_level]
class MonoCompiler(CsCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice):
super().__init__(exelist, version, for_machine, 'mono',

@ -12,19 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import re, os.path
import os.path
import typing
from .. import mlog
from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe
from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args,
cuda_debug_args, CompilerType)
from .mixins.gnu import get_gcc_soname_args
if typing.TYPE_CHECKING:
from ..environment import Environment # noqa: F401
class CudaCompiler(Compiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs):
if not hasattr(self, 'language'):
self.language = 'cuda'
super().__init__(exelist, version, for_machine)
super().__init__(exelist, version, for_machine, **kwargs)
self.is_cross = is_cross
self.exe_wrapper = exe_wrapper
self.id = 'nvcc'
@ -48,7 +52,7 @@ class CudaCompiler(Compiler):
return []
def thread_link_flags(self, environment):
return ['-Xcompiler=-pthread']
return self._cook_link_args(super().thread_link_flags())
def sanity_check(self, work_dir, environment):
mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist))
@ -143,9 +147,6 @@ class CudaCompiler(Compiler):
else:
mlog.debug('cudaGetDeviceCount() returned ' + stde)
def get_compiler_check_args(self):
return super().get_compiler_check_args() + []
def has_header_symbol(self, hname, symbol, prefix, env, extra_args=None, dependencies=None):
result, cached = super().has_header_symbol(hname, symbol, prefix, env, extra_args, dependencies)
if result:
@ -160,22 +161,24 @@ class CudaCompiler(Compiler):
return self.compiles(t.format(**fargs), env, extra_args, dependencies)
@staticmethod
def _cook_link_args(args):
def _cook_link_args(args: typing.List[str]) -> typing.List[str]:
"""
Converts GNU-style arguments -Wl,-arg,-arg
to NVCC-style arguments -Xlinker=-arg,-arg
"""
return [re.sub('^-Wl,', '-Xlinker=', arg) for arg in args]
def get_output_args(self, target):
return ['-o', target]
cooked = [] # type: typing.List[str]
for arg in args:
if arg.startswith('-Wl,'):
arg = arg.replace('-Wl,', '-Xlinker=', 1)
arg = arg.replace(' ', '\\')
cooked.append(arg)
return cooked
def name_string(self):
return ' '.join(self.exelist)
def get_soname_args(self, *args):
rawargs = get_gcc_soname_args(CompilerType.GCC_STANDARD, *args)
return self._cook_link_args(rawargs)
return self._cook_link_args(super().get_soname_args(*args))
def get_dependency_gen_args(self, outtarget, outfile):
return []
@ -195,12 +198,6 @@ class CudaCompiler(Compiler):
def get_werror_args(self):
return ['-Werror=cross-execution-space-call,deprecated-declarations,reorder']
def get_linker_exelist(self):
return self.exelist[:]
def get_linker_output_args(self, outputname):
return ['-o', outputname]
def get_warn_args(self, level):
return self.warn_args[level]
@ -212,27 +209,17 @@ class CudaCompiler(Compiler):
path = '.'
return ['-I' + path]
def get_std_shared_lib_link_args(self):
return ['-shared']
def depfile_for_object(self, objfile):
return objfile + '.' + self.get_depfile_suffix()
def get_depfile_suffix(self):
return 'd'
def get_buildtype_linker_args(self, buildtype):
return []
def get_std_exe_link_args(self):
return []
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
rawargs = self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
return self._cook_link_args(rawargs)
def get_linker_search_args(self, dirname):
return ['-L' + dirname]
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
return self._cook_link_args(super().build_rpath_args(
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath))
def linker_to_compiler_args(self, args):
return args
@ -242,3 +229,9 @@ class CudaCompiler(Compiler):
def compute_parameters_with_absolute_paths(self, parameter_list, build_dir):
return []
def get_output_args(self, target: str) -> typing.List[str]:
return ['-o', target]
def get_std_exe_link_args(self) -> typing.List[str]:
return []

@ -13,6 +13,7 @@
# limitations under the License.
import os.path, subprocess
import typing
from ..mesonlib import (
EnvironmentException, MachineChoice, version_compare, is_windows, is_osx
@ -27,7 +28,8 @@ from .compilers import (
Compiler,
CompilerArgs,
)
from .mixins.gnu import get_gcc_soname_args, gnu_color_args, gnu_optimization_args
from .mixins.gnu import GnuCompiler
from .mixins.islinker import LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin
d_feature_args = {'gcc': {'unittest': '-funittest',
'debug': '-fdebug',
@ -62,44 +64,8 @@ dmd_optimization_args = {'0': [],
's': ['-O'],
}
class DCompiler(Compiler):
mscrt_args = {
'none': ['-mscrtlib='],
'md': ['-mscrtlib=msvcrt'],
'mdd': ['-mscrtlib=msvcrtd'],
'mt': ['-mscrtlib=libcmt'],
'mtd': ['-mscrtlib=libcmtd'],
}
def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs):
self.language = 'd'
super().__init__(exelist, version, for_machine, **kwargs)
self.id = 'unknown'
self.arch = arch
def sanity_check(self, work_dir, environment):
source_name = os.path.join(work_dir, 'sanity.d')
output_name = os.path.join(work_dir, 'dtest')
with open(source_name, 'w') as ofile:
ofile.write('''void main() { }''')
pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + self.get_target_arch_args() + [source_name], cwd=work_dir)
pc.wait()
if pc.returncode != 0:
raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string())
if subprocess.call(output_name) != 0:
raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string())
def needs_static_linker(self):
return True
def name_string(self):
return ' '.join(self.exelist)
def get_exelist(self):
return self.exelist
def get_linker_exelist(self):
return self.exelist[:]
class DmdLikeCompilerMixin:
def get_output_args(self, target):
return ['-of=' + target]
@ -133,11 +99,6 @@ class DCompiler(Compiler):
# DMD and LDC does not currently return Makefile-compatible dependency info.
return []
def get_linker_search_args(self, dirname):
# -L is recognized as "add this to the search path" by the linker,
# while the compiler recognizes it as "pass to linker".
return ['-Wl,-L' + dirname]
def get_coverage_args(self):
return ['-cov']
@ -158,21 +119,6 @@ class DCompiler(Compiler):
return []
return ['-fPIC']
def get_std_shared_lib_link_args(self):
return ['-shared']
def get_soname_args(self, *args):
# FIXME: Make this work for cross-compiling
if is_windows():
return []
elif is_osx():
soname_args = get_gcc_soname_args(CompilerType.GCC_OSX, *args)
if soname_args:
return ['-Wl,' + ','.join(soname_args)]
return []
return get_gcc_soname_args(CompilerType.GCC_STANDARD, *args)
def get_feature_args(self, kwargs, build_to_src):
res = []
if 'unittest' in kwargs:
@ -266,7 +212,7 @@ class DCompiler(Compiler):
def gen_import_library_args(self, implibname):
return ['-Wl,--out-implib=' + implibname]
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
if is_windows():
return []
@ -285,54 +231,6 @@ class DCompiler(Compiler):
paths = paths + ':' + padding
return ['-Wl,-rpath,{}'.format(paths)]
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
if callable(extra_args):
extra_args = extra_args(mode)
if extra_args is None:
extra_args = []
elif isinstance(extra_args, str):
extra_args = [extra_args]
if dependencies is None:
dependencies = []
elif not isinstance(dependencies, list):
dependencies = [dependencies]
# Collect compiler arguments
args = CompilerArgs(self)
for d in dependencies:
# Add compile flags needed by dependencies
args += d.get_compile_args()
if mode == 'link':
# Add link flags needed to find dependencies
args += d.get_link_args()
if mode == 'compile':
# Add DFLAGS from the env
args += env.coredata.get_external_args(self.for_machine, self.language)
elif mode == 'link':
# Add LDFLAGS from the env
args += env.coredata.get_external_link_args(self.for_machine, self.language)
# extra_args must override all other arguments, so we add them last
args += extra_args
return args
def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
with self.cached_compile(code, env.coredata, extra_args=args, mode=mode) as p:
return p.returncode == 0, p.cached
def has_multi_arguments(self, args, env):
return self.compiles('int i;\n', env, extra_args=args)
def get_target_arch_args(self):
# LDC2 on Windows targets to current OS architecture, but
# it should follow the target specified by the MSVC toolchain.
if is_windows():
if self.arch == 'x86_64':
return ['-m64']
return ['-m32']
return []
@classmethod
def translate_args_to_nongnu(cls, args):
dcargs = []
@ -480,6 +378,191 @@ class DCompiler(Compiler):
assert(buildtype == 'custom')
raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".')
def get_soname_args(self, *args, **kwargs) -> typing.List[str]:
# LDC and DMD actually do use a linker, but they proxy all of that with
# their own arguments
return Compiler.get_soname_args(self, *args, **kwargs)
class DCompiler(Compiler):
mscrt_args = {
'none': ['-mscrtlib='],
'md': ['-mscrtlib=msvcrt'],
'mdd': ['-mscrtlib=msvcrtd'],
'mt': ['-mscrtlib=libcmt'],
'mtd': ['-mscrtlib=libcmtd'],
}
def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs):
self.language = 'd'
super().__init__(exelist, version, for_machine, **kwargs)
self.id = 'unknown'
self.arch = arch
def sanity_check(self, work_dir, environment):
source_name = os.path.join(work_dir, 'sanity.d')
output_name = os.path.join(work_dir, 'dtest')
with open(source_name, 'w') as ofile:
ofile.write('''void main() { }''')
pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + self.get_target_arch_args() + [source_name], cwd=work_dir)
pc.wait()
if pc.returncode != 0:
raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string())
if subprocess.call(output_name) != 0:
raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string())
def needs_static_linker(self):
return True
def depfile_for_object(self, objfile):
return objfile + '.' + self.get_depfile_suffix()
def get_depfile_suffix(self):
return 'deps'
def get_pic_args(self):
if is_windows():
return []
return ['-fPIC']
def get_feature_args(self, kwargs, build_to_src):
res = []
if 'unittest' in kwargs:
unittest = kwargs.pop('unittest')
unittest_arg = d_feature_args[self.id]['unittest']
if not unittest_arg:
raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string())
if unittest:
res.append(unittest_arg)
if 'debug' in kwargs:
debug_level = -1
debugs = kwargs.pop('debug')
if not isinstance(debugs, list):
debugs = [debugs]
debug_arg = d_feature_args[self.id]['debug']
if not debug_arg:
raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string())
# Parse all debug identifiers and the largest debug level identifier
for d in debugs:
if isinstance(d, int):
if d > debug_level:
debug_level = d
elif isinstance(d, str) and d.isdigit():
if int(d) > debug_level:
debug_level = int(d)
else:
res.append('{0}={1}'.format(debug_arg, d))
if debug_level >= 0:
res.append('{0}={1}'.format(debug_arg, debug_level))
if 'versions' in kwargs:
version_level = -1
versions = kwargs.pop('versions')
if not isinstance(versions, list):
versions = [versions]
version_arg = d_feature_args[self.id]['version']
if not version_arg:
raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string())
# Parse all version identifiers and the largest version level identifier
for v in versions:
if isinstance(v, int):
if v > version_level:
version_level = v
elif isinstance(v, str) and v.isdigit():
if int(v) > version_level:
version_level = int(v)
else:
res.append('{0}={1}'.format(version_arg, v))
if version_level >= 0:
res.append('{0}={1}'.format(version_arg, version_level))
if 'import_dirs' in kwargs:
import_dirs = kwargs.pop('import_dirs')
if not isinstance(import_dirs, list):
import_dirs = [import_dirs]
import_dir_arg = d_feature_args[self.id]['import_dir']
if not import_dir_arg:
raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string())
for idir_obj in import_dirs:
basedir = idir_obj.get_curdir()
for idir in idir_obj.get_incdirs():
# Avoid superfluous '/.' at the end of paths when d is '.'
if idir not in ('', '.'):
expdir = os.path.join(basedir, idir)
else:
expdir = basedir
srctreedir = os.path.join(build_to_src, expdir)
res.append('{0}{1}'.format(import_dir_arg, srctreedir))
if kwargs:
raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys()))
return res
def get_buildtype_linker_args(self, buildtype):
if buildtype != 'plain':
return self.get_target_arch_args()
return []
def get_std_exe_link_args(self):
return []
def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
if callable(extra_args):
extra_args = extra_args(mode)
if extra_args is None:
extra_args = []
elif isinstance(extra_args, str):
extra_args = [extra_args]
if dependencies is None:
dependencies = []
elif not isinstance(dependencies, list):
dependencies = [dependencies]
# Collect compiler arguments
args = CompilerArgs(self)
for d in dependencies:
# Add compile flags needed by dependencies
args += d.get_compile_args()
if mode == 'link':
# Add link flags needed to find dependencies
args += d.get_link_args()
if mode == 'compile':
# Add DFLAGS from the env
args += env.coredata.get_external_args(self.for_machine, self.language)
elif mode == 'link':
# Add LDFLAGS from the env
args += env.coredata.get_external_link_args(self.for_machine, self.language)
# extra_args must override all other arguments, so we add them last
args += extra_args
return args
def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'):
args = self._get_compiler_check_args(env, extra_args, dependencies, mode)
with self.cached_compile(code, env.coredata, extra_args=args, mode=mode) as p:
return p.returncode == 0, p.cached
def has_multi_arguments(self, args, env):
return self.compiles('int i;\n', env, extra_args=args)
def get_target_arch_args(self):
# LDC2 on Windows targets to current OS architecture, but
# it should follow the target specified by the MSVC toolchain.
if is_windows():
if self.arch == 'x86_64':
return ['-m64']
return ['-m32']
return []
def get_crt_compile_args(self, crt_val, buildtype):
return []
@ -489,7 +572,11 @@ class DCompiler(Compiler):
def thread_link_flags(self, env):
return ['-pthread']
class GnuDCompiler(DCompiler):
def name_string(self):
return ' '.join(self.exelist)
class GnuDCompiler(DCompiler, GnuCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs):
DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs)
self.id = 'gcc'
@ -507,32 +594,17 @@ class GnuDCompiler(DCompiler):
def get_colorout_args(self, colortype):
if self._has_color_support:
return gnu_color_args[colortype][:]
super().get_colorout_args(colortype)
return []
def get_dependency_gen_args(self, outtarget, outfile):
if not self._has_deps_support:
return []
return ['-MD', '-MQ', outtarget, '-MF', outfile]
def get_output_args(self, target):
return ['-o', target]
def get_linker_output_args(self, target):
return ['-o', target]
def get_include_args(self, path, is_system):
return ['-I' + path]
if self._has_deps_support:
return super().get_dependency_gen_args(outtarget, outfile)
return []
def get_warn_args(self, level):
return self.warn_args[level]
def get_werror_args(self):
return ['-Werror']
def get_linker_search_args(self, dirname):
return ['-L' + dirname]
def get_coverage_args(self):
return []
@ -546,13 +618,8 @@ class GnuDCompiler(DCompiler):
return parameter_list
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
def get_optimization_args(self, optimization_level):
return gnu_optimization_args[optimization_level]
class LLVMDCompiler(DCompiler):
class LLVMDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, DCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs):
DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs)
self.id = 'llvm'
@ -590,7 +657,7 @@ class LLVMDCompiler(DCompiler):
return ldc_optimization_args[optimization_level]
class DmdDCompiler(DCompiler):
class DmdDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, DCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs):
DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs)
self.id = 'dmd'

@ -11,9 +11,11 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pathlib import Path
from typing import List
import subprocess, os
from pathlib import Path
import typing
from .compilers import (
CompilerType,
@ -22,8 +24,7 @@ from .compilers import (
)
from .mixins.clike import CLikeCompiler
from .mixins.gnu import (
GnuCompiler, apple_buildtype_linker_args, gnulike_buildtype_args,
gnulike_buildtype_linker_args, gnu_optimization_args,
GnuCompiler, gnulike_buildtype_args, gnu_optimization_args,
)
from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
from .mixins.clang import ClangCompiler
@ -99,11 +100,6 @@ class FortranCompiler(CLikeCompiler, Compiler):
def get_debug_args(self, is_debug):
return clike_debug_args[is_debug]
def get_buildtype_linker_args(self, buildtype):
if is_osx():
return apple_buildtype_linker_args[buildtype]
return gnulike_buildtype_linker_args[buildtype]
def get_dependency_gen_args(self, outtarget, outfile):
return []
@ -256,6 +252,10 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler):
def language_stdlib_only_link_flags(self):
return ['-lifcore', '-limf']
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> typing.List[str]:
return ['-gen-dep=' + outtarget, '-gen-depformat=make']
class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler):
file_suffixes = ['f90', 'f', 'for', 'ftn', 'fpp']
@ -270,8 +270,8 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler):
'custom': [],
}
def __init__(self, exelist, for_machine: MachineChoice, version, is_cross, target: str, exe_wrapper=None):
FortranCompiler.__init__(self, exelist, for_machine, version, is_cross, exe_wrapper)
def __init__(self, exelist, for_machine: MachineChoice, version, is_cross, target: str, exe_wrapper=None, **kwargs):
FortranCompiler.__init__(self, exelist, for_machine, version, is_cross, exe_wrapper, **kwargs)
IntelVisualStudioLikeCompiler.__init__(self, target)
default_warn_args = ['/warn:general', '/warn:truncated_source']

@ -17,8 +17,9 @@ import os.path, shutil, subprocess
from ..mesonlib import EnvironmentException, MachineChoice
from .compilers import Compiler, java_buildtype_args
from .mixins.islinker import BasicLinkerIsCompilerMixin
class JavaCompiler(Compiler):
class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler):
def __init__(self, exelist, version, for_machine: MachineChoice):
self.language = 'java'
super().__init__(exelist, version, for_machine)
@ -26,24 +27,15 @@ class JavaCompiler(Compiler):
self.is_cross = False
self.javarunner = 'java'
def get_soname_args(self, *args):
return []
def get_werror_args(self):
return ['-Werror']
def split_shlib_to_parts(self, fname):
return None, fname
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return []
def get_dependency_gen_args(self, outtarget, outfile):
return []
def get_linker_exelist(self):
return self.exelist[:]
def get_compile_only_args(self):
return []
@ -52,15 +44,9 @@ class JavaCompiler(Compiler):
subdir = './'
return ['-d', subdir, '-s', subdir]
def get_linker_output_args(self, outputname):
return []
def get_coverage_args(self):
return []
def get_coverage_link_args(self):
return []
def get_std_exe_link_args(self):
return []

@ -35,15 +35,6 @@ arm_buildtype_args = {
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
arm_buildtype_linker_args = {
'plain': [],
'debug': [],
'debugoptimized': [],
'release': [],
'minsize': [],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
arm_optimization_args = {
'0': ['-O0'],
'g': ['-g'],
@ -87,8 +78,6 @@ class ArmCompiler:
# Assembly
self.can_compile_suffixes.add('s')
def can_linker_accept_rsp(self) -> bool:
return False
def get_pic_args(self) -> typing.List[str]:
# FIXME: Add /ropi, /rwpi, /fpic etc. qualifiers to --apcs
@ -97,9 +86,6 @@ class ArmCompiler:
def get_buildtype_args(self, buildtype: str) -> typing.List[str]:
return arm_buildtype_args[buildtype]
def get_buildtype_linker_args(self, buildtype: str) -> typing.List[str]:
return arm_buildtype_linker_args[buildtype]
# Override CCompiler.get_always_args
def get_always_args(self) -> typing.List[str]:
return []
@ -108,10 +94,6 @@ class ArmCompiler:
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> typing.List[str]:
return []
# Override CCompiler.get_std_shared_lib_link_args
def get_std_shared_lib_link_args(self) -> typing.List[str]:
return []
def get_pch_use_args(self, pch_dir: str, header: str) -> typing.List[str]:
# FIXME: Add required arguments
# NOTE from armcc user guide:
@ -130,19 +112,9 @@ class ArmCompiler:
def thread_flags(self, env: 'Environment') -> typing.List[str]:
return []
def thread_link_flags(self, env: 'Environment') -> typing.List[str]:
return []
def get_linker_exelist(self) -> typing.List[str]:
args = ['armlink']
return args
def get_coverage_args(self) -> typing.List[str]:
return []
def get_coverage_link_args(self) -> typing.List[str]:
return []
def get_optimization_args(self, optimization_level: str) -> typing.List[str]:
return arm_optimization_args[optimization_level]
@ -191,9 +163,6 @@ class ArmclangCompiler:
# Assembly
self.can_compile_suffixes.update('s')
def can_linker_accept_rsp(self) -> bool:
return False
def get_pic_args(self) -> typing.List[str]:
# PIC support is not enabled by default for ARM,
# if users want to use it, they need to add the required arguments explicitly
@ -205,13 +174,6 @@ class ArmclangCompiler:
def get_buildtype_args(self, buildtype: str) -> typing.List[str]:
return armclang_buildtype_args[buildtype]
def get_buildtype_linker_args(self, buildtype: str) -> typing.List[str]:
return arm_buildtype_linker_args[buildtype]
# Override CCompiler.get_std_shared_lib_link_args
def get_std_shared_lib_link_args(self) -> typing.List[str]:
return []
def get_pch_suffix(self) -> str:
return 'gch'
@ -225,34 +187,12 @@ class ArmclangCompiler:
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> typing.List[str]:
return []
# Override CCompiler.build_rpath_args
def build_rpath_args(self, build_dir: str, from_dir: str, rpath_paths: str,
build_rpath: str, install_rpath: str) -> typing.List[str]:
return []
def get_linker_exelist(self) -> typing.List[str]:
return [self.linker_exe]
def get_optimization_args(self, optimization_level: str) -> typing.List[str]:
return armclang_optimization_args[optimization_level]
def get_debug_args(self, is_debug: bool) -> typing.List[str]:
return clike_debug_args[is_debug]
def gen_export_dynamic_link_args(self, env: 'Environment') -> typing.List[str]:
"""
The args for export dynamic
"""
return ['--export_dynamic']
def gen_import_library_args(self, implibname: str) -> typing.List[str]:
"""
The args of the outputted import library
ArmLinker's symdefs output can be used as implib
"""
return ['--symdefs=' + implibname]
def compute_parameters_with_absolute_paths(self, parameter_list: typing.List[str], build_dir: str) -> typing.List[str]:
for idx, i in enumerate(parameter_list):
if i[:2] == '-I' or i[:2] == '-L':

@ -32,15 +32,6 @@ ccrx_buildtype_args = {
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
ccrx_buildtype_linker_args = {
'plain': [],
'debug': [],
'debugoptimized': [],
'release': [],
'minsize': [],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
ccrx_optimization_args = {
'0': ['-optimize=0'],
'g': ['-optimize=0'],
@ -60,14 +51,6 @@ class CcrxCompiler:
def __init__(self, compiler_type: 'CompilerType'):
if not self.is_cross:
raise EnvironmentException('ccrx supports only cross-compilation.')
# Check whether 'rlink.exe' is available in path
self.linker_exe = 'rlink.exe'
args = '--version'
try:
p, stdo, stderr = Popen_safe(self.linker_exe, args)
except OSError as e:
err_msg = 'Unknown linker\nRunning "{0}" gave \n"{1}"'.format(' '.join([self.linker_exe] + [args]), e)
raise EnvironmentException(err_msg)
self.id = 'ccrx'
self.compiler_type = compiler_type
# Assembly
@ -78,9 +61,6 @@ class CcrxCompiler:
'2': default_warn_args + [],
'3': default_warn_args + []}
def can_linker_accept_rsp(self) -> bool:
return False
def get_pic_args(self) -> typing.List[str]:
# PIC support is not enabled by default for CCRX,
# if users want to use it, they need to add the required arguments explicitly
@ -89,13 +69,6 @@ class CcrxCompiler:
def get_buildtype_args(self, buildtype: str) -> typing.List[str]:
return ccrx_buildtype_args[buildtype]
def get_buildtype_linker_args(self, buildtype: str) -> typing.List[str]:
return ccrx_buildtype_linker_args[buildtype]
# Override CCompiler.get_std_shared_lib_link_args
def get_std_shared_lib_link_args(self) -> typing.List[str]:
return []
def get_pch_suffix(self) -> str:
return 'pch'
@ -106,28 +79,12 @@ class CcrxCompiler:
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> typing.List[str]:
return []
# Override CCompiler.build_rpath_args
def build_rpath_args(self, build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, install_rpath: str) -> typing.List[str]:
return []
def thread_flags(self, env: 'Environment') -> typing.List[str]:
return []
def thread_link_flags(self, env: 'Environment') -> typing.List[str]:
return []
def get_linker_exelist(self) -> typing.List[str]:
return [self.linker_exe]
def get_linker_lib_prefix(self) -> str:
return '-lib='
def get_coverage_args(self) -> typing.List[str]:
return []
def get_coverage_link_args(self) -> typing.List[str]:
return []
def get_optimization_args(self, optimization_level: str) -> typing.List[str]:
return ccrx_optimization_args[optimization_level]

@ -61,9 +61,6 @@ class CLikeCompiler:
else:
self.exe_wrapper = exe_wrapper.get_command()
# Set to None until we actually need to check this
self.has_fatal_warnings_link_arg = None
def needs_static_linker(self):
return True # When compiling static libraries, so yes.
@ -73,13 +70,6 @@ class CLikeCompiler:
'''
return ['-pipe'] + compilers.get_largefile_args(self)
def get_linker_debug_crt_args(self):
"""
Arguments needed to select a debug crt for the linker
This is only needed for MSVC
"""
return []
def get_no_stdinc_args(self):
return ['-nostdinc']
@ -93,22 +83,9 @@ class CLikeCompiler:
# Almost every compiler uses this for disabling warnings
return ['-w']
def get_soname_args(self, *args):
return []
def split_shlib_to_parts(self, fname):
return None, fname
# The default behavior is this, override in MSVC
@functools.lru_cache(maxsize=None)
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
if self.compiler_type.is_windows_compiler:
return []
return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
def get_dependency_gen_args(self, outtarget, outfile):
return ['-MD', '-MQ', outtarget, '-MF', outfile]
def depfile_for_object(self, objfile):
return objfile + '.' + self.get_depfile_suffix()
@ -118,9 +95,6 @@ class CLikeCompiler:
def get_exelist(self):
return self.exelist[:]
def get_linker_exelist(self):
return self.exelist[:]
def get_preprocess_only_args(self):
return ['-E', '-P']
@ -140,19 +114,17 @@ class CLikeCompiler:
def get_output_args(self, target):
return ['-o', target]
def get_linker_output_args(self, outputname):
return ['-o', outputname]
def get_coverage_args(self):
return ['--coverage']
def get_coverage_link_args(self):
return ['--coverage']
def get_coverage_link_args(self) -> typing.List[str]:
return self.linker.get_coverage_args()
def get_werror_args(self):
return ['-Werror']
def get_std_exe_link_args(self):
# TODO: is this a linker property?
return []
def get_include_args(self, path, is_system):
@ -162,9 +134,6 @@ class CLikeCompiler:
return ['-isystem', path]
return ['-I' + path]
def get_std_shared_lib_link_args(self):
return ['-shared']
def get_compiler_dirs(self, env: 'Environment', name: str) -> typing.List[str]:
'''
Get dirs from the compiler, either `libraries:` or `programs:`
@ -222,27 +191,16 @@ class CLikeCompiler:
return os.path.basename(header_name) + '.' + self.get_pch_suffix()
def get_linker_search_args(self, dirname: str) -> typing.List[str]:
return ['-L' + dirname]
return self.linker.get_search_args(dirname)
def get_default_include_dirs(self):
return []
def gen_export_dynamic_link_args(self, env) -> typing.List[str]:
m = env.machines[self.for_machine]
if m.is_windows() or m.is_cygwin():
return ['-Wl,--export-all-symbols']
elif env.machines[self.for_machine].is_darwin():
return []
else:
return ['-Wl,-export-dynamic']
def gen_export_dynamic_link_args(self, env: 'Environment') -> typing.List[str]:
return self.linker.export_dynamic_args(env)
def gen_import_library_args(self, implibname: str) -> typing.List[str]:
"""
The name of the outputted import library
This implementation is used only on Windows by compilers that use GNU ld
"""
return ['-Wl,--out-implib=' + implibname]
return self.linker.import_library_args(implibname)
def sanity_check_impl(self, work_dir, environment, sname, code):
mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist))
@ -1104,11 +1062,8 @@ class CLikeCompiler:
return []
return ['-pthread']
def thread_link_flags(self, env):
host_m = env.machines[self.for_machine]
if host_m.is_haiku() or host_m.is_darwin():
return []
return ['-pthread']
def thread_link_flags(self, env: 'Environment') -> typing.List[str]:
return self.linker.thread_flags(env)
def linker_to_compiler_args(self, args):
return args
@ -1139,14 +1094,7 @@ class CLikeCompiler:
# First time we check for link flags we need to first check if we have
# --fatal-warnings, otherwise some linker checks could give some
# false positive.
fatal_warnings_args = ['-Wl,--fatal-warnings']
if self.has_fatal_warnings_link_arg is None:
self.has_fatal_warnings_link_arg = False
self.has_fatal_warnings_link_arg = self.has_multi_link_arguments(fatal_warnings_args, env)[0]
if self.has_fatal_warnings_link_arg:
args = fatal_warnings_args + args
args = self.linker.fatal_warnings() + args
args = self.linker_to_compiler_args(args)
code = 'int main() { return 0; }'
return self.has_arguments(args, env, code, mode='link')

@ -46,24 +46,6 @@ gnulike_buildtype_args = {
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
apple_buildtype_linker_args = {
'plain': [],
'debug': [],
'debugoptimized': [],
'release': [],
'minsize': [],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
gnulike_buildtype_linker_args = {
'plain': [],
'debug': [],
'debugoptimized': [],
'release': ['-Wl,-O1'],
'minsize': [],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
gnu_optimization_args = {
'0': [],
'g': ['-Og'],
@ -102,35 +84,6 @@ gnu_color_args = {
} # type: typing.Dict[str, typing.List[str]]
def get_macos_dylib_install_name(prefix: str, shlib_name: str, suffix: str, soversion: str) -> str:
install_name = prefix + shlib_name
if soversion is not None:
install_name += '.' + soversion
install_name += '.dylib'
return '@rpath/' + install_name
def get_gcc_soname_args(compiler_type: 'CompilerType', prefix: str,
shlib_name: str, suffix: str, soversion: str, darwin_versions:
typing.Tuple[str, str], is_shared_module: bool) -> typing.List[str]:
if compiler_type.is_standard_compiler:
sostr = '' if soversion is None else '.' + soversion
return ['-Wl,-soname,%s%s.%s%s' % (prefix, shlib_name, suffix, sostr)]
elif compiler_type.is_windows_compiler:
# For PE/COFF the soname argument has no effect with GNU LD
return []
elif compiler_type.is_osx_compiler:
if is_shared_module:
return []
name = get_macos_dylib_install_name(prefix, shlib_name, suffix, soversion)
args = ['-install_name', name]
if darwin_versions:
args += ['-compatibility_version', darwin_versions[0], '-current_version', darwin_versions[1]]
return args
else:
raise RuntimeError('Not implemented yet.')
# TODO: The result from calling compiler should be cached. So that calling this
# function multiple times don't add latency.
def gnulike_default_include_dirs(compiler: typing.List[str], lang: str) -> typing.List[str]:
@ -179,25 +132,13 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
self.compiler_type = compiler_type
self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage',
'b_ndebug', 'b_staticpic', 'b_pie']
if (not self.compiler_type.is_osx_compiler and
not self.compiler_type.is_windows_compiler and
not mesonlib.is_openbsd()):
if not (self.compiler_type.is_windows_compiler or mesonlib.is_openbsd()):
self.base_options.append('b_lundef')
if not self.compiler_type.is_windows_compiler:
self.base_options.append('b_asneeded')
# All GCC-like backends can do assembly
self.can_compile_suffixes.add('s')
def get_asneeded_args(self) -> typing.List[str]:
# GNU ld cannot be installed on macOS
# https://github.com/Homebrew/homebrew-core/issues/17794#issuecomment-328174395
# Hence, we don't need to differentiate between OS and ld
# for the sake of adding as-needed support
if self.compiler_type.is_osx_compiler:
return ['-Wl,-dead_strip_dylibs']
else:
return ['-Wl,--as-needed']
def get_pic_args(self) -> typing.List[str]:
if self.compiler_type.is_osx_compiler or self.compiler_type.is_windows_compiler:
return [] # On Window and OS X, pic is always on.
@ -206,9 +147,6 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
def get_pie_args(self) -> typing.List[str]:
return ['-fPIE']
def get_pie_link_args(self) -> typing.List[str]:
return ['-pie']
def get_buildtype_args(self, buildtype: str) -> typing.List[str]:
return gnulike_buildtype_args[buildtype]
@ -219,11 +157,6 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
def get_debug_args(self, is_debug: bool) -> typing.List[str]:
return clike_debug_args[is_debug]
def get_buildtype_linker_args(self, buildtype: str) -> typing.List[str]:
if self.compiler_type.is_osx_compiler:
return apple_buildtype_linker_args[buildtype]
return gnulike_buildtype_linker_args[buildtype]
@abc.abstractmethod
def get_pch_suffix(self) -> str:
raise NotImplementedError("get_pch_suffix not implemented")
@ -231,27 +164,6 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
def split_shlib_to_parts(self, fname: str) -> typing.Tuple[str, str]:
return os.path.dirname(fname), fname
# We're doing argument proxying here, I don't think there's anyway to
# accurately model this without copying the real signature
def get_soname_args(self, *args: typing.Any) -> typing.List[str]:
return get_gcc_soname_args(self.compiler_type, *args)
def get_std_shared_lib_link_args(self) -> typing.List[str]:
return ['-shared']
def get_std_shared_module_link_args(self, options: typing.Dict[str, 'UserOption[typing.Any]']) -> typing.List[str]:
if self.compiler_type.is_osx_compiler:
return ['-bundle', '-Wl,-undefined,dynamic_lookup']
return ['-shared']
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
if self.compiler_type.is_osx_compiler:
result = [] # type: typing.List[str]
for a in args:
result += ['-Wl,-force_load', a]
return result
return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive']
def get_instruction_set_args(self, instruction_set: str) -> typing.Optional[typing.List[str]]:
return gnulike_instruction_set_args.get(instruction_set, None)
@ -284,19 +196,6 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
def get_profile_use_args(self) -> typing.List[str]:
return ['-fprofile-use', '-fprofile-correction']
def get_allow_undefined_link_args(self) -> typing.List[str]:
if self.compiler_type.is_osx_compiler:
# Apple ld
return ['-Wl,-undefined,dynamic_lookup']
elif self.compiler_type.is_windows_compiler:
# For PE/COFF this is impossible
return []
elif mesonlib.is_sunos():
return []
else:
# GNU ld and LLVM lld
return ['-Wl,--allow-shlib-undefined']
def get_gui_app_args(self, value: bool) -> typing.List[str]:
if self.compiler_type.is_windows_compiler:
return ['-mwindows' if value else '-mconsole']
@ -369,9 +268,6 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
def get_lto_compile_args(self) -> typing.List[str]:
return ['-flto']
def get_lto_link_args(self) -> typing.List[str]:
return ['-flto']
def sanitizer_compile_args(self, value: str) -> typing.List[str]:
if value == 'none':
return []
@ -380,10 +276,19 @@ class GnuLikeCompiler(metaclass=abc.ABCMeta):
args.append('-fno-omit-frame-pointer')
return args
def sanitizer_link_args(self, value: str) -> typing.List[str]:
if value == 'none':
return []
return ['-fsanitize=' + value]
def get_output_args(self, target: str) -> typing.List[str]:
return ['-o', target]
def get_dependency_gen_args(self, outtarget, outfile):
return ['-MD', '-MQ', outtarget, '-MF', outfile]
def get_compile_only_args(self) -> typing.List[str]:
return ['-c']
def get_include_args(self, path: str, is_system: bool) -> typing.List[str]:
if is_system:
return ['-isystem' + path]
return ['-I' + path]
class GnuCompiler(GnuLikeCompiler):

@ -133,8 +133,5 @@ class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler):
version = int(v1 + v2)
return self._calculate_toolset_version(version)
def get_linker_exelist(self) -> typing.List[str]:
return ['xilink']
def openmp_flags(self) -> typing.List[str]:
return ['/Qopenmp']

@ -0,0 +1,124 @@
# Copyright 2019 The Meson development team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Mixins for compilers that *are* linkers.
While many compilers (such as gcc and clang) are used by meson to dispatch
linker commands and other (like MSVC) are not, a few (such as DMD) actually
are both the linker and compiler in one binary. This module provides mixin
classes for those cases.
"""
import os
import shlex
import typing
from ... import mesonlib
if typing.TYPE_CHECKING:
from ...coredata import OptionDictType
from ...environment import Environment
class LinkerEnvVarsMixin:
"""Mixin reading LDFLAGS from the environment."""
def get_linker_args_from_envvars(self) -> typing.List[str]:
flags = os.environ.get('LDFLAGS')
if not flags:
return []
return shlex.split(flags)
class BasicLinkerIsCompilerMixin:
"""Provides a baseline of methods that a linker would implement.
In every case this provides a "no" or "empty" answer. If a compiler
implements any of these it needs a different mixin or to override that
functionality itself.
"""
def sanitizer_link_args(self, value: str) -> typing.List[str]:
return []
def get_lto_link_args(self) -> typing.List[str]:
return []
def can_linker_accept_rsp(self) -> bool:
return mesonlib.is_windows()
def get_linker_exelist(self) -> typing.List[str]:
return self.exelist.copy()
def get_linker_output_args(self, output: str) -> typing.List[str]:
return []
def get_linker_always_args(self) -> typing.List[str]:
return []
def get_linker_lib_prefix(self) -> str:
return ''
def get_option_link_args(self, options: 'OptionDictType') -> typing.List[str]:
return []
def has_multi_link_args(self, args: typing.List[str], env: 'Environment') -> typing.Tuple[bool, bool]:
return False, False
def get_link_debugfile_args(self, targetfile: str) -> typing.List[str]:
return []
def get_std_shared_lib_link_args(self) -> typing.List[str]:
return []
def get_std_shared_module_args(self, options: 'OptionDictType') -> typing.List[str]:
return self.get_std_shared_lib_link_args()
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
raise mesonlib.EnvironmentException(
'Linker {} does not support link_whole'.format(self.id))
def get_allow_undefined_args(self) -> typing.List[str]:
raise mesonlib.EnvironmentException(
'Linker {} does not support allow undefined'.format(self.id))
def get_pie_link_args(self) -> typing.List[str]:
m = 'Linker {} does not support position-independent executable'
raise mesonlib.EnvironmentException(m.format(self.id))
def get_undefined_link_args(self) -> typing.List[str]:
return []
def get_coverage_link_args(self) -> typing.List[str]:
m = "Linker {} doesn't implement coverage data generation.".format(self.id)
raise mesonlib.EnvironmentException(m)
def no_undefined_link_args(self) -> typing.List[str]:
return []
def bitcode_args(self) -> typing.List[str]:
raise mesonlib.MesonException("This linker doesn't support bitcode bundles")
def get_soname_args(self, for_machine: 'mesonlib.MachineChoice',
prefix: str, shlib_name: str, suffix: str, soversion: str,
darwin_versions: typing.Tuple[str, str],
is_shared_module: bool) -> typing.List[str]:
raise mesonlib.MesonException("This linker doesn't support soname args")
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
return []

@ -33,17 +33,7 @@ pgi_buildtype_args = {
} # type: typing.Dict[str, typing.List[str]]
pgi_buildtype_linker_args = {
'plain': [],
'debug': [],
'debugoptimized': [],
'release': [],
'minsize': [],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
class PGICompiler():
class PGICompiler:
def __init__(self, compiler_type: 'CompilerType'):
self.base_options = ['b_pch']
self.id = 'pgi'
@ -64,19 +54,11 @@ class PGICompiler():
def gen_import_library_args(self, implibname: str) -> typing.List[str]:
return []
def get_std_shared_lib_link_args(self) -> typing.List[str]:
# PGI -shared is Linux only.
if self.compiler_type.is_windows_compiler:
return ['-Bdynamic', '-Mmakedll']
elif not self.compiler_type.is_osx_compiler:
return ['-shared']
return []
def get_pic_args(self) -> typing.List[str]:
# PGI -fPIC is Linux only.
if self.compiler_type.is_osx_compiler or self.compiler_type.is_windows_compiler:
return []
return ['-fPIC']
if self.compiler_type.is_linux_compiler():
return ['-fPIC']
return []
def openmp_flags(self) -> typing.List[str]:
return ['-mp']
@ -84,9 +66,6 @@ class PGICompiler():
def get_buildtype_args(self, buildtype: str) -> typing.List[str]:
return pgi_buildtype_args[buildtype]
def get_buildtype_linker_args(self, buildtype: str) -> typing.List[str]:
return pgi_buildtype_linker_args[buildtype]
def get_optimization_args(self, optimization_level: str) -> typing.List[str]:
return clike_optimization_args[optimization_level]
@ -99,9 +78,6 @@ class PGICompiler():
parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))
return parameter_list
def get_allow_undefined_link_args(self) -> typing.List[str]:
return []
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> typing.List[str]:
return []

@ -61,17 +61,6 @@ msvc_buildtype_args = {
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
msvc_buildtype_linker_args = {
'plain': [],
'debug': [],
'debugoptimized': [],
# The otherwise implicit REF and ICF linker optimisations are disabled by
# /DEBUG. REF implies ICF.
'release': ['/OPT:REF'],
'minsize': ['/INCREMENTAL:NO', '/OPT:REF'],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
msvc_optimization_args = {
'0': [],
'g': ['/O0'],
@ -133,31 +122,18 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
self.machine = 'x86'
else:
self.machine = target
self.linker.machine = self.machine
# Override CCompiler.get_always_args
def get_always_args(self) -> typing.List[str]:
return self.always_args
def get_linker_debug_crt_args(self) -> typing.List[str]:
"""
Arguments needed to select a debug crt for the linker
Sometimes we need to manually select the CRT (C runtime) to use with
MSVC. One example is when trying to link with static libraries since
MSVC won't auto-select a CRT for us in that case and will error out
asking us to select one.
"""
return ['/MDd']
def get_buildtype_args(self, buildtype: str) -> typing.List[str]:
args = msvc_buildtype_args[buildtype]
if self.id == 'msvc' and mesonlib.version_compare(self.version, '<18.0'):
args = [arg for arg in args if arg != '/Gw']
return args
def get_buildtype_linker_args(self, buildtype: str) -> typing.List[str]:
return msvc_buildtype_linker_args[buildtype]
def get_pch_suffix(self) -> str:
return 'pch'
@ -197,23 +173,6 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> typing.List[str]:
return []
def get_linker_exelist(self) -> typing.List[str]:
# FIXME, should have same path as compiler.
# FIXME, should be controllable via cross-file.
if self.id == 'clang-cl':
return ['lld-link']
else:
return ['link']
def get_linker_always_args(self) -> typing.List[str]:
return ['/nologo']
def get_linker_output_args(self, outputname: str) -> typing.List[str]:
return ['/MACHINE:' + self.machine, '/OUT:' + outputname]
def get_linker_search_args(self, dirname: str) -> typing.List[str]:
return ['/LIBPATH:' + dirname]
def linker_to_compiler_args(self, args: typing.List[str]) -> typing.List[str]:
return ['/link'] + args
@ -228,12 +187,6 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
def get_pic_args(self) -> typing.List[str]:
return [] # PIC is handled by the loader on Windows
def gen_export_dynamic_link_args(self, env: 'Environment') -> typing.List[str]:
return [] # Not applicable with MSVC
def get_std_shared_lib_link_args(self) -> typing.List[str]:
return ['/DLL']
def gen_vs_module_defs_args(self, defsfile: str) -> typing.List[str]:
if not isinstance(defsfile, str):
raise RuntimeError('Module definitions file should be str')
@ -249,9 +202,6 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
"The name of the outputted import library"
return ['/IMPLIB:' + implibname]
def build_rpath_args(self, build_dir: str, from_dir: str, rpath_paths: str, build_rpath: str, install_rpath: str) -> typing.List[str]:
return []
def openmp_flags(self) -> typing.List[str]:
return ['/openmp']
@ -259,9 +209,6 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
def thread_flags(self, env: 'Environment') -> typing.List[str]:
return []
def thread_link_flags(self, env: 'Environment') -> typing.List[str]:
return []
@classmethod
def unix_args_to_native(cls, args: typing.List[str]) -> typing.List[str]:
result = []
@ -331,16 +278,6 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
args = ['/FS'] + args
return args
def get_link_debugfile_args(self, targetfile: str) -> typing.List[str]:
pdbarr = targetfile.split('.')[:-1]
pdbarr += ['pdb']
return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)]
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
# Only since VS2015
args = mesonlib.listify(args)
return ['/WHOLEARCHIVE:' + x for x in args]
def get_instruction_set_args(self, instruction_set: str) -> typing.Optional[typing.List[str]]:
if self.is_64:
return vs64_instruction_set_args.get(instruction_set, None)
@ -418,7 +355,3 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta):
def get_argument_syntax(self) -> str:
return 'msvc'
def get_allow_undefined_link_args(self) -> typing.List[str]:
# link.exe
return ['/FORCE:UNRESOLVED']

@ -23,9 +23,9 @@ from .mixins.gnu import GnuCompiler
from .mixins.clang import ClangCompiler
class ObjCCompiler(CLikeCompiler, Compiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap: typing.Optional[str]):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap: typing.Optional[str], **kwargs):
self.language = 'objc'
Compiler.__init__(self, exelist, version, for_machine)
Compiler.__init__(self, exelist, version, for_machine, **kwargs)
CLikeCompiler.__init__(self, is_cross, exe_wrap)
def get_display_language(self):
@ -57,8 +57,8 @@ class ObjCCompiler(CLikeCompiler, Compiler):
class GnuObjCCompiler(GnuCompiler, ObjCCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None):
ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper)
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs):
ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs)
GnuCompiler.__init__(self, compiler_type, defines)
default_warn_args = ['-Wall', '-Winvalid-pch']
self.warn_args = {'0': [],
@ -68,8 +68,8 @@ class GnuObjCCompiler(GnuCompiler, ObjCCompiler):
class ClangObjCCompiler(ClangCompiler, ObjCCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None):
ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper)
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs):
ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs)
ClangCompiler.__init__(self, compiler_type)
default_warn_args = ['-Wall', '-Winvalid-pch']
self.warn_args = {'0': [],

@ -23,9 +23,9 @@ from .mixins.gnu import GnuCompiler
from .mixins.clang import ClangCompiler
class ObjCPPCompiler(CLikeCompiler, Compiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap: typing.Optional[str]):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap: typing.Optional[str], **kwargs):
self.language = 'objcpp'
Compiler.__init__(self, exelist, version, for_machine)
Compiler.__init__(self, exelist, version, for_machine, **kwargs)
CLikeCompiler.__init__(self, is_cross, exe_wrap)
def get_display_language(self):
@ -58,8 +58,8 @@ class ObjCPPCompiler(CLikeCompiler, Compiler):
class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None):
ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper)
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs):
ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs)
GnuCompiler.__init__(self, compiler_type, defines)
default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor']
self.warn_args = {'0': [],
@ -69,8 +69,8 @@ class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler):
class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler):
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None):
ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper)
def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs):
ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs)
ClangCompiler.__init__(self, compiler_type)
default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor']
self.warn_args = {'0': [],

@ -13,11 +13,14 @@
# limitations under the License.
import subprocess, os.path
import typing
from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe
from .compilers import Compiler, rust_buildtype_args, clike_debug_args
if typing.TYPE_CHECKING:
from ..environment import Environment # noqa: F401
rust_optimization_args = {'0': [],
'g': ['-C', 'opt-level=0'],
'1': ['-C', 'opt-level=1'],
@ -27,9 +30,9 @@ rust_optimization_args = {'0': [],
}
class RustCompiler(Compiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs):
self.language = 'rust'
super().__init__(exelist, version, for_machine)
super().__init__(exelist, version, for_machine, **kwargs)
self.exe_wrapper = exe_wrapper
self.id = 'rustc'
self.is_cross = is_cross
@ -77,9 +80,6 @@ class RustCompiler(Compiler):
def get_buildtype_args(self, buildtype):
return rust_buildtype_args[buildtype]
def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath):
return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
def get_sysroot(self):
cmd = self.exelist + ['--print', 'sysroot']
p, stdo, stde = Popen_safe(cmd)
@ -102,8 +102,5 @@ class RustCompiler(Compiler):
return parameter_list
def get_buildtype_linker_args(self, build_type):
return []
def get_std_exe_link_args(self):
return []

@ -27,16 +27,13 @@ swift_optimization_args = {'0': [],
}
class SwiftCompiler(Compiler):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross):
def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, **kwargs):
self.language = 'swift'
super().__init__(exelist, version, for_machine)
super().__init__(exelist, version, for_machine, **kwargs)
self.version = version
self.id = 'llvm'
self.is_cross = is_cross
def get_linker_exelist(self):
return self.exelist[:]
def name_string(self):
return ' '.join(self.exelist)
@ -58,9 +55,6 @@ class SwiftCompiler(Compiler):
def get_output_args(self, target):
return ['-o', target]
def get_linker_output_args(self, target):
return ['-o', target]
def get_header_import_args(self, headername):
return ['-import-objc-header', headername]
@ -70,9 +64,6 @@ class SwiftCompiler(Compiler):
def get_buildtype_args(self, buildtype):
return swift_buildtype_args[buildtype]
def get_buildtype_linker_args(self, buildtype):
return []
def get_std_exe_link_args(self):
return ['-emit-executable']
@ -82,9 +73,6 @@ class SwiftCompiler(Compiler):
def get_mod_gen_args(self):
return ['-emit-module']
def build_rpath_args(self, *args):
return [] # FIXME
def get_include_args(self, dirname):
return ['-I' + dirname]

@ -13,6 +13,7 @@
# limitations under the License.
import os, platform, re, sys, shlex, shutil, subprocess, typing
import tempfile
from . import coredata
from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, IntelVisualStudioLinker
@ -38,6 +39,23 @@ from .compilers import (
is_object,
is_source,
)
from .linkers import (
AppleDynamicLinker,
ArmClangDynamicLinker,
ArmDynamicLinker,
CcrxDynamicLinker,
ClangClDynamicLinker,
DynamicLinker,
GnuDynamicLinker,
LLVMDynamicLinker,
MSVCDynamicLinker,
OptlinkDynamicLinker,
PGIDynamicLinker,
SolarisDynamicLinker,
XildAppleDynamicLinker,
XildLinuxDynamicLinker,
XilinkDynamicLinker,
)
from functools import lru_cache
from .compilers import (
ArmCCompiler,
@ -63,8 +81,8 @@ from .compilers import (
EmscriptenCCompiler,
EmscriptenCPPCompiler,
IntelCCompiler,
IntelCPPCompiler,
IntelClCCompiler,
IntelCPPCompiler,
IntelClCPPCompiler,
IntelFortranCompiler,
IntelClFortranCompiler,
@ -639,7 +657,57 @@ class Environment:
errmsg += '\nRunning "{0}" gave "{1}"'.format(c, e)
raise EnvironmentException(errmsg)
def _detect_c_or_cpp_compiler(self, lang, for_machine):
@staticmethod
def _guess_nix_linker(compiler: typing.List[str], for_machine: MachineChoice, *,
prefix: typing.Union[str, typing.List[str]] = '-Wl,',
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.
:extra_args: Any addtional arguments rquired (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
else:
check_args = prefix + ['--version'] + extra_args
_, o, e = Popen_safe(compiler + check_args)
v = search_version(o)
if o.startswith('LLD'):
linker = LLVMDynamicLinker(compiler, for_machine, 'lld', version=v) # type: DynamicLinker
# 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)
else:
_, _, e = Popen_safe(compiler + prefix + ['-v'] + extra_args)
i = 'APPLE ld'
for line in e.split('\n'):
if 'PROJECT:ld' in line:
v = line.split('-')[1]
break
else:
v = 'unknown version'
linker = AppleDynamicLinker(compiler, for_machine, i, 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, version=v)
elif 'Solaris' in e:
linker = SolarisDynamicLinker(compiler, for_machine, 'solaris', version=search_version(e))
else:
raise MesonException('Unable to determine dynamic linker.')
return linker
def _detect_c_or_cpp_compiler(self, lang: str, for_machine: MachineChoice) -> Compiler:
popen_exceptions = {}
compilers, ccache, exe_wrap = self._get_compilers(lang, for_machine)
is_cross = not self.machines.matches_build_machine(for_machine)
@ -701,13 +769,18 @@ class Environment:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
continue
compiler_type = self.get_gnu_compiler_type(defines)
linker = self._guess_nix_linker(compiler, for_machine)
if guess_gcc_or_lcc == 'lcc':
version = self.get_lcc_version_from_defines(defines)
cls = ElbrusCCompiler if lang == 'c' else ElbrusCPPCompiler
else:
version = self.get_gnu_version_from_defines(defines)
cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version)
return cls(ccache + compiler, version, compiler_type,
for_machine, is_cross, exe_wrap, defines,
full_version=full_version, linker=linker)
if 'Emscripten' in out:
cls = EmscriptenCCompiler if lang == 'c' else EmscriptenCPPCompiler
@ -730,7 +803,8 @@ class Environment:
full_version = arm_ver_str
compiler_type = CompilerType.ARM_WIN
cls = ArmclangCCompiler if lang == 'c' else ArmclangCPPCompiler
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = ArmClangDynamicLinker(for_machine, version=version)
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'CL.EXE COMPATIBILITY' in out:
# if this is clang-cl masquerading as cl, detect it as cl, not
# clang
@ -746,7 +820,8 @@ class Environment:
else:
target = 'unknown target'
cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler
return cls(compiler, version, for_machine, is_cross, exe_wrap, target)
linker = ClangClDynamicLinker(for_machine, version=version)
return cls(compiler, version, for_machine, is_cross, exe_wrap, target, linker=linker)
if 'clang' in out:
if 'Apple' in out or self.machines[for_machine].is_darwin():
compiler_type = CompilerType.CLANG_OSX
@ -755,12 +830,15 @@ class Environment:
else:
compiler_type = CompilerType.CLANG_STANDARD
cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = self._guess_nix_linker(compiler, for_machine)
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'Intel(R) C++ Intel(R)' in err:
version = search_version(err)
target = 'x86' if 'IA-32' in err else 'x86_64'
cls = IntelClCCompiler if lang == 'c' else IntelClCPPCompiler
return cls(compiler, version, for_machine, is_cross, exe_wrap, target)
linker = XilinkDynamicLinker(for_machine, version=version)
return cls(compiler, version, for_machine, is_cross, exe_wrap, target, linker=linker)
if 'Microsoft' in out or 'Microsoft' in err:
# Latest versions of Visual Studio print version
# number to stderr but earlier ones print version
@ -778,8 +856,9 @@ class Environment:
target = match.group(1)
else:
target = 'x86'
linker = MSVCDynamicLinker(for_machine, version=version)
cls = VisualStudioCCompiler if lang == 'c' else VisualStudioCPPCompiler
return cls(compiler, version, for_machine, is_cross, exe_wrap, target)
return cls(compiler, version, for_machine, is_cross, exe_wrap, target, linker=linker)
if 'PGI Compilers' in out:
if self.machines[for_machine].is_darwin():
compiler_type = CompilerType.PGI_OSX
@ -788,25 +867,27 @@ class Environment:
else:
compiler_type = CompilerType.PGI_STANDARD
cls = PGICCompiler if lang == 'c' else PGICPPCompiler
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap)
linker = PGIDynamicLinker(compiler, for_machine, 'pgi', version=version)
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, linker=linker)
if '(ICC)' in out:
if self.machines[for_machine].is_darwin():
compiler_type = CompilerType.ICC_OSX
elif self.machines[for_machine].is_windows():
# TODO: fix ICC on Windows
compiler_type = CompilerType.ICC_WIN
l = XildAppleDynamicLinker(compiler, for_machine, 'xild', version=version)
else:
compiler_type = CompilerType.ICC_STANDARD
l = XildLinuxDynamicLinker(compiler, for_machine, 'xild', version=version)
cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version)
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=l)
if 'ARM' in out:
compiler_type = CompilerType.ARM_WIN
cls = ArmCCompiler if lang == 'c' else ArmCPPCompiler
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = ArmDynamicLinker(for_machine, version=version)
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'RX Family' in out:
compiler_type = CompilerType.CCRX_WIN
cls = CcrxCCompiler if lang == 'c' else CcrxCPPCompiler
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = CcrxDynamicLinker(for_machine, version=version)
return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
self._handle_exceptions(popen_exceptions, compilers)
@ -846,8 +927,8 @@ class Environment:
# Luckily, the "V" also makes it very simple to extract
# the full version:
version = out.strip().split('V')[-1]
cls = CudaCompiler
return cls(ccache + compiler, version, for_machine, exe_wrap)
linker = self._guess_nix_linker(compiler, for_machine, prefix='-Xlinker=')
return CudaCompiler(ccache + compiler, version, for_machine, exe_wrap, linker=linker)
raise EnvironmentException('Could not find suitable CUDA compiler: "' + ' '.join(compilers) + '"')
def detect_fortran_compiler(self, for_machine: MachineChoice):
@ -885,22 +966,27 @@ class Environment:
else:
version = self.get_gnu_version_from_defines(defines)
cls = GnuFortranCompiler
return cls(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version)
linker = self._guess_nix_linker(compiler, for_machine)
return cls(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version, linker=linker)
if 'G95' in out:
return G95FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = self._guess_nix_linker(compiler, for_machine)
return G95FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'Sun Fortran' in err:
version = search_version(err)
return SunFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = self._guess_nix_linker(compiler, for_machine)
return SunFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'Intel(R) Visual Fortran' in err:
version = search_version(err)
target = 'x86' if 'IA-32' in err else 'x86_64'
return IntelClFortranCompiler(compiler, version, for_machine, is_cross, target, exe_wrap)
linker = XilinkDynamicLinker(for_machine, version=version)
return IntelClFortranCompiler(compiler, version, for_machine, is_cross, target, exe_wrap, linker=linker)
if 'ifort (IFORT)' in out:
return IntelFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = XildLinuxDynamicLinker(compiler, for_machine, 'xild', version=version)
return IntelFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'PathScale EKOPath(tm)' in err:
return PathScaleFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version)
@ -912,54 +998,34 @@ class Environment:
compiler_type = CompilerType.PGI_WIN
else:
compiler_type = CompilerType.PGI_STANDARD
return PGIFortranCompiler(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = PGIDynamicLinker(compiler, for_machine, 'pgi', version=version)
return PGIFortranCompiler(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'flang' in out or 'clang' in out:
return FlangFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = self._guess_nix_linker(compiler, for_machine)
return FlangFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'Open64 Compiler Suite' in err:
return Open64FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = self._guess_nix_linker(compiler, for_machine)
return Open64FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
if 'NAG Fortran' in err:
return NAGFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version)
linker = self._guess_nix_linker(compiler, for_machine)
return NAGFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version, linker=linker)
self._handle_exceptions(popen_exceptions, compilers)
def get_scratch_dir(self):
return self.scratch_dir
def detect_objc_compiler(self, for_machine):
popen_exceptions = {}
compilers, ccache, exe_wrap = self._get_compilers('objc', for_machine)
is_cross = not self.machines.matches_build_machine(for_machine)
for compiler in compilers:
if isinstance(compiler, str):
compiler = [compiler]
arg = ['--version']
try:
p, out, err = Popen_safe(compiler + arg)
except OSError as e:
popen_exceptions[' '.join(compiler + arg)] = e
continue
version = search_version(out)
if 'Free Software Foundation' in out or ('e2k' in out and 'lcc' in out):
defines = self.get_gnu_compiler_defines(compiler)
if not defines:
popen_exceptions[' '.join(compiler)] = 'no pre-processor defines'
continue
compiler_type = self.get_gnu_compiler_type(defines)
version = self.get_gnu_version_from_defines(defines)
return GnuObjCCompiler(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines)
if out.startswith('Apple LLVM') or out.startswith('Apple clang'):
return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, for_machine, is_cross, exe_wrap)
if 'windows' in out:
return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, for_machine, is_cross, exe_wrap)
if out.startswith(('clang', 'OpenBSD clang')):
return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, for_machine, is_cross, exe_wrap)
self._handle_exceptions(popen_exceptions, compilers)
def detect_objc_compiler(self, for_machine: MachineInfo) -> 'Compiler':
return self._detect_objc_or_objcpp_compiler(for_machine, True)
def detect_objcpp_compiler(self, for_machine):
def detect_objcpp_compiler(self, for_machine: MachineInfo) -> 'Compiler':
return self._detect_objc_or_objcpp_compiler(for_machine, False)
def _detect_objc_or_objcpp_compiler(self, for_machine: MachineInfo, objc: bool) -> 'Compiler':
popen_exceptions = {}
compilers, ccache, exe_wrap = self._get_compilers('objcpp', for_machine)
compilers, ccache, exe_wrap = self._get_compilers('objc' if objc else 'objcpp', for_machine)
is_cross = not self.machines.matches_build_machine(for_machine)
for compiler in compilers:
if isinstance(compiler, str):
@ -978,13 +1044,19 @@ class Environment:
continue
compiler_type = self.get_gnu_compiler_type(defines)
version = self.get_gnu_version_from_defines(defines)
return GnuObjCPPCompiler(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines)
if out.startswith('Apple LLVM') or out.startswith('Apple clang'):
return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, for_machine, is_cross, exe_wrap)
if 'windows' in out:
return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, for_machine, is_cross, exe_wrap)
if out.startswith(('clang', 'OpenBSD clang')):
return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, for_machine, is_cross, exe_wrap)
comp = GnuObjCCompiler if objc else GnuObjCPPCompiler
linker = self._guess_nix_linker(compiler, for_machine)
return comp(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, linker=linker)
if 'clang' in out:
comp = ClangObjCCompiler if objc else ClangObjCPPCompiler
if 'Apple' in out or self.machines[for_machine].is_darwin():
compiler_type = CompilerType.CLANG_OSX
elif 'windows' in out or self.machines[for_machine].is_windows():
compiler_type = CompilerType.CLANG_MINGW
else:
compiler_type = CompilerType.CLANG_STANDARD
linker = self._guess_nix_linker(compiler, for_machine)
return comp(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, linker=linker)
self._handle_exceptions(popen_exceptions, compilers)
def detect_java_compiler(self, for_machine):
@ -1059,7 +1131,18 @@ class Environment:
version = search_version(out)
if 'rustc' in out:
return RustCompiler(compiler, version, for_machine, is_cross, exe_wrap)
# 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.
# Currenty 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')
else:
linker = GnuDynamicLinker([], for_machine, 'GNU ld')
return RustCompiler(compiler, version, for_machine, is_cross, exe_wrap, linker=linker)
self._handle_exceptions(popen_exceptions, compilers)
@ -1100,11 +1183,31 @@ class Environment:
arch = 'x86_mscoff'
if 'LLVM D compiler' in out:
return compilers.LLVMDCompiler(exelist, version, for_machine, arch, full_version=full_version)
# LDC seems to require a file
m = self.machines[for_machine]
if m.is_windows() or m.is_cygwin():
# Getting LDC on windows to give useful linker output when not
# doing real work is painfully hard. It ships with a verison 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))
else:
with tempfile.NamedTemporaryFile(suffix='.d') as f:
linker = self._guess_nix_linker(exelist, for_machine, prefix='-L', extra_args=[f.name])
return compilers.LLVMDCompiler(exelist, version, for_machine, arch, full_version=full_version, linker=linker)
elif 'gdc' in out:
return compilers.GnuDCompiler(exelist, version, for_machine, arch, full_version=full_version)
linker = self._guess_nix_linker(exelist, for_machine)
return compilers.GnuDCompiler(exelist, version, for_machine, arch, full_version=full_version, linker=linker)
elif 'The D Language Foundation' in out or 'Digital Mars' in out:
return compilers.DmdDCompiler(exelist, version, for_machine, arch, full_version=full_version)
# DMD seems to require a file
m = self.machines[for_machine]
if m.is_windows() or m.is_cygwin():
linker = OptlinkDynamicLinker(for_machine, version=full_version)
else:
with tempfile.NamedTemporaryFile(suffix='.d') as f:
linker = self._guess_nix_linker(exelist, for_machine, prefix='-L', extra_args=[f.name])
return compilers.DmdDCompiler(exelist, version, for_machine, arch, full_version=full_version, linker=linker)
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
def detect_swift_compiler(self, for_machine):
@ -1120,7 +1223,12 @@ class Environment:
raise EnvironmentException('Could not execute Swift compiler "%s"' % ' '.join(exelist))
version = search_version(err)
if 'Swift' in err:
return compilers.SwiftCompiler(exelist, version, for_machine, is_cross)
# 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, prefix=['-Xlinker'], extra_args=[f.name])
return compilers.SwiftCompiler(exelist, version, for_machine, is_cross, linker=linker)
raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"')
def compiler_from_language(self, lang: str, for_machine: MachineChoice):

@ -2831,12 +2831,16 @@ external dependencies (including libraries) must go to "dependencies".''')
continue
else:
raise
if for_machine == MachineChoice.HOST or self.environment.is_cross_build():
logger_fun = mlog.log
else:
logger_fun = mlog.debug
logger_fun(comp.get_display_language(), 'compiler for the', machine_name, 'machine:',
mlog.bold(' '.join(comp.get_exelist())), comp.get_version_string())
if comp.linker is not None:
logger_fun(comp.get_display_language(), 'linker for the', machine_name, 'machine:',
mlog.bold(comp.linker.id), comp.linker.version)
self.build.ensure_static_linker(comp)
langs = self.coredata.compilers[for_machine].keys()

@ -12,6 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import abc
import os
import shlex
import typing
from . import mesonlib
@ -51,8 +54,9 @@ class StaticLinker:
def get_coverage_link_args(self) -> typing.List[str]:
return []
def build_rpath_args(self, build_dir: str, from_dir: str, rpath_paths: str,
build_rpath: str, install_rpath: str) -> typing.List[str]:
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
return []
def thread_link_flags(self, env: 'Environment') -> typing.List[str]:
@ -189,3 +193,693 @@ class CcrxLinker(StaticLinker):
def get_linker_always_args(self) -> typing.List[str]:
return ['-nologo', '-form=library']
def prepare_rpaths(raw_rpaths: str, build_dir: str, from_dir: str) -> typing.List[str]:
# The rpaths we write must be relative if they point to the build dir,
# because otherwise they have different length depending on the build
# directory. This breaks reproducible builds.
internal_format_rpaths = [evaluate_rpath(p, build_dir, from_dir) for p in raw_rpaths]
ordered_rpaths = order_rpaths(internal_format_rpaths)
return ordered_rpaths
def order_rpaths(rpath_list: typing.List[str]) -> typing.List[str]:
# We want rpaths that point inside our build dir to always override
# those pointing to other places in the file system. This is so built
# binaries prefer our libraries to the ones that may lie somewhere
# in the file system, such as /lib/x86_64-linux-gnu.
#
# The correct thing to do here would be C++'s std::stable_partition.
# Python standard library does not have it, so replicate it with
# sort, which is guaranteed to be stable.
return sorted(rpath_list, key=os.path.isabs)
def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str:
if p == from_dir:
return '' # relpath errors out in this case
elif os.path.isabs(p):
return p # These can be outside of build dir.
else:
return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir))
class DynamicLinker(metaclass=abc.ABCMeta):
"""Base class for dynamic linkers."""
_BUILDTYPE_ARGS = {
'plain': [],
'debug': [],
'debugoptimized': [],
'release': [],
'minsize': [],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
def __init__(self, exelist: typing.List[str], for_machine: mesonlib.MachineChoice,
id_: str, *, version: str = 'unknown version'):
self.exelist = exelist
self.for_machine = for_machine
self.version = version
self.id = id_
def __repr__(self) -> str:
return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist))
def get_id(self) -> str:
return self.id
def get_version_string(self) -> str:
return '({} {})'.format(self.id, self.version)
def get_exelist(self) -> typing.List[str]:
return self.exelist.copy()
def get_accepts_rsp(self) -> bool:
# TODO: is it really a matter of is_windows or is it for_windows?
return mesonlib.is_windows()
def get_always_args(self) -> typing.List[str]:
return []
def get_lib_prefix(self) -> str:
return ''
# XXX: is use_ldflags a compiler or a linker attribute?
def get_args_from_envvars(self) -> typing.List[str]:
flags = os.environ.get('LDFLAGS')
if not flags:
return []
return shlex.split(flags)
def get_option_args(self, options: 'OptionDictType') -> typing.List[str]:
return []
def has_multi_arguments(self, args: typing.List[str], env: 'Environment') -> typing.Tuple[bool, bool]:
m = 'Language {} does not support has_multi_link_arguments.'
raise mesonlib.EnvironmentException(m.format(self.id))
def get_debugfile_args(self, targetfile: str) -> typing.List[str]:
"""Some compilers (MSVC) write debug into a separate file.
This method takes the target object path and returns a list of
commands to append to the linker invocation to control where that
file is written.
"""
return []
def get_std_shared_lib_args(self) -> typing.List[str]:
return []
def get_std_shared_module_args(self, options: 'OptionDictType') -> typing.List[str]:
return self.get_std_shared_lib_args()
def get_pie_args(self) -> typing.List[str]:
# TODO: this really needs to take a boolean and return the args to
# disable pie, otherwise it only acts to enable pie if pie *isn't* the
# default.
m = 'Linker {} does not support position-independent executable'
raise mesonlib.EnvironmentException(m.format(self.id))
def get_lto_args(self) -> typing.List[str]:
return []
def sanitizer_args(self, value: str) -> typing.List[str]:
return []
def get_buildtype_args(self, buildtype: str) -> typing.List[str]:
# We can override these in children by just overriding the
# _BUILDTYPE_ARGS value.
return self._BUILDTYPE_ARGS[buildtype]
def get_asneeded_args(self) -> typing.List[str]:
return []
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
raise mesonlib.EnvironmentException(
'Linker {} does not support link_whole'.format(self.id))
def get_allow_undefined_args(self) -> typing.List[str]:
raise mesonlib.EnvironmentException(
'Linker {} does not support allow undefined'.format(self.id))
def invoked_by_compiler(self) -> bool:
"""True if meson uses the compiler to invoke the linker."""
return True
@abc.abstractmethod
def get_output_args(self, outname: str) -> typing.List[str]:
pass
def get_coverage_args(self) -> typing.List[str]:
m = "Linker {} doesn't implement coverage data generation.".format(self.id)
raise mesonlib.EnvironmentException(m)
@abc.abstractmethod
def get_search_args(self, dirname: str) -> typing.List[str]:
pass
def export_dynamic_args(self, env: 'Environment') -> typing.List[str]:
return []
def import_library_args(self, implibname: str) -> typing.List[str]:
"""The name of the outputted import library.
This implementation is used only on Windows by compilers that use GNU ld
"""
return []
def thread_flags(self, env: 'Environment') -> typing.List[str]:
return []
def no_undefined_args(self) -> typing.List[str]:
"""Arguments to error if there are any undefined symbols at link time.
This is the inverse of get_allow_undefined_args().
TODO: A future cleanup might merge this and
get_allow_undefined_args() into a single method taking a
boolean
"""
return []
def fatal_warnings(self) -> typing.List[str]:
"""Arguments to make all warnings errors."""
return []
def bitcode_args(self) -> typing.List[str]:
raise mesonlib.MesonException('This linker does not support bitcode bundles')
def get_debug_crt_args(self) -> typing.List[str]:
return []
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
return []
class PosixDynamicLinkerMixin:
"""Mixin class for POSIX-ish linkers.
This is obviously a pretty small subset of the linker interface, but
enough dynamic linkers that meson supports are POSIX-like but not
GNU-like that it makes sense to split this out.
"""
def get_output_args(self, outname: str) -> typing.List[str]:
return ['-o', outname]
def get_std_shared_lib_args(self) -> typing.List[str]:
return ['-shared']
def get_search_args(self, dirname: str) -> typing.List[str]:
return ['-L', dirname]
class GnuLikeDynamicLinkerMixin:
"""Mixin class for dynamic linkers that provides gnu-like interface.
This acts as a base for the GNU linkers (bfd and gold), the Intel Xild
(which comes with ICC), LLVM's lld, and other linkers like GNU-ld.
"""
_BUILDTYPE_ARGS = {
'plain': [],
'debug': [],
'debugoptimized': [],
'release': ['-Wl,-O1'],
'minsize': [],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
def get_pie_args(self) -> typing.List[str]:
return ['-pie']
def get_asneeded_args(self) -> typing.List[str]:
return ['-Wl,--as-needed']
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
if not args:
return args
return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive']
def get_allow_undefined_args(self) -> typing.List[str]:
return ['-Wl,--allow-shlib-undefined']
def get_lto_args(self) -> typing.List[str]:
return ['-flto']
def sanitizer_args(self, value: str) -> typing.List[str]:
if value == 'none':
return []
return ['-fsanitize=' + value]
def invoked_by_compiler(self) -> bool:
"""True if meson uses the compiler to invoke the linker."""
return True
def get_coverage_args(self) -> typing.List[str]:
return ['--coverage']
def export_dynamic_args(self, env: 'Environment') -> typing.List[str]:
m = env.machines[self.for_machine]
if m.is_windows() or m.is_cygwin():
return ['-Wl,--export-all-symbols']
return ['-Wl,-export-dynamic']
def import_library_args(self, implibname: str) -> typing.List[str]:
return ['-Wl,--out-implib=' + implibname]
def thread_flags(self, env: 'Environment') -> typing.List[str]:
if env.machines[self.for_machine].is_haiku():
return []
return ['-pthread']
def no_undefined_args(self) -> typing.List[str]:
return ['-Wl,--no-undefined']
def fatal_warnings(self) -> typing.List[str]:
return ['-Wl,--fatal-warnings']
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]:
m = env.machines[self.for_machine]
if m.is_windows() or m.is_cygwin():
# For PE/COFF the soname argument has no effect
return []
sostr = '' if soversion is None else '.' + soversion
return ['-Wl,-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)]
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
m = env.machines[self.for_machine]
if m.is_windows() or m.is_cygwin():
return []
if not rpath_paths and not install_rpath and not build_rpath:
return []
args = []
origin_placeholder = '$ORIGIN'
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
# Need to deduplicate rpaths, as macOS's install_name_tool
# is *very* allergic to duplicate -delete_rpath arguments
# when calling depfixer on installation.
all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
# Build_rpath is used as-is (it is usually absolute).
if build_rpath != '':
all_paths.add(build_rpath)
# TODO: should this actually be "for (dragonfly|open)bsd"?
if mesonlib.is_dragonflybsd() or mesonlib.is_openbsd():
# This argument instructs the compiler to record the value of
# ORIGIN in the .dynamic section of the elf. On Linux this is done
# by default, but is not on dragonfly/openbsd for some reason. Without this
# $ORIGIN in the runtime path will be undefined and any binaries
# linked against local libraries will fail to resolve them.
args.append('-Wl,-z,origin')
# In order to avoid relinking for RPATH removal, the binary needs to contain just
# enough space in the ELF header to hold the final installation RPATH.
paths = ':'.join(all_paths)
if len(paths) < len(install_rpath):
padding = 'X' * (len(install_rpath) - len(paths))
if not paths:
paths = padding
else:
paths = paths + ':' + padding
args.append('-Wl,-rpath,' + paths)
# TODO: should this actually be "for solaris/sunos"?
if mesonlib.is_sunos():
return args
# Rpaths to use while linking must be absolute. These are not
# written to the binary. Needed only with GNU ld:
# https://sourceware.org/bugzilla/show_bug.cgi?id=16936
# Not needed on Windows or other platforms that don't use RPATH
# https://github.com/mesonbuild/meson/issues/1897
#
# In addition, this linker option tends to be quite long and some
# compilers have trouble dealing with it. That's why we will include
# one option per folder, like this:
#
# -Wl,-rpath-link,/path/to/folder1 -Wl,-rpath,/path/to/folder2 ...
#
# ...instead of just one single looooong option, like this:
#
# -Wl,-rpath-link,/path/to/folder1:/path/to/folder2:...
args.extend(['-Wl,-rpath-link,' + os.path.join(build_dir, p) for p in rpath_paths])
return args
class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
"""Apple's ld implementation."""
def get_asneeded_args(self) -> typing.List[str]:
return ['-Wl,-dead_strip_dylibs']
def get_allow_undefined_args(self) -> typing.List[str]:
return ['-Wl,-undefined,dynamic_lookup']
def get_std_shared_module_args(self, options: 'OptionDictType') -> typing.List[str]:
return ['-bundle', '-Wl,-undefined,dynamic_lookup']
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
result = [] # type: typing.List[str]
for a in args:
result.extend(['-Wl,-force_load', a])
return result
def no_undefined_args(self) -> typing.List[str]:
return ['-Wl,-undefined,error']
def get_always_args(self) -> typing.List[str]:
return ['-Wl,-headerpad_max_install_names']
def bitcode_args(self) -> typing.List[str]:
return ['-Wl,-bitcode_bundle']
def fatal_warnings(self) -> typing.List[str]:
return ['-Wl,-fatal_warnings']
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]:
if is_shared_module:
return []
install_name = ['@rpath/', prefix, shlib_name]
if soversion is not None:
install_name.append('.' + soversion)
install_name.append('.dylib')
args = ['-install_name', ''.join(install_name)]
if darwin_versions:
args.extend(['-compatibility_version', darwin_versions[0],
'-current_version', darwin_versions[1]])
return args
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
if not rpath_paths and not install_rpath and not build_rpath:
return []
# Ensure that there is enough space for install_name_tool in-place
# editing of large RPATHs
args = ['-Wl,-headerpad_max_install_names']
# @loader_path is the equivalent of $ORIGIN on macOS
# https://stackoverflow.com/q/26280738
origin_placeholder = '@loader_path'
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
if build_rpath != '':
all_paths.add(build_rpath)
args.extend(['-Wl,-rpath,' + rp for rp in all_paths])
return args
class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
"""Representation of GNU ld.bfd and ld.gold."""
pass
class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker):
"""Representation of LLVM's lld (not lld-link) linker.
This is only the posix-like linker.
"""
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."""
def __init__(self, for_machine: mesonlib.MachineChoice,
*, version: str = 'unknown version'):
super().__init__(['rlink.exe'], for_machine, 'rlink',
version=version)
def get_accepts_rsp(self) -> bool:
return False
def get_lib_prefix(self) -> str:
return '-lib='
def get_std_shared_lib_args(self) -> typing.List[str]:
return []
def get_output_args(self, outputname: str) -> typing.List[str]:
return ['-output=%s' % outputname]
def get_search_args(self, dirname: str) -> typing.NoReturn:
raise EnvironmentError('rlink.exe does not have a search dir argument')
def get_allow_undefined_args(self) -> 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 ArmDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
"""Linker for the ARM compiler."""
def __init__(self, for_machine: mesonlib.MachineChoice,
*, version: str = 'unknown version'):
super().__init__(['armlink'], for_machine, 'armlink',
version=version)
def get_accepts_rsp(self) -> bool:
return False
def get_std_shared_lib_args(self) -> typing.NoReturn:
raise mesonlib.MesonException('The Arm Linkers do not support shared libraries')
def get_allow_undefined_args(self) -> typing.List[str]:
return []
class ArmClangDynamicLinker(ArmDynamicLinker):
"""Linker used with ARM's clang fork.
The interface is similar enough to the old ARM ld that it inherits and
extends a few things as needed.
"""
def export_dynamic_args(self, env: 'Environment') -> typing.List[str]:
return ['--export_dynamic']
def import_library_args(self, implibname: str) -> typing.List[str]:
return ['--symdefs=' + implibname]
class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
"""PGI linker."""
def get_allow_undefined_args(self) -> 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 []
def get_std_shared_lib_args(self) -> typing.List[str]:
# PGI -shared is Linux only.
if mesonlib.is_windows():
return ['-Bdynamic', '-Mmakedll']
elif mesonlib.is_linux:
return ['-shared']
return []
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
if env.machines[self.for_machine].is_windows():
return ['-R' + os.path.join(build_dir, p) for p in rpath_paths]
return []
class VisualStudioLikeLinkerMixin:
_BUILDTYPE_ARGS = {
'plain': [],
'debug': [],
'debugoptimized': [],
# The otherwise implicit REF and ICF linker optimisations are disabled by
# /DEBUG. REF implies ICF.
'release': ['/OPT:REF'],
'minsize': ['/INCREMENTAL:NO', '/OPT:REF'],
'custom': [],
} # type: typing.Dict[str, typing.List[str]]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.machine = 'x86'
def get_debug_crt_args(self) -> typing.List[str]:
"""Arguments needed to select a debug crt for the linker.
Sometimes we need to manually select the CRT (C runtime) to use with
MSVC. One example is when trying to link with static libraries since
MSVC won't auto-select a CRT for us in that case and will error out
asking us to select one.
"""
return ['/MDd']
def get_output_args(self, outputname: str) -> typing.List[str]:
return ['/MACHINE:' + self.machine, '/OUT:' + outputname]
def get_always_args(self) -> typing.List[str]:
return ['/nologo']
def get_search_args(self, dirname: str) -> typing.List[str]:
return ['/LIBPATH:' + dirname]
def get_std_shared_lib_args(self) -> typing.List[str]:
return ['/DLL']
def get_debugfile_args(self, targetfile: str) -> typing.List[str]:
pdbarr = targetfile.split('.')[:-1]
pdbarr += ['pdb']
return ['/DEBUG', '/PDB:' + '.'.join(pdbarr)]
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
# Only since VS2015
args = mesonlib.listify(args)
return ['/WHOLEARCHIVE:' + x for x in args]
def get_allow_undefined_args(self) -> typing.List[str]:
# link.exe
return ['/FORCE:UNRESOLVED']
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 MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
"""Microsoft's Link.exe."""
def __init__(self, for_machine: mesonlib.MachineChoice,
*, version: str = 'unknown version'):
super().__init__(['link.exe'], for_machine, 'link', version=version)
class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
"""Clang's lld-link.exe."""
def __init__(self, for_machine: mesonlib.MachineChoice,
*, version: str = 'unknown version'):
super().__init__(['lld-link.exe'], for_machine, 'lld-link',
version=version)
class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
"""Intel's Xilink.exe."""
def __init__(self, for_machine: mesonlib.MachineChoice,
*, version: str = 'unknown version'):
super().__init__(['xilink.exe'], for_machine, 'xilink', version=version)
class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker):
"""Sys-V derived linker used on Solaris and OpenSolaris."""
def get_link_whole_for(self, args: typing.List[str]) -> typing.List[str]:
if not args:
return args
return ['-Wl,--whole-archive'] + args + ['-Wl,--no-whole-archive']
def no_undefined_args(self) -> typing.List[str]:
return ['-z', 'defs']
def get_allow_undefined_args(self) -> typing.List[str]:
return ['-z', 'nodefs']
def fatal_warnings(self) -> typing.List[str]:
return ['-z', 'fatal-warnings']
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: str, build_rpath: str,
install_rpath: str) -> typing.List[str]:
if not rpath_paths and not install_rpath and not build_rpath:
return []
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths])
if build_rpath != '':
all_paths.add(build_rpath)
# In order to avoid relinking for RPATH removal, the binary needs to contain just
# enough space in the ELF header to hold the final installation RPATH.
paths = ':'.join(all_paths)
if len(paths) < len(install_rpath):
padding = 'X' * (len(install_rpath) - len(paths))
if not paths:
paths = padding
else:
paths = paths + ':' + padding
return ['-Wl,-rpath,{}'.format(paths)]
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]:
sostr = '' if soversion is None else '.' + soversion
return ['-Wl,-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)]
class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
"""Digital Mars dynamic linker for windows."""
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', version=version)
def get_allow_undefined_args(self) -> typing.List[str]:
return []

@ -636,6 +636,7 @@ def detect_tests_to_run(only: typing.List[str]) -> typing.List[typing.Tuple[str,
('fpga', 'fpga', shutil.which('yosys') is None),
('frameworks', 'frameworks', False),
('nasm', 'nasm', False),
('wasm', 'wasm', shutil.which('emcc') is None or backend is not Backend.ninja),
]
if only:

@ -444,7 +444,8 @@ class InternalTests(unittest.TestCase):
def test_compiler_args_class_gnuld(self):
cargsfunc = mesonbuild.compilers.CompilerArgs
## Test --start/end-group
gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False, MachineChoice.HOST)
linker = mesonbuild.linkers.GnuDynamicLinker([], MachineChoice.HOST, 'fake')
gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False, MachineChoice.HOST, linker=linker)
## Test that 'direct' append and extend works
l = cargsfunc(gcc, ['-Lfoodir', '-lfoo'])
self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group'])
@ -5032,7 +5033,7 @@ class LinuxlikeTests(BasePlatformTests):
raise unittest.SkipTest('-fsanitize=address is not supported on OpenBSD')
testdir = os.path.join(self.common_test_dir, '13 pch')
self.init(testdir, extra_args=['-Db_sanitize=address'])
self.init(testdir, extra_args=['-Db_sanitize=address', '-Db_lundef=false'])
self.build()
compdb = self.get_compdb()
for i in compdb:
@ -5950,9 +5951,10 @@ class NativeFileTests(BasePlatformTests):
f.write("{}='{}'\n".format(k, v))
return filename
def helper_create_binary_wrapper(self, binary, dir_=None, **kwargs):
def helper_create_binary_wrapper(self, binary, dir_=None, extra_args=None, **kwargs):
"""Creates a wrapper around a binary that overrides specific values."""
filename = os.path.join(dir_ or self.builddir, 'binary_wrapper{}.py'.format(self.current_wrapper))
extra_args = extra_args or {}
self.current_wrapper += 1
if is_haiku():
chbang = '#!/bin/env python3'
@ -5969,10 +5971,10 @@ class NativeFileTests(BasePlatformTests):
def main():
parser = argparse.ArgumentParser()
'''.format(chbang)))
for name in kwargs:
for name in chain(extra_args, kwargs):
f.write(' parser.add_argument("-{0}", "--{0}", action="store_true")\n'.format(name))
f.write(' args, extra_args = parser.parse_known_args()\n')
for name, value in kwargs.items():
for name, value in chain(extra_args.items(), kwargs.items()):
f.write(' if args.{}:\n'.format(name))
f.write(' print("{}", file=sys.{})\n'.format(value, kwargs.get('outfile', 'stdout')))
f.write(' sys.exit(0)\n')
@ -6223,7 +6225,8 @@ class NativeFileTests(BasePlatformTests):
@skip_if_not_language('swift')
def test_swift_compiler(self):
wrapper = self.helper_create_binary_wrapper(
'swiftc', version='Swift 1.2345', outfile='stderr')
'swiftc', version='Swift 1.2345', outfile='stderr',
extra_args={'Xlinker': 'macosx_version. PROJECT:ld - 1.2.3'})
env = get_fake_env()
env.binaries.host.binaries['swift'] = wrapper
compiler = env.detect_swift_compiler(MachineChoice.HOST)

@ -9,6 +9,11 @@ project('shared module resolving symbol in executable', 'c')
# See testcase 125 for an example of the more complex portability gymnastics
# required if we do not know (at link-time) what provides the symbol.
cc = meson.get_compiler('c')
if cc.get_id() == 'pgi'
error('MESON_SKIP_TEST PGI has its own unique set of macros that would need to be handled')
endif
dl = meson.get_compiler('c').find_library('dl', required: false)
e = executable('prog', 'prog.c', dependencies: dl, export_dynamic: true)
m = shared_module('module', 'module.c', link_with: e)

@ -8,15 +8,16 @@ if cc.get_argument_syntax() == 'msvc'
useless = '/DEBUG'
isnt_arg = '/iambroken'
else
is_arg = '-Wl,-Lfoo'
useless = '-Wl,-Lbar'
is_arg = '-Wl,-L/tmp'
useless = '-Wl,-L/usr'
isnt_arg = '-Wl,-iambroken'
endif
assert(cc.has_link_argument(is_arg), 'Arg that should have worked does not work.')
assert(not cc.has_link_argument(isnt_arg), 'Arg that should be broken is not.')
assert(cpp.has_link_argument(is_arg), 'Arg that should have worked does not work.')
if cc.get_id() != 'pgi'
assert(not cc.has_link_argument(isnt_arg), 'Arg that should be broken is not.')
assert(not cpp.has_link_argument(isnt_arg), 'Arg that should be broken is not.')
assert(cc.get_supported_link_arguments([is_arg, isnt_arg, useless]) == [is_arg, useless], 'Arg filtering returned different result.')
@ -38,7 +39,9 @@ assert(l1.get(0) == is_arg, 'First supported returned wrong argument.')
assert(l2.length() == 0, 'First supported did not return empty array.')
assert(not cc.has_multi_link_arguments([isnt_arg, is_arg]), 'Arg that should be broken is not.')
assert(cc.has_multi_link_arguments(is_arg), 'Arg that should have worked does not work.')
assert(cc.has_multi_link_arguments([useless, is_arg]), 'Arg that should have worked does not work.')
assert(not cc.has_link_argument('-Wl,-z,nodelete42'), 'Did not detect wrong -z linker argument')
endif
assert(cc.has_multi_link_arguments(is_arg), 'Arg that should have worked does not work.')
assert(cc.has_multi_link_arguments([useless, is_arg]), 'Arg that should have worked does not work.')

@ -19,6 +19,10 @@ project('gcc func attributes', ['c', 'cpp'])
c = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')
if c.get_id() == 'pgi'
error('MESON_SKIP_TEST: PGI supports its own set of features, will need a seperate list for PGI to test it.')
endif
expected_result = not ['msvc', 'clang-cl', 'intel-cl'].contains(c.get_id())
# Q: Why is ifunc not in this list or any of the below lists?

Loading…
Cancel
Save