mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
meson: add -Drust= for programs written in Rust
Add optional support for programs written in Rust. Nothing else changes. libsystemd-shared, libsystemd and the NSS and PAM modules stay C and a program written in Rust links libsystemd-shared dynamically just like the C programs do. Rust code gets core. There's no std, the alloc crate isn't used either and there are no external crates. The option is a feature and defaults to auto. We need rustc >= 1.85 and bindgen >= 0.71.1 which is exactly what Debian 13 ships. 1.85 is the minimum supported Rust version and we hand it to bindgen as well so the generated bindings never require a newer compiler than the hand-written code. bindgen 0.72.0 is refused as it generates code that doesn't compile. With auto the toolchain is used when it's found and -Drust=enabled fails loudly when it isn't. Rust support also needs meson 1.4.0 for the rust module's bindgen() integration. The tree keeps its meson floor and -Drust=auto silently turns itself off on older meson. Cross-compilation isn't supported yet as bindgen would need to be told about the target. HAVE_RUST tells units, man pages and tests whether Rust programs are built. bindgen loads libclang at runtime so finding the binary proves nothing about being able to generate bindings. So run it once at configure time over tools/bindgen-probe.h. That reports the libclang version, which is shown in the summary, and contains the construct bindgen < 0.72.1 mishandles with libclang >= 22. A broken combination is thus refused or disables Rust support instead of failing the build later. The lints and the codegen options are project-wide rustc arguments. Warnings are only errors with --werror just like for C. The lint set is the kernel's: - unsafe operations need an unsafe block - every unsafe block needs a SAFETY comment and every unsafe function a Safety section, enforced via clippy's undocumented_unsafe_blocks and friends - public items need docs - the pointer cast lints keep raw pointer handling explicit Overflow checks are enabled in every build type. rustc's default depends on the optimization level and meson always passes overflow-checks=no but Rust code shouldn't get to wrap silently where C code checks. Everything is built with panic=abort. Unwinding couldn't cross the C frames of an event loop anyway and without std there's no unwinder. meson passes source paths relative to the build directory and that's what file!() and thus CODE_FILE= in the journal would show. So remap the prefix away like PROJECT_FILE does for C. rustfmt.toml and .clippy.toml carry the formatting and lint settings for Rust code. rustfmt uses its defaults except for the line length the tree already uses and clippy gets the MSRV. The edition is 2021 for the whole project and .editorconfig learns about *.rs files. Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
1 parent
da22c6eeed
commit
770c05374e
6 files changed
+151
No files matched your search
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
msrv = "1.85"
|
||||
check-private-items = true
|
||||
@@ -32,6 +32,11 @@ indent_size = 4
|
||||
indent_style = space
|
||||
indent_size = 8
|
||||
|
||||
[*.rs]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 109
|
||||
|
||||
[man/*.xml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
+125
@@ -5,6 +5,7 @@ project('systemd', 'c',
|
||||
license : 'LGPLv2+',
|
||||
default_options: [
|
||||
'c_std=gnu17',
|
||||
'rust_std=2021',
|
||||
'prefix=/usr',
|
||||
'sysconfdir=/etc',
|
||||
'localstatedir=/var',
|
||||
@@ -371,6 +372,129 @@ else
|
||||
cxx_cmd = ''
|
||||
endif
|
||||
|
||||
#####################################################################
|
||||
|
||||
rust_feature = get_option('rust')
|
||||
# The oldest rustc we support. Also handed to bindgen, so that the generated bindings never require a
|
||||
# newer compiler than the hand-written code does.
|
||||
rust_msrv = '1.85'
|
||||
bindgen_min_version = '0.71.1'
|
||||
have_rust = false
|
||||
|
||||
if rust_feature.allowed()
|
||||
# The rust module's bindgen() integration needs this meson version.
|
||||
if meson.version().version_compare('< 1.4.0')
|
||||
if rust_feature.enabled()
|
||||
error('Rust support requires meson >= 1.4.0, found @0@'.format(meson.version()))
|
||||
endif
|
||||
message('Rust support requires meson >= 1.4.0, disabling')
|
||||
elif meson.is_cross_build()
|
||||
if rust_feature.enabled()
|
||||
error('Rust support is not available when cross-compiling yet')
|
||||
endif
|
||||
message('Rust support is not available when cross-compiling yet, disabling')
|
||||
else
|
||||
have_rust = add_languages('rust', native : false, required : rust_feature)
|
||||
endif
|
||||
endif
|
||||
|
||||
if have_rust
|
||||
rustc = meson.get_compiler('rust')
|
||||
if rustc.version().version_compare('< ' + rust_msrv)
|
||||
if rust_feature.enabled()
|
||||
error('rustc >= @0@ is required, found @1@'.format(rust_msrv, rustc.version()))
|
||||
endif
|
||||
message('rustc >= @0@ is required, found @1@, disabling Rust support'.format(rust_msrv, rustc.version()))
|
||||
have_rust = false
|
||||
endif
|
||||
endif
|
||||
|
||||
if have_rust
|
||||
bindgen = find_program('bindgen', required : rust_feature, version : '>= ' + bindgen_min_version)
|
||||
have_rust = bindgen.found()
|
||||
|
||||
# 0.72.0 generates bindings that do not compile, 0.72.1 fixed that.
|
||||
if have_rust and bindgen.version() == '0.72.0'
|
||||
if rust_feature.enabled()
|
||||
error('bindgen 0.72.0 is known to be broken, use 0.71.1 or >= 0.72.1')
|
||||
endif
|
||||
message('bindgen 0.72.0 is known to be broken, disabling Rust support')
|
||||
have_rust = false
|
||||
endif
|
||||
endif
|
||||
|
||||
if have_rust
|
||||
# bindgen parses C with libclang, which it loads at run time, so find_program() proves nothing about
|
||||
# it. Run it once over a header that reports the libclang version and contains the construct bindgen
|
||||
# < 0.72.1 mishandles with libclang >= 22 (https://github.com/rust-lang/rust-bindgen/pull/3278).
|
||||
bindgen_probe = run_command(bindgen, files('tools/bindgen-probe.h'), '--formatter', 'none', check : false)
|
||||
libclang_version = ''
|
||||
if bindgen_probe.returncode() == 0
|
||||
foreach line : bindgen_probe.stderr().split('\n')
|
||||
if line.contains('clang version ')
|
||||
libclang_version = line.split('clang version ')[1].split(' ')[0]
|
||||
endif
|
||||
endforeach
|
||||
endif
|
||||
|
||||
if libclang_version == ''
|
||||
if rust_feature.enabled()
|
||||
error('bindgen cannot generate bindings, is libclang installed?\n' + bindgen_probe.stderr())
|
||||
endif
|
||||
message('bindgen cannot generate bindings, disabling Rust support')
|
||||
have_rust = false
|
||||
elif libclang_version.version_compare('>= 22') and bindgen.version().version_compare('< 0.72.1') and not bindgen_probe.stdout().contains('pub foo')
|
||||
if rust_feature.enabled()
|
||||
error('bindgen @0@ does not work with libclang @1@, use bindgen >= 0.72.1'.format(bindgen.version(), libclang_version))
|
||||
endif
|
||||
message('bindgen @0@ does not work with libclang @1@, disabling Rust support'.format(bindgen.version(), libclang_version))
|
||||
have_rust = false
|
||||
endif
|
||||
endif
|
||||
|
||||
conf.set10('HAVE_RUST', have_rust)
|
||||
|
||||
if have_rust
|
||||
rustfmt = find_program('rustfmt', required : false)
|
||||
|
||||
# Warnings are errors only under --werror, like for C.
|
||||
rust_args = [
|
||||
'-Dnon_ascii_idents',
|
||||
'-Dunsafe_op_in_unsafe_fn',
|
||||
'-Wmissing_docs',
|
||||
'-Wrust_2018_idioms',
|
||||
'-Wunreachable_pub',
|
||||
'-Wclippy::undocumented_unsafe_blocks',
|
||||
'-Wclippy::unnecessary_safety_comment',
|
||||
'-Wclippy::unnecessary_safety_doc',
|
||||
'-Wclippy::ptr_as_ptr',
|
||||
'-Wclippy::ptr_cast_constness',
|
||||
'-Wclippy::ref_as_ptr',
|
||||
'-Wclippy::as_ptr_cast_mut',
|
||||
'-Wclippy::cast_lossless',
|
||||
'-Wclippy::dbg_macro',
|
||||
'-Wrustdoc::missing_crate_level_docs',
|
||||
# rustc's default depends on the optimization level. C code in systemd checks its arithmetic
|
||||
# where it matters, Rust code does not get to wrap silently either.
|
||||
'-Coverflow-checks=yes',
|
||||
# Unwinding could not cross the C frames of an event loop anyway, and without std there is no
|
||||
# unwinder.
|
||||
'-Cpanic=abort',
|
||||
]
|
||||
# meson passes source paths relative to the build directory, which is what file!() and hence
|
||||
# CODE_FILE= in the journal would show. Strip the prefix like PROJECT_FILE does for C. This also
|
||||
# makes the paths in the debug info relative to the source root (--remap-path-scope=macro would
|
||||
# limit it to file!(), but rustdoc does not accept that flag on stable).
|
||||
rust_args += ['--remap-path-prefix=' + relative_source_path + '/=']
|
||||
add_project_arguments(rust_args, language : 'rust')
|
||||
|
||||
summary({
|
||||
'rustc' : rustc.version(),
|
||||
'bindgen' : bindgen.version(),
|
||||
'libclang' : libclang_version,
|
||||
}, section : 'Rust')
|
||||
endif
|
||||
|
||||
if want_libfuzzer
|
||||
if cc.has_argument('-fsanitize=fuzzer-no-link')
|
||||
userspace_c_args += '-fsanitize=fuzzer-no-link'
|
||||
@@ -3286,6 +3410,7 @@ foreach tuple : [
|
||||
['report'],
|
||||
['resolve'],
|
||||
['rfkill'],
|
||||
['rust', have_rust],
|
||||
['sysext'],
|
||||
['sysinstall'],
|
||||
['systemd-analyze', conf.get('ENABLE_ANALYZE') == 1],
|
||||
|
||||
@@ -524,6 +524,8 @@ option('pwquality', type : 'feature', deprecated : { 'true' : 'enabled', 'false'
|
||||
description : 'libpwquality support')
|
||||
option('qrencode', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||
description : 'libqrencode support')
|
||||
option('rust', type : 'feature',
|
||||
description : 'support for programs written in Rust (needs rustc and bindgen)')
|
||||
option('tpm2', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||
description : 'TPM2 support')
|
||||
option('tpm2-nvpcr-base', type : 'integer', value: 0x01d10200,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
edition = "2021"
|
||||
max_width = 109
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
/* Run through bindgen at configure time: it reports the libclang version and contains the construct that
|
||||
* bindgen < 0.72.1 mishandles with libclang >= 22 (https://github.com/rust-lang/rust-bindgen/pull/3278). */
|
||||
|
||||
#pragma message("clang version " __clang_version__)
|
||||
|
||||
struct S;
|
||||
struct S {
|
||||
int foo;
|
||||
};
|
||||
Reference in new issue
Block a user