Detect clang-cl as msvc-like, not clang-like

Handle clang's cl or clang-cl being in PATH, or set in CC/CXX

Future work: checking the name of the executable here seems like a bad idea.
These compilers will fail to be detected if they are renamed.

v2:
Update compiler.get_argument_type() test
Fix comparisons of id inside CCompiler, backends and elsewhere

v3:
ClangClCPPCompiler should be a subclass of ClangClCCompier, as well

Future work: mocking in test_find_library_patterns() is effected, as we
now test for a subclass, rather than self.id in CCompiler.get_library_naming()
pull/4250/head
Jon Turney 6 years ago
parent 63f4f9481e
commit 64edfd5069
No known key found for this signature in database
GPG Key ID: C7C86F0370285C81
  1. 4
      mesonbuild/backend/backends.py
  2. 14
      mesonbuild/backend/ninjabackend.py
  3. 2
      mesonbuild/build.py
  4. 4
      mesonbuild/compilers/__init__.py
  5. 10
      mesonbuild/compilers/c.py
  6. 6
      mesonbuild/compilers/cpp.py
  7. 4
      mesonbuild/dependencies/boost.py
  8. 22
      mesonbuild/environment.py
  9. 4
      run_unittests.py
  10. 2
      test cases/common/206 argument syntax/meson.build

@ -23,7 +23,7 @@ import subprocess
from ..mesonlib import MesonException, OrderedSet
from ..mesonlib import classify_unity_sources
from ..mesonlib import File
from ..compilers import CompilerArgs
from ..compilers import CompilerArgs, VisualStudioCCompiler
from collections import OrderedDict
import shlex
from functools import lru_cache
@ -491,7 +491,7 @@ class Backend:
return args
extra_args = []
# Compiler-specific escaping is needed for -D args but not for any others
if compiler.get_id() == 'msvc':
if isinstance(compiler, VisualStudioCCompiler):
# MSVC needs escaping when a -D argument ends in \ or \"
for arg in args:
if arg.startswith('-D') or arg.startswith('/D'):

