summaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2025-10-06 10:21:07 -0700
committerDylan Baker <dylan@pnwbakers.com>2025-10-06 10:22:41 -0700
commita6af0ad50373324ec9fe569e8315b03439491865 (patch)
treeed221189af614ce578190dfb51193e1efcb72b17 /mesonbuild
parent6c5a88632f1d3319124d03eab596d57416ef16c6 (diff)
downloadmeson-a6af0ad50373324ec9fe569e8315b03439491865.tar.gz
Revert "compilers: refactor sanity checking code"
This reverts commit 806289a5d27958a084bc6cba41b7cf9ccee4ecf4.
Diffstat (limited to 'mesonbuild')
-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, 264 insertions, 284 deletions
diff --git a/mesonbuild/compilers/asm.py b/mesonbuild/compilers/asm.py
index 5f065e193..d4af77f89 100644
--- a/mesonbuild/compilers/asm.py
+++ b/mesonbuild/compilers/asm.py
@@ -10,7 +10,6 @@ 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
@@ -40,12 +39,6 @@ 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 a0786d55c..424b61251 100644
--- a/mesonbuild/compilers/c.py
+++ b/mesonbuild/compilers/c.py
@@ -76,8 +76,9 @@ class CCompiler(CLikeCompiler, Compiler):
def get_no_stdinc_args(self) -> T.List[str]:
return ['-nostdinc']
- def _sanity_check_source_code(self) -> str:
- return 'int main(void) { int class=0; return class; }\n'
+ 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 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 4c28eb2fd..624226d33 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -1196,7 +1196,8 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
def name_string(self) -> str:
return ' '.join(self.exelist)
- def sanity_check(self, work_dir: str, env: Environment) -> None:
+ @abc.abstractmethod
+ def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
"""Check that this compiler actually works.
This should provide a simple compile/link test. Something as simple as:
@@ -1204,103 +1205,24 @@ 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.
- :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))
+ 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))
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 8da100483..fa032ec79 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -86,8 +86,9 @@ class CPPCompiler(CLikeCompiler, Compiler):
def get_no_stdlib_link_args(self) -> T.List[str]:
return ['-nostdlib++']
- def _sanity_check_source_code(self) -> str:
- return 'class breakCCompiler;int main(void) { return 0; }\n'
+ 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 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 e515c338f..4bbddeb20 100644
--- a/mesonbuild/compilers/cs.py
+++ b/mesonbuild/compilers/cs.py
@@ -3,10 +3,11 @@
from __future__ import annotations
-import os.path
+import os.path, subprocess
import textwrap
import typing as T
+from ..mesonlib import EnvironmentException
from ..linkers import RSPFileSyntax
from .compilers import Compiler
@@ -82,21 +83,26 @@ class CsCompiler(BasicLinkerIsCompilerMixin, Compiler):
def get_pch_name(self, header_name: str) -> str:
return ''
- def _sanity_check_source_code(self) -> str:
- return textwrap.dedent('''
- public class Sanity {
- static public void Main () {
+ 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_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]:
+ '''))
+ 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())
if self.runner:
- return [self.runner] + command
- return command
+ 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)
def needs_static_linker(self) -> bool:
return False
diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py
index a9e6a7669..7e050f140 100644
--- a/mesonbuild/compilers/cuda.py
+++ b/mesonbuild/compilers/cuda.py
@@ -5,14 +5,15 @@
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, is_windows, LibType, version_compare
+ EnvironmentException, Popen_safe,
+ is_windows, LibType, version_compare
)
from .compilers import Compiler, CompileCheckMode
@@ -186,7 +187,6 @@ 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,36 +499,55 @@ 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_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);
- }
+ 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);
}
}
- 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', sourcename]
+ flags += ['-w', '-cudart', 'static', source_name]
# Use the -ccbin option, if available, even during sanity checking.
# Otherwise, on systems where CUDA does not support the default compiler,
@@ -543,30 +562,33 @@ 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(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')
+ 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:
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))
+ cmdlist = self.exelist + ['--run', f'"{binary_name}"']
try:
- 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:
+ stdo, stde = self.run_sanity_check(env, cmdlist, work_dir)
+ except EnvironmentException:
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 2814ca0d6..50bb4652b 100644
--- a/mesonbuild/compilers/cython.py
+++ b/mesonbuild/compilers/cython.py
@@ -1,14 +1,13 @@
# 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 version_compare
+from ..mesonlib import EnvironmentException, version_compare
from .compilers import Compiler
if T.TYPE_CHECKING:
@@ -50,22 +49,16 @@ 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 4df8f6570..9f662add3 100644
--- a/mesonbuild/compilers/d.py
+++ b/mesonbuild/compilers/d.py
@@ -5,6 +5,7 @@ from __future__ import annotations
import os.path
import re
+import subprocess
import typing as T
from .. import mesonlib
@@ -437,11 +438,24 @@ class DCompiler(Compiler):
full_version=full_version, is_cross=is_cross)
self.arch = arch
- def _sanity_check_source_code(self) -> str:
- return 'void main() { }'
+ 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_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]
+ 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 needs_static_linker(self) -> bool:
return True
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py
index 2853ee24c..6f4f3d2c1 100644
--- a/mesonbuild/compilers/fortran.py
+++ b/mesonbuild/compilers/fortran.py
@@ -3,7 +3,6 @@
from __future__ import annotations
-import textwrap
import typing as T
import functools
import os
@@ -62,12 +61,10 @@ class FortranCompiler(CLikeCompiler, Compiler):
largs = env.coredata.get_external_link_args(self.for_machine, self.language)
return cargs, largs
- def _sanity_check_source_code(self) -> str:
- return textwrap.dedent('''
- PROGRAM MAIN
- PRINT *, "Fortran compilation is working."
- END
- ''')
+ 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 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 13e48475c..47d2ac9cd 100644
--- a/mesonbuild/compilers/java.py
+++ b/mesonbuild/compilers/java.py
@@ -6,6 +6,7 @@ from __future__ import annotations
import os
import os.path
import shutil
+import subprocess
import textwrap
import typing as T
@@ -71,32 +72,33 @@ class JavaCompiler(BasicLinkerIsCompilerMixin, Compiler):
return parameter_list
- 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]:
+ 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.')
runner = shutil.which(self.javarunner)
- if runner is None:
+ if runner:
+ cmdlist = [runner, '-cp', '.', obj]
+ self.run_sanity_check(environment, cmdlist, work_dir, use_exe_wrapper_for_cross=False)
+ else:
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 bd139d21c..a492fffed 100644
--- a/mesonbuild/compilers/mixins/clike.py
+++ b/mesonbuild/compilers/mixins/clike.py
@@ -268,15 +268,50 @@ class CLikeCompiler(Compiler):
def gen_import_library_args(self, implibname: str) -> T.List[str]:
return self.linker.import_library_args(implibname)
- 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)
+ 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)
extra_flags = cargs + self.linker_to_compiler_args(largs)
- # 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
+
+ # 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)
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 b6deddde9..d013417fc 100644
--- a/mesonbuild/compilers/objc.py
+++ b/mesonbuild/compilers/objc.py
@@ -48,8 +48,9 @@ class ObjCCompiler(CLikeCompiler, Compiler):
def get_display_language() -> str:
return 'Objective-C'
- def _sanity_check_source_code(self) -> str:
- return '#import<stddef.h>\nint main(void) { return 0; }\n'
+ 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 form_compileropt_key(self, basename: str) -> OptionKey:
if basename == 'std':
diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py
index e59d32708..441428b2f 100644
--- a/mesonbuild/compilers/objcpp.py
+++ b/mesonbuild/compilers/objcpp.py
@@ -50,8 +50,9 @@ class ObjCPPCompiler(CLikeCompiler, Compiler):
def get_display_language() -> str:
return 'Objective-C++'
- def _sanity_check_source_code(self) -> str:
- return '#import<stdio.h>\nclass MyClass;int main(void) { return 0; }\n'
+ 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 get_options(self) -> MutableKeyedOptionDictType:
opts = super().get_options()
diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py
index 07faba840..d0f92668a 100644
--- a/mesonbuild/compilers/rust.py
+++ b/mesonbuild/compilers/rust.py
@@ -107,43 +107,44 @@ class RustCompiler(Compiler):
def needs_static_linker(self) -> bool:
return False
- def _sanity_check_compile_args(self, env: Environment, sourcename: str, binname: str) -> T.List[str]:
+ 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')
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 {}
- }
- ''')
- def sanity_check(self, work_dir: str, environment: Environment) -> None:
- super().sanity_check(work_dir, environment)
- source_name = self._sanity_check_filenames()[0]
+ 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.')
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 94e565a7c..4ad3affb5 100644
--- a/mesonbuild/compilers/swift.py
+++ b/mesonbuild/compilers/swift.py
@@ -177,21 +177,22 @@ class SwiftCompiler(Compiler):
return parameter_list
- 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
+ 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)
if self.is_cross:
- cmdlist.extend(self.get_compile_only_args())
+ extra_flags += self.get_compile_only_args()
else:
- 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.")'
+ 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)
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 230a7739b..bbaefedb6 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 version_compare, LibType
+from ..mesonlib import EnvironmentException, version_compare, LibType
from ..options import OptionKey
from .compilers import CompileCheckMode, Compiler
@@ -99,25 +99,18 @@ class ValaCompiler(Compiler):
return parameter_list
- 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))
+ 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)
if self.is_cross:
- cmdlist.extend(self.get_compile_only_args())
+ extra_flags += self.get_compile_only_args()
else:
- 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)
+ 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)
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 b746fa8e6..72dbfdf2d 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -55,11 +55,8 @@ class MissingCompiler(_MissingCompilerBase):
def get_output_args(self, outputname: str) -> T.List[str]:
return []
- 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 sanity_check(self, work_dir: str, environment: 'Environment') -> None:
+ return None
def __getattr__(self, item: str) -> T.Any:
if item.startswith('__'):