aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/compilers/d.py
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2019-07-25 08:37:30 -0700
committerDylan Baker <dylan@pnwbakers.com>2019-08-14 13:13:22 -0700
commit90e43dbdfe06d062939803ec4ee261315096aee7 (patch)
tree439410e93cd78d206c1a2f16e2bc809f734747e4 /mesonbuild/compilers/d.py
parenta6ab28b1992cb1afb7f68b2d2b835dc74dd97c88 (diff)
downloadmeson-90e43dbdfe06d062939803ec4ee261315096aee7.zip
meson-90e43dbdfe06d062939803ec4ee261315096aee7.tar.gz
meson-90e43dbdfe06d062939803ec4ee261315096aee7.tar.bz2
re-architect the D compiler abstractions
We support 3 D compilers, DMD, LDC, and GDC. DMD is the reference compiler, and LDC attempts to largely mirror it's command line usage. GDC does not, it instead acts like GCC (which makes sense). The current abstraction puts DMD behavior in the base D compiler and then overrides then in the GnuDCompiler class. This is messy, but it becomes more problematic when splitting the linker and compiler abstractions apart. I've opted to instead split the DCompiler class into two separate classes. The DCompiler implements core D functinoality, and DmdLikeCompilerMixin, which implements the DMD and LDC command line arguments. I've then mxed that into the DmdDCompiler and LLVMDCompiler classes, and mixed the GnuCompiler into the GnuDCompiler class to get Gnu command line behavior.
Diffstat (limited to 'mesonbuild/compilers/d.py')
-rw-r--r--mesonbuild/compilers/d.py412
1 files changed, 197 insertions, 215 deletions
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 1a37c63..27ca6fc 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -27,7 +27,7 @@ from .compilers import (
Compiler,
CompilerArgs,
)
-from .mixins.gnu import get_gcc_soname_args, gnu_color_args, gnu_optimization_args
+from .mixins.gnu import get_gcc_soname_args, GnuCompiler
d_feature_args = {'gcc': {'unittest': '-funittest',
'debug': '-fdebug',
@@ -62,44 +62,11 @@ 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
+class DmdLikeCompilerMixin:
def get_linker_exelist(self):
- return self.exelist[:]
+ return self.get_exelist()
def get_output_args(self, target):
return ['-of=' + target]
@@ -147,20 +114,6 @@ class DCompiler(Compiler):
def get_compile_only_args(self):
return ['-c']
- 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_std_shared_lib_link_args(self):
- return ['-shared']
-
def get_soname_args(self, *args):
# FIXME: Make this work for cross-compiling
if is_windows():
@@ -173,96 +126,6 @@ class DCompiler(Compiler):
return get_gcc_soname_args(CompilerType.GCC_STANDARD, *args)
- 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 gen_import_library_args(self, implibname):
return ['-Wl,--out-implib=' + implibname]
@@ -285,54 +148,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 +295,189 @@ class DCompiler(Compiler):
assert(buildtype == 'custom')
raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".')
+
+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_std_shared_lib_link_args(self):
+ return ['-shared']
+
+ 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 +487,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 +509,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 +533,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, 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 +572,7 @@ class LLVMDCompiler(DCompiler):
return ldc_optimization_args[optimization_level]
-class DmdDCompiler(DCompiler):
+class DmdDCompiler(DmdLikeCompilerMixin, DCompiler):
def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs):
DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs)
self.id = 'dmd'