@ -29,7 +29,7 @@ from .. import build
from .. import mlog
from .. import dependencies
from .. import compilers
from ..compilers import CompilerArgs, CCompiler
from ..compilers import CompilerArgs, CCompiler, VisualStudioCCompiler
from ..linkers import ArLinker
from ..mesonlib import File, MesonException, OrderedSet
from ..mesonlib import get_compiler_for_source, has_path_sep
@ -169,7 +169,7 @@ class NinjaBackend(backends.Backend):
Detect the search prefix to use.'''
for compiler in self.build.compilers.values():
# Have to detect the dependency format
if compiler.id == 'msvc':
if isinstance(compiler, VisualStudioCCompiler):
break
else:
# None of our compilers are MSVC, we're done.
@ -1604,7 +1604,7 @@ rule FORTRAN_DEP_HACK%s
compile_only_args=' '.join(compiler.get_compile_only_args())
)
description = ' description = Compiling %s object $out.\n' % compiler.get_display_language()
if compiler.get_id() == 'msvc':
if isinstance(compiler, VisualStudioCCompiler):
deps = ' deps = msvc\n'
else:
deps = ' deps = gcc\n'
@ -1636,7 +1636,7 @@ rule FORTRAN_DEP_HACK%s
if d != '$out' and d != '$in':
d = quote_func(d)
quoted_depargs.append(d)
if compiler.get_id() == 'msvc':
if isinstance(compiler, VisualStudioCCompiler):
output = ''
else:
output = ' '.join(compiler.get_output_args('$out'))
@ -1648,7 +1648,7 @@ rule FORTRAN_DEP_HACK%s
compile_only_args=' '.join(compiler.get_compile_only_args())
)
description = ' description = Precompiling header %s.\n' % '$in'
if compiler.get_id() == 'msvc':
if isinstance(compiler, VisualStudioCCompiler):
deps = ' deps = msvc\n'
else:
deps = ' deps = gcc\n'
@ -1839,7 +1839,7 @@ rule FORTRAN_DEP_HACK%s
return compiler.get_no_stdinc_args()
def get_compile_debugfile_args(self, compiler, target, objfile):
if compiler.id != 'msvc':
if not isinstance(compiler, VisualStudioCCompiler):
return []
# The way MSVC uses PDB files is documented exactly nowhere so
# the following is what we have been able to decipher via
@ -2203,7 +2203,7 @@ rule FORTRAN_DEP_HACK%s
''.format(target.get_basename())
raise InvalidArguments(msg)
compiler = target.compilers[lang]
if compiler.id == 'msvc':
if isinstance(compiler, VisualStudioCCompiler):
src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[-1])
(commands, dep, dst, objs) = self.generate_msvc_pch_command(target, compiler, pch)
extradep = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0])

@ -1168,7 +1168,7 @@ You probably should put it in link_with instead.''')
'''
linker, _ = self.get_clink_dynamic_linker_and_stdlibs()
# Mixing many languages with MSVC is not supported yet so ignore stdlibs.
if linker and linker.get_id() in ['msvc', 'llvm', 'dmd']:
if linker and linker.get_id() in ['msvc', 'clang-cl', 'llvm', 'dmd']:
return True
return False

@ -45,6 +45,8 @@ __all__ = [
'ClangCPPCompiler',
'ClangObjCCompiler',
'ClangObjCPPCompiler',
'ClangClCCompiler',
'ClangClCPPCompiler',
'CompilerArgs',
'CPPCompiler',
'DCompiler',
@ -114,6 +116,7 @@ from .c import (
ArmCCompiler,
ArmclangCCompiler,
ClangCCompiler,
ClangClCCompiler,
GnuCCompiler,
ElbrusCCompiler,
IntelCCompiler,
@ -124,6 +127,7 @@ from .cpp import (
ArmCPPCompiler,
ArmclangCPPCompiler,
ClangCPPCompiler,
ClangClCPPCompiler,
GnuCPPCompiler,
ElbrusCPPCompiler,
IntelCPPCompiler,

@ -170,7 +170,7 @@ class CCompiler(Compiler):
else:
# GNU ld and LLVM lld
return ['-Wl,--allow-shlib-undefined']
elif self.id == 'msvc':
elif isinstance(self, VisualStudioCCompiler):
# link.exe
return ['/FORCE:UNRESOLVED']
# FIXME: implement other linkers
@ -890,7 +890,7 @@ class CCompiler(Compiler):
stlibext = ['a']
# We've always allowed libname to be both `foo` and `libfoo`,
# and now people depend on it
if strict and self.id != 'msvc': # lib prefix is not usually used with msvc
if strict and not isinstance(self, VisualStudioCCompiler): # lib prefix is not usually used with msvc
prefixes = ['lib']
else:
prefixes = ['lib', '']
@ -900,7 +900,7 @@ class CCompiler(Compiler):
elif for_windows(env.is_cross_build(), env):
# FIXME: .lib files can be import or static so we should read the
# file, figure out which one it is, and reject the wrong kind.
if self.id == 'msvc':
if isinstance(self, VisualStudioCCompiler):
shlibext = ['lib']
else:
shlibext = ['dll.a', 'lib', 'dll']
@ -1546,6 +1546,10 @@ class VisualStudioCCompiler(CCompiler):
def get_argument_syntax(self):
return 'msvc'
class ClangClCCompiler(VisualStudioCCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap, is_64):
super().__init__(exelist, version, is_cross, exe_wrap, is_64)
self.id = 'clang-cl'
class ArmCCompiler(ArmCompiler, CCompiler):
def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs):

@ -19,7 +19,7 @@ from .. import coredata
from .. import mlog
from ..mesonlib import MesonException, version_compare
from .c import CCompiler, VisualStudioCCompiler
from .c import CCompiler, VisualStudioCCompiler, ClangClCCompiler
from .compilers import (
CompilerType,
gnu_winlibs,
@ -378,6 +378,10 @@ class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler):
# so just use the plain C args.
return VisualStudioCCompiler.get_compiler_check_args(self)
class ClangClCPPCompiler(VisualStudioCPPCompiler, ClangClCCompiler):
def __init__(self, exelist, version, is_cross, exe_wrap, is_64):
VisualStudioCPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, is_64)
self.id = 'clang-cl'
class ArmCPPCompiler(ArmCompiler, CPPCompiler):
def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap=None, **kwargs):

@ -288,7 +288,7 @@ class BoostDependency(ExternalDependency):
tag = None
compiler = self.env.detect_cpp_compiler(self.want_cross)
if mesonlib.for_windows(self.want_cross, self.env):
if compiler.get_id() == 'msvc':
if compiler.get_id() in ['msvc', 'clang-cl']:
comp_ts_version = compiler.get_toolset_version()
compiler_ts = comp_ts_version.split('.')
# FIXME - what about other compilers?
@ -320,7 +320,7 @@ class BoostDependency(ExternalDependency):
def arch_tag(self):
# currently only applies to windows msvc installed binaries
if self.env.detect_cpp_compiler(self.want_cross).get_id() != 'msvc':
if self.env.detect_cpp_compiler(self.want_cross).get_id() not in ['msvc', 'clang-cl']:
return ''
# pre-compiled binaries only added arch tag for versions > 1.64
if float(self.version) < 1.65:

@ -39,6 +39,8 @@ from .compilers import (
ClangCPPCompiler,
ClangObjCCompiler,
ClangObjCPPCompiler,
ClangClCCompiler,
ClangClCPPCompiler,
G95FortranCompiler,
GnuCCompiler,
GnuCPPCompiler,
@ -190,6 +192,8 @@ def detect_windows_arch(compilers):
platform = os.environ.get('Platform', 'x86').lower()
if platform == 'x86':
return platform
if compiler.id == 'clang-cl' and not compiler.is_64:
return 'x86'
if compiler.id == 'gcc' and compiler.has_builtin_define('__i386__'):
return 'x86'
return os_arch
@ -344,8 +348,8 @@ class Environment:
# List of potential compilers.
if mesonlib.is_windows():
self.default_c = ['cl', 'cc', 'gcc', 'clang']
self.default_cpp = ['cl', 'c++', 'g++', 'clang++']
self.default_c = ['cl', 'cc', 'gcc', 'clang', 'clang-cl']
self.default_cpp = ['cl', 'c++', 'g++', 'clang++', 'clang-cl']
else:
self.default_c = ['cc', 'gcc', 'clang']
self.default_cpp = ['c++', 'g++', 'clang++']
@ -537,7 +541,7 @@ This is probably wrong, it should always point to the native compiler.''' % evar
for compiler in compilers:
if isinstance(compiler, str):
compiler = [compiler]
if 'cl' in compiler or 'cl.exe' in compiler:
if not set(['cl', 'cl.exe', 'clang-cl', 'clang-cl.exe']).isdisjoint(compiler):
# Watcom C provides it's own cl.exe clone that mimics an older
# version of Microsoft's compiler. Since Watcom's cl.exe is
# just a wrapper, we skip using it if we detect its presence
@ -606,6 +610,18 @@ This is probably wrong, it should always point to the native compiler.''' % evar
compiler_type = CompilerType.ARM_WIN
cls = ArmclangCCompiler if lang == 'c' else ArmclangCPPCompiler
return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version)
if 'CL.EXE COMPATIBILITY' in out:
# if this is clang-cl masquerading as cl, detect it as cl, not
# clang
arg = '--version'
try:
p, out, err = Popen_safe(compiler + [arg])
except OSError as e:
popen_exceptions[' '.join(compiler + [arg])] = e
version = search_version(out)
is_64 = 'Target: x86_64' in out
cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler
return cls(compiler, version, is_cross, exe_wrap, is_64)
if 'clang' in out:
if 'Apple' in out or mesonlib.for_darwin(want_cross, self):
compiler_type = CompilerType.CLANG_OSX

@ -624,10 +624,6 @@ class InternalTests(unittest.TestCase):
with PatchModule(mesonbuild.compilers.c.for_windows,
'mesonbuild.compilers.c.for_windows', true):
self._test_all_naming(cc, env, patterns, 'windows-mingw')
cc.id = 'msvc'
with PatchModule(mesonbuild.compilers.c.for_windows,
'mesonbuild.compilers.c.for_windows', true):
self._test_all_naming(cc, env, patterns, 'windows-msvc')
def test_pkgconfig_parse_libs(self):
'''

@ -7,7 +7,7 @@ cc = meson.get_compiler('c')
if ['gcc', 'lcc', 'clang'].contains(cc.get_id())
expected = 'gcc'
elif cc.get_id() == 'msvc'
elif ['msvc', 'clang-cl'].contains(cc.get_id())
expected = 'msvc'
elif cc.get_id() == 'intel'
if host_machine.system() == 'windows'

Loading…
Cancel
Save