From 64edfd50691be21fae1e61b8864d6de6fcead1d4 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 20 Sep 2018 20:29:57 +0100 Subject: 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() --- mesonbuild/backend/backends.py | 4 ++-- mesonbuild/backend/ninjabackend.py | 14 +++++++------- mesonbuild/build.py | 2 +- mesonbuild/compilers/__init__.py | 4 ++++ mesonbuild/compilers/c.py | 10 +++++++--- mesonbuild/compilers/cpp.py | 6 +++++- mesonbuild/dependencies/boost.py | 4 ++-- mesonbuild/environment.py | 22 +++++++++++++++++++--- 8 files changed, 47 insertions(+), 19 deletions(-) (limited to 'mesonbuild') diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 7dc1b83..370e35b 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -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'): diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 229980d..b6ed515 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -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]) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index df67c8e..8bb49c0 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -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 diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py index 677301e..7050b0c 100644 --- a/mesonbuild/compilers/__init__.py +++ b/mesonbuild/compilers/__init__.py @@ -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, diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 9b24e85..d17dd3a 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -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): diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 9dc2876..1045c7d 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -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): diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 17f9240..6a8050d 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -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: diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 8c6c60e..d9de7db 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -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 -- cgit v1.1 From e57fd018308e0ea5185391b3b6a76bb47479b7d7 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 21 Sep 2018 14:48:07 +0100 Subject: Accomodate clang-cl /showIncludes output Accomodate clang-cl /showIncludes output in detect_vs_dep_prefix(). clang-cl outputs lines terminated with \n, not \r\n v2: should invoke the detected compiler, not hardcode 'cl' --- mesonbuild/backend/ninjabackend.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'mesonbuild') diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index b6ed515..28c6480 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -185,7 +185,8 @@ int dummy; # and locale dependent. Any attempt at converting it to # Python strings leads to failure. We _must_ do this detection # in raw byte mode and write the result in raw bytes. - pc = subprocess.Popen(['cl', '/showIncludes', '/c', 'incdetect.c'], + pc = subprocess.Popen([compiler.get_exelist(), + '/showIncludes', '/c', 'incdetect.c'], cwd=self.environment.get_scratch_dir(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdo, _) = pc.communicate() @@ -195,7 +196,7 @@ int dummy; # different locales have different messages with a different # number of colons. Match up to the the drive name 'd:\'. matchre = re.compile(rb"^(.*\s)[a-zA-Z]:\\.*stdio.h$") - for line in stdo.split(b'\r\n'): + for line in re.split(rb'\r?\n', stdo): match = matchre.match(line) if match: with open(tempfilename, 'ab') as binfile: -- cgit v1.1 From bb31a8c1c752cff6f969e345f3a170f935f159cf Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 21 Sep 2018 17:38:46 +0100 Subject: Only add link arguments when needed in Compiler object methods Currently, ComplierHolder.determine_args() unconditionally adds the link arguments to the commmand, even if we aren't linking, because it doesn't have access to the mode (preprocess, compile, link) that _get_compiler_check_args() will use. This leads to command lines like: 'cl testfile.c /nologo /showIncludes /c /Fooutput.obj /Od kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib' which clang-cl considers invalid; MSVS cl accepts this, ignoring the unneeded libraries Change from passing extra_args down to _get_compiler_check_args(), to passing down a callback to CompilerHolder.determine_args() (with a bound kwargs argument), so it can consult mode and kwargs to determine the args to use. --- mesonbuild/compilers/c.py | 2 ++ mesonbuild/compilers/d.py | 2 ++ mesonbuild/interpreter.py | 30 ++++++++++++++++-------------- 3 files changed, 20 insertions(+), 14 deletions(-) (limited to 'mesonbuild') diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index d17dd3a..b41625c 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -392,6 +392,8 @@ class CCompiler(Compiler): return self.compiles(t.format(**fargs), env, extra_args, dependencies) def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): + if callable(extra_args): + extra_args = extra_args(mode) if extra_args is None: extra_args = [] elif isinstance(extra_args, str): diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 099d907..0a59e7f 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -274,6 +274,8 @@ class DCompiler(Compiler): return ['-Wl,-rpath,{}'.format(paths)] def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): + if callable(extra_args): + extra_args = extra_args(mode) if extra_args is None: extra_args = [] elif isinstance(extra_args, str): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c2cfe5c..86b761e 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -38,6 +38,7 @@ import subprocess from collections import namedtuple from pathlib import PurePath import traceback +import functools import importlib @@ -965,7 +966,7 @@ class CompilerHolder(InterpreterObject): def cmd_array_method(self, args, kwargs): return self.compiler.exelist - def determine_args(self, kwargs): + def determine_args(self, kwargs, mode='link'): nobuiltins = kwargs.get('no_builtin_args', False) if not isinstance(nobuiltins, bool): raise InterpreterException('Type of no_builtin_args not a boolean.') @@ -981,7 +982,8 @@ class CompilerHolder(InterpreterObject): if not nobuiltins: opts = self.environment.coredata.compiler_options args += self.compiler.get_option_compile_args(opts) - args += self.compiler.get_option_link_args(opts) + if mode == 'link': + args += self.compiler.get_option_link_args(opts) args += mesonlib.stringlistify(kwargs.get('args', [])) return args @@ -1039,7 +1041,7 @@ class CompilerHolder(InterpreterObject): testname = kwargs.get('name', '') if not isinstance(testname, str): raise InterpreterException('Testname argument must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs, endl=None) result = self.compiler.run(code, self.environment, extra_args, deps) if len(testname) > 0: @@ -1094,7 +1096,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_member must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) had = self.compiler.has_members(typename, [membername], prefix, self.environment, extra_args, deps) @@ -1122,7 +1124,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_members must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) had = self.compiler.has_members(typename, membernames, prefix, self.environment, extra_args, deps) @@ -1175,7 +1177,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_type must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) had = self.compiler.has_type(typename, prefix, self.environment, extra_args, deps) if had: @@ -1213,7 +1215,7 @@ class CompilerHolder(InterpreterObject): raise InterpreterException('High argument of compute_int must be an int.') if guess is not None and not isinstance(guess, int): raise InterpreterException('Guess argument of compute_int must be an int.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) res = self.compiler.compute_int(expression, low, high, guess, prefix, self.environment, extra_args, deps) mlog.log('Computing int of', mlog.bold(expression, True), msg, res) @@ -1234,7 +1236,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of sizeof must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) esize = self.compiler.sizeof(element, prefix, self.environment, extra_args, deps) mlog.log('Checking for size of', mlog.bold(element, True), msg, esize) @@ -1256,7 +1258,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of get_define() must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) value = self.compiler.get_define(element, prefix, self.environment, extra_args, deps) mlog.log('Fetching value of define', mlog.bold(element, True), msg, value) @@ -1281,7 +1283,7 @@ class CompilerHolder(InterpreterObject): testname = kwargs.get('name', '') if not isinstance(testname, str): raise InterpreterException('Testname argument must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs, endl=None) result = self.compiler.compiles(code, self.environment, extra_args, deps) if len(testname) > 0: @@ -1311,7 +1313,7 @@ class CompilerHolder(InterpreterObject): testname = kwargs.get('name', '') if not isinstance(testname, str): raise InterpreterException('Testname argument must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs, endl=None) result = self.compiler.links(code, self.environment, extra_args, deps) if len(testname) > 0: @@ -1338,7 +1340,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_header must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) haz = self.compiler.check_header(hname, prefix, self.environment, extra_args, deps) if haz: @@ -1363,7 +1365,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_header must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) haz = self.compiler.has_header(hname, prefix, self.environment, extra_args, deps) if haz: @@ -1389,7 +1391,7 @@ class CompilerHolder(InterpreterObject): prefix = kwargs.get('prefix', '') if not isinstance(prefix, str): raise InterpreterException('Prefix argument of has_header_symbol must be a string.') - extra_args = self.determine_args(kwargs) + extra_args = functools.partial(self.determine_args, kwargs) deps, msg = self.determine_dependencies(kwargs) haz = self.compiler.has_header_symbol(hname, symbol, prefix, self.environment, extra_args, deps) if haz: -- cgit v1.1 From b5b7e5b94ae7aaacc04a9d15e60892c385e9388e Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 1 Oct 2018 21:57:39 +0100 Subject: Teach VisualStudioCCompiler.has_arguments() about clang-cl When invoked as clang-cl to compile, it doesn't emit cl-compatible D9002 warnings about unknown options, but fortunately also supports -Werror-unknown-argument instead. When invoked to link, and using LINK, it does emit cl-compatible LNK4044 warnings about unknown options. --- mesonbuild/compilers/c.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'mesonbuild') diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index b41625c..24f661f 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1451,6 +1451,8 @@ class VisualStudioCCompiler(CCompiler): # http://stackoverflow.com/questions/15259720/how-can-i-make-the-microsoft-c-compiler-treat-unknown-flags-as-errors-rather-t def has_arguments(self, args, env, code, mode): warning_text = '4044' if mode == 'link' else '9002' + if self.id == 'clang-cl' and mode != 'link': + args = args + ['-Werror=unknown-argument'] with self._build_wrapper(code, env, extra_args=args, mode=mode) as p: if p.returncode != 0: return False -- cgit v1.1 From e820c66a4c367397111093bc7531868e2f0ef2e3 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 1 Oct 2018 23:06:29 +0100 Subject: Teach VisualStudioCCompiler.get_pch_use_args() to handle clang-cl It seems that clang-cl isn't quite compatible with cl in the way it handles pch, and when the precompiled header is used, the pathname of the header is needed, not just its filename. This fixes test\common\13 pch with clang-cl --- mesonbuild/compilers/c.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'mesonbuild') diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 24f661f..b185dfb 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1316,6 +1316,8 @@ class VisualStudioCCompiler(CCompiler): def get_pch_use_args(self, pch_dir, header): base = os.path.basename(header) + if self.id == 'clang-cl': + base = header pchname = self.get_pch_name(header) return ['/FI' + base, '/Yu' + base, '/Fp' + os.path.join(pch_dir, pchname)] -- cgit v1.1 From d35034b21bfdcbdb21853340ff983e908ada101f Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Tue, 23 Oct 2018 16:14:40 +0100 Subject: Use 'rc' resource compiler with clang-cl toolchain The LLVM toolchain doesn't come with a Windows resource compiler at the moment. Use 'rc' from the Windows SDK. --- mesonbuild/modules/windows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mesonbuild') diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index f0d5113..4d0f244 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -60,7 +60,7 @@ class WindowsModule(ExtensionModule): if not rescomp or not rescomp.found(): comp = self.detect_compiler(state.compilers) - if comp.id == 'msvc': + if comp.id == 'msvc' or comp.id == 'clang-cl': rescomp = ExternalProgram('rc', silent=True) else: rescomp = ExternalProgram('windres', silent=True) -- cgit v1.1 From a025c98d3082806321f53c4dfae9c738d1dc1584 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Wed, 24 Oct 2018 14:47:02 +0100 Subject: Qualify checks of self.version by self.id in VisualStudioC/CPPCompiler --- mesonbuild/compilers/c.py | 10 +++++++--- mesonbuild/compilers/cpp.py | 17 ++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'mesonbuild') diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index b185dfb..ab62afd 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1298,7 +1298,7 @@ class VisualStudioCCompiler(CCompiler): def get_buildtype_args(self, buildtype): args = compilers.msvc_buildtype_args[buildtype] - if version_compare(self.version, '<18.0'): + if self.id == 'msvc' and version_compare(self.version, '<18.0'): args = [arg for arg in args if arg != '/Gw'] return args @@ -1470,7 +1470,7 @@ class VisualStudioCCompiler(CCompiler): # build obviously, which is why we only do this when PCH is on. # This was added in Visual Studio 2013 (MSVC 18.0). Before that it was # always on: https://msdn.microsoft.com/en-us/library/dn502518.aspx - if pch and version_compare(self.version, '>=18.0'): + if pch and self.id == 'msvc' and version_compare(self.version, '>=18.0'): args = ['/FS'] + args return args @@ -1487,7 +1487,7 @@ class VisualStudioCCompiler(CCompiler): def get_instruction_set_args(self, instruction_set): if self.is_64: return vs64_instruction_set_args.get(instruction_set, None) - if self.version.split('.')[0] == '16' and instruction_set == 'avx': + if self.id == 'msvc' and self.version.split('.')[0] == '16' and instruction_set == 'avx': # VS documentation says that this exists and should work, but # it does not. The headers do not contain AVX intrinsics # and the can not be called. @@ -1495,6 +1495,10 @@ class VisualStudioCCompiler(CCompiler): return vs32_instruction_set_args.get(instruction_set, None) def get_toolset_version(self): + if self.id == 'clang-cl': + # I have no idea + return '14.1' + # See boost/config/compiler/visualc.cpp for up to date mapping try: version = int(''.join(self.version.split('.')[0:2])) diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 1045c7d..65a1033 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -310,12 +310,15 @@ class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler): def get_options(self): cpp_stds = ['none', 'c++11', 'vc++11'] - # Visual Studio 2015 and later - if version_compare(self.version, '>=19'): - cpp_stds.extend(['c++14', 'vc++14', 'c++latest', 'vc++latest']) - # Visual Studio 2017 and later - if version_compare(self.version, '>=19.11'): - cpp_stds.extend(['c++17', 'vc++17']) + if self.id == 'clang-cl': + cpp_stds.extend(['c++14', 'vc++14', 'c++17', 'vc++17', 'c++latest']) + else: + # Visual Studio 2015 and later + if version_compare(self.version, '>=19'): + cpp_stds.extend(['c++14', 'vc++14', 'c++latest', 'vc++latest']) + # Visual Studio 2017 and later + if version_compare(self.version, '>=19.11'): + cpp_stds.extend(['c++17', 'vc++17']) opts = CPPCompiler.get_options(self) opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', @@ -356,7 +359,7 @@ class VisualStudioCPPCompiler(VisualStudioCCompiler, CPPCompiler): # which means setting the C++ standard version to C++14, in compilers that support it # (i.e., after VS2015U3) # if one is using anything before that point, one cannot set the standard. - if version_compare(self.version, '>=19.00.24210'): + if self.id == 'clang-cl' or version_compare(self.version, '>=19.00.24210'): mlog.warning('MSVC does not support C++11; ' 'attempting best effort; setting the standard to C++14') args.append('/std:c++14') -- cgit v1.1 From 2993fc4e8a9dcd78d581277f7100bc68d603fd5d Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 8 Oct 2018 18:14:01 +0100 Subject: Use llvm-lib as an alternative to lib Detect llvm-lib as an alternative Windows static linker to lib --- mesonbuild/environment.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'mesonbuild') diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index d9de7db..dfed376 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -363,6 +363,7 @@ class Environment: self.default_rust = ['rustc'] self.default_static_linker = ['ar'] self.vs_static_linker = ['lib'] + self.clang_cl_static_linker = ['llvm-lib'] self.gcc_static_linker = ['gcc-ar'] self.clang_static_linker = ['llvm-ar'] @@ -919,7 +920,7 @@ This is probably wrong, it should always point to the native compiler.''' % evar if evar in os.environ: linkers = [shlex.split(os.environ[evar])] elif isinstance(compiler, compilers.VisualStudioCCompiler): - linkers = [self.vs_static_linker] + linkers = [self.vs_static_linker, self.clang_cl_static_linker] elif isinstance(compiler, compilers.GnuCompiler): # Use gcc-ar if available; needed for LTO linkers = [self.gcc_static_linker, self.default_static_linker] @@ -929,14 +930,14 @@ This is probably wrong, it should always point to the native compiler.''' % evar elif isinstance(compiler, compilers.DCompiler): # Prefer static linkers over linkers used by D compilers if mesonlib.is_windows(): - linkers = [self.vs_static_linker, compiler.get_linker_exelist()] + linkers = [self.vs_static_linker, self.clang_cl_static_linker, compiler.get_linker_exelist()] else: linkers = [self.default_static_linker, compiler.get_linker_exelist()] else: linkers = [self.default_static_linker] popen_exceptions = {} for linker in linkers: - if 'lib' in linker or 'lib.exe' in linker: + if not set(['lib', 'lib.exe', 'llvm-lib', 'llvm-lib.exe']).isdisjoint(linker): arg = '/?' else: arg = '--version' @@ -945,7 +946,7 @@ This is probably wrong, it should always point to the native compiler.''' % evar except OSError as e: popen_exceptions[' '.join(linker + [arg])] = e continue - if '/OUT:' in out or '/OUT:' in err: + if '/OUT:' in out.upper() or '/OUT:' in err.upper(): return VisualStudioLinker(linker) if p.returncode == 0 and ('armar' in linker or 'armar.exe' in linker): return ArmarLinker(linker) -- cgit v1.1 From c789efb8c883a719b308e023b82fab4d808ab460 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 8 Oct 2018 19:39:41 +0100 Subject: Use lld-link with clang-cl Use lld-link dynamic linker with clang-cl Don't hardcode dynamic linker name in tests --- mesonbuild/compilers/c.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'mesonbuild') diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index ab62afd..35c71df 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1345,7 +1345,12 @@ class VisualStudioCCompiler(CCompiler): return [] def get_linker_exelist(self): - return ['link'] # FIXME, should have same path as compiler. + # FIXME, should have same path as compiler. + # FIXME, should be controllable via cross-file. + if self.id == 'clang-cl': + return ['lld-link'] + else: + return ['link'] def get_linker_always_args(self): return ['/nologo'] -- cgit v1.1