aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/compilers/d.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/compilers/d.py')
-rw-r--r--mesonbuild/compilers/d.py335
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'