summaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorL. E. Segovia <amy@amyspark.me>2025-08-03 22:26:07 -0300
committerJussi Pakkanen <jussi.pakkanen@mailbox.org>2025-09-06 16:58:56 +0300
commitc3ea8d5aa1b48fbc4137ef783c567a32cd596993 (patch)
treea1c729133a5e92ad516623192fd48c742db31fa2 /mesonbuild
parent4b7a23c047ef5139f84cf96da37d132fe5fd84bc (diff)
downloadmeson-c3ea8d5aa1b48fbc4137ef783c567a32cd596993.tar.gz
compilers: Enable out-of-the-box MSVC compatibility with ccache
ccache has been for a long time compatible with MSVC (since 4.6) but when using debug mode, the /Z7 flag must be passed instead of /Zi. See https://ccache.dev/releasenotes.html#_ccache_4_6
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/backend/vs2010backend.py8
-rw-r--r--mesonbuild/cmake/interpreter.py4
-rw-r--r--mesonbuild/cmake/toolchain.py10
-rw-r--r--mesonbuild/compilers/detect.py21
-rw-r--r--mesonbuild/compilers/mixins/visualstudio.py10
-rw-r--r--mesonbuild/envconfig.py26
6 files changed, 45 insertions, 34 deletions
diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py
index deb3dfb23..8804b8daa 100644
--- a/mesonbuild/backend/vs2010backend.py
+++ b/mesonbuild/backend/vs2010backend.py
@@ -865,6 +865,8 @@ class Vs2010Backend(backends.Backend):
# FIXME add args as needed.
if entry[1:].startswith('fsanitize'):
return True
+ if entry[1:] in frozenset(['Zi', 'Z7', 'ZI']):
+ return True
return entry[1:].startswith('M')
def add_additional_options(self, lang, parent_node, file_args):
@@ -1348,11 +1350,11 @@ class Vs2010Backend(backends.Backend):
if '/fsanitize=address' in build_args:
ET.SubElement(type_config, 'EnableASAN').text = 'true'
# Debug format
- if '/ZI' in build_args:
+ if '/ZI' in build_args or '-ZI' in build_args:
ET.SubElement(clconf, 'DebugInformationFormat').text = 'EditAndContinue'
- elif '/Zi' in build_args:
+ elif '/Zi' in build_args or '-Zi' in build_args:
ET.SubElement(clconf, 'DebugInformationFormat').text = 'ProgramDatabase'
- elif '/Z7' in build_args:
+ elif '/Z7' in build_args or '-Z7' in build_args:
ET.SubElement(clconf, 'DebugInformationFormat').text = 'OldStyle'
else:
ET.SubElement(clconf, 'DebugInformationFormat').text = 'None'
diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py
index 1019246c5..54c9ae696 100644
--- a/mesonbuild/cmake/interpreter.py
+++ b/mesonbuild/cmake/interpreter.py
@@ -851,6 +851,10 @@ class CMakeInterpreter:
trace_args = self.trace.trace_args()
cmcmp_args = [f'-DCMAKE_POLICY_WARNING_{x}=OFF' for x in DISABLE_POLICY_WARNINGS]
+ if mesonlib.version_compare(cmake_exe.version(), '>= 3.25'):
+ # Enable MSVC debug information variable
+ cmcmp_args += ['-DCMAKE_POLICY_CMP0141=NEW']
+
self.fileapi.setup_request()
# Run CMake
diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py
index 11a00be5d..902d6b088 100644
--- a/mesonbuild/cmake/toolchain.py
+++ b/mesonbuild/cmake/toolchain.py
@@ -174,6 +174,16 @@ class CMakeToolchain:
return p
# Set the compiler variables
+ comp_obj = self.compilers.get('c', self.compilers.get('cpp', None))
+ if comp_obj and comp_obj.get_id() == 'msvc':
+ debug_args = comp_obj.get_debug_args(True)
+ if '/Z7' in debug_args:
+ defaults['CMAKE_MSVC_DEBUG_INFORMATION_FORMAT'] = ['Embedded']
+ elif '/Zi' in debug_args:
+ defaults['CMAKE_MSVC_DEBUG_INFORMATION_FORMAT'] = ['ProgramDatabase']
+ elif '/ZI' in debug_args:
+ defaults['CMAKE_MSVC_DEBUG_INFORMATION_FORMAT'] = ['EditAndContinue']
+
for lang, comp_obj in self.compilers.items():
language = language_map.get(lang, None)
diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py
index f57957f0b..a0ae8108d 100644
--- a/mesonbuild/compilers/detect.py
+++ b/mesonbuild/compilers/detect.py
@@ -5,8 +5,9 @@ from __future__ import annotations
from ..mesonlib import (
MesonException, EnvironmentException, MachineChoice, join_args,
- search_version, is_windows, Popen_safe, Popen_safe_logged, windows_proof_rm,
+ search_version, is_windows, Popen_safe, Popen_safe_logged, version_compare, windows_proof_rm,
)
+from ..programs import ExternalProgram
from ..envconfig import BinaryTable
from .. import mlog
@@ -118,7 +119,7 @@ def detect_compiler_for(env: 'Environment', lang: str, for_machine: MachineChoic
# =======
def _get_compilers(env: 'Environment', lang: str, for_machine: MachineChoice,
- allow_build_machine: bool = False) -> T.Tuple[T.List[T.List[str]], T.List[str]]:
+ allow_build_machine: bool = False) -> T.Tuple[T.List[T.List[str]], T.Union[None, ExternalProgram]]:
'''
The list of compilers is detected in the exact same way for
C, C++, ObjC, ObjC++, Fortran, CS so consolidate it here.
@@ -269,7 +270,8 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin
from . import c, cpp
from ..linkers import linkers
popen_exceptions: T.Dict[str, T.Union[Exception, str]] = {}
- compilers, ccache = _get_compilers(env, lang, for_machine)
+ compilers, ccache_exe = _get_compilers(env, lang, for_machine)
+ ccache = ccache_exe.get_command() if (ccache_exe and ccache_exe.found()) else []
if override_compiler is not None:
compilers = [override_compiler]
is_cross = env.is_cross_build(for_machine)
@@ -516,9 +518,10 @@ def _detect_c_or_cpp_compiler(env: 'Environment', lang: str, for_machine: Machin
raise EnvironmentException(m)
cls = c.VisualStudioCCompiler if lang == 'c' else cpp.VisualStudioCPPCompiler
linker = guess_win_linker(env, ['link'], cls, version, for_machine)
- # As of this writing, CCache does not support MSVC but sccache does.
- if 'sccache' not in ccache:
- ccache = []
+ if ccache_exe and ccache_exe.found():
+ if ccache_exe.get_name() == 'ccache' and version_compare(ccache_exe.get_version(), '< 4.6'):
+ mlog.warning('Visual Studio support requires ccache 4.6 or higher. You have ccache {}. '.format(ccache_exe.get_version()), once=True)
+ ccache = []
return cls(
ccache, compiler, version, for_machine, is_cross, info, target,
full_version=cl_signature, linker=linker)
@@ -641,7 +644,8 @@ def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Comp
from ..linkers.linkers import CudaLinker
popen_exceptions = {}
is_cross = env.is_cross_build(for_machine)
- compilers, ccache = _get_compilers(env, 'cuda', for_machine)
+ compilers, ccache_exe = _get_compilers(env, 'cuda', for_machine)
+ ccache = ccache_exe.get_command() if (ccache_exe and ccache_exe.found()) else []
info = env.machines[for_machine]
for compiler in compilers:
arg = '--version'
@@ -876,7 +880,8 @@ def detect_objcpp_compiler(env: 'Environment', for_machine: MachineChoice) -> 'C
def _detect_objc_or_objcpp_compiler(env: 'Environment', lang: str, for_machine: MachineChoice) -> 'Compiler':
from . import objc, objcpp
popen_exceptions: T.Dict[str, T.Union[Exception, str]] = {}
- compilers, ccache = _get_compilers(env, lang, for_machine)
+ compilers, ccache_exe = _get_compilers(env, lang, for_machine)
+ ccache = ccache_exe.get_command() if (ccache_exe and ccache_exe.found()) else []
is_cross = env.is_cross_build(for_machine)
info = env.machines[for_machine]
comp: T.Union[T.Type[objc.ObjCCompiler], T.Type[objcpp.ObjCPPCompiler]]
diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py
index 275e7ab0a..4125ed885 100644
--- a/mesonbuild/compilers/mixins/visualstudio.py
+++ b/mesonbuild/compilers/mixins/visualstudio.py
@@ -66,11 +66,6 @@ msvc_optimization_args: T.Dict[str, T.List[str]] = {
's': ['/O1', '/Gw'],
}
-msvc_debug_args: T.Dict[bool, T.List[str]] = {
- False: [],
- True: ['/Zi']
-}
-
class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta):
@@ -180,7 +175,10 @@ class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta):
return ['/Fo' + outputname]
def get_debug_args(self, is_debug: bool) -> T.List[str]:
- return msvc_debug_args[is_debug]
+ if is_debug:
+ return ['/Z7']
+ else:
+ return []
def get_optimization_args(self, optimization_level: str) -> T.List[str]:
args = msvc_optimization_args[optimization_level]
diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py
index 43fad0cd2..447639e00 100644
--- a/mesonbuild/envconfig.py
+++ b/mesonbuild/envconfig.py
@@ -4,12 +4,12 @@
from __future__ import annotations
from dataclasses import dataclass
-import subprocess
import typing as T
from enum import Enum
from . import mesonlib
from .mesonlib import EnvironmentException, HoldableObject
+from .programs import ExternalProgram
from . import mlog
from pathlib import Path
@@ -423,31 +423,23 @@ class BinaryTable:
del self.binaries['pkgconfig']
@staticmethod
- def detect_ccache() -> T.List[str]:
- try:
- subprocess.check_call(['ccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- except (OSError, subprocess.CalledProcessError):
- return []
- return ['ccache']
+ def detect_ccache() -> ExternalProgram:
+ return ExternalProgram('ccache')
@staticmethod
- def detect_sccache() -> T.List[str]:
- try:
- subprocess.check_call(['sccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- except (OSError, subprocess.CalledProcessError):
- return []
- return ['sccache']
+ def detect_sccache() -> ExternalProgram:
+ return ExternalProgram('sccache')
@staticmethod
- def detect_compiler_cache() -> T.List[str]:
+ def detect_compiler_cache() -> ExternalProgram:
# Sccache is "newer" so it is assumed that people would prefer it by default.
cache = BinaryTable.detect_sccache()
- if cache:
+ if cache.found():
return cache
return BinaryTable.detect_ccache()
@classmethod
- def parse_entry(cls, entry: T.Union[str, T.List[str]]) -> T.Tuple[T.List[str], T.List[str]]:
+ def parse_entry(cls, entry: T.Union[str, T.List[str]]) -> T.Tuple[T.List[str], T.Union[None, ExternalProgram]]:
parts = mesonlib.stringlistify(entry)
# Ensure ccache exists and remove it if it doesn't
if parts[0] == 'ccache':
@@ -458,7 +450,7 @@ class BinaryTable:
ccache = cls.detect_sccache()
else:
compiler = parts
- ccache = []
+ ccache = None
if not compiler:
raise EnvironmentException(f'Compiler cache specified without compiler: {parts[0]}')
# Return value has to be a list of compiler 'choices'