Skip to content

Commit 30c38e2

Browse files
authored
Merge pull request #12144 from amyspark/fix-msvc-clangcl-linker-flag-detection
linkers: Fix detection of link arguments to Clang(-cl) + MSVC
2 parents e00710a + f3fad6c commit 30c38e2

File tree

5 files changed

+55
-1
lines changed

5 files changed

+55
-1
lines changed

mesonbuild/compilers/mixins/clang.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from ... import mesonlib
1313
from ...linkers.linkers import AppleDynamicLinker, ClangClDynamicLinker, LLVMDynamicLinker, GnuGoldDynamicLinker, \
14-
MoldDynamicLinker
14+
MoldDynamicLinker, MSVCDynamicLinker
1515
from ...mesonlib import OptionKey
1616
from ..compilers import CompileCheckMode
1717
from .gnu import GnuLikeCompiler
@@ -111,6 +111,13 @@ def openmp_flags(self) -> T.List[str]:
111111
# Shouldn't work, but it'll be checked explicitly in the OpenMP dependency.
112112
return []
113113

114+
def gen_vs_module_defs_args(self, defsfile: str) -> T.List[str]:
115+
if isinstance(self.linker, (MSVCDynamicLinker)):
116+
# With MSVC, DLLs only export symbols that are explicitly exported,
117+
# so if a module defs file is specified, we use that to export symbols
118+
return ['-Wl,/DEF:' + defsfile]
119+
return super().gen_vs_module_defs_args(defsfile)
120+
114121
@classmethod
115122
def use_linker_args(cls, linker: str, version: str) -> T.List[str]:
116123
# Clang additionally can use a linker specified as a path, which GCC
@@ -155,6 +162,12 @@ def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T.
155162
args.extend(super().get_lto_compile_args(threads=threads))
156163
return args
157164

165+
def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]:
166+
if isinstance(self.linker, (ClangClDynamicLinker, MSVCDynamicLinker)):
167+
return [flag if flag.startswith('-Wl,') else f'-Wl,{flag}' for flag in args]
168+
else:
169+
return args
170+
158171
def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default',
159172
thinlto_cache_dir: T.Optional[str] = None) -> T.List[str]:
160173
args = self.get_lto_compile_args(threads=threads, mode=mode)

mesonbuild/compilers/mixins/visualstudio.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,18 @@ def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
460460
path = '.'
461461
return ['/clang:-isystem' + path] if is_system else ['-I' + path]
462462

463+
@classmethod
464+
def use_linker_args(cls, linker: str, version: str) -> T.List[str]:
465+
# Clang additionally can use a linker specified as a path, unlike MSVC.
466+
if linker == 'lld-link':
467+
return ['-fuse-ld=lld-link']
468+
return super().use_linker_args(linker, version)
469+
470+
def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]:
471+
# clang-cl forwards arguments span-wise with the /LINK flag
472+
# therefore -Wl will be received by lld-link or LINK and rejected
473+
return super().use_linker_args(self.linker.id, '') + super().linker_to_compiler_args([flag[4:] if flag.startswith('-Wl,') else flag for flag in args])
474+
463475
def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]:
464476
if dep.get_include_type() == 'system':
465477
converted: T.List[str] = []

mesonbuild/linkers/detect.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty
5555
if value is not None:
5656
override = comp_class.use_linker_args(value[0], comp_version)
5757
check_args += override
58+
elif 'lld-link' in compiler:
59+
override = comp_class.use_linker_args('lld-link', comp_version)
60+
check_args += override
5861

5962
if extra_args is not None:
6063
check_args.extend(extra_args)

mesonbuild/linkers/linkers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,9 @@ def get_always_args(self) -> T.List[str]:
13191319
def get_win_subsystem_args(self, value: str) -> T.List[str]:
13201320
return self._apply_prefix([f'/SUBSYSTEM:{value.upper()}'])
13211321

1322+
def fatal_warnings(self) -> T.List[str]:
1323+
return ['-WX']
1324+
13221325

13231326
class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
13241327

@@ -1348,6 +1351,9 @@ def get_win_subsystem_args(self, value: str) -> T.List[str]:
13481351
def get_thinlto_cache_args(self, path: str) -> T.List[str]:
13491352
return ["/lldltocache:" + path]
13501353

1354+
def fatal_warnings(self) -> T.List[str]:
1355+
return ['-WX']
1356+
13511357

13521358
class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker):
13531359

test cases/common/180 has link arg/meson.build

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,23 @@ endif
4545

4646
assert(cc.has_multi_link_arguments(is_arg), 'Arg that should have worked does not work.')
4747
assert(cc.has_multi_link_arguments([useless, is_arg]), 'Arg that should have worked does not work.')
48+
49+
# These are Visual Studio only flags
50+
# Testing has_argument_syntax is incorrect as it skips Microsoft Clang
51+
if cc.get_define('_MSC_FULL_VER') != ''
52+
if cc.get_linker_id() == 'link'
53+
is_only = '/OPT:REF'
54+
is_shared = '/GUARD:CF'
55+
else # ld-link
56+
is_only = '--color-diagnostics'
57+
is_shared = '-guard:cf'
58+
endif
59+
60+
# requires -Wl,xxx as it goes through the compiler
61+
if cc.get_argument_syntax() != 'msvc'
62+
is_only = '-Wl,@0@'.format(is_only)
63+
is_shared = '-Wl,@0@'.format(is_shared)
64+
endif
65+
66+
assert(cc.has_multi_link_arguments([is_only, is_shared]), 'Arg that should have worked does not work.')
67+
endif

0 commit comments

Comments
 (0)