diff options
author | Remi Thebault <remi.thebault@gmail.com> | 2022-03-11 22:46:09 +0100 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2022-04-30 10:07:38 -0400 |
commit | f24ad87e05400a67d5b47525b24281857c1f671c (patch) | |
tree | 537bb86274b19349637547603bbbee99862fe37e | |
parent | c16fdaeecafe94461d6048b90bd337a04c25ad3c (diff) | |
download | meson-f24ad87e05400a67d5b47525b24281857c1f671c.zip meson-f24ad87e05400a67d5b47525b24281857c1f671c.tar.gz meson-f24ad87e05400a67d5b47525b24281857c1f671c.tar.bz2 |
implement and test a few compiler checks for D
- run
- sizeof
- alignment
- has_header
-rw-r--r-- | mesonbuild/compilers/d.py | 101 | ||||
-rw-r--r-- | test cases/d/15 compiler run checks/meson.build | 50 | ||||
-rw-r--r-- | test cases/d/15 compiler run checks/test_sizeof.d | 17 |
3 files changed, 166 insertions, 2 deletions
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index ec0b155..35ab024 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -17,22 +17,27 @@ import re import subprocess import typing as T +from .. import mesonlib +from .. import mlog +from ..arglist import CompilerArgs +from ..linkers import RSPFileSyntax from ..mesonlib import ( EnvironmentException, MachineChoice, version_compare, OptionKey, is_windows ) -from ..arglist import CompilerArgs -from ..linkers import RSPFileSyntax +from . import compilers from .compilers import ( d_dmd_buildtype_args, d_gdc_buildtype_args, d_ldc_buildtype_args, clike_debug_args, Compiler, + CompileCheckMode, ) from .mixins.gnu import GnuCompiler if T.TYPE_CHECKING: + from ..dependencies import Dependency from ..programs import ExternalProgram from ..envconfig import MachineInfo from ..environment import Environment @@ -678,6 +683,98 @@ class DCompiler(Compiler): def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]: return [] + def _get_compile_extra_args(self, extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None) -> T.List[str]: + args = self._get_target_arch_args() + if extra_args: + if callable(extra_args): + extra_args = extra_args(CompileCheckMode.COMPILE) + if isinstance(extra_args, list): + args.extend(extra_args) + elif isinstance(extra_args, str): + args.append(extra_args) + return args + + def run(self, code: 'mesonlib.FileOrString', env: 'Environment', *, + extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> compilers.RunResult: + need_exe_wrapper = env.need_exe_wrapper(self.for_machine) + if need_exe_wrapper and self.exe_wrapper is None: + raise compilers.CrossNoRunException('Can not run test applications in this cross environment.') + extra_args = self._get_compile_extra_args(extra_args) + with self._build_wrapper(code, env, extra_args, dependencies, mode='link', want_output=True) as p: + if p.returncode != 0: + mlog.debug(f'Could not compile test file {p.input_name}: {p.returncode}\n') + return compilers.RunResult(False) + if need_exe_wrapper: + cmdlist = self.exe_wrapper.get_command() + [p.output_name] + else: + cmdlist = [p.output_name] + try: + pe, so, se = mesonlib.Popen_safe(cmdlist) + except Exception as e: + mlog.debug(f'Could not run: {cmdlist} (error: {e})\n') + return compilers.RunResult(False) + + mlog.debug('Program stdout:\n') + mlog.debug(so) + mlog.debug('Program stderr:\n') + mlog.debug(se) + return compilers.RunResult(True, pe.returncode, so, se) + + def sizeof(self, typename: str, prefix: str, env: 'Environment', *, + extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> int: + if extra_args is None: + extra_args = [] + t = f''' + import std.stdio : writeln; + {prefix} + void main() {{ + writeln(({typename}).sizeof); + }} + ''' + res = self.run(t, env, extra_args=extra_args, + dependencies=dependencies) + if not res.compiled: + return -1 + if res.returncode != 0: + raise mesonlib.EnvironmentException('Could not run sizeof test binary.') + return int(res.stdout) + + def alignment(self, typename: str, prefix: str, env: 'Environment', *, + extra_args: T.Optional[T.List[str]] = None, + dependencies: T.Optional[T.List['Dependency']] = None) -> int: + if extra_args is None: + extra_args = [] + t = f''' + import std.stdio : writeln; + {prefix} + void main() {{ + writeln(({typename}).alignof); + }} + ''' + res = self.run(t, env, extra_args=extra_args, + dependencies=dependencies) + if not res.compiled: + raise mesonlib.EnvironmentException('Could not compile alignment test.') + if res.returncode != 0: + raise mesonlib.EnvironmentException('Could not run alignment test binary.') + align = int(res.stdout) + if align == 0: + raise mesonlib.EnvironmentException(f'Could not determine alignment of {typename}. Sorry. You might want to file a bug.') + return align + + def has_header(self, hname: str, prefix: str, env: 'Environment', *, + extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None, + dependencies: T.Optional[T.List['Dependency']] = None, + disable_cache: bool = False) -> T.Tuple[bool, bool]: + + extra_args = self._get_compile_extra_args(extra_args) + code = f'''{prefix} + import {hname}; + ''' + return self.compiles(code, env, extra_args=extra_args, + dependencies=dependencies, mode='compile', disable_cache=disable_cache) class GnuDCompiler(GnuCompiler, DCompiler): diff --git a/test cases/d/15 compiler run checks/meson.build b/test cases/d/15 compiler run checks/meson.build new file mode 100644 index 0000000..a80e528 --- /dev/null +++ b/test cases/d/15 compiler run checks/meson.build @@ -0,0 +1,50 @@ +project('test-d-run-checks', 'd') + +dc = meson.get_compiler('d') + +run_sizeof = dc.run('int main() { return (void*).sizeof; }') +if run_sizeof.returncode() == 8 + run_versions = ['Is64bits'] +elif run_sizeof.returncode() == 4 + run_versions = ['Is32bits'] +endif +run_sizeof_exe = executable('run_sizeof', 'test_sizeof.d', + d_module_versions: run_versions, +) +test('test D compiler run', run_sizeof_exe) + +sizeof_sizeof = dc.sizeof('void*') +if sizeof_sizeof == 8 + run_versions = ['Is64bits'] +elif sizeof_sizeof == 4 + run_versions = ['Is32bits'] +endif +sizeof_sizeof_exe = executable('sizeof_sizeof', 'test_sizeof.d', + d_module_versions: run_versions, +) +test('test D compiler sizeof', sizeof_sizeof_exe) + +if not dc.has_header('std.stdio') + error('Could not find std.stdio import') +endif + +if dc.has_header('not_a_d_module') + error('has_header inconsistent result') +endif + +# same checks as C/C++ alignments (D has same alignment requirements as C) + +# These tests should return the same value on all +# platforms. If (and when) they don't, fix 'em up. +if dc.alignment('char') != 1 +error('Alignment of char misdetected.') +endif + +dbl_alignment = dc.alignment('double') + +if dbl_alignment == 8 or dbl_alignment == 4 +message('Alignment of double ok.') +else +error('Alignment of double misdetected.') +endif + diff --git a/test cases/d/15 compiler run checks/test_sizeof.d b/test cases/d/15 compiler run checks/test_sizeof.d new file mode 100644 index 0000000..c7099d0 --- /dev/null +++ b/test cases/d/15 compiler run checks/test_sizeof.d @@ -0,0 +1,17 @@ +module test_sizeof; + +alias voidp = void*; + +int main() +{ + version(Is64bits) { + enum expectedSz = 8; + } + else version(Is32bits) { + enum expectedSz = 4; + } + else { + assert(false, "No version set!"); + } + return expectedSz == voidp.sizeof ? 0 : 1; +} |