summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/compilers/asm.py7
-rw-r--r--mesonbuild/compilers/c.py5
-rw-r--r--mesonbuild/compilers/compilers.py100
-rw-r--r--mesonbuild/compilers/cpp.py5
-rw-r--r--mesonbuild/compilers/cs.py34
-rw-r--r--mesonbuild/compilers/cuda.py114
-rw-r--r--mesonbuild/compilers/cython.py23
-rw-r--r--mesonbuild/compilers/d.py22
-rw-r--r--mesonbuild/compilers/fortran.py11
-rw-r--r--mesonbuild/compilers/java.py40
-rw-r--r--mesonbuild/compilers/mixins/clike.py51
-rw-r--r--mesonbuild/compilers/objc.py5
-rw-r--r--mesonbuild/compilers/objcpp.py5
-rw-r--r--mesonbuild/compilers/rust.py63
-rw-r--r--mesonbuild/compilers/swift.py27
-rw-r--r--mesonbuild/compilers/vala.py29
-rw-r--r--mesonbuild/dependencies/base.py7
17 files changed, 284 insertions, 264 deletions
diff --git a/mesonbuild/compilers/asm.py b/mesonbuild/compilers/asm.py
index d4af77f89..5f065e193 100644
--- a/mesonbuild/compilers/asm.py
+++ b/mesonbuild/compilers/asm.py
@@ -10,6 +10,7 @@ from .mixins.metrowerks import MetrowerksCompiler, mwasmarm_instruction_set_args
from .mixins.ti import TICompiler
if T.TYPE_CHECKING:
+ from ..environment import Environment
from ..linkers.linkers import DynamicLinker
from ..mesonlib import MachineChoice
from ..envconfig import MachineInfo
@@ -39,6 +40,12 @@ class ASMCompiler(Compiler):
raise EnvironmentException(f'ASM Compiler {self.id} does not support building for {info.cpu_family} CPU family.')
super().__init__(ccache, exelist, version, for_machine, info, linker, full_version, is_cross)
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ return []
+
+ def _sanity_check_source_code(self) -> str:
+ return ''
+
class NasmCompiler(ASMCompiler):
language = 'nasm'
diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py
index 424b61251..a0786d55c 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -76,9 +76,8 @@ class CCompiler(CLikeCompiler, Compiler):
def get_no_stdinc_args(self) -> T.List[str]:
return ['-nostdinc']
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- code = 'int main(void) { int class=0; return class; }\n'
- return self._sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code)
+ def _sanity_check_source_code(self) -> str:
+ return 'int main(void) { int class=0; return class; }\n'
def has_header_symbol(self, hname: str, symbol: str, prefix: str,
env: 'Environment', *,
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 624226d33..4c28eb2fd 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -1196,8 +1196,7 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
def name_string(self) -> str:
return ' '.join(self.exelist)
- @abc.abstractmethod
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
+ def sanity_check(self, work_dir: str, env: Environment) -> None:
"""Check that this compiler actually works.
This should provide a simple compile/link test. Something as simple as:
@@ -1205,24 +1204,103 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
main(): return 0
```
is good enough here.
+
+ :param work_dir: A directory to put temporary artifacts
+ :param env: The :class:`environment.Environment` instance to use with
+ this check
+ :raises mesonlib.EnvironmentException: If building the binary fails
+ :raises mesonlib.EnvironmentException: If running the binary is attempted and fails
"""
+ sourcename, binname = self._sanity_check_filenames()
+ cmdlist = self._sanity_check_compile_args(env, sourcename, binname)
+
+ with open(os.path.join(work_dir, sourcename), 'w', encoding='utf-8') as f:
+ f.write(self._sanity_check_source_code())
+
+ pc, stdo, stde = mesonlib.Popen_safe(cmdlist, cwd=work_dir)
+ mlog.debug('Sanity check compiler command line:', mesonlib.join_args(cmdlist))
+ mlog.debug('Sanity check compile stdout:')
+ mlog.debug(stdo)
+ mlog.debug('-----\nSanity check compile stderr:')
+ mlog.debug(stde)
+ mlog.debug('-----')
+ if pc.returncode != 0:
+ raise mesonlib.EnvironmentException(f'Compiler {self.name_string()} cannot compile programs.')
+
+ self._run_sanity_check(env, [os.path.join(work_dir, binname)], work_dir)
+
+ def _sanity_check_filenames(self) -> T.Tuple[str, str]:
+ """Generate the name of the source and binary file for the sanity check.
+
+ The returned names should be just the names of the files with
+ extensions, but no paths.
+
+ :return: A tuple of (sourcename, binaryname)
+ """
+ default_ext = lang_suffixes[self.language][0]
+ template = f'sanity_check_for_{self.language}'
+ sourcename = f'{template}.{default_ext}'
+ binaryname = f'{template}{"_cross" if self.is_cross else ""}.exe'
+ return sourcename, binaryname
+
+ @abc.abstractmethod
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ """Get arguments to run compiler for sanity check.
- def run_sanity_check(self, environment: Environment, cmdlist: T.List[str], work_dir: str, use_exe_wrapper_for_cross: bool = True) -> T.Tuple[str, str]:
- # Run sanity check
- if self.is_cross and use_exe_wrapper_for_cross:
- if not environment.has_exe_wrapper():
- # Can't check if the binaries run so we have to assume they do
- return ('', '')
- cmdlist = environment.exe_wrapper.get_command() + cmdlist
- mlog.debug('Running test binary command: ', mesonlib.join_args(cmdlist))
+ :param env: The :class:`environment.Environment` instance to use
+ :param sourcename: the name of the source file to generate
+ :param binname: the name of the binary file to generate
+ :return: a list of strings to pass to :func:`subprocess.run` or equivalent
+ """
+
+ @abc.abstractmethod
+ def _sanity_check_source_code(self) -> str:
+ """Get the source code to run for a sanity check
+
+ :return: A string to be written into a file and ran.
+ """
+
+ def _sanity_check_run_with_exe_wrapper(self, env: Environment, command: T.List[str]) -> T.List[str]:
+ """Wrap the binary to run in the test with the exe_wrapper if necessary
+
+ Languages that do no want to use an exe_wrapper (or always want to use
+ some kind of wrapper) should override this method
+
+ :param env: the :class:`environment.Environment` instance to use
+ :param command: The string list of commands to run
+ :return: The list of commands wrapped by the exe_wrapper if it is needed, otherwise the original commands
+ """
+ if self.is_cross and env.has_exe_wrapper():
+ assert env.exe_wrapper is not None, 'for mypy'
+ return env.exe_wrapper.get_command() + command
+ return command
+
+ def _run_sanity_check(self, env: Environment, cmdlist: T.List[str], work_dir: str) -> None:
+ """Run a sanity test binary
+
+ :param env: the :class:`environment.Environment` instance to use
+ :param cmdlist: A list of strings to pass to :func:`subprocess.run` or equivalent to run the test
+ :param work_dir: A directory to place temporary artifacts
+ :raises mesonlib.EnvironmentException: If the binary cannot be run or if it returns a non-zero exit code
+ """
+ # Can't check binaries, so we have to assume they work
+ if self.is_cross and not env.has_exe_wrapper():
+ mlog.debug('Cannot run cross check')
+ return
+
+ cmdlist = self._sanity_check_run_with_exe_wrapper(env, cmdlist)
+ mlog.debug('Sanity check built target output for', self.for_machine, self.language, 'compiler')
+ mlog.debug(' -- Running test binary command: ', mesonlib.join_args(cmdlist))
try:
pe, stdo, stde = Popen_safe_logged(cmdlist, 'Sanity check', cwd=work_dir)
+ mlog.debug(' -- stdout:\n', stdo)
+ mlog.debug(' -- stderr:\n', stde)
+ mlog.debug(' -- returncode:', pe.returncode)
except Exception as e:
raise mesonlib.EnvironmentException(f'Could not invoke sanity check executable: {e!s}.')
if pe.returncode != 0:
raise mesonlib.EnvironmentException(f'Executables created by {self.language} compiler {self.name_string()} are not runnable.')
- return stdo, stde
def split_shlib_to_parts(self, fname: str) -> T.Tuple[T.Optional[str], str]:
return None, fname
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index fa032ec79..8da100483 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -86,9 +86,8 @@ class CPPCompiler(CLikeCompiler, Compiler):
def get_no_stdlib_link_args(self) -> T.List[str]:
return ['-nostdlib++']
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- code = 'class breakCCompiler;int main(void) { return 0; }\n'
- return self._sanity_check_impl(work_dir, environment, 'sanitycheckcpp.cc', code)
+ def _sanity_check_source_code(self) -> str:
+ return 'class breakCCompiler;int main(void) { return 0; }\n'
def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
# -fpermissive allows non-conforming code to compile which is necessary
diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py
index 4bbddeb20..e515c338f 100644
--- a/mesonbuild/compilers/cs.py
+++ b/mesonbuild/compilers/cs.py
@@ -3,11 +3,10 @@
from __future__ import annotations
-import os.path, subprocess
+import os.path
import textwrap
import typing as T
-from ..mesonlib import EnvironmentException
from ..linkers import RSPFileSyntax
from .compilers import Compiler
@@ -83,26 +82,21 @@ class CsCompiler(BasicLinkerIsCompilerMixin, Compiler):
def get_pch_name(self, header_name: str) -> str:
return ''
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- src = 'sanity.cs'
- obj = 'sanity.exe'
- source_name = os.path.join(work_dir, src)
- with open(source_name, 'w', encoding='utf-8') as ofile:
- ofile.write(textwrap.dedent('''
- public class Sanity {
- static public void Main () {
- }
+ def _sanity_check_source_code(self) -> str:
+ return textwrap.dedent('''
+ public class Sanity {
+ static public void Main () {
}
- '''))
- pc = subprocess.Popen(self.exelist + self.get_always_args() + [src], cwd=work_dir)
- pc.wait()
- if pc.returncode != 0:
- raise EnvironmentException('C# compiler %s cannot compile programs.' % self.name_string())
+ }
+ ''')
+
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ return self.exelist + self.get_always_args() + [sourcename] + self.get_output_args(binname)
+
+ def _sanity_check_run_with_exe_wrapper(self, env: Environment, command: T.List[str]) -> T.List[str]:
if self.runner:
- cmdlist = [self.runner, obj]
- else:
- cmdlist = [os.path.join(work_dir, obj)]
- self.run_sanity_check(environment, cmdlist, work_dir, use_exe_wrapper_for_cross=False)
+ return [self.runner] + command
+ return command
def needs_static_linker(self) -> bool:
return False
diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py
index 7e050f140..a9e6a7669 100644
--- a/mesonbuild/compilers/cuda.py
+++ b/mesonbuild/compilers/cuda.py
@@ -5,15 +5,14 @@
from __future__ import annotations
import enum
-import os.path
import string
import typing as T
from .. import options
from .. import mlog
+from .. import mesonlib
from ..mesonlib import (
- EnvironmentException, Popen_safe,
- is_windows, LibType, version_compare
+ EnvironmentException, is_windows, LibType, version_compare
)
from .compilers import Compiler, CompileCheckMode
@@ -187,6 +186,7 @@ class CudaCompiler(Compiler):
host_compiler: Compiler, info: 'MachineInfo',
linker: T.Optional['DynamicLinker'] = None,
full_version: T.Optional[str] = None):
+ self.detected_cc = ''
super().__init__(ccache, exelist, version, for_machine, info, linker=linker, full_version=full_version, is_cross=is_cross)
self.host_compiler = host_compiler
self.base_options = host_compiler.base_options
@@ -499,55 +499,36 @@ class CudaCompiler(Compiler):
def thread_link_flags(self, environment: 'Environment') -> T.List[str]:
return self._to_host_flags(self.host_compiler.thread_link_flags(environment), Phase.LINKER)
- def sanity_check(self, work_dir: str, env: 'Environment') -> None:
- mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist))
- mlog.debug('Is cross compiler: %s.' % str(self.is_cross))
-
- sname = 'sanitycheckcuda.cu'
- code = r'''
- #include <cuda_runtime.h>
- #include <stdio.h>
-
- __global__ void kernel (void) {}
-
- int main(void){
- struct cudaDeviceProp prop;
- int count, i;
- cudaError_t ret = cudaGetDeviceCount(&count);
- if(ret != cudaSuccess){
- fprintf(stderr, "%d\n", (int)ret);
- }else{
- for(i=0;i<count;i++){
- if(cudaGetDeviceProperties(&prop, i) == cudaSuccess){
- fprintf(stdout, "%d.%d\n", prop.major, prop.minor);
+ def _sanity_check_source_code(self) -> str:
+ return r'''
+ #include <cuda_runtime.h>
+ #include <stdio.h>
+
+ __global__ void kernel (void) {}
+
+ int main(void){
+ struct cudaDeviceProp prop;
+ int count, i;
+ cudaError_t ret = cudaGetDeviceCount(&count);
+ if(ret != cudaSuccess){
+ fprintf(stderr, "%d\n", (int)ret);
+ }else{
+ for(i=0;i<count;i++){
+ if(cudaGetDeviceProperties(&prop, i) == cudaSuccess){
+ fprintf(stdout, "%d.%d\n", prop.major, prop.minor);
+ }
}
}
+ fflush(stderr);
+ fflush(stdout);
+ return 0;
}
- fflush(stderr);
- fflush(stdout);
- return 0;
- }
- '''
- binname = sname.rsplit('.', 1)[0]
- binname += '_cross' if self.is_cross else ''
- source_name = os.path.join(work_dir, sname)
- binary_name = os.path.join(work_dir, binname + '.exe')
- with open(source_name, 'w', encoding='utf-8') as ofile:
- ofile.write(code)
-
- # The Sanity Test for CUDA language will serve as both a sanity test
- # and a native-build GPU architecture detection test, useful later.
- #
- # For this second purpose, NVCC has very handy flags, --run and
- # --run-args, that allow one to run an application with the
- # environment set up properly. Of course, this only works for native
- # builds; For cross builds we must still use the exe_wrapper (if any).
- self.detected_cc = ''
- flags = []
+ '''
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
# Disable warnings, compile with statically-linked runtime for minimum
# reliance on the system.
- flags += ['-w', '-cudart', 'static', source_name]
+ flags = ['-w', '-cudart', 'static', sourcename]
# Use the -ccbin option, if available, even during sanity checking.
# Otherwise, on systems where CUDA does not support the default compiler,
@@ -562,33 +543,30 @@ class CudaCompiler(Compiler):
# a ton of compiler flags to differentiate between
# arm and x86_64. So just compile.
flags += self.get_compile_only_args()
- flags += self.get_output_args(binary_name)
-
- # Compile sanity check
- cmdlist = self.exelist + flags
- mlog.debug('Sanity check compiler command line: ', ' '.join(cmdlist))
- pc, stdo, stde = Popen_safe(cmdlist, cwd=work_dir)
- mlog.debug('Sanity check compile stdout: ')
- mlog.debug(stdo)
- mlog.debug('-----\nSanity check compile stderr:')
- mlog.debug(stde)
- mlog.debug('-----')
- if pc.returncode != 0:
- raise EnvironmentException(f'Compiler {self.name_string()} cannot compile programs.')
-
- # Run sanity check (if possible)
- if self.is_cross:
+ flags += self.get_output_args(binname)
+
+ return self.exelist + flags
+
+ def _run_sanity_check(self, env: Environment, cmdlist: T.List[str], work_dir: str) -> None:
+ # Can't check binaries, so we have to assume they work
+ if self.is_cross and not env.has_exe_wrapper():
+ mlog.debug('Cannot run cross check')
return
- cmdlist = self.exelist + ['--run', f'"{binary_name}"']
+ cmdlist = self._sanity_check_run_with_exe_wrapper(env, cmdlist)
+ mlog.debug('Sanity check built target output for', self.for_machine, self.language, 'compiler')
+ mlog.debug(' -- Running test binary command: ', mesonlib.join_args(cmdlist))
try:
- stdo, stde = self.run_sanity_check(env, cmdlist, work_dir)
- except EnvironmentException:
+ pe, stdo, stde = mesonlib.Popen_safe_logged(cmdlist, 'Sanity check', cwd=work_dir)
+ mlog.debug(' -- stdout:\n', stdo)
+ mlog.debug(' -- stderr:\n', stde)
+ mlog.debug(' -- returncode:', pe.returncode)
+ except Exception as e:
+ raise EnvironmentException(f'Could not invoke sanity check executable: {e!s}.')
+
+ if pe.returncode != 0:
raise EnvironmentException(f'Executables created by {self.language} compiler {self.name_string()} are not runnable.')
- # Interpret the result of the sanity test.
- # As mentioned above, it is not only a sanity test but also a GPU
- # architecture detection test.
if stde == '':
self.detected_cc = stdo
diff --git a/mesonbuild/compilers/cython.py b/mesonbuild/compilers/cython.py
index 50bb4652b..2814ca0d6 100644
--- a/mesonbuild/compilers/cython.py
+++ b/mesonbuild/compilers/cython.py
@@ -1,13 +1,14 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright © 2021-2025 Intel Corporation
-from __future__ import annotations
"""Abstraction for Cython language compilers."""
+from __future__ import annotations
+import os
import typing as T
from .. import options
-from ..mesonlib import EnvironmentException, version_compare
+from ..mesonlib import version_compare
from .compilers import Compiler
if T.TYPE_CHECKING:
@@ -49,16 +50,22 @@ class CythonCompiler(Compiler):
def get_depfile_suffix(self) -> str:
return 'dep'
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- code = 'print("hello world")'
- with self.cached_compile(code, environment.coredata) as p:
- if p.returncode != 0:
- raise EnvironmentException(f'Cython compiler {self.id!r} cannot compile programs')
-
def get_pic_args(self) -> T.List[str]:
# We can lie here, it's fine
return []
+ def _sanity_check_source_code(self) -> str:
+ return 'print("Hello world")'
+
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ return self.exelist + self.get_always_args() + self.get_output_args(binname) + [sourcename]
+
+ def _run_sanity_check(self, env: Environment, cmdlist: T.List[str], work_dir: str) -> None:
+ # Cython will do a Cython -> C -> Exe, so the output file will actually have
+ # the name of the C compiler.
+ # TODO: find a way to not make this so hacky
+ return super()._run_sanity_check(env, [os.path.join(work_dir, 'sanity_check_for_c.exe')], work_dir)
+
def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str],
build_dir: str) -> T.List[str]:
new: T.List[str] = []
diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py
index 9f662add3..4df8f6570 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -5,7 +5,6 @@ from __future__ import annotations
import os.path
import re
-import subprocess
import typing as T
from .. import mesonlib
@@ -438,24 +437,11 @@ class DCompiler(Compiler):
full_version=full_version, is_cross=is_cross)
self.arch = arch
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- source_name = os.path.join(work_dir, 'sanity.d')
- output_name = os.path.join(work_dir, 'dtest')
- with open(source_name, 'w', encoding='utf-8') as ofile:
- ofile.write('''void main() { }''')
+ def _sanity_check_source_code(self) -> str:
+ return 'void main() { }'
- compile_cmdlist = self.exelist + self.get_output_args(output_name) + self._get_target_arch_args() + [source_name]
-
- # If cross-compiling, we can't run the sanity check, only compile it.
- if self.is_cross and not environment.has_exe_wrapper():
- compile_cmdlist += self.get_compile_only_args()
-
- pc = subprocess.Popen(compile_cmdlist, cwd=work_dir)
- pc.wait()
- if pc.returncode != 0:
- raise EnvironmentException('D compiler %s cannot compile programs.' % self.name_string())
-
- stdo, stde = self.run_sanity_check(environment, [output_name], work_dir)
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ return self.exelist + self.get_output_args(binname) + self._get_target_arch_args() + [sourcename]
def needs_static_linker(self) -> bool:
return True
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index 6f4f3d2c1..2853ee24c 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -3,6 +3,7 @@
from __future__ import annotations
+import textwrap
import typing as T
import functools
import os
@@ -61,10 +62,12 @@ class FortranCompiler(CLikeCompiler, Compiler):
largs = env.coredata.get_external_link_args(self.for_machine, self.language)
return cargs, largs
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- source_name = 'sanitycheckf.f'
- code = ' PROGRAM MAIN\n PRINT *, "Fortran compilation is working."\n END\n'
- return self._sanity_check_impl(work_dir, environment, source_name, code)
+ def _sanity_check_source_code(self) -> str:
+ return textwrap.dedent('''
+ PROGRAM MAIN
+ PRINT *, "Fortran compilation is working."
+ END
+ ''')
def get_optimization_args(self, optimization_level: str) -> T.List[str]:
return gnu_optimization_args[optimization_level]
diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py
index 47d2ac9cd..13e48475c 100644
--- a/mesonbuild/compilers/java.py
+++ b/mesonbuild/compilers/java.py
@@ -6,7 +6,6 @@ from __future__ import annotations
import os
import os.path
import shutil
-import subprocess
import textwrap
import typing as T
@@ -72,33 +71,32 @@ class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler):
return parameter_list
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- src = 'SanityCheck.java'
- obj = 'SanityCheck'
- source_name = os.path.join(work_dir, src)
- with open(source_name, 'w', encoding='utf-8') as ofile:
- ofile.write(textwrap.dedent(
- '''class SanityCheck {
- public static void main(String[] args) {
- int i;
- }
- }
- '''))
- pc = subprocess.Popen(self.exelist + [src], cwd=work_dir)
- pc.wait()
- if pc.returncode != 0:
- raise EnvironmentException(f'Java compiler {self.name_string()} cannot compile programs.')
+ def _sanity_check_filenames(self) -> T.Tuple[str, str]:
+ sup = super()._sanity_check_filenames()
+ return sup[0], 'SanityCheck'
+
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ return self.exelist + self.get_always_args() + [sourcename]
+
+ def _sanity_check_run_with_exe_wrapper(self, env: Environment, command: T.List[str]) -> T.List[str]:
runner = shutil.which(self.javarunner)
- if runner:
- cmdlist = [runner, '-cp', '.', obj]
- self.run_sanity_check(environment, cmdlist, work_dir, use_exe_wrapper_for_cross=False)
- else:
+ if runner is None:
m = "Java Virtual Machine wasn't found, but it's needed by Meson. " \
"Please install a JRE.\nIf you have specific needs where this " \
"requirement doesn't make sense, please open a bug at " \
"https://github.com/mesonbuild/meson/issues/new and tell us " \
"all about it."
raise EnvironmentException(m)
+ return [runner, '-cp', '.', os.path.basename(command[0])]
+
+ def _sanity_check_source_code(self) -> str:
+ return textwrap.dedent(
+ '''class SanityCheck {
+ public static void main(String[] args) {
+ int i;
+ }
+ }
+ ''')
def needs_static_linker(self) -> bool:
return False
diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py
index a492fffed..bd139d21c 100644
--- a/mesonbuild/compilers/mixins/clike.py
+++ b/mesonbuild/compilers/mixins/clike.py
@@ -268,50 +268,15 @@ class CLikeCompiler(Compiler):
def gen_import_library_args(self, implibname: str) -> T.List[str]:
return self.linker.import_library_args(implibname)
- def _sanity_check_impl(self, work_dir: str, environment: 'Environment',
- sname: str, code: str) -> None:
- mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', mesonlib.join_args(self.exelist))
- mlog.debug(f'Is cross compiler: {self.is_cross!s}.')
-
- source_name = os.path.join(work_dir, sname)
- binname = sname.rsplit('.', 1)[0]
- mode = CompileCheckMode.LINK
- if self.is_cross:
- binname += '_cross'
- if not environment.has_exe_wrapper():
- # Linking cross built C/C++ apps is painful. You can't really
- # tell if you should use -nostdlib or not and for example
- # on OSX the compiler binary is the same but you need
- # a ton of compiler flags to differentiate between
- # arm and x86_64. So just compile.
- mode = CompileCheckMode.COMPILE
- cargs, largs = self._get_basic_compiler_args(environment, mode)
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ # Cross-compiling is hard. For example, you might need -nostdlib, or to pass --target, etc.
+ mode = CompileCheckMode.COMPILE if self.is_cross and not env.has_exe_wrapper() else CompileCheckMode.LINK
+ cargs, largs = self._get_basic_compiler_args(env, mode)
extra_flags = cargs + self.linker_to_compiler_args(largs)
-
- # Is a valid executable output for all toolchains and platforms
- binname += '.exe'
- # Write binary check source
- binary_name = os.path.join(work_dir, binname)
- with open(source_name, 'w', encoding='utf-8') as ofile:
- ofile.write(code)
- # Compile sanity check
- # NOTE: extra_flags must be added at the end. On MSVC, it might contain a '/link' argument
- # after which all further arguments will be passed directly to the linker
- cmdlist = self.exelist + [sname] + self.get_output_args(binname) + extra_flags
- pc, stdo, stde = mesonlib.Popen_safe(cmdlist, cwd=work_dir)
- mlog.debug('Sanity check compiler command line:', mesonlib.join_args(cmdlist))
- mlog.debug('Sanity check compile stdout:')
- mlog.debug(stdo)
- mlog.debug('-----\nSanity check compile stderr:')
- mlog.debug(stde)
- mlog.debug('-----')
- if pc.returncode != 0:
- raise mesonlib.EnvironmentException(f'Compiler {self.name_string()} cannot compile programs.')
- self.run_sanity_check(environment, [binary_name], work_dir)
-
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- code = 'int main(void) { int class=0; return class; }\n'
- return self._sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code)
+ # It is important that extra_flags is last as it may contain `/link`
+ # directives, MSVC-compatible compilers will pass all arguments after
+ # that to the linker
+ return self.exelist + [sourcename] + self.get_output_args(binname) + extra_flags
def check_header(self, hname: 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/objc.py b/mesonbuild/compilers/objc.py
index d013417fc..b6deddde9 100644
--- a/mesonbuild/compilers/objc.py
+++ b/mesonbuild/compilers/objc.py
@@ -48,9 +48,8 @@ class ObjCCompiler(CLikeCompiler, Compiler):
def get_display_language() -> str:
return 'Objective-C'
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- code = '#import<stddef.h>\nint main(void) { return 0; }\n'
- return self._sanity_check_impl(work_dir, environment, 'sanitycheckobjc.m', code)
+ def _sanity_check_source_code(self) -> str:
+ return '#import<stddef.h>\nint main(void) { return 0; }\n'
def form_compileropt_key(self, basename: str) -> OptionKey:
if basename == 'std':
diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py
index 441428b2f..e59d32708 100644
--- a/mesonbuild/compilers/objcpp.py
+++ b/mesonbuild/compilers/objcpp.py
@@ -50,9 +50,8 @@ class ObjCPPCompiler(CLikeCompiler, Compiler):
def get_display_language() -> str:
return 'Objective-C++'
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- code = '#import<stdio.h>\nclass MyClass;int main(void) { return 0; }\n'
- return self._sanity_check_impl(work_dir, environment, 'sanitycheckobjcpp.mm', code)
+ def _sanity_check_source_code(self) -> str:
+ return '#import<stdio.h>\nclass MyClass;int main(void) { return 0; }\n'
def get_options(self) -> MutableKeyedOptionDictType:
opts = super().get_options()
diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py
index d0f92668a..07faba840 100644
--- a/mesonbuild/compilers/rust.py
+++ b/mesonbuild/compilers/rust.py
@@ -107,44 +107,43 @@ class RustCompiler(Compiler):
def needs_static_linker(self) -> bool:
return False
- def sanity_check(self, work_dir: str, environment: Environment) -> None:
- source_name = os.path.join(work_dir, 'sanity.rs')
- output_name = os.path.join(work_dir, 'rusttest.exe')
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
cmdlist = self.exelist.copy()
+ assert self.linker is not None, 'for mypy'
+ if self.info.kernel == 'none' and 'ld.' in self.linker.id:
+ cmdlist.extend(['-C', 'link-arg=-nostartfiles'])
+ cmdlist.extend(self.get_output_args(binname))
+ cmdlist.append(sourcename)
+ return cmdlist
+
+ def _sanity_check_source_code(self) -> str:
+ if self.info.kernel != 'none':
+ return textwrap.dedent(
+ '''fn main() {
+ }
+ ''')
+ return textwrap.dedent(
+ '''#![no_std]
+ #![no_main]
+ #[no_mangle]
+ pub fn _start() {
+ }
+ #[panic_handler]
+ fn panic(_info: &core::panic::PanicInfo) -> ! {
+ loop {}
+ }
+ ''')
- with open(source_name, 'w', encoding='utf-8') as ofile:
- # If machine kernel is not `none`, try to compile a dummy program.
- # If 'none', this is likely a `no-std`(i.e. bare metal) project.
- if self.info.kernel != 'none':
- ofile.write(textwrap.dedent(
- '''fn main() {
- }
- '''))
- else:
- # If rustc linker is gcc, add `-nostartfiles`
- if 'ld.' in self.linker.id:
- cmdlist.extend(['-C', 'link-arg=-nostartfiles'])
- ofile.write(textwrap.dedent(
- '''#![no_std]
- #![no_main]
- #[no_mangle]
- pub fn _start() {
- }
- #[panic_handler]
- fn panic(_info: &core::panic::PanicInfo) -> ! {
- loop {}
- }
- '''))
-
- cmdlist.extend(['-o', output_name, source_name])
- pc, stdo, stde = Popen_safe_logged(cmdlist, cwd=work_dir)
- if pc.returncode != 0:
- raise EnvironmentException(f'Rust compiler {self.name_string()} cannot compile programs.')
+ def sanity_check(self, work_dir: str, environment: Environment) -> None:
+ super().sanity_check(work_dir, environment)
+ source_name = self._sanity_check_filenames()[0]
self._native_static_libs(work_dir, source_name)
- self.run_sanity_check(environment, [output_name], work_dir)
def _native_static_libs(self, work_dir: str, source_name: str) -> None:
# Get libraries needed to link with a Rust staticlib
+ if self.native_static_libs:
+ return
+
cmdlist = self.exelist + ['--crate-type', 'staticlib', '--print', 'native-static-libs', source_name]
p, stdo, stde = Popen_safe_logged(cmdlist, cwd=work_dir)
if p.returncode != 0:
diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py
index 4ad3affb5..94e565a7c 100644
--- a/mesonbuild/compilers/swift.py
+++ b/mesonbuild/compilers/swift.py
@@ -177,22 +177,21 @@ class SwiftCompiler(Compiler):
return parameter_list
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- src = 'swifttest.swift'
- source_name = os.path.join(work_dir, src)
- output_name = os.path.join(work_dir, 'swifttest')
- extra_flags: T.List[str] = []
- extra_flags += environment.coredata.get_external_args(self.for_machine, self.language)
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ cmdlist = self.exelist.copy()
+ # TODO: I can't test this, but it doesn't seem right
if self.is_cross:
- extra_flags += self.get_compile_only_args()
+ cmdlist.extend(self.get_compile_only_args())
else:
- extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language)
- with open(source_name, 'w', encoding='utf-8') as ofile:
- ofile.write('''print("Swift compilation is working.")
-''')
- pc = subprocess.Popen(self.exelist + extra_flags + ['-emit-executable', '-o', output_name, src], cwd=work_dir)
- pc.wait()
- self.run_sanity_check(environment, [output_name], work_dir)
+ cmdlist.extend(env.coredata.get_external_link_args(self.for_machine, self.language))
+ cmdlist.extend(self.get_std_exe_link_args())
+ cmdlist.extend(self.get_output_args(binname))
+ cmdlist.append(sourcename)
+
+ return cmdlist
+
+ def _sanity_check_source_code(self) -> str:
+ return 'print("Swift compilation is working.")'
def get_debug_args(self, is_debug: bool) -> T.List[str]:
return clike_debug_args[is_debug]
diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py
index bbaefedb6..230a7739b 100644
--- a/mesonbuild/compilers/vala.py
+++ b/mesonbuild/compilers/vala.py
@@ -8,7 +8,7 @@ import typing as T
from .. import mlog
from .. import mesonlib
-from ..mesonlib import EnvironmentException, version_compare, LibType
+from ..mesonlib import version_compare, LibType
from ..options import OptionKey
from .compilers import CompileCheckMode, Compiler
@@ -99,18 +99,25 @@ class ValaCompiler(Compiler):
return parameter_list
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- code = 'class MesonSanityCheck : Object { }'
- extra_flags: T.List[str] = []
- extra_flags += environment.coredata.get_external_args(self.for_machine, self.language)
+ def _sanity_check_source_code(self) -> str:
+ return 'public static int main() { return 0; }'
+
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ cmdlist = self.exelist.copy()
+ cmdlist.extend(env.coredata.get_external_args(self.for_machine, self.language))
if self.is_cross:
- extra_flags += self.get_compile_only_args()
+ cmdlist.extend(self.get_compile_only_args())
else:
- extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language)
- with self.cached_compile(code, environment.coredata, extra_args=extra_flags, mode=CompileCheckMode.COMPILE) as p:
- if p.returncode != 0:
- msg = f'Vala compiler {self.name_string()!r} cannot compile programs'
- raise EnvironmentException(msg)
+ cmdlist.extend(env.coredata.get_external_link_args(self.for_machine, self.language))
+ cmdlist.extend(self.get_output_args(binname))
+ cmdlist.append(sourcename)
+ return cmdlist
+
+ def _run_sanity_check(self, env: Environment, cmdlist: T.List[str], work_dir: str) -> None:
+ # Vala will do a Vala -> C -> Exe, so the output file will actually have
+ # the name of the C compiler.
+ # TODO: find a way to not make this so hacky
+ return super()._run_sanity_check(env, [os.path.join(work_dir, 'sanity_check_for_c.exe')], work_dir)
def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str],
libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True, ignore_system_dirs: bool = False) -> T.Optional[T.List[str]]:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 72dbfdf2d..b746fa8e6 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -55,8 +55,11 @@ class MissingCompiler(_MissingCompilerBase):
def get_output_args(self, outputname: str) -> T.List[str]:
return []
- def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
- return None
+ def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ return []
+
+ def _sanity_check_source_code(self) -> str:
+ return ''
def __getattr__(self, item: str) -> T.Any:
if item.startswith('__'):