aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2019-08-20 23:14:05 +0300
committerGitHub <noreply@github.com>2019-08-20 23:14:05 +0300
commit1ea3ddc6ad7458bbcb51704ccb5ef266c5164074 (patch)
tree62540e1b93a4844a5e5c45395a63bbfa3ec419d3
parent0384487fc52c445d005ca1ea5b2a1c83ce56200c (diff)
parent142012ab73bf1cfedb59f539400f0c18df055ec8 (diff)
downloadmeson-1ea3ddc6ad7458bbcb51704ccb5ef266c5164074.zip
meson-1ea3ddc6ad7458bbcb51704ccb5ef266c5164074.tar.gz
meson-1ea3ddc6ad7458bbcb51704ccb5ef266c5164074.tar.bz2
Merge pull request #5681 from dcbaker/dynamic-linker-split
split dynamic linker representations from compilers
-rw-r--r--docs/markdown/snippets/b_lundef_on_apple.md5
-rw-r--r--docs/markdown/snippets/split-compiler-and-linker-representations.md6
-rw-r--r--mesonbuild/backend/ninjabackend.py13
-rw-r--r--mesonbuild/build.py10
-rw-r--r--mesonbuild/compilers/__init__.py3
-rw-r--r--mesonbuild/compilers/c.py36
-rw-r--r--mesonbuild/compilers/compilers.py264
-rw-r--r--mesonbuild/compilers/cpp.py30
-rw-r--r--mesonbuild/compilers/cs.py16
-rw-r--r--mesonbuild/compilers/cuda.py65
-rw-r--r--mesonbuild/compilers/d.py335
-rw-r--r--mesonbuild/compilers/fortran.py20
-rw-r--r--mesonbuild/compilers/java.py18
-rw-r--r--mesonbuild/compilers/mixins/arm.py60
-rw-r--r--mesonbuild/compilers/mixins/ccrx.py43
-rw-r--r--mesonbuild/compilers/mixins/clike.py72
-rw-r--r--mesonbuild/compilers/mixins/gnu.py123
-rw-r--r--mesonbuild/compilers/mixins/intel.py3
-rw-r--r--mesonbuild/compilers/mixins/islinker.py124
-rw-r--r--mesonbuild/compilers/mixins/pgi.py32
-rw-r--r--mesonbuild/compilers/mixins/visualstudio.py69
-rw-r--r--mesonbuild/compilers/objc.py12
-rw-r--r--mesonbuild/compilers/objcpp.py12
-rw-r--r--mesonbuild/compilers/rust.py15
-rw-r--r--mesonbuild/compilers/swift.py16
-rw-r--r--mesonbuild/environment.py246
-rw-r--r--mesonbuild/interpreter.py4
-rw-r--r--mesonbuild/linkers.py698
-rwxr-xr-xrun_project_tests.py1
-rwxr-xr-xrun_unittests.py15
-rw-r--r--test cases/common/152 shared module resolving symbol in executable/meson.build5
-rw-r--r--test cases/common/185 has link arg/meson.build15
-rw-r--r--test cases/common/203 function attributes/meson.build4
33 files changed, 1464 insertions, 926 deletions
diff --git a/docs/markdown/snippets/b_lundef_on_apple.md b/docs/markdown/snippets/b_lundef_on_apple.md
new file mode 100644
index 0000000..850a412
--- /dev/null
+++ b/docs/markdown/snippets/b_lundef_on_apple.md
@@ -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 \ No newline at end of file
diff --git a/docs/markdown/snippets/split-compiler-and-linker-representations.md b/docs/markdown/snippets/split-compiler-and-linker-representations.md
new file mode 100644
index 0000000..fd2e622
--- /dev/null
+++ b/docs/markdown/snippets/split-compiler-and-linker-representations.md
@@ -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. \ No newline at end of file
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index eb28f1a..82e70c9 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -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,
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index eab2057..49ec8e8 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -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
diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py
index 5cd56b8..c81fe75 100644
--- a/mesonbuild/compilers/__init__.py
+++ b/mesonbuild/compilers/__init__.py
@@ -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
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index f50b77c..1ec9146 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -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']
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 5249068..f16e447 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -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
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index 5808b2e..f93db3e 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -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 []
diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py
index 8069ab1..7c884c9 100644
--- a/mesonbuild/compilers/cs.py
+++ b/mesonbuild/compilers/cs.py
@@ -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',
diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py
index 152c8ba..b6bafe7 100644
--- a/mesonbuild/compilers/cuda.py
+++ b/mesonbuild/compilers/cuda.py
@@ -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 []
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 1a37c63..18e3bf9 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -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'
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index c10e2ca..30ec6fe 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -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']
diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py
index ea1fa0f..fb1a190 100644
--- a/mesonbuild/compilers/java.py
+++ b/mesonbuild/compilers/java.py
@@ -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 []
diff --git a/mesonbuild/compilers/mixins/arm.py b/mesonbuild/compilers/mixins/arm.py
index 02654ce..fca3d66 100644
--- a/mesonbuild/compilers/mixins/arm.py
+++ b/mesonbuild/compilers/mixins/arm.py
@@ -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':
diff --git a/mesonbuild/compilers/mixins/ccrx.py b/mesonbuild/compilers/mixins/ccrx.py
index 48b5ed1..4de06fd 100644
--- a/mesonbuild/compilers/mixins/ccrx.py
+++ b/mesonbuild/compilers/mixins/ccrx.py
@@ -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]
diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py
index 37d2424..3af1768 100644
--- a/mesonbuild/compilers/mixins/clike.py
+++ b/mesonbuild/compilers/mixins/clike.py
@@ -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')
diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py
index 9756604..757dc65 100644
--- a/mesonbuild/compilers/mixins/gnu.py
+++ b/mesonbuild/compilers/mixins/gnu.py
@@ -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):
diff --git a/mesonbuild/compilers/mixins/intel.py b/mesonbuild/compilers/mixins/intel.py
index 7fadb50..d7e1b21 100644
--- a/mesonbuild/compilers/mixins/intel.py
+++ b/mesonbuild/compilers/mixins/intel.py
@@ -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']
diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py
new file mode 100644
index 0000000..4c1a476
--- /dev/null
+++ b/mesonbuild/compilers/mixins/islinker.py
@@ -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 []
diff --git a/mesonbuild/compilers/mixins/pgi.py b/mesonbuild/compilers/mixins/pgi.py
index 0613e79..c13c7bc 100644
--- a/mesonbuild/compilers/mixins/pgi.py
+++ b/mesonbuild/compilers/mixins/pgi.py
@@ -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 []
diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py
index edb104d..5fe8599 100644
--- a/mesonbuild/compilers/mixins/visualstudio.py
+++ b/mesonbuild/compilers/mixins/visualstudio.py
@@ -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']
diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py
index b9ce0b1..7a778d7 100644
--- a/mesonbuild/compilers/objc.py
+++ b/mesonbuild/compilers/objc.py
@@ -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': [],
diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py
index a090bed..70a86c5 100644
--- a/mesonbuild/compilers/objcpp.py
+++ b/mesonbuild/compilers/objcpp.py
@@ -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': [],
diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py
index 665b3c2..479c5a7 100644
--- a/mesonbuild/compilers/rust.py
+++ b/mesonbuild/compilers/rust.py
@@ -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 []
diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py
index 0038264..6c639fd 100644
--- a/mesonbuild/compilers/swift.py
+++ b/mesonbuild/compilers/swift.py
@@ -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]
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index cd55ace..2630ae9 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -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):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index c102978..0fd2f06 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -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()
diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py
index dc9a825..a641cd0 100644
--- a/mesonbuild/linkers.py
+++ b/mesonbuild/linkers.py
@@ -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 []
diff --git a/run_project_tests.py b/run_project_tests.py
index 88d6a57..2dff885 100755
--- a/run_project_tests.py
+++ b/run_project_tests.py
@@ -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:
diff --git a/run_unittests.py b/run_unittests.py
index 26850b7..c79b4e2 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -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)
diff --git a/test cases/common/152 shared module resolving symbol in executable/meson.build b/test cases/common/152 shared module resolving symbol in executable/meson.build
index 282a4d2..4e5188f 100644
--- a/test cases/common/152 shared module resolving symbol in executable/meson.build
+++ b/test cases/common/152 shared module resolving symbol in executable/meson.build
@@ -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)
diff --git a/test cases/common/185 has link arg/meson.build b/test cases/common/185 has link arg/meson.build
index 10f2218..6bfbd59 100644
--- a/test cases/common/185 has link arg/meson.build
+++ b/test cases/common/185 has link arg/meson.build
@@ -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.')
diff --git a/test cases/common/203 function attributes/meson.build b/test cases/common/203 function attributes/meson.build
index 58ac7c8..43ed011 100644
--- a/test cases/common/203 function attributes/meson.build
+++ b/test cases/common/203 function attributes/meson.build
@@ -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?