Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

b_sanitize as an array, with compiler checks #12648

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 39 additions & 32 deletions docs/markdown/Builtin-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,22 @@ not be relied on, since they can be absolute paths in the following cases:

### Directories

| Option | Default value | Description |
| ------ | ------------- | ----------- |
| prefix | see below | Installation prefix |
| bindir | bin | Executable directory |
| datadir | share | Data file directory |
| includedir | include | Header file directory |
| infodir | share/info | Info page directory |
| libdir | see below | Library directory |
| licensedir | see below | Licenses directory (since 1.1.0)|
| libexecdir | libexec | Library executable directory |
| localedir | share/locale | Locale data directory |
| localstatedir | var | Localstate data directory |
| mandir | share/man | Manual page directory |
| sbindir | sbin | System executable directory |
| sharedstatedir | com | Architecture-independent data directory |
| sysconfdir | etc | Sysconf data directory |
| Option | Default value | Description |
| -------------- | ------------- | --------------------------------------- |
| prefix | see below | Installation prefix |
| bindir | bin | Executable directory |
| datadir | share | Data file directory |
| includedir | include | Header file directory |
| infodir | share/info | Info page directory |
| libdir | see below | Library directory |
| licensedir | see below | Licenses directory (since 1.1.0) |
| libexecdir | libexec | Library executable directory |
| localedir | share/locale | Locale data directory |
| localstatedir | var | Localstate data directory |
| mandir | share/man | Manual page directory |
| sbindir | sbin | System executable directory |
| sharedstatedir | com | Architecture-independent data directory |
| sysconfdir | etc | Sysconf data directory |


`prefix` defaults to `C:/` on Windows, and `/usr/local` otherwise. You
Expand Down Expand Up @@ -139,7 +139,7 @@ from it. For example, `-Dbuildtype=debugoptimized` is the same as
the two-way mapping:

| buildtype | debug | optimization |
| --------- | ----- | ------------ |
| -------------- | ----- | ------------ |
| plain | false | plain |
| debug | true | 0 |
| debugoptimized | true | 2 |
Expand All @@ -154,7 +154,7 @@ Exact flags per warning level is compiler specific, but there is an approximativ
table for most common compilers.

| Warning level | GCC/Clang | MSVC |
| ------------- | --- | ---- |
| ------------- | ------------------------ | ----- |
| 0 | | |
| 1 | -Wall | /W2 |
| 2 | -Wall -Wextra | /W3 |
Expand Down Expand Up @@ -205,7 +205,7 @@ The following options are available. Note that they may not be
available on all platforms or with all compilers:

| Option | Default value | Possible values | Description |
|---------------------|----------------------|---------------------------------------------------------------|--------------------------------------------------------------------------------|
| ------------------- | -------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| b_asneeded | true | true, false | Use -Wl,--as-needed when linking |
| b_bitcode | false | true, false | Embed Apple bitcode, see below |
| b_colorout | always | auto, always, never | Use colored output |
Expand All @@ -224,10 +224,17 @@ available on all platforms or with all compilers:
| b_pie | false | true, false | Build position-independent executables (since 0.49.0) |
| b_vscrt | from_buildtype | none, md, mdd, mt, mtd, from_buildtype, static_from_buildtype | VS runtime library to use (since 0.48.0) (static_from_buildtype since 0.56.0) |

The value of `b_sanitize` can be one of: `none`, `address`, `thread`,
`undefined`, `memory`, `leak`, `address,undefined`, but note that some
compilers might not support all of them. For example Visual Studio
only supports the address sanitizer.
† The default and possible values of sanitizers changed in 1.6. Before 1.6 they
were string values, and restricted to a specific subset of values: `none`,
`address`, `thread`, `undefined`, `memory`, `leak`, or `address,undefined`. In
1.6 it was changed to a free form array of sanitizers, which are checked by a
compiler and linker check. For backwards compatibility reasons
`get_option('b_sanitize')` continues to return a string value, which is
guaranteed to match the old string value if the array value contains the same
values (ie, `['undefined', 'address'] == 'address,undefined`). If a value not
allowed before 1.6 is used `b_sanitize` will return a string in undefined order.
In 1.6 `get_option('b_sanitize', format : 2)`, will return a free form array,
with no ordering guarantees.

\* < 0 means disable, == 0 means automatic selection, > 0 sets a specific number to use

Expand All @@ -240,7 +247,7 @@ used internally to pick the CRT compiler arguments for `from_buildtype` or
option:

| buildtype | from_buildtype | static_from_buildtype |
| -------- | -------------- | --------------------- |
| -------------- | -------------- | --------------------- |
| debug | `/MDd` | `/MTd` |
| debugoptimized | `/MD` | `/MT` |
| release | `/MD` | `/MT` |
Expand Down Expand Up @@ -378,7 +385,7 @@ option with the module's name:
### Pkgconfig module

| Option | Default value | Possible values | Description |
|-------------|---------------|-----------------|------------------------------------------------------------|
| ----------- | ------------- | --------------- | ---------------------------------------------------------- |
| relocatable | false | true, false | Generate the pkgconfig files as relocatable (Since 0.63.0) |

*Since 0.63.0* The `pkgconfig.relocatable` option is used by the
Expand All @@ -399,13 +406,13 @@ install prefix. For example: if the install prefix is `/usr` and the

### Python module

| Option | Default value | Possible values | Description |
| ------ | ------------- | ----------------- | ----------- |
| bytecompile | 0 | integer from -1 to 2 | What bytecode optimization level to use (Since 1.2.0) |
| install_env | prefix | {auto,prefix,system,venv} | Which python environment to install to (Since 0.62.0) |
| platlibdir | | Directory path | Directory for site-specific, platform-specific files (Since 0.60.0) |
| purelibdir | | Directory path | Directory for site-specific, non-platform-specific files (Since 0.60.0) |
| allow_limited_api | true | true, false | Disables project-wide use of the Python Limited API (Since 1.3.0) |
| Option | Default value | Possible values | Description |
| ----------------- | ------------- | ------------------------- | ------------------------------------------------------------------------ |
| bytecompile | 0 | integer from -1 to 2 | What bytecode optimization level to use (Since 1.2.0) |
| install_env | prefix | {auto,prefix,system,venv} | Which python environment to install to (Since 0.62.0) |
| platlibdir | | Directory path | Directory for site-specific, platform-specific files (Since 0.60.0) |
| purelibdir | | Directory path | Directory for site-specific, non-platform-specific files (Since 0.60.0) |
| allow_limited_api | true | true, false | Disables project-wide use of the Python Limited API (Since 1.3.0) |

*Since 0.60.0* The `python.platlibdir` and `python.purelibdir` options are used
by the python module methods `python.install_sources()` and
Expand Down
17 changes: 17 additions & 0 deletions docs/markdown/snippets/b_sanitizer_changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Changes to the b_sanitize option

In meson <= 1.6 the b_sanitize option is a combo, which is an enumerated set of
values. One picks one of the values as provided by that enumeration. In 1.6
this was changed to a free array of options, and a compiler check for the
validity of those options.

This solves a number of longstanding issues such as:
- sanitizers may be supported by a compiler, but not on a specific platform (OpenBSD)
- new sanitizers are not recognized by Meson
- using sanitizers in different combinations

In order to not break backwards compatibility, meson will continue to
return `get_option('b_sanitize')` as a string, with a guarantee that
`address,undefined` will remain ordered. Calling
`get_option('b_sanitize', format : 2)`
returns a free form list with no ordering guarantees.
2 changes: 1 addition & 1 deletion mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3444,7 +3444,7 @@ def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.
commands += compilers.get_base_link_args(target.get_options(),
linker,
isinstance(target, build.SharedModule),
self.environment.get_build_dir())
self.environment)
# Add -nostdlib if needed; can't be overridden
commands += self.get_no_stdlib_link_args(target, linker)
# Add things like /NOLOGO; usually can't be overridden
Expand Down
3 changes: 2 additions & 1 deletion mesonbuild/backend/vs2010backend.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2014-2016 The Meson development team
# Copyright © 2023-2024 Intel Corporation

from __future__ import annotations
import copy
Expand Down Expand Up @@ -272,7 +273,7 @@ def generate(self,
try:
self.sanitize = self.environment.coredata.get_option(OptionKey('b_sanitize'))
except MesonException:
self.sanitize = 'none'
self.sanitize = []
sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln')
projlist = self.generate_projects(vslite_ctx)
self.gen_testproj()
Expand Down
29 changes: 21 additions & 8 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,7 @@ def init_option(self, name: OptionKey) -> options._U:
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_sanitize'): BaseOption(options.UserArrayOption, 'Code sanitizers to use', []),
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',
Expand Down Expand Up @@ -300,7 +299,14 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler',
except (KeyError, AttributeError):
pass
try:
args += compiler.sanitizer_compile_args(options.get_value(OptionKey('b_sanitize')))
sani_opt = options.get_value(OptionKey('b_sanitize'))
assert isinstance(sani_opt, list), 'for mypy'
sani_args = compiler.sanitizer_compile_args(sani_opt)
# We consider that if there are no sanitizer arguments returned, then the language doesn't support them
if sani_args:
if not compiler.has_multi_arguments(sani_args, env)[0]:
raise MesonException(f'Compiler {compiler.name_string()} does not support sanitizer arguments {sani_args}')
args.extend(sani_args)
except (KeyError, AttributeError):
pass
try:
Expand Down Expand Up @@ -335,7 +341,7 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler',
return args

def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
is_shared_module: bool, build_dir: str) -> T.List[str]:
is_shared_module: bool, env: Environment) -> T.List[str]:
args: T.List[str] = []
try:
if options.get_value('b_lto'):
Expand All @@ -346,15 +352,22 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
if get_option_value(options, OptionKey('b_thinlto_cache'), False):
thinlto_cache_dir = get_option_value(options, OptionKey('b_thinlto_cache_dir'), '')
if thinlto_cache_dir == '':
thinlto_cache_dir = os.path.join(build_dir, 'meson-private', 'thinlto-cache')
thinlto_cache_dir = os.path.join(env.get_build_dir(), 'meson-private', 'thinlto-cache')
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'),
thinlto_cache_dir=thinlto_cache_dir))
except (KeyError, AttributeError):
pass
try:
args += linker.sanitizer_link_args(options.get_value('b_sanitize'))
sani_opt = options.get_value(OptionKey('b_sanitize'))
assert isinstance(sani_opt, list), 'for mypy'
sani_args = linker.sanitizer_link_args(sani_opt)
# We consider that if there are no sanitizer arguments returned, then the language doesn't support them
if sani_args:
if not linker.has_multi_link_arguments(sani_args, env)[0]:
raise MesonException(f'Linker {linker.name_string()} does not support sanitizer arguments {sani_args}')
args.extend(sani_args)
except (KeyError, AttributeError):
pass
try:
Expand Down Expand Up @@ -1011,10 +1024,10 @@ def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default',
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]:
Expand Down
18 changes: 14 additions & 4 deletions mesonbuild/compilers/cuda.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2012-2017 The Meson development team
# Copyright © 2023-2024 Intel Corporation

from __future__ import annotations

Expand All @@ -16,10 +17,9 @@
is_windows, LibType, version_compare
)
from ..options import OptionKey
from .compilers import Compiler
from .compilers import Compiler, CompileCheckMode

if T.TYPE_CHECKING:
from .compilers import CompileCheckMode
from ..build import BuildTarget
from ..coredata import MutableKeyedOptionDictType, KeyedOptionDictType
from ..dependencies import Dependency
Expand Down Expand Up @@ -707,10 +707,10 @@ def get_optimization_args(self, optimization_level: str) -> T.List[str]:
# return self._to_host_flags(self.host_compiler.get_optimization_args(optimization_level))
return cuda_optimization_args[optimization_level]

def sanitizer_compile_args(self, value: str) -> T.List[str]:
def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]:
return self._to_host_flags(self.host_compiler.sanitizer_compile_args(value))

def sanitizer_link_args(self, value: str) -> T.List[str]:
def sanitizer_link_args(self, value: T.List[str]) -> T.List[str]:
return self._to_host_flags(self.host_compiler.sanitizer_link_args(value))

def get_debug_args(self, is_debug: bool) -> T.List[str]:
Expand Down Expand Up @@ -813,3 +813,13 @@ def get_profile_use_args(self) -> T.List[str]:

def get_assert_args(self, disable: bool, env: 'Environment') -> T.List[str]:
return self.host_compiler.get_assert_args(disable, env)

def has_multi_arguments(self, args: T.List[str], env: Environment) -> T.Tuple[bool, bool]:
args = self._to_host_flags(args)
return self.compiles(
'int main(void) { return 0; }', env, extra_args=args, mode=CompileCheckMode.COMPILE)

def has_multi_link_arguments(self, args: T.List[str], env: Environment) -> T.Tuple[bool, bool]:
args = self._to_host_flags(self.linker.fatal_warnings() + args, phase=Phase.LINKER)
return self.compiles(
'int main(void) { return 0; }', env, extra_args=args, mode=CompileCheckMode.LINK)
11 changes: 6 additions & 5 deletions mesonbuild/compilers/mixins/gnu.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2019-2022 The meson development team
# Copyright © 2023 Intel Corporation

from __future__ import annotations

Expand Down Expand Up @@ -497,11 +498,11 @@ def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T.
# for their specific arguments
return ['-flto']

def sanitizer_compile_args(self, value: str) -> T.List[str]:
if value == 'none':
return []
args = ['-fsanitize=' + value]
if 'address' in value: # for -fsanitize=address,undefined
def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]:
if not value:
return value
args = ['-fsanitize=' + ','.join(value)]
if 'address' in value:
args.append('-fno-omit-frame-pointer')
return args

Expand Down
3 changes: 2 additions & 1 deletion mesonbuild/compilers/mixins/islinker.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2019 The Meson development team
# Copyright © 2023 Intel Corporation

from __future__ import annotations

Expand Down Expand Up @@ -36,7 +37,7 @@ class BasicLinkerIsCompilerMixin(Compiler):
functionality itself.
"""

def sanitizer_link_args(self, value: str) -> T.List[str]:
def sanitizer_link_args(self, value: T.List[str]) -> T.List[str]:
return []

def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default',
Expand Down
Loading
Loading