aboutsummaryrefslogtreecommitdiffstats
path: root/meson/mesonbuild/compilers/mixins/clang.py
diff options
context:
space:
mode:
Diffstat (limited to 'meson/mesonbuild/compilers/mixins/clang.py')
-rw-r--r--meson/mesonbuild/compilers/mixins/clang.py162
1 files changed, 162 insertions, 0 deletions
diff --git a/meson/mesonbuild/compilers/mixins/clang.py b/meson/mesonbuild/compilers/mixins/clang.py
new file mode 100644
index 000000000..f7e94928c
--- /dev/null
+++ b/meson/mesonbuild/compilers/mixins/clang.py
@@ -0,0 +1,162 @@
+# Copyright 2019 The meson development team
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Abstractions for the LLVM/Clang compiler family."""
+
+import os
+import shutil
+import typing as T
+
+from ... import mesonlib
+from ...linkers import AppleDynamicLinker, ClangClDynamicLinker, LLVMDynamicLinker, GnuGoldDynamicLinker
+from ...mesonlib import OptionKey
+from ..compilers import CompileCheckMode
+from .gnu import GnuLikeCompiler
+
+if T.TYPE_CHECKING:
+ from ...environment import Environment
+ from ...dependencies import Dependency # noqa: F401
+
+clang_color_args = {
+ 'auto': ['-fcolor-diagnostics'],
+ 'always': ['-fcolor-diagnostics'],
+ 'never': ['-fno-color-diagnostics'],
+} # type: T.Dict[str, T.List[str]]
+
+clang_optimization_args = {
+ '0': ['-O0'],
+ 'g': ['-Og'],
+ '1': ['-O1'],
+ '2': ['-O2'],
+ '3': ['-O3'],
+ 's': ['-Os'],
+} # type: T.Dict[str, T.List[str]]
+
+class ClangCompiler(GnuLikeCompiler):
+
+ def __init__(self, defines: T.Optional[T.Dict[str, str]]):
+ super().__init__()
+ self.id = 'clang'
+ self.defines = defines or {}
+ self.base_options.update(
+ {OptionKey('b_colorout'), OptionKey('b_lto_threads'), OptionKey('b_lto_mode')})
+
+ # TODO: this really should be part of the linker base_options, but
+ # linkers don't have base_options.
+ if isinstance(self.linker, AppleDynamicLinker):
+ self.base_options.add(OptionKey('b_bitcode'))
+ # All Clang backends can also do LLVM IR
+ self.can_compile_suffixes.add('ll')
+
+ def get_colorout_args(self, colortype: str) -> T.List[str]:
+ return clang_color_args[colortype][:]
+
+ def has_builtin_define(self, define: str) -> bool:
+ return define in self.defines
+
+ def get_builtin_define(self, define: str) -> T.Optional[str]:
+ return self.defines.get(define)
+
+ def get_optimization_args(self, optimization_level: str) -> T.List[str]:
+ return clang_optimization_args[optimization_level]
+
+ def get_pch_suffix(self) -> str:
+ return 'pch'
+
+ def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
+ # Workaround for Clang bug http://llvm.org/bugs/show_bug.cgi?id=15136
+ # This flag is internal to Clang (or at least not documented on the man page)
+ # so it might change semantics at any time.
+ return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))]
+
+ def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
+ # Clang is different than GCC, it will return True when a symbol isn't
+ # defined in a header. Specifically this seems ot have something to do
+ # with functions that may be in a header on some systems, but not all of
+ # them. `strlcat` specifically with can trigger this.
+ myargs: T.List[str] = ['-Werror=implicit-function-declaration']
+ if mode is CompileCheckMode.COMPILE:
+ myargs.extend(['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument'])
+ if mesonlib.version_compare(self.version, '>=3.6.0'):
+ myargs.append('-Werror=ignored-optimization-argument')
+ return super().get_compiler_check_args(mode) + myargs
+
+ def has_function(self, funcname: str, prefix: str, env: 'Environment', *,
+ extra_args: T.Optional[T.List[str]] = None,
+ dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
+ if extra_args is None:
+ extra_args = []
+ # Starting with XCode 8, we need to pass this to force linker
+ # visibility to obey OS X/iOS/tvOS minimum version targets with
+ # -mmacosx-version-min, -miphoneos-version-min, -mtvos-version-min etc.
+ # https://github.com/Homebrew/homebrew-core/issues/3727
+ # TODO: this really should be communicated by the linker
+ if isinstance(self.linker, AppleDynamicLinker) and mesonlib.version_compare(self.version, '>=8.0'):
+ extra_args.append('-Wl,-no_weak_imports')
+ return super().has_function(funcname, prefix, env, extra_args=extra_args,
+ dependencies=dependencies)
+
+ def openmp_flags(self) -> T.List[str]:
+ if mesonlib.version_compare(self.version, '>=3.8.0'):
+ return ['-fopenmp']
+ elif mesonlib.version_compare(self.version, '>=3.7.0'):
+ return ['-fopenmp=libomp']
+ else:
+ # Shouldn't work, but it'll be checked explicitly in the OpenMP dependency.
+ return []
+
+ @classmethod
+ def use_linker_args(cls, linker: str) -> T.List[str]:
+ # Clang additionally can use a linker specified as a path, which GCC
+ # (and other gcc-like compilers) cannot. This is becuse clang (being
+ # llvm based) is retargetable, while GCC is not.
+ #
+
+ # qcld: Qualcomm Snapdragon linker, based on LLVM
+ if linker == 'qcld':
+ return ['-fuse-ld=qcld']
+
+ if shutil.which(linker):
+ if not shutil.which(linker):
+ raise mesonlib.MesonException(
+ f'Cannot find linker {linker}.')
+ return [f'-fuse-ld={linker}']
+ return super().use_linker_args(linker)
+
+ def get_has_func_attribute_extra_args(self, name: str) -> T.List[str]:
+ # Clang only warns about unknown or ignored attributes, so force an
+ # error.
+ return ['-Werror=attributes']
+
+ def get_coverage_link_args(self) -> T.List[str]:
+ return ['--coverage']
+
+ def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T.List[str]:
+ args: T.List[str] = []
+ if mode == 'thin':
+ # Thin LTO requires the use of gold, lld, ld64, or lld-link
+ if not isinstance(self.linker, (AppleDynamicLinker, ClangClDynamicLinker, LLVMDynamicLinker, GnuGoldDynamicLinker)):
+ raise mesonlib.MesonException(f"LLVM's thinLTO only works with gnu gold, lld, lld-link, and ld64, not {self.linker.id}")
+ args.append(f'-flto={mode}')
+ else:
+ assert mode == 'default', 'someone forgot to wire something up'
+ args.extend(super().get_lto_compile_args(threads=threads))
+ return args
+
+ def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default') -> T.List[str]:
+ args = self.get_lto_compile_args(threads=threads, mode=mode)
+ # In clang -flto=0 means auto
+ if threads >= 0:
+ args.append(f'-flto-jobs={threads}')
+ return args