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.py324
1 files changed, 324 insertions, 0 deletions
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
new file mode 100644
index 0000000..e1d534f
--- /dev/null
+++ b/mesonbuild/compilers/d.py
@@ -0,0 +1,324 @@
+# Copyright 2012-2017 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.
+
+import os.path, subprocess
+
+from ..mesonlib import EnvironmentException, version_compare
+
+from .compilers import (
+ GCC_STANDARD,
+ d_dmd_buildtype_args,
+ d_gdc_buildtype_args,
+ d_ldc_buildtype_args,
+ get_gcc_soname_args,
+ gnu_color_args,
+ Compiler,
+ CompilerArgs,
+)
+
+class DCompiler(Compiler):
+ def __init__(self, exelist, version, is_cross):
+ self.language = 'd'
+ super().__init__(exelist, version)
+ self.id = 'unknown'
+ self.is_cross = is_cross
+
+ 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) + [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_linker_exelist(self):
+ return self.exelist[:]
+
+ def get_preprocess_only_args(self):
+ return ['-E']
+
+ 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 'dep'
+
+ def get_pic_args(self):
+ return ['-fPIC']
+
+ def get_std_shared_lib_link_args(self):
+ return ['-shared']
+
+ def get_soname_args(self, prefix, shlib_name, suffix, path, soversion, is_shared_module):
+ # FIXME: Make this work for Windows, MacOS and cross-compiling
+ return get_gcc_soname_args(GCC_STANDARD, prefix, shlib_name, suffix, path, soversion, is_shared_module)
+
+ def get_unittest_args(self):
+ return ['-unittest']
+
+ 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, install_rpath):
+ # This method is to be used by LDC and DMD.
+ # GDC can deal with the verbatim flags.
+ if not rpath_paths and not install_rpath:
+ return []
+ paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths])
+ if len(paths) < len(install_rpath):
+ padding = 'X' * (len(install_rpath) - len(paths))
+ if not paths:
+ paths = padding
+ else:
+ paths = paths + ':' + padding
+ return ['-L-rpath={}'.format(paths)]
+
+ def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'):
+ 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.external_args[self.language]
+ elif mode == 'link':
+ # Add LDFLAGS from the env
+ args += env.coredata.external_link_args[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.compile(code, args, mode) as p:
+ return p.returncode == 0
+
+ def has_multi_arguments(self, args, env):
+ return self.compiles('int i;\n', env, extra_args=args)
+
+ @classmethod
+ def translate_args_to_nongnu(cls, args):
+ dcargs = []
+ # Translate common arguments to flags the LDC/DMD compilers
+ # can understand.
+ # The flags might have been added by pkg-config files,
+ # and are therefore out of the user's control.
+ for arg in args:
+ if arg == '-pthread':
+ continue
+ if arg.startswith('-Wl,'):
+ linkargs = arg[arg.index(',') + 1:].split(',')
+ for la in linkargs:
+ dcargs.append('-L' + la.strip())
+ continue
+ elif arg.startswith('-l'):
+ # translate library link flag
+ dcargs.append('-L' + arg)
+ continue
+ elif arg.startswith('-L/') or arg.startswith('-L./'):
+ # we need to handle cases where -L is set by e.g. a pkg-config
+ # setting to select a linker search path. We can however not
+ # unconditionally prefix '-L' with '-L' because the user might
+ # have set this flag too to do what it is intended to for this
+ # compiler (pass flag through to the linker)
+ # Hence, we guess here whether the flag was intended to pass
+ # a linker search path.
+ dcargs.append('-L' + arg)
+ continue
+ dcargs.append(arg)
+
+ return dcargs
+
+
+class GnuDCompiler(DCompiler):
+ def __init__(self, exelist, version, is_cross):
+ DCompiler.__init__(self, exelist, version, is_cross)
+ self.id = 'gcc'
+ default_warn_args = ['-Wall', '-Wdeprecated']
+ self.warn_args = {'1': default_warn_args,
+ '2': default_warn_args + ['-Wextra'],
+ '3': default_warn_args + ['-Wextra', '-Wpedantic']}
+ self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic']
+
+ def get_colorout_args(self, colortype):
+ if version_compare(self.version, '>=4.9.0'):
+ return gnu_color_args[colortype][:]
+ return []
+
+ def get_dependency_gen_args(self, outtarget, outfile):
+ return ['-fmake-deps=' + 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]
+
+ 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_buildtype_args(self, buildtype):
+ return d_gdc_buildtype_args[buildtype]
+
+ def build_rpath_args(self, build_dir, from_dir, rpath_paths, install_rpath):
+ return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, install_rpath)
+
+ def get_unittest_args(self):
+ return ['-funittest']
+
+
+class LLVMDCompiler(DCompiler):
+ def __init__(self, exelist, version, is_cross):
+ DCompiler.__init__(self, exelist, version, is_cross)
+ self.id = 'llvm'
+ self.base_options = ['b_coverage', 'b_colorout']
+
+ def get_colorout_args(self, colortype):
+ if colortype == 'always':
+ return ['-enable-color']
+ return []
+
+ def get_dependency_gen_args(self, outtarget, outfile):
+ # LDC using the -deps flag returns a non-Makefile dependency-info file, which
+ # the backends can not use. So we disable this feature for now.
+ return []
+
+ def get_output_args(self, target):
+ return ['-of', target]
+
+ def get_linker_output_args(self, target):
+ return ['-of', target]
+
+ def get_include_args(self, path, is_system):
+ return ['-I' + path]
+
+ def get_warn_args(self, level):
+ if level == '2' or level == '3':
+ return ['-wi', '-dw']
+ else:
+ return ['-wi']
+
+ def get_werror_args(self):
+ return ['-w']
+
+ def get_coverage_args(self):
+ return ['-cov']
+
+ def get_buildtype_args(self, buildtype):
+ return d_ldc_buildtype_args[buildtype]
+
+ def get_pic_args(self):
+ return ['-relocation-model=pic']
+
+ 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". So, the first
+ # -L is for the compiler, telling it to pass the second -L to the linker.
+ return ['-L-L' + dirname]
+
+ @classmethod
+ def unix_args_to_native(cls, args):
+ return cls.translate_args_to_nongnu(args)
+
+
+class DmdDCompiler(DCompiler):
+ def __init__(self, exelist, version, is_cross):
+ DCompiler.__init__(self, exelist, version, is_cross)
+ self.id = 'dmd'
+ self.base_options = ['b_coverage', 'b_colorout']
+
+ def get_colorout_args(self, colortype):
+ if colortype == 'always':
+ return ['-color=on']
+ return []
+
+ def get_dependency_gen_args(self, outtarget, outfile):
+ # LDC using the -deps flag returns a non-Makefile dependency-info file, which
+ # the backends can not use. So we disable this feature for now.
+ return []
+
+ def get_output_args(self, target):
+ return ['-of' + target]
+
+ def get_werror_args(self):
+ return ['-w']
+
+ def get_linker_output_args(self, target):
+ return ['-of' + target]
+
+ def get_include_args(self, path, is_system):
+ return ['-I' + path]
+
+ def get_warn_args(self, level):
+ return ['-wi']
+
+ def get_coverage_args(self):
+ return ['-cov']
+
+ 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". So, the first
+ # -L is for the compiler, telling it to pass the second -L to the linker.
+ return ['-L-L' + dirname]
+
+ def get_buildtype_args(self, buildtype):
+ return d_dmd_buildtype_args[buildtype]
+
+ def get_std_shared_lib_link_args(self):
+ return ['-shared', '-defaultlib=libphobos2.so']
+
+ @classmethod
+ def unix_args_to_native(cls, args):
+ return cls.translate_args_to_nongnu(args)