Skip to content

Commit c3ea8d5

Browse files
amysparkjpakkane
authored andcommitted
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
1 parent 4b7a23c commit c3ea8d5

File tree

6 files changed

+45
-34
lines changed

6 files changed

+45
-34
lines changed

mesonbuild/backend/vs2010backend.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,8 @@ def is_argument_with_msbuild_xml_entry(self, entry):
865865
# FIXME add args as needed.
866866
if entry[1:].startswith('fsanitize'):
867867
return True
868+
if entry[1:] in frozenset(['Zi', 'Z7', 'ZI']):
869+
return True
868870
return entry[1:].startswith('M')
869871

870872
def add_additional_options(self, lang, parent_node, file_args):
@@ -1348,11 +1350,11 @@ def add_non_makefile_vcxproj_elements(
13481350
if '/fsanitize=address' in build_args:
13491351
ET.SubElement(type_config, 'EnableASAN').text = 'true'
13501352
# Debug format
1351-
if '/ZI' in build_args:
1353+
if '/ZI' in build_args or '-ZI' in build_args:
13521354
ET.SubElement(clconf, 'DebugInformationFormat').text = 'EditAndContinue'
1353-
elif '/Zi' in build_args:
1355+
elif '/Zi' in build_args or '-Zi' in build_args:
13541356
ET.SubElement(clconf, 'DebugInformationFormat').text = 'ProgramDatabase'
1355-
elif '/Z7' in build_args:
1357+
elif '/Z7' in build_args or '-Z7' in build_args:
13561358
ET.SubElement(clconf, 'DebugInformationFormat').text = 'OldStyle'
13571359
else:
13581360
ET.SubElement(clconf, 'DebugInformationFormat').text = 'None'

mesonbuild/cmake/interpreter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,10 @@ def configure(self, extra_cmake_options: T.List[str]) -> CMakeExecutor:
851851
trace_args = self.trace.trace_args()
852852
cmcmp_args = [f'-DCMAKE_POLICY_WARNING_{x}=OFF' for x in DISABLE_POLICY_WARNINGS]
853853

854+
if mesonlib.version_compare(cmake_exe.version(), '>= 3.25'):
855+
# Enable MSVC debug information variable
856+
cmcmp_args += ['-DCMAKE_POLICY_CMP0141=NEW']
857+
854858
self.fileapi.setup_request()
855859

856860
# Run CMake

mesonbuild/cmake/toolchain.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,16 @@ def make_abs(exe: str) -> str:
174174
return p
175175

176176
# Set the compiler variables
177+
comp_obj = self.compilers.get('c', self.compilers.get('cpp', None))
178+
if comp_obj and comp_obj.get_id() == 'msvc':
179+
debug_args = comp_obj.get_debug_args(True)
180+
if '/Z7' in debug_args:
181+
defaults['CMAKE_MSVC_DEBUG_INFORMATION_FORMAT'] = ['Embedded']
182+
elif '/Zi' in debug_args:
183+
defaults['CMAKE_MSVC_DEBUG_INFORMATION_FORMAT'] = ['ProgramDatabase']
184+
elif '/ZI' in debug_args:
185+
defaults['CMAKE_MSVC_DEBUG_INFORMATION_FORMAT'] = ['EditAndContinue']
186+
177187
for lang, comp_obj in self.compilers.items():
178188
language = language_map.get(lang, None)
179189

mesonbuild/compilers/detect.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
from ..mesonlib import (
77
MesonException, EnvironmentException, MachineChoice, join_args,
8-
search_version, is_windows, Popen_safe, Popen_safe_logged, windows_proof_rm,
8+
search_version, is_windows, Popen_safe, Popen_safe_logged, version_compare, windows_proof_rm,
99
)
10+
from ..programs import ExternalProgram
1011
from ..envconfig import BinaryTable
1112
from .. import mlog
1213

@@ -118,7 +119,7 @@ def detect_compiler_for(env: 'Environment', lang: str, for_machine: MachineChoic
118119
# =======
119120

120121
def _get_compilers(env: 'Environment', lang: str, for_machine: MachineChoice,
121-
allow_build_machine: bool = False) -> T.Tuple[T.List[T.List[str]], T.List[str]]:
122+
allow_build_machine: bool = False) -> T.Tuple[T.List[T.List[str]], T.Union[None, ExternalProgram]]:
122123
'''
123124
The list of compilers is detected in the exact same way for
124125
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
269270
from . import c, cpp
270271
from ..linkers import linkers
271272
popen_exceptions: T.Dict[str, T.Union[Exception, str]] = {}
272-
compilers, ccache = _get_compilers(env, lang, for_machine)
273+
compilers, ccache_exe = _get_compilers(env, lang, for_machine)
274+
ccache = ccache_exe.get_command() if (ccache_exe and ccache_exe.found()) else []
273275
if override_compiler is not None:
274276
compilers = [override_compiler]
275277
is_cross = env.is_cross_build(for_machine)
@@ -516,9 +518,10 @@ def sanitize(p: T.Optional[str]) -> T.Optional[str]:
516518
raise EnvironmentException(m)
517519
cls = c.VisualStudioCCompiler if lang == 'c' else cpp.VisualStudioCPPCompiler
518520
linker = guess_win_linker(env, ['link'], cls, version, for_machine)
519-
# As of this writing, CCache does not support MSVC but sccache does.
520-
if 'sccache' not in ccache:
521-
ccache = []
521+
if ccache_exe and ccache_exe.found():
522+
if ccache_exe.get_name() == 'ccache' and version_compare(ccache_exe.get_version(), '< 4.6'):
523+
mlog.warning('Visual Studio support requires ccache 4.6 or higher. You have ccache {}. '.format(ccache_exe.get_version()), once=True)
524+
ccache = []
522525
return cls(
523526
ccache, compiler, version, for_machine, is_cross, info, target,
524527
full_version=cl_signature, linker=linker)
@@ -641,7 +644,8 @@ def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Comp
641644
from ..linkers.linkers import CudaLinker
642645
popen_exceptions = {}
643646
is_cross = env.is_cross_build(for_machine)
644-
compilers, ccache = _get_compilers(env, 'cuda', for_machine)
647+
compilers, ccache_exe = _get_compilers(env, 'cuda', for_machine)
648+
ccache = ccache_exe.get_command() if (ccache_exe and ccache_exe.found()) else []
645649
info = env.machines[for_machine]
646650
for compiler in compilers:
647651
arg = '--version'
@@ -876,7 +880,8 @@ def detect_objcpp_compiler(env: 'Environment', for_machine: MachineChoice) -> 'C
876880
def _detect_objc_or_objcpp_compiler(env: 'Environment', lang: str, for_machine: MachineChoice) -> 'Compiler':
877881
from . import objc, objcpp
878882
popen_exceptions: T.Dict[str, T.Union[Exception, str]] = {}
879-
compilers, ccache = _get_compilers(env, lang, for_machine)
883+
compilers, ccache_exe = _get_compilers(env, lang, for_machine)
884+
ccache = ccache_exe.get_command() if (ccache_exe and ccache_exe.found()) else []
880885
is_cross = env.is_cross_build(for_machine)
881886
info = env.machines[for_machine]
882887
comp: T.Union[T.Type[objc.ObjCCompiler], T.Type[objcpp.ObjCPPCompiler]]

mesonbuild/compilers/mixins/visualstudio.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,6 @@
6666
's': ['/O1', '/Gw'],
6767
}
6868

69-
msvc_debug_args: T.Dict[bool, T.List[str]] = {
70-
False: [],
71-
True: ['/Zi']
72-
}
73-
7469

7570
class VisualStudioLikeCompiler(Compiler, metaclass=abc.ABCMeta):
7671

@@ -180,7 +175,10 @@ def get_output_args(self, outputname: str) -> T.List[str]:
180175
return ['/Fo' + outputname]
181176

182177
def get_debug_args(self, is_debug: bool) -> T.List[str]:
183-
return msvc_debug_args[is_debug]
178+
if is_debug:
179+
return ['/Z7']
180+
else:
181+
return []
184182

185183
def get_optimization_args(self, optimization_level: str) -> T.List[str]:
186184
args = msvc_optimization_args[optimization_level]

mesonbuild/envconfig.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
from __future__ import annotations
55

66
from dataclasses import dataclass
7-
import subprocess
87
import typing as T
98
from enum import Enum
109

1110
from . import mesonlib
1211
from .mesonlib import EnvironmentException, HoldableObject
12+
from .programs import ExternalProgram
1313
from . import mlog
1414
from pathlib import Path
1515

@@ -423,31 +423,23 @@ def __init__(
423423
del self.binaries['pkgconfig']
424424

425425
@staticmethod
426-
def detect_ccache() -> T.List[str]:
427-
try:
428-
subprocess.check_call(['ccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
429-
except (OSError, subprocess.CalledProcessError):
430-
return []
431-
return ['ccache']
426+
def detect_ccache() -> ExternalProgram:
427+
return ExternalProgram('ccache')
432428

433429
@staticmethod
434-
def detect_sccache() -> T.List[str]:
435-
try:
436-
subprocess.check_call(['sccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
437-
except (OSError, subprocess.CalledProcessError):
438-
return []
439-
return ['sccache']
430+
def detect_sccache() -> ExternalProgram:
431+
return ExternalProgram('sccache')
440432

441433
@staticmethod
442-
def detect_compiler_cache() -> T.List[str]:
434+
def detect_compiler_cache() -> ExternalProgram:
443435
# Sccache is "newer" so it is assumed that people would prefer it by default.
444436
cache = BinaryTable.detect_sccache()
445-
if cache:
437+
if cache.found():
446438
return cache
447439
return BinaryTable.detect_ccache()
448440

449441
@classmethod
450-
def parse_entry(cls, entry: T.Union[str, T.List[str]]) -> T.Tuple[T.List[str], T.List[str]]:
442+
def parse_entry(cls, entry: T.Union[str, T.List[str]]) -> T.Tuple[T.List[str], T.Union[None, ExternalProgram]]:
451443
parts = mesonlib.stringlistify(entry)
452444
# Ensure ccache exists and remove it if it doesn't
453445
if parts[0] == 'ccache':
@@ -458,7 +450,7 @@ def parse_entry(cls, entry: T.Union[str, T.List[str]]) -> T.Tuple[T.List[str], T
458450
ccache = cls.detect_sccache()
459451
else:
460452
compiler = parts
461-
ccache = []
453+
ccache = None
462454
if not compiler:
463455
raise EnvironmentException(f'Compiler cache specified without compiler: {parts[0]}')
464456
# Return value has to be a list of compiler 'choices'

0 commit comments

Comments
 (0)