aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/compilers/compilers.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/compilers/compilers.py')
-rw-r--r--mesonbuild/compilers/compilers.py396
1 files changed, 211 insertions, 185 deletions
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index c03f1fd..af6b050 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2022 The Meson development team
-# Copyright © 2023 Intel Corporation
+# Copyright © 2023-2025 Intel Corporation
from __future__ import annotations
@@ -9,25 +9,24 @@ import contextlib, os.path, re
import enum
import itertools
import typing as T
-from dataclasses import dataclass
+from dataclasses import dataclass, field
from functools import lru_cache
-from .. import coredata
from .. import mlog
from .. import mesonlib
from .. import options
from ..mesonlib import (
HoldableObject,
EnvironmentException, MesonException,
- Popen_safe_logged, LibType, TemporaryDirectoryWinProof, OptionKey,
+ Popen_safe_logged, LibType, TemporaryDirectoryWinProof,
)
-
+from ..options import OptionKey
from ..arglist import CompilerArgs
if T.TYPE_CHECKING:
- from typing import Any
+ from .. import coredata
from ..build import BuildTarget, DFeatures
- from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType
+ from ..options import MutableKeyedOptionDictType
from ..envconfig import MachineInfo
from ..environment import Environment
from ..linkers import RSPFileSyntax
@@ -36,8 +35,8 @@ if T.TYPE_CHECKING:
from ..dependencies import Dependency
CompilerType = T.TypeVar('CompilerType', bound='Compiler')
- _T = T.TypeVar('_T')
- UserOptionType = T.TypeVar('UserOptionType', bound=options.UserOption)
+
+_T = T.TypeVar('_T')
"""This file contains the data files of all compilers Meson knows
about. To support a new compiler, add its information below.
@@ -50,9 +49,9 @@ lib_suffixes = {'a', 'lib', 'dll', 'dll.a', 'dylib', 'so', 'js'}
# Mapping of language to suffixes of files that should always be in that language
# This means we can't include .h headers here since they could be C, C++, ObjC, etc.
# First suffix is the language's default.
-lang_suffixes = {
+lang_suffixes: T.Mapping[str, T.Tuple[str, ...]] = {
'c': ('c',),
- 'cpp': ('cpp', 'cppm', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx', 'ino', 'ixx', 'C', 'H'),
+ 'cpp': ('cpp', 'cppm', 'cc', 'cp', 'cxx', 'c++', 'hh', 'hp', 'hpp', 'ipp', 'hxx', 'h++', 'ino', 'ixx', 'CPP', 'C', 'HPP', 'H'),
'cuda': ('cu',),
# f90, f95, f03, f08 are for free-form fortran ('f90' recommended)
# f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended)
@@ -68,6 +67,7 @@ lang_suffixes = {
'cython': ('pyx', ),
'nasm': ('asm', 'nasm',),
'masm': ('masm',),
+ 'linearasm': ('sa',),
}
all_languages = lang_suffixes.keys()
c_cpp_suffixes = {'h'}
@@ -132,11 +132,15 @@ def is_header(fname: 'mesonlib.FileOrString') -> bool:
def is_source_suffix(suffix: str) -> bool:
return suffix in source_suffixes
+@lru_cache(maxsize=None)
+def cached_is_source_by_name(fname: str) -> bool:
+ suffix = fname.split('.')[-1].lower()
+ return is_source_suffix(suffix)
+
def is_source(fname: 'mesonlib.FileOrString') -> bool:
if isinstance(fname, mesonlib.File):
fname = fname.fname
- suffix = fname.split('.')[-1].lower()
- return is_source_suffix(suffix)
+ return cached_is_source_by_name(fname)
def is_assembly(fname: 'mesonlib.FileOrString') -> bool:
if isinstance(fname, mesonlib.File):
@@ -144,6 +148,12 @@ def is_assembly(fname: 'mesonlib.FileOrString') -> bool:
suffix = fname.split('.')[-1]
return suffix in assembler_suffixes
+def is_java(fname: mesonlib.FileOrString) -> bool:
+ if isinstance(fname, mesonlib.File):
+ fname = fname.fname
+ suffix = fname.split('.')[-1]
+ return suffix in lang_suffixes['java']
+
def is_llvm_ir(fname: 'mesonlib.FileOrString') -> bool:
if isinstance(fname, mesonlib.File):
fname = fname.fname
@@ -151,14 +161,14 @@ def is_llvm_ir(fname: 'mesonlib.FileOrString') -> bool:
return suffix in llvm_ir_suffixes
@lru_cache(maxsize=None)
-def cached_by_name(fname: 'mesonlib.FileOrString') -> bool:
+def cached_is_object_by_name(fname: str) -> bool:
suffix = fname.split('.')[-1]
return suffix in obj_suffixes
def is_object(fname: 'mesonlib.FileOrString') -> bool:
if isinstance(fname, mesonlib.File):
fname = fname.fname
- return cached_by_name(fname)
+ return cached_is_object_by_name(fname)
def is_library(fname: 'mesonlib.FileOrString') -> bool:
if isinstance(fname, mesonlib.File):
@@ -208,64 +218,26 @@ clike_debug_args: T.Dict[bool, T.List[str]] = {
}
-MSCRT_VALS = ['none', 'md', 'mdd', 'mt', 'mtd']
-
-@dataclass
-class BaseOption(T.Generic[options._T, options._U]):
- opt_type: T.Type[options._U]
- description: str
- default: T.Any = None
- choices: T.Any = None
-
- def init_option(self, name: OptionKey) -> options._U:
- keywords = {'value': self.default}
- if self.choices:
- keywords['choices'] = self.choices
- return self.opt_type(name.name, self.description, **keywords)
-
-BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = {
- OptionKey('b_pch'): BaseOption(options.UserBooleanOption, 'Use precompiled headers', True),
- OptionKey('b_lto'): BaseOption(options.UserBooleanOption, 'Use link time optimization', False),
- OptionKey('b_lto_threads'): BaseOption(options.UserIntegerOption, 'Use multiple threads for Link Time Optimization', (None, None, 0)),
- OptionKey('b_lto_mode'): BaseOption(options.UserComboOption, 'Select between different LTO modes.', 'default',
- choices=['default', 'thin']),
- OptionKey('b_thinlto_cache'): BaseOption(options.UserBooleanOption, 'Use LLVM ThinLTO caching for faster incremental builds', False),
- OptionKey('b_thinlto_cache_dir'): BaseOption(options.UserStringOption, 'Directory to store ThinLTO cache objects', ''),
- OptionKey('b_sanitize'): BaseOption(options.UserComboOption, 'Code sanitizer to use', 'none',
- choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined']),
- OptionKey('b_lundef'): BaseOption(options.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True),
- OptionKey('b_asneeded'): BaseOption(options.UserBooleanOption, 'Use -Wl,--as-needed when linking', True),
- OptionKey('b_pgo'): BaseOption(options.UserComboOption, 'Use profile guided optimization', 'off',
- choices=['off', 'generate', 'use']),
- OptionKey('b_coverage'): BaseOption(options.UserBooleanOption, 'Enable coverage tracking.', False),
- OptionKey('b_colorout'): BaseOption(options.UserComboOption, 'Use colored output', 'always',
- choices=['auto', 'always', 'never']),
- OptionKey('b_ndebug'): BaseOption(options.UserComboOption, 'Disable asserts', 'false', choices=['true', 'false', 'if-release']),
- OptionKey('b_staticpic'): BaseOption(options.UserBooleanOption, 'Build static libraries as position independent', True),
- OptionKey('b_pie'): BaseOption(options.UserBooleanOption, 'Build executables as position independent', False),
- OptionKey('b_bitcode'): BaseOption(options.UserBooleanOption, 'Generate and embed bitcode (only macOS/iOS/tvOS)', False),
- OptionKey('b_vscrt'): BaseOption(options.UserComboOption, 'VS run-time library type to use.', 'from_buildtype',
- choices=MSCRT_VALS + ['from_buildtype', 'static_from_buildtype']),
-}
-
-base_options = {key: base_opt.init_option(key) for key, base_opt in BASE_OPTIONS.items()}
-
-def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType',
- option: OptionKey) -> bool:
+def option_enabled(boptions: T.Set[OptionKey],
+ target: 'BuildTarget',
+ env: 'Environment',
+ option: T.Union[str, OptionKey]) -> bool:
+ if isinstance(option, str):
+ option = OptionKey(option)
try:
if option not in boptions:
return False
- ret = options.get_value(option)
+ ret = env.coredata.get_option_for_target(target, option)
assert isinstance(ret, bool), 'must return bool' # could also be str
return ret
except KeyError:
return False
-def get_option_value(options: 'KeyedOptionDictType', opt: OptionKey, fallback: '_T') -> '_T':
+def get_option_value_for_target(env: 'Environment', target: 'BuildTarget', opt: OptionKey, fallback: '_T') -> '_T':
"""Get the value of an option, or the fallback value."""
try:
- v: '_T' = options.get_value(opt)
+ v = env.coredata.get_option_for_target(target, opt)
except (KeyError, AttributeError):
return fallback
@@ -274,36 +246,58 @@ def get_option_value(options: 'KeyedOptionDictType', opt: OptionKey, fallback: '
return v
-def are_asserts_disabled(options: KeyedOptionDictType) -> bool:
+def are_asserts_disabled(target: 'BuildTarget', env: 'Environment') -> bool:
"""Should debug assertions be disabled
- :param options: OptionDictionary
+ :param target: a target to check for
+ :param env: the environment
:return: whether to disable assertions or not
"""
- return (options.get_value('b_ndebug') == 'true' or
- (options.get_value('b_ndebug') == 'if-release' and
- options.get_value('buildtype') in {'release', 'plain'}))
+ return (env.coredata.get_option_for_target(target, 'b_ndebug') == 'true' or
+ (env.coredata.get_option_for_target(target, 'b_ndebug') == 'if-release' and
+ env.coredata.get_option_for_target(target, 'buildtype') in {'release', 'plain'}))
-def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler', env: 'Environment') -> T.List[str]:
+def are_asserts_disabled_for_subproject(subproject: str, env: 'Environment') -> bool:
+ key = OptionKey('b_ndebug', subproject)
+ return (env.coredata.optstore.get_value_for(key) == 'true' or
+ (env.coredata.optstore.get_value_for(key) == 'if-release' and
+ env.coredata.optstore.get_value_for(key.evolve(name='buildtype')) in {'release', 'plain'}))
+
+
+def get_base_compile_args(target: 'BuildTarget', compiler: 'Compiler', env: 'Environment') -> T.List[str]:
args: T.List[str] = []
try:
- if options.get_value(OptionKey('b_lto')):
+ if env.coredata.get_option_for_target(target, 'b_lto'):
+ num_threads = get_option_value_for_target(env, target, OptionKey('b_lto_threads'), 0)
+ ltomode = get_option_value_for_target(env, target, OptionKey('b_lto_mode'), 'default')
args.extend(compiler.get_lto_compile_args(
- threads=get_option_value(options, OptionKey('b_lto_threads'), 0),
- mode=get_option_value(options, OptionKey('b_lto_mode'), 'default')))
+ threads=num_threads,
+ mode=ltomode))
except (KeyError, AttributeError):
pass
try:
- args += compiler.get_colorout_args(options.get_value(OptionKey('b_colorout')))
- except (KeyError, AttributeError):
+ clrout = env.coredata.get_option_for_target(target, 'b_colorout')
+ assert isinstance(clrout, str)
+ args += compiler.get_colorout_args(clrout)
+ except KeyError:
pass
try:
- args += compiler.sanitizer_compile_args(options.get_value(OptionKey('b_sanitize')))
- except (KeyError, AttributeError):
+ sanitize = env.coredata.get_option_for_target(target, 'b_sanitize')
+ assert isinstance(sanitize, list)
+ if sanitize == ['none']:
+ sanitize = []
+ sanitize_args = compiler.sanitizer_compile_args(sanitize)
+ # We consider that if there are no sanitizer arguments returned, then
+ # the language doesn't support them.
+ if sanitize_args:
+ if not compiler.has_multi_arguments(sanitize_args, env)[0]:
+ raise MesonException(f'Compiler {compiler.name_string()} does not support sanitizer arguments {sanitize_args}')
+ args.extend(sanitize_args)
+ except KeyError:
pass
try:
- pgo_val = options.get_value(OptionKey('b_pgo'))
+ pgo_val = env.coredata.get_option_for_target(target, 'b_pgo')
if pgo_val == 'generate':
args.extend(compiler.get_profile_generate_args())
elif pgo_val == 'use':
@@ -311,21 +305,23 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler',
except (KeyError, AttributeError):
pass
try:
- if options.get_value(OptionKey('b_coverage')):
+ if env.coredata.get_option_for_target(target, 'b_coverage'):
args += compiler.get_coverage_args()
except (KeyError, AttributeError):
pass
try:
- args += compiler.get_assert_args(are_asserts_disabled(options), env)
- except (KeyError, AttributeError):
+ args += compiler.get_assert_args(are_asserts_disabled(target, env), env)
+ except KeyError:
pass
# This does not need a try...except
- if option_enabled(compiler.base_options, options, OptionKey('b_bitcode')):
+ if option_enabled(compiler.base_options, target, env, 'b_bitcode'):
args.append('-fembed-bitcode')
try:
+ crt_val = env.coredata.get_option_for_target(target, 'b_vscrt')
+ assert isinstance(crt_val, str)
+ buildtype = env.coredata.get_option_for_target(target, 'buildtype')
+ assert isinstance(buildtype, str)
try:
- crt_val = options.get_value(OptionKey('b_vscrt'))
- buildtype = options.get_value(OptionKey('buildtype'))
args += compiler.get_crt_compile_args(crt_val, buildtype)
except AttributeError:
pass
@@ -333,31 +329,46 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler',
pass
return args
-def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
- is_shared_module: bool, build_dir: str) -> T.List[str]:
+def get_base_link_args(target: 'BuildTarget',
+ linker: 'Compiler',
+ env: 'Environment') -> T.List[str]:
args: T.List[str] = []
+ build_dir = env.get_build_dir()
try:
- if options.get_value('b_lto'):
- if options.get_value('werror'):
+ if env.coredata.get_option_for_target(target, 'b_lto'):
+ if env.coredata.get_option_for_target(target, 'werror'):
args.extend(linker.get_werror_args())
thinlto_cache_dir = None
- if get_option_value(options, OptionKey('b_thinlto_cache'), False):
- thinlto_cache_dir = get_option_value(options, OptionKey('b_thinlto_cache_dir'), '')
+ cachedir_key = OptionKey('b_thinlto_cache')
+ if get_option_value_for_target(env, target, cachedir_key, False):
+ thinlto_cache_dir = get_option_value_for_target(env, target, OptionKey('b_thinlto_cache_dir'), '')
if thinlto_cache_dir == '':
thinlto_cache_dir = os.path.join(build_dir, 'meson-private', 'thinlto-cache')
+ num_threads = get_option_value_for_target(env, target, OptionKey('b_lto_threads'), 0)
+ lto_mode = get_option_value_for_target(env, target, OptionKey('b_lto_mode'), 'default')
args.extend(linker.get_lto_link_args(
- threads=get_option_value(options, OptionKey('b_lto_threads'), 0),
- mode=get_option_value(options, OptionKey('b_lto_mode'), 'default'),
+ threads=num_threads,
+ mode=lto_mode,
thinlto_cache_dir=thinlto_cache_dir))
except (KeyError, AttributeError):
pass
try:
- args += linker.sanitizer_link_args(options.get_value('b_sanitize'))
- except (KeyError, AttributeError):
+ sanitizer = env.coredata.get_option_for_target(target, 'b_sanitize')
+ assert isinstance(sanitizer, list)
+ if sanitizer == ['none']:
+ sanitizer = []
+ sanitizer_args = linker.sanitizer_link_args(sanitizer)
+ # We consider that if there are no sanitizer arguments returned, then
+ # the language doesn't support them.
+ if sanitizer_args:
+ if not linker.has_multi_link_arguments(sanitizer_args, env)[0]:
+ raise MesonException(f'Linker {linker.name_string()} does not support sanitizer arguments {sanitizer_args}')
+ args.extend(sanitizer_args)
+ except KeyError:
pass
try:
- pgo_val = options.get_value('b_pgo')
+ pgo_val = env.coredata.get_option_for_target(target, 'b_pgo')
if pgo_val == 'generate':
args.extend(linker.get_profile_generate_args())
elif pgo_val == 'use':
@@ -365,16 +376,16 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
except (KeyError, AttributeError):
pass
try:
- if options.get_value('b_coverage'):
+ if env.coredata.get_option_for_target(target, 'b_coverage'):
args += linker.get_coverage_link_args()
except (KeyError, AttributeError):
pass
- as_needed = option_enabled(linker.base_options, options, OptionKey('b_asneeded'))
- bitcode = option_enabled(linker.base_options, options, OptionKey('b_bitcode'))
+ as_needed = option_enabled(linker.base_options, target, env, 'b_asneeded')
+ bitcode = option_enabled(linker.base_options, target, env, 'b_bitcode')
# Shared modules cannot be built with bitcode_bundle because
# -bitcode_bundle is incompatible with -undefined and -bundle
- if bitcode and not is_shared_module:
+ if bitcode and not target.typename == 'shared module':
args.extend(linker.bitcode_args())
elif as_needed:
# -Wl,-dead_strip_dylibs is incompatible with bitcode
@@ -383,18 +394,23 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
# Apple's ld (the only one that supports bitcode) does not like -undefined
# arguments or -headerpad_max_install_names when bitcode is enabled
if not bitcode:
+ from ..build import SharedModule
args.extend(linker.headerpad_args())
- if (not is_shared_module and
- option_enabled(linker.base_options, options, OptionKey('b_lundef'))):
+ if (not isinstance(target, SharedModule) and
+ option_enabled(linker.base_options, target, env, 'b_lundef')):
args.extend(linker.no_undefined_link_args())
else:
args.extend(linker.get_allow_undefined_link_args())
try:
+ crt_val = env.coredata.get_option_for_target(target, 'b_vscrt')
+ assert isinstance(crt_val, str)
+ buildtype = env.coredata.get_option_for_target(target, 'buildtype')
+ assert isinstance(buildtype, str)
try:
- crt_val = options.get_value(OptionKey('b_vscrt'))
- buildtype = options.get_value(OptionKey('buildtype'))
- args += linker.get_crt_link_args(crt_val, buildtype)
+ crtargs = linker.get_crt_link_args(crt_val, buildtype)
+ assert isinstance(crtargs, list)
+ args += crtargs
except AttributeError:
pass
except KeyError:
@@ -405,37 +421,30 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
class CrossNoRunException(MesonException):
pass
+@dataclass
class RunResult(HoldableObject):
- def __init__(self, compiled: bool, returncode: int = 999,
- stdout: str = 'UNDEFINED', stderr: str = 'UNDEFINED',
- cached: bool = False):
- self.compiled = compiled
- self.returncode = returncode
- self.stdout = stdout
- self.stderr = stderr
- self.cached = cached
+ compiled: bool
+ returncode: int = 999
+ stdout: str = 'UNDEFINED'
+ stderr: str = 'UNDEFINED'
+ cached: bool = False
+@dataclass
class CompileResult(HoldableObject):
"""The result of Compiler.compiles (and friends)."""
- def __init__(self, stdo: T.Optional[str] = None, stde: T.Optional[str] = None,
- command: T.Optional[T.List[str]] = None,
- returncode: int = 999,
- input_name: T.Optional[str] = None,
- output_name: T.Optional[str] = None,
- cached: bool = False):
- self.stdout = stdo
- self.stderr = stde
- self.input_name = input_name
- self.output_name = output_name
- self.command = command or []
- self.cached = cached
- self.returncode = returncode
-
+ stdout: str
+ stderr: str
+ command: T.List[str]
+ returncode: int
+ input_name: str
+ output_name: T.Optional[str] = field(default=None, init=False)
+ cached: bool = field(default=False, init=False)
class Compiler(HoldableObject, metaclass=abc.ABCMeta):
+
# Libraries to ignore in find_library() since they are provided by the
# compiler or the C library. Currently only used for MSVC.
ignore_libs: T.List[str] = []
@@ -457,11 +466,8 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
full_version: T.Optional[str] = None, is_cross: bool = False):
self.exelist = ccache + exelist
self.exelist_no_ccache = exelist
- # In case it's been overridden by a child class already
- if not hasattr(self, 'file_suffixes'):
- self.file_suffixes = lang_suffixes[self.language]
- if not hasattr(self, 'can_compile_suffixes'):
- self.can_compile_suffixes: T.Set[str] = set(self.file_suffixes)
+ self.file_suffixes = lang_suffixes[self.language]
+ self.can_compile_suffixes = set(self.file_suffixes)
self.default_suffix = self.file_suffixes[0]
self.version = version
self.full_version = full_version
@@ -492,6 +498,12 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
def get_modes(self) -> T.List[Compiler]:
return self.modes
+ def get_exe(self) -> str:
+ return self.exelist[0]
+
+ def get_exe_args(self) -> T.List[str]:
+ return self.exelist[1:]
+
def get_linker_id(self) -> str:
# There is not guarantee that we have a dynamic linker instance, as
# some languages don't have separate linkers and compilers. In those
@@ -591,22 +603,25 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
"""
return []
- def create_option(self, option_type: T.Type[UserOptionType], option_key: OptionKey, *args: T.Any, **kwargs: T.Any) -> T.Tuple[OptionKey, UserOptionType]:
- return option_key, option_type(f'{self.language}_{option_key.name}', *args, **kwargs)
+ def make_option_name(self, key: OptionKey) -> str:
+ return f'{self.language}_{key.name}'
@staticmethod
- def update_options(options: MutableKeyedOptionDictType, *args: T.Tuple[OptionKey, UserOptionType]) -> MutableKeyedOptionDictType:
+ def update_options(options: MutableKeyedOptionDictType, *args: T.Tuple[OptionKey, options.AnyOptionType]) -> MutableKeyedOptionDictType:
options.update(args)
return options
def get_options(self) -> 'MutableKeyedOptionDictType':
return {}
- def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
+ def get_option_compile_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]:
return []
- def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
- return self.linker.get_option_args(options)
+ def get_option_std_args(self, target: BuildTarget, env: Environment, subproject: T.Optional[str] = None) -> T.List[str]:
+ return []
+
+ def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subproject: T.Optional[str] = None) -> T.List[str]:
+ return self.linker.get_option_link_args(target, env, subproject)
def check_header(self, hname: str, prefix: str, env: 'Environment', *,
extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None,
@@ -734,7 +749,7 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
return args.copy()
def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str],
- libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]:
+ libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True, ignore_system_dirs: bool = False) -> T.Optional[T.List[str]]:
raise EnvironmentException(f'Language {self.get_display_language()} does not support library finding.')
def get_library_naming(self, env: 'Environment', libtype: LibType,
@@ -811,6 +826,8 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
'testfile.' + self.default_suffix)
with open(srcname, 'w', encoding='utf-8') as ofile:
ofile.write(code)
+ if not code.endswith('\n'):
+ ofile.write('\n')
# ccache would result in a cache miss
no_ccache = True
code_debug = f'Code:\n{code}'
@@ -896,8 +913,8 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
def get_std_shared_lib_link_args(self) -> T.List[str]:
return self.linker.get_std_shared_lib_args()
- def get_std_shared_module_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
- return self.linker.get_std_shared_module_args(options)
+ def get_std_shared_module_link_args(self, target: 'BuildTarget') -> T.List[str]:
+ return self.linker.get_std_shared_module_args(target)
def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
return self.linker.get_link_whole_for(args)
@@ -936,11 +953,11 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
def thread_link_flags(self, env: 'Environment') -> T.List[str]:
return self.linker.thread_flags(env)
- def openmp_flags(self) -> T.List[str]:
+ def openmp_flags(self, env: Environment) -> T.List[str]:
raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language())
- def openmp_link_flags(self) -> T.List[str]:
- return self.openmp_flags()
+ def openmp_link_flags(self, env: Environment) -> T.List[str]:
+ return self.openmp_flags(env)
def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]:
return []
@@ -969,7 +986,8 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
def get_pie_link_args(self) -> T.List[str]:
return self.linker.get_pie_args()
- def get_argument_syntax(self) -> str:
+ @staticmethod
+ def get_argument_syntax() -> str:
"""Returns the argument family type.
Compilers fall into families if they try to emulate the command line
@@ -1016,10 +1034,10 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
thinlto_cache_dir: T.Optional[str] = None) -> T.List[str]:
return self.linker.get_lto_args()
- def sanitizer_compile_args(self, value: str) -> T.List[str]:
+ def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]:
return []
- def sanitizer_link_args(self, value: str) -> T.List[str]:
+ def sanitizer_link_args(self, value: T.List[str]) -> T.List[str]:
return self.linker.sanitizer_args(value)
def get_asneeded_args(self) -> T.List[str]:
@@ -1071,7 +1089,7 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
return []
def get_crt_val(self, crt_val: str, buildtype: str) -> str:
- if crt_val in MSCRT_VALS:
+ if crt_val in options.MSCRT_VALS:
return crt_val
assert crt_val in {'from_buildtype', 'static_from_buildtype'}
@@ -1101,6 +1119,9 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
def get_compile_only_args(self) -> T.List[str]:
return []
+ def get_cxx_interoperability_args(self, lang: T.Dict[str, Compiler]) -> T.List[str]:
+ raise EnvironmentException('This compiler does not support CXX interoperability')
+
def get_preprocess_only_args(self) -> T.List[str]:
raise EnvironmentException('This compiler does not have a preprocessor')
@@ -1182,6 +1203,23 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
is good enough here.
"""
+ def run_sanity_check(self, environment: Environment, cmdlist: T.List[str], work_dir: str, use_exe_wrapper_for_cross: bool = True) -> T.Tuple[str, str]:
+ # Run sanity check
+ if self.is_cross and use_exe_wrapper_for_cross:
+ if not environment.has_exe_wrapper():
+ # Can't check if the binaries run so we have to assume they do
+ return ('', '')
+ cmdlist = environment.exe_wrapper.get_command() + cmdlist
+ mlog.debug('Running test binary command: ', mesonlib.join_args(cmdlist))
+ try:
+ pe, stdo, stde = Popen_safe_logged(cmdlist, 'Sanity check', cwd=work_dir)
+ except Exception as e:
+ raise mesonlib.EnvironmentException(f'Could not invoke sanity check executable: {e!s}.')
+
+ if pe.returncode != 0:
+ raise mesonlib.EnvironmentException(f'Executables created by {self.language} compiler {self.name_string()} are not runnable.')
+ return stdo, stde
+
def split_shlib_to_parts(self, fname: str) -> T.Tuple[T.Optional[str], str]:
return None, fname
@@ -1329,9 +1367,13 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
# TODO: using a TypeDict here would improve this
raise EnvironmentException(f'{self.id} does not implement get_feature_args')
- def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]:
+ def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.Tuple[T.List[str], T.List[str]]:
raise EnvironmentException(f'{self.id} does not know how to do prelinking.')
+ def get_prelink_append_compile_args(self) -> bool:
+ """Controls whether compile args have to be used for prelinking or not"""
+ return False
+
def rsp_file_syntax(self) -> 'RSPFileSyntax':
"""The format of the RSP file that this compiler supports.
@@ -1352,42 +1394,26 @@ class Compiler(HoldableObject, metaclass=abc.ABCMeta):
"""
raise EnvironmentException(f'{self.get_id()} does not support preprocessor')
- def form_langopt_key(self, basename: str) -> OptionKey:
- return OptionKey(basename, machine=self.for_machine, lang=self.language)
-
-def get_global_options(lang: str,
- comp: T.Type[Compiler],
- for_machine: MachineChoice,
- env: 'Environment') -> 'dict[OptionKey, options.UserOption[Any]]':
- """Retrieve options that apply to all compilers for a given language."""
- description = f'Extra arguments passed to the {lang}'
- argkey = OptionKey('args', lang=lang, machine=for_machine)
- largkey = argkey.evolve('link_args')
- envkey = argkey.evolve('env_args')
-
- comp_key = argkey if argkey in env.options else envkey
-
- comp_options = env.options.get(comp_key, [])
- link_options = env.options.get(largkey, [])
-
- cargs = options.UserArrayOption(
- f'{lang}_{argkey.name}',
- description + ' compiler',
- comp_options, split_args=True, allow_dups=True)
-
- largs = options.UserArrayOption(
- f'{lang}_{largkey.name}',
- description + ' linker',
- link_options, split_args=True, allow_dups=True)
-
- if comp.INVOKES_LINKER and comp_key == envkey:
- # If the compiler acts as a linker driver, and we're using the
- # environment variable flags for both the compiler and linker
- # arguments, then put the compiler flags in the linker flags as well.
- # This is how autotools works, and the env vars feature is for
- # autotools compatibility.
- largs.extend_value(comp_options)
-
- opts: 'dict[OptionKey, options.UserOption[Any]]' = {argkey: cargs, largkey: largs}
-
- return opts
+ def form_compileropt_key(self, basename: str) -> OptionKey:
+ return OptionKey(f'{self.language}_{basename}', machine=self.for_machine)
+
+ def get_compileropt_value(self,
+ key: T.Union[str, OptionKey],
+ env: Environment,
+ target: T.Optional[BuildTarget],
+ subproject: T.Optional[str] = None
+ ) -> options.ElementaryOptionValues:
+ if isinstance(key, str):
+ key = self.form_compileropt_key(key)
+ if target:
+ return env.coredata.get_option_for_target(target, key)
+ else:
+ return env.coredata.optstore.get_value_for(key.evolve(subproject=subproject))
+
+ def _update_language_stds(self, opts: MutableKeyedOptionDictType, value: T.List[str]) -> None:
+ key = self.form_compileropt_key('std')
+ std = opts[key]
+ assert isinstance(std, (options.UserStdOption, options.UserComboOption)), 'for mypy'
+ if 'none' not in value:
+ value = ['none'] + value
+ std.choices = value