New features (in development)
New b_freestanding base option
The new b_freestanding base option tells supported compilers that targets do
not assume a hosted standard library. GCC-compatible C-family compilers receive
-ffreestanding, while clang-cl receives /clang:-ffreestanding.
For Rust targets, the option declares that the crate uses #![no_std]. Meson
uses this information when determining the native libraries required by Rust
static libraries. Meson does not add the crate attribute itself.
Added support for buildcache
Meson now recognizes BuildCache
as a compiler wrapper, so setting e.g. CC="buildcache cc" works like it
already does for Ccache and sccache. BuildCache is also auto-detected
alongside Ccache and sccache, and is used as a fallback after both of those
when no compiler is specified explicitly.
Support for workspace.exclude in Cargo manifests
Directories that are listed in the workspace.exclude field of Cargo.toml
are not treated as workspace members anymore. Such packages can still be
used through a path dependency, as long as they are placed directly in the
subprojects directory. This allows using nested workspaces if needed.
CMake command wrappers accept arguments with backslashes
CMake subprojects can now configure add_custom_command(),
add_custom_target(), and set_property() calls whose arguments contain
backslashes. Meson's preload wrappers previously expanded those arguments a
second time, which could reject valid values such as regular expression
backreferences during configuration.
BuildTarget now has an embed_directories keyword argument
This provides an include_directories like path for the c23 and c++26 #embed
preprocessor directive.
New search order for find_program()
find_program() searches for programs in machine files and in the system;
starting with Meson 1.13.0, the search process is applied separately for
each name passed to the function:
-
If the first name is defined in a machine file, Meson uses that entry.
-
Otherwise, Meson searches for the first name in the project's source tree, the directories listed in
dirs:, andPATH. -
If the program is not found or does not satisfy the requested version, Meson tries the next name.
Previous versions of Meson looked for all names in the machine files first.
Meson never searched for the program in the system if the machine file
pointed to one of the programs, using the program in the machine file
even if it did not satisfy the version requirement in meson.build.
Likewise, if no name was in a machine file, the search stopped at the first
name found in the system, even if a later name would have satisfied the
version requirement.
Target introspection reports all direct target dependencies
The depends entry in intro-targets.json now reports direct target
dependencies from target inputs, generated sources, extracted objects,
internal linking, and explicit depends arguments. Previously it only
reported the dependencies attribute used by alias and run targets, so most
build target and custom target dependencies were omitted.
Per-subproject options are included in buildoptions introspection
meson introspect --buildoptions and meson-info/intro-buildoptions.json
now contain rows for per-subproject options in configured build
directories: non-yielding builtin options get one row per subproject
(e.g. sub:warning_level), and options with a per-subproject value set
(e.g. via -Dsub:c_args=...) are reported with the value in effect for
that subproject.
Added support for kache
Meson now recognizes kache as
a compiler wrapper, so setting e.g. CC="kache cc" works like it
already does for Ccache and sccache. Unlike those, kache is not
auto-detected, because it must be invoked with a compiler subcommand
(kache cc, kache c++, ...) rather than in front of an arbitrary
compiler.
meson format suppression directives
meson format now leaves untouched the lines between
# meson-format off and # meson-format on comments. When
# meson-format off is not followed by # meson-format on, formatting
is disabled until the end of the file. muon fmt's # fmt: off and
# fmt: on directives are also recognized.
# meson-format off
sources = files(
'a.c', 'b.c',
'c.c', 'd.c',
)
# meson-format on
cpp_rtti is honored for Objective-C++
The cpp_rtti option is now respected when compiling Objective-C++
sources. Setting cpp_rtti=false passes -fno-rtti for .mm files,
just like it already did for C++ sources.
Allow using generator with any build_tgt object
Passing any build target to generator.process() is now allowed.
Added support for the QNX qcc/q++ compiler driver
Meson can now detect and use qcc and q++, the C and C++ compiler drivers shipped with the QNX Software Development Platform (SDP), and recognizes QNX as a target platform.
Cross-compiling for QNX
Point a cross file's [binaries] section at qcc/q++ including the
required -V target selector, and declare system = 'qnx' in
[host_machine], for example:
[binaries]
c = ['qcc', '-Vgcc_ntoaarch64le']
cpp = ['q++', '-Vgcc_ntoaarch64le']
[host_machine]
system = 'qnx'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'
Known Issues:
- ThinLTO incremental cache doesn't work — -Db_thinlto_cache=true raises a clear error at configure time; plain -Db_lto=true is unaffected. -flto-incremental= is rejected outright by cc1.
- No alternate linker selection — c_ld/cpp_ld in a cross/native file (e.g. 'lld', 'gold') raises MesonException. qcc's driver never invokes a separate linker binary itself, and QNX documents no equivalent mechanism.
- Stale dependency-file entries after deleting a header — -MP's phony-header rules aren't emitted by this cc1, unlike stock gcc. Narrow, unfixed; only shows up as a missed rebuild until a clean build.
- No static sanitizer runtime — -static-libasan is rejected as unknown; only the shared sanitizer runtime can ever be linked.
- Sanitizer runtime availability is SDP-version-dependent — SDP 7.1 ships only libubsan (no asan/lsan/tsan at all), so -Db_sanitize=address/=leak fail to link there; SDP 8.0 adds asan/lsan (still no tsan on either SDP). =undefined works on both.
- C++20 named modules are broken, differently per SDP — SDP 8.0: -fmodules-ts compiles but silently no-ops on .cppm/.ixx files (no code-level fix possible — it's driver-level source-suffix dispatch before cc1plus ever runs). SDP 7.1: worse — -fmodules-ts itself is hard-rejected as unrecognized on any C++ source. Plain -fmodules is hard-rejected on both SDPs. Only bites a project that explicitly opts into modules via cpp_args.
- Symbol-extraction relink-avoidance only applies natively — the gnu_syms() optimization (skip relinking when a shared library's exported symbols haven't changed) only kicks in for a native/self-hosted QNX build; cross-compiling to QNX from another host (the SDP's primary use case) always falls back to unconditional relinking, same as before this work.
Jar files are now installed reproducibly
Installing a jar target used to invoke the jar tool to strip the
Class-Path attribute from its manifest, even when there was none.
This replaced the manifest's timestamp inside the jar with the time of
installation, so two builds of the same sources produced different
installed jars.
Manifests are now edited with Python's zipfile module instead. Jars
without a Class-Path attribute are installed unmodified, and when the
attribute has to be stripped, all entry metadata such as timestamps is
preserved. As a side effect, the jar binary is no longer needed at
install time.
meson.can_run_host_binaries() now accounts for Rosetta 2 on Apple Silicon
Previously, when cross-compiling for x86_64 on an aarch64 Mac,
meson.can_run_host_binaries() (and the underlying needs_exe_wrapper
logic) always returned false, even though Rosetta 2 lets these Macs
execute x86_64 binaries directly. Meson now detects whether Rosetta 2
is installed and, if so, reports that x86_64 host binaries can run
natively without requiring an exe_wrapper.
Rust now supports the has_define method
This method returns true if the given cfg (either a valueless symbol, or
name="value") is defined, else false is returned. Rust does not support
get_define.
New Rust compiler options matching Cargo profile keys
Several new per-machine Rust compiler options have been added so that the
settings found in a Cargo [profile] section can be expressed natively:
-
rust_panic(none,unwind,abort): selects the panic strategy (-C panic=). It is ignored fordylibandproc-macrocrates, which must always unwind. -
rust_overflow_checks(true,false): toggles runtime integer overflow checks (-C overflow-checks=). -
rust_codegen_units(integer,0to use the compiler default): number of code generation units to split a crate into (-C codegen-units=). -
rust_incremental(true,false): enables incremental compilation (-C incremental=). -
rust_incremental_cache_dir(path): directory used to store the incremental compilation data. When left empty a per-target directory under the build directory is used.
The remaining Cargo profile keys map onto existing built-in options:
opt-level to optimization, debug to debug, debug-assertions
to b_ndebug and lto to b_lto.
The Cargo workspace object will also add these automatically based on
the value of another new option, rust_cargo_profile.
c_std=clatest support for MSVC
The option enables all currently implemented compiler and standard library features proposed in the next draft C standard, as well as some in-progress and experimental features.
Per-subproject language arguments are now applied
Compiler and linker arguments set for a specific subproject, for example
-Dsub:c_args=-DFOO on the command line or c_args in the
default_options of a subproject() call, are now added to the compile
and link commands of that subproject's targets. Previously such values
were accepted and stored but silently ignored.
Similarly, <lang>_args and <lang>_link_args entries in a target's
override_options now take effect.
In all cases the per-subproject or per-target value replaces the global
value (including flags coming from environment variables such as
CFLAGS), it is not appended to it. This matches what
get_option('c_args') already returned inside a subproject.
TAP tests report how many subtests were skipped
The result line of a TAP test now reports how many of its subtests were skipped, so environment-gated subtests no longer disappear silently from a passing test:
1/1 project:gated OK 0.02s 21 subtests passed, 5 skipped
Failing TAP tests list their subtests in the summary of failures
The summary of failures, printed with --print-errorlogs or --verbose,
now lists the failing and skipped subtests of each failing TAP test, both
on the console and in testlog.txt. On the console, --verbose lists all
subtests, including the passing ones:
Summary of Failures:
1/1 project:mixed FAIL 0.02s 2/3 subtests passed, 1 skipped
▶ sub-fail FAIL
▶ sub-skip SKIP
Use werror for gnome.generate_gir(fatal_warnings:)
If fatal_warnings is not passed to gnome.generate_gir(), the value of
the werror option is now read to determine whether to turn it on.
Explicitly passing fatal_warnings: true or fatal_warnings: false
still takes precedence over werror.
Wild linker is now supported on Linux
When CC_LD environment variables is set to wild, Meson will configure GCC 16+ or Clang
to use Wild as the linker on Linux. You should expect to see line like this in the output:
C linker for the host machine: cc ld.wild 0.10.0 confirming that Wild was picked up.
The results of the search are