From f41a95ddf28317abf9b58f913e1650a006c26c76 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 3 Nov 2023 15:12:24 -0400 Subject: [PATCH] compilers: Every compiler can run code Compiling and linking code is part of the Compiler base class, there is no reason it cannot also run executables. --- docs/markdown/snippets/compiler_run.md | 4 ++++ mesonbuild/compilers/compilers.py | 25 +++++++++++++++++++++++-- mesonbuild/compilers/d.py | 26 ++------------------------ mesonbuild/compilers/mixins/clike.py | 26 -------------------------- mesonbuild/interpreter/compiler.py | 3 +++ test cases/rust/1 basic/meson.build | 3 +++ 6 files changed, 35 insertions(+), 52 deletions(-) create mode 100644 docs/markdown/snippets/compiler_run.md diff --git a/docs/markdown/snippets/compiler_run.md b/docs/markdown/snippets/compiler_run.md new file mode 100644 index 000000000..f4b0847a5 --- /dev/null +++ b/docs/markdown/snippets/compiler_run.md @@ -0,0 +1,4 @@ +## compiler.run() method is now available for all languages + +It used to be only implemented for C-like and D languages, but it is now available +for all languages. diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 8bc1294f8..faa147ad7 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -623,10 +623,31 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta): dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]: raise EnvironmentException('Language %s does not support header symbol checks.' % self.get_display_language()) - def run(self, code: 'mesonlib.FileOrString', env: 'Environment', *, + 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) -> RunResult: - raise EnvironmentException('Language %s does not support run checks.' % self.get_display_language()) + need_exe_wrapper = env.need_exe_wrapper(self.for_machine) + if need_exe_wrapper and self.exe_wrapper is None: + raise CrossNoRunException('Can not run test applications in this cross environment.') + with self._build_wrapper(code, env, extra_args, dependencies, mode=CompileCheckMode.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 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 RunResult(False) + + mlog.debug('Program stdout:\n') + mlog.debug(so) + mlog.debug('Program stderr:\n') + mlog.debug(se) + return RunResult(True, pe.returncode, so, se) # Caching run() in general seems too risky (no way to know what the program # depends on), but some callers know more about the programs they intend to diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 32f6d04ed..0ebeef4be 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -9,7 +9,6 @@ import subprocess import typing as T from .. import mesonlib -from .. import mlog from ..arglist import CompilerArgs from ..linkers import RSPFileSyntax from ..mesonlib import ( @@ -571,32 +570,11 @@ class DCompiler(Compiler): args.append(extra_args) return args - def run(self, code: 'mesonlib.FileOrString', env: 'Environment', *, + 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=CompileCheckMode.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) + return super().run(code, env, extra_args, dependencies) def sizeof(self, typename: str, prefix: str, env: 'Environment', *, extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None, diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index 5e6adedcf..eb3a4f150 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -459,32 +459,6 @@ class CLikeCompiler(Compiler): args = cargs + extra_args + largs 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.') - with self._build_wrapper(code, env, extra_args, dependencies, mode=CompileCheckMode.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 _compile_int(self, expression: str, prefix: str, env: 'Environment', extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], dependencies: T.Optional[T.List['Dependency']]) -> bool: diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index 0cd6aecf3..0f91ba1e0 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -302,6 +302,9 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.run', (str, mesonlib.File)) @typed_kwargs('compiler.run', *_COMPILES_KWS) def run_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> 'RunResult': + if self.compiler.language not in {'d', 'c', 'cpp', 'objc', 'objcpp'}: + FeatureNew.single_use(f'compiler.run for {self.compiler.get_display_language()} language', + '1.5.0', self.subproject, location=self.current_node) code = args[0] if isinstance(code, mesonlib.File): self.interpreter.add_build_def_file(code) diff --git a/test cases/rust/1 basic/meson.build b/test cases/rust/1 basic/meson.build index 3ba987710..f422beb74 100644 --- a/test cases/rust/1 basic/meson.build +++ b/test cases/rust/1 basic/meson.build @@ -18,3 +18,6 @@ test( ), should_fail : true, ) + +rustc = meson.get_compiler('rust') +assert(rustc.run('fn main(){}').returncode() == 0)