diff --git a/mesonbuild/compilers/mixins/clang.py b/mesonbuild/compilers/mixins/clang.py index a57b9a9af..f982509f4 100644 --- a/mesonbuild/compilers/mixins/clang.py +++ b/mesonbuild/compilers/mixins/clang.py @@ -11,7 +11,7 @@ import typing as T from ... import mesonlib from ...linkers.linkers import AppleDynamicLinker, ClangClDynamicLinker, LLVMDynamicLinker, GnuGoldDynamicLinker, \ - MoldDynamicLinker + MoldDynamicLinker, MSVCDynamicLinker from ...mesonlib import OptionKey from ..compilers import CompileCheckMode from .gnu import GnuLikeCompiler @@ -111,6 +111,13 @@ class ClangCompiler(GnuLikeCompiler): # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency. return [] + def gen_vs_module_defs_args(self, defsfile: str) -> T.List[str]: + if isinstance(self.linker, (MSVCDynamicLinker)): + # With MSVC, DLLs only export symbols that are explicitly exported, + # so if a module defs file is specified, we use that to export symbols + return ['-Wl,/DEF:' + defsfile] + return super().gen_vs_module_defs_args(defsfile) + @classmethod def use_linker_args(cls, linker: str, version: str) -> T.List[str]: # Clang additionally can use a linker specified as a path, which GCC @@ -155,6 +162,12 @@ class ClangCompiler(GnuLikeCompiler): args.extend(super().get_lto_compile_args(threads=threads)) return args + def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: + if isinstance(self.linker, (ClangClDynamicLinker, MSVCDynamicLinker)): + return [flag if flag.startswith('-Wl,') else f'-Wl,{flag}' for flag in args] + else: + return args + def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default', thinlto_cache_dir: T.Optional[str] = None) -> T.List[str]: args = self.get_lto_compile_args(threads=threads, mode=mode) diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index d6ebd6e0d..4e2ce099f 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -460,6 +460,18 @@ class ClangClCompiler(VisualStudioLikeCompiler): path = '.' return ['/clang:-isystem' + path] if is_system else ['-I' + path] + @classmethod + def use_linker_args(cls, linker: str, version: str) -> T.List[str]: + # Clang additionally can use a linker specified as a path, unlike MSVC. + if linker == 'lld-link': + return ['-fuse-ld=lld-link'] + return super().use_linker_args(linker, version) + + def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: + # clang-cl forwards arguments span-wise with the /LINK flag + # therefore -Wl will be received by lld-link or LINK and rejected + 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]) + def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: if dep.get_include_type() == 'system': converted: T.List[str] = [] diff --git a/mesonbuild/linkers/detect.py b/mesonbuild/linkers/detect.py index 1bce413f4..bb391d171 100644 --- a/mesonbuild/linkers/detect.py +++ b/mesonbuild/linkers/detect.py @@ -55,6 +55,9 @@ def guess_win_linker(env: 'Environment', compiler: T.List[str], comp_class: T.Ty if value is not None: override = comp_class.use_linker_args(value[0], comp_version) check_args += override + elif 'lld-link' in compiler: + override = comp_class.use_linker_args('lld-link', comp_version) + check_args += override if extra_args is not None: check_args.extend(extra_args) diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index 657e3618b..ca3c85471 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -1319,6 +1319,9 @@ class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): def get_win_subsystem_args(self, value: str) -> T.List[str]: return self._apply_prefix([f'/SUBSYSTEM:{value.upper()}']) + def fatal_warnings(self) -> T.List[str]: + return ['-WX'] + class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): @@ -1348,6 +1351,9 @@ class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): def get_thinlto_cache_args(self, path: str) -> T.List[str]: return ["/lldltocache:" + path] + def fatal_warnings(self) -> T.List[str]: + return ['-WX'] + class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): diff --git a/test cases/common/180 has link arg/meson.build b/test cases/common/180 has link arg/meson.build index 6bfbd59e7..111b0b9ea 100644 --- a/test cases/common/180 has link arg/meson.build +++ b/test cases/common/180 has link arg/meson.build @@ -45,3 +45,23 @@ endif assert(cc.has_multi_link_arguments(is_arg), 'Arg that should have worked does not work.') assert(cc.has_multi_link_arguments([useless, is_arg]), 'Arg that should have worked does not work.') + +# These are Visual Studio only flags +# Testing has_argument_syntax is incorrect as it skips Microsoft Clang +if cc.get_define('_MSC_FULL_VER') != '' + if cc.get_linker_id() == 'link' + is_only = '/OPT:REF' + is_shared = '/GUARD:CF' + else # ld-link + is_only = '--color-diagnostics' + is_shared = '-guard:cf' + endif + + # requires -Wl,xxx as it goes through the compiler + if cc.get_argument_syntax() != 'msvc' + is_only = '-Wl,@0@'.format(is_only) + is_shared = '-Wl,@0@'.format(is_shared) + endif + + assert(cc.has_multi_link_arguments([is_only, is_shared]), 'Arg that should have worked does not work.') +endif