diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2019-08-20 23:14:05 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-20 23:14:05 +0300 |
commit | 1ea3ddc6ad7458bbcb51704ccb5ef266c5164074 (patch) | |
tree | 62540e1b93a4844a5e5c45395a63bbfa3ec419d3 /mesonbuild/compilers/d.py | |
parent | 0384487fc52c445d005ca1ea5b2a1c83ce56200c (diff) | |
parent | 142012ab73bf1cfedb59f539400f0c18df055ec8 (diff) | |
download | meson-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
Diffstat (limited to 'mesonbuild/compilers/d.py')
-rw-r--r-- | mesonbuild/compilers/d.py | 335 |
1 files changed, 201 insertions, 134 deletions
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' |