[PATCH RFC v3 1/8] meson: add infrastructure to build internal Rust library
- From
Patrick Steinhardt <ps@pks.im>
- Date
- Sep 8, 2025, 14:13 UTC
- Message-ID
- <20250908-b4-pks-rust-breaking-change-v3-1-1cd7189fed3b@pks.im>
- In-Reply-To
- <20250908-b4-pks-rust-breaking-change-v3-0-1cd7189fed3b@pks.im>
Add the infrastructure into Meson to build an internal Rust library. Building the Rust parts of Git are for now entirely optional, as they are mostly intended as a test balloon for both Git developers, but also for distributors of Git. So for now, they may contain:
- New features that are not mission critical to Git and that users can
easily live without.- Alternative implementations of small subsystems.
If these test balloons are successful, we will eventually make Rust a mandatory dependency for our build process in Git 3.0.
The availability of a Rust toolchain will be auto-detected by Meson at setup time. This behaviour can be tweaked via the `-Drust=` feature toggle.
Next to the linkable Rust library, also wire up tests that can be executed via `meson test`. This allows us to use the native unit testing capabilities of Rust.
Note that the Rust edition is currently set to 2018. This edition is supported by Rust 1.49, which is the target for the upcoming gcc-rs backend. For now we don't use any features of Rust that would require a newer version, so settling on this old version makes sense so that gcc-rs may become an alternative backend for compiling Git. If we _do_ want to introduce features that were added in more recent editions of Rust though we should reevaluate that choice.
Signed-off-by: Patrick Steinhardt <ps@pks.im> --- Cargo.lock | 22 +++++++++++++++++++ Cargo.toml | 9 ++++++++ meson.build | 19 ++++++++++++++++- meson_options.txt | 2 ++ src/lib.rs | 0 src/meson.build | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000000..2b80a01e22a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,22 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +# Fix this to version 3. This is required so that older toolchains can still +# read the lock file. Furthermore, while an argument could be made that we +# should not even commit the "Cargo.lock" file in the first place, there's two +# reasons to still do so: +# +# - It thwarts supply-chain attacks by committing checksums into the +# repository. +# +# - It is required by Meson so that it can extract Cargo dependencies. +# +# Cargo dependencies can be accessed in Meson via: +# +# dependency('${package_name}-${package_api_version}-rs') +# +# E.g. with a dependency "time-0.3.43", you would pass "time-0.3-rs". +version = 3 + +[[package]] +name = "git" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000000..b9a41dbc792 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "git" +version = "0.1.0" +edition = "2018" + +[lib] +crate-type = ["staticlib"] + +[dependencies] diff --git a/meson.build b/meson.build index e8ec0eca165..3d6601225ba 100644 --- a/meson.build +++ b/meson.build @@ -220,7 +220,7 @@ project('git', 'c', # learned to define __STDC_VERSION__ with C11 and later. We thus require # GNU C99 and fall back to C11. Meson only learned to handle the fallback # with version 1.3.0, so on older versions we use GNU C99 unconditionally. - default_options: meson.version().version_compare('>=1.3.0') ? ['c_std=gnu99,c11'] : ['c_std=gnu99'], + default_options: meson.version().version_compare('>=1.3.0') ? ['rust_std=2018', 'c_std=gnu99,c11'] : ['rust_std=2018', 'c_std=gnu99'], ) fs = import('fs') @@ -1702,6 +1702,22 @@ version_def_h = custom_target( ) libgit_sources += version_def_h +# Starting with Meson 1.5, it knows to parse the "Cargo.lock" file and extract +# dependencies from it. So from hereon we don't need Cargo anymore to build +# Git. +if meson.version().version_compare('>=1.5.0') + rust_available = add_languages('rust', native: false, required: get_option('rust')) +else + cargo = find_program('cargo', dirs: program_path, native: true, required: get_option('rust')) + rust_available = cargo.found() +endif +rust_option = get_option('rust').disable_auto_if(not rust_available) + +if rust_option.allowed() + subdir('src') + libgit_c_args += '-DWITH_RUST' +endif + libgit = declare_dependency( link_with: static_library('git', sources: libgit_sources, @@ -2239,6 +2255,7 @@ summary({ 'pcre2': pcre2, 'perl': perl_features_enabled, 'python': target_python.found(), + 'rust': rust_option.allowed(), }, section: 'Auto-detected features', bool_yn: true) summary({ diff --git a/meson_options.txt b/meson_options.txt index 1668f260a18..143dee9237c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -71,6 +71,8 @@ option('zlib_backend', type: 'combo', choices: ['auto', 'zlib', 'zlib-ng'], valu # Build tweaks. option('breaking_changes', type: 'boolean', value: false, description: 'Enable upcoming breaking changes.') +option('rust', type: 'feature', value: 'auto', + description: 'Enable building with Rust.') option('macos_use_homebrew_gettext', type: 'boolean', value: true, description: 'Use gettext from Homebrew instead of the slightly-broken system-provided one.') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 00000000000..59e810b4d41 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,63 @@ +libgit_rs_sources = [ + 'lib.rs', +] + +if meson.version().version_compare('>=1.5.0') + libgit_rs = static_library('git_rs', + sources: libgit_rs_sources, + rust_abi: 'c', + ) + + # The Rust module does not seem to work on macOS as expected right now. As + # such, we only conditionally enable tests. + if get_option('tests') and host_machine.system() != 'darwin' + rustmod = import('rust') + rustmod.test('rust', libgit_rs) + endif +else + cargo_command = [ + cargo, + 'build', + '--lib', + '--quiet', + '--manifest-path', + meson.project_source_root() / 'Cargo.toml', + '--target-dir', + meson.current_build_dir() / 'target', + # `--out-dir` is unstable, but supported since 2018. It's been recently + # renamed to `--artifact-dir`, but for now both options are supported. + '-Z', + 'unstable-options', + '--out-dir', + meson.current_build_dir(), + ] + + if get_option('buildtype') == 'release' + cargo_command += '--release' + endif + + libgit_rs = custom_target('git_rs', + input: libgit_rs_sources + [ + meson.project_source_root() / 'Cargo.lock', + meson.project_source_root() / 'Cargo.toml', + ], + output: 'libgit.a', + command: cargo_command, + ) + + if get_option('tests') + test('rust', cargo, + args: [ + 'test', + '--manifest-path', + meson.project_source_root() / 'Cargo.toml', + '--target-dir', + meson.current_build_dir() / 'target', + ], + timeout: 0, + protocol: 'rust', + ) + endif +endif + +libgit_dependencies += declare_dependency(link_with: libgit_rs)
-- 2.51.0.417.g1ba7204a04.dirty