On August 22, 2025 11:56 PM, Ezekiel Newren wrote: >From: Ezekiel Newren <ezekielnewren@xxxxxxxxx> > >Upcoming patches will simplify xdiff, while also porting parts of it to Rust. In >preparation, add some stubs and setup the Rust build. For now, it is easier to let >cargo build rust and have make or meson merely link against the static library that >cargo builds. In line with ongoing libification efforts, use multiple crates to allow >more modularity on the Rust side. xdiff is the crate that this series will focus on, but >we also introduce the interop crate for future patch series. > >In order to facilitate interoperability between C and Rust, introduce C definitions for >Rust primitive types in git-compat-util.h. > >Signed-off-by: Ezekiel Newren <ezekielnewren@xxxxxxxxx> >--- > .gitignore | 3 +++ > Makefile | 53 ++++++++++++++++++++++++++++---------- > build_rust.sh | 57 +++++++++++++++++++++++++++++++++++++++++ > git-compat-util.h | 17 ++++++++++++ > meson.build | 52 +++++++++++++++++++++++++++++++------ > rust/Cargo.toml | 6 +++++ > rust/interop/Cargo.toml | 14 ++++++++++ rust/interop/src/lib.rs | 0 > rust/xdiff/Cargo.toml | 15 +++++++++++ > rust/xdiff/src/lib.rs | 0 > 10 files changed, 196 insertions(+), 21 deletions(-) create mode 100755 >build_rust.sh create mode 100644 rust/Cargo.toml create mode 100644 >rust/interop/Cargo.toml create mode 100644 rust/interop/src/lib.rs create mode >100644 rust/xdiff/Cargo.toml create mode 100644 rust/xdiff/src/lib.rs > >diff --git a/.gitignore b/.gitignore >index 04c444404e4b..ff81e3580c4e 100644 >--- a/.gitignore >+++ b/.gitignore >@@ -254,3 +254,6 @@ Release/ > /contrib/buildsystems/out > /contrib/libgit-rs/target > /contrib/libgit-sys/target >+/.idea/ >+/rust/target/ >+/rust/Cargo.lock >diff --git a/Makefile b/Makefile >index 70d1543b6b86..1ec0c1ee6603 100644 >--- a/Makefile >+++ b/Makefile >@@ -919,6 +919,29 @@ TEST_SHELL_PATH = $(SHELL_PATH) > > LIB_FILE = libgit.a > XDIFF_LIB = xdiff/lib.a >+ >+EXTLIBS = >+ >+ifeq ($(DEBUG), 1) >+ RUST_BUILD_MODE = debug >+else >+ RUST_BUILD_MODE = release >+endif >+ >+RUST_TARGET_DIR = rust/target/$(RUST_BUILD_MODE) RUST_FLAGS_FOR_C = >+-L$(RUST_TARGET_DIR) >+ >+.PHONY: compile_rust >+compile_rust: >+ ./build_rust.sh . $(RUST_BUILD_MODE) xdiff >+ >+EXTLIBS += ./$(RUST_TARGET_DIR)/libxdiff.a >+ >+UNAME_S := $(shell uname -s) >+ifeq ($(UNAME_S),Linux) >+ EXTLIBS += -ldl >+endif >+ > REFTABLE_LIB = reftable/libreftable.a > > GENERATED_H += command-list.h >@@ -1390,7 +1413,7 @@ UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o > > # xdiff and reftable libs may in turn depend on what is in libgit.a GITLIBS = >common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE) -EXTLIBS = >+ > > GIT_USER_AGENT = git/$(GIT_VERSION) > >@@ -2541,7 +2564,7 @@ git.sp git.s git.o: EXTRA_CPPFLAGS = \ > '-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \ > '-DGIT_INFO_PATH="$(infodir_relative_SQ)"' > >-git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS) >+git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS) compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ > $(filter %.o,$^) $(LIBS) > >@@ -2891,17 +2914,17 @@ headless-git.o: compat/win32/headless.c GIT- >CFLAGS > headless-git$X: headless-git.o git.res GIT-LDFLAGS > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -mwindows -o $@ >$< git.res > >-git-%$X: %.o GIT-LDFLAGS $(GITLIBS) >+git-%$X: %.o GIT-LDFLAGS $(GITLIBS) compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter >%.o,$^) $(LIBS) > >-git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS >$(GITLIBS) >+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS >+$(GITLIBS) compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter >%.o,$^) \ > $(IMAP_SEND_LDFLAGS) $(LIBS) > >-git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS) >+git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS >+$(GITLIBS) compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter >%.o,$^) \ > $(CURL_LIBCURL) $(LIBS) >-git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS) >+git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS) compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter >%.o,$^) \ > $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS) > >@@ -2911,11 +2934,11 @@ $(REMOTE_CURL_ALIASES): >$(REMOTE_CURL_PRIMARY) > ln -s $< $@ 2>/dev/null || \ > cp $< $@ > >-$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS >$(GITLIBS) >+$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS >+$(GITLIBS) compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter >%.o,$^) \ > $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS) > >-scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS) >+scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS) compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ > $(filter %.o,$^) $(LIBS) > >@@ -2925,6 +2948,7 @@ $(LIB_FILE): $(LIB_OBJS) > $(XDIFF_LIB): $(XDIFF_OBJS) > $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ > >+ > $(REFTABLE_LIB): $(REFTABLE_OBJS) > $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ > >@@ -3294,7 +3318,7 @@ perf: all > > t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) >$(UNIT_TEST_DIR)/test-lib.o > >-t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) >+t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) >+compile_rust > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter >%.o,$^) $(filter %.a,$^) $(LIBS) > > check-sha1:: t/helper/test-tool$X >@@ -3756,7 +3780,10 @@ cocciclean: > $(RM) -r .build/contrib/coccinelle > $(RM) contrib/coccinelle/*.cocci.patch > >-clean: profile-clean coverage-clean cocciclean >+rustclean: >+ cd rust && cargo clean >+ >+clean: profile-clean coverage-clean cocciclean rustclean > $(RM) -r .build $(UNIT_TEST_BIN) > $(RM) GIT-TEST-SUITES > $(RM) po/git.pot po/git-core.pot >@@ -3911,13 +3938,13 @@ FUZZ_CXXFLAGS ?= $(ALL_CFLAGS) > .PHONY: fuzz-all > fuzz-all: $(FUZZ_PROGRAMS) > >-$(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) GIT- >LDFLAGS >+$(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) >+GIT-LDFLAGS compile_rust > $(QUIET_LINK)$(FUZZ_CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) \ > -Wl,--allow-multiple-definition \ > $(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE) > > $(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o >$(UNIT_TEST_OBJS) \ >- $(GITLIBS) GIT-LDFLAGS >+ $(GITLIBS) GIT-LDFLAGS compile_rust > $(call mkdir_p_parent_template) > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ > $(filter %.o,$^) $(filter %.a,$^) $(LIBS) @@ -3936,7 +3963,7 @@ >$(UNIT_TEST_DIR)/clar.suite: $(UNIT_TEST_DIR)/clar-decls.h >$(UNIT_TEST_DIR)/gene > $(UNIT_TEST_DIR)/clar/clar.o: $(UNIT_TEST_DIR)/clar.suite > $(CLAR_TEST_OBJS): $(UNIT_TEST_DIR)/clar-decls.h > $(CLAR_TEST_OBJS): EXTRA_CPPFLAGS = -I$(UNIT_TEST_DIR) >-$(CLAR_TEST_PROG): $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS) $(GITLIBS) >GIT-LDFLAGS >+$(CLAR_TEST_PROG): $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS) >+$(GITLIBS) GIT-LDFLAGS compile_rust > $(call mkdir_p_parent_template) > $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter >%.o,$^) $(LIBS) > >diff --git a/build_rust.sh b/build_rust.sh new file mode 100755 index >000000000000..192385a1d961 >--- /dev/null >+++ b/build_rust.sh >@@ -0,0 +1,57 @@ >+#!/bin/sh >+ >+ >+rustc -vV || exit $? >+cargo --version || exit $? >+ >+dir_git_root=${0%/*} >+dir_build=$1 >+rust_build_profile=$2 >+crate=$3 >+ >+dir_rust=$dir_git_root/rust >+ >+if [ "$dir_git_root" = "" ]; then >+ echo "did not specify the directory for the root of git" >+ exit 1 >+fi >+ >+if [ "$dir_build" = "" ]; then >+ echo "did not specify the build directory" >+ exit 1 >+fi >+ >+if [ "$rust_build_profile" = "" ]; then >+ echo "did not specify the rust_build_profile" >+ exit 1 >+fi >+ >+if [ "$rust_build_profile" = "release" ]; then >+ rust_args="--release" >+ export RUSTFLAGS='' >+elif [ "$rust_build_profile" = "debug" ]; then >+ rust_args="" >+ export RUSTFLAGS='-C debuginfo=2 -C opt-level=1 -C force-frame-pointers=yes' >+else >+ echo "illegal rust_build_profile value $rust_build_profile" >+ exit 1 >+fi >+ >+cd $dir_rust && cargo clean && pwd && cargo build -p $crate $rust_args; >+cd $dir_git_root >+ >+libfile="lib${crate}.a" >+if rustup show active-toolchain | grep windows-msvc; then >+ libfile="${crate}.lib" >+fi >+dst=$dir_build/$libfile >+ >+if [ "$dir_git_root" != "$dir_build" ]; then >+ src=$dir_rust/target/$rust_build_profile/$libfile >+ if [ ! -f $src ]; then >+ echo >&2 "::error:: cannot find path of static library $src is not a file or does not >exist" >+ exit 5 >+ fi >+ >+ rm $dst 2>/dev/null >+ mv $src $dst >+fi >diff --git a/git-compat-util.h b/git-compat-util.h index >4678e21c4cb8..82dc99764ac0 100644 >--- a/git-compat-util.h >+++ b/git-compat-util.h >@@ -196,6 +196,23 @@ static inline int is_xplatform_dir_sep(int c) #include >"compat/msvc.h" > #endif > >+/* rust types */ >+typedef uint8_t u8; >+typedef uint16_t u16; >+typedef uint32_t u32; >+typedef uint64_t u64; >+ >+typedef int8_t i8; >+typedef int16_t i16; >+typedef int32_t i32; >+typedef int64_t i64; >+ >+typedef float f32; >+typedef double f64; >+ >+typedef size_t usize; >+typedef ptrdiff_t isize; >+ > /* used on Mac OS X */ > #ifdef PRECOMPOSE_UNICODE > #include "compat/precompose_utf8.h" >diff --git a/meson.build b/meson.build >index 596f5ac7110e..324f968338b9 100644 >--- a/meson.build >+++ b/meson.build >@@ -267,6 +267,40 @@ version_gen_environment.set('GIT_DATE', >get_option('build_date')) version_gen_environment.set('GIT_USER_AGENT', >get_option('user_agent')) version_gen_environment.set('GIT_VERSION', >get_option('version')) > >+if get_option('optimization') in ['2', '3', 's', 'z'] >+ rust_build_profile = 'release' >+else >+ rust_build_profile = 'debug' >+endif >+ >+# Run `rustup show active-toolchain` and capture output rustup_out = >+run_command('rustup', 'show', 'active-toolchain', >+ check: true).stdout().strip() >+ >+rust_crates = ['xdiff'] >+rust_builds = [] >+ >+foreach crate : rust_crates >+ if rustup_out.contains('windows-msvc') >+ libfile = crate + '.lib' >+ else >+ libfile = 'lib' + crate + '.a' >+ endif >+ >+ rust_builds += custom_target( >+ 'rust_build_'+crate, >+ output: libfile, >+ build_by_default: true, >+ build_always_stale: true, >+ command: [ >+ meson.project_source_root() / 'build_rust.sh', >+ meson.current_build_dir(), rust_build_profile, crate, >+ ], >+ install: false, >+ ) >+endforeach >+ >+ > compiler = meson.get_compiler('c') > > libgit_sources = [ >@@ -1678,14 +1712,16 @@ version_def_h = custom_target( libgit_sources += >version_def_h > > libgit = declare_dependency( >- link_with: static_library('git', >- sources: libgit_sources, >- c_args: libgit_c_args + [ >- '-DGIT_VERSION_H="' + version_def_h.full_path() + '"', >- ], >- dependencies: libgit_dependencies, >- include_directories: libgit_include_directories, >- ), >+ link_with: [ >+ static_library('git', >+ sources: libgit_sources, >+ c_args: libgit_c_args + [ >+ '-DGIT_VERSION_H="' + version_def_h.full_path() + '"', >+ ], >+ dependencies: libgit_dependencies, >+ include_directories: libgit_include_directories, >+ ), >+ ] + rust_builds, > compile_args: libgit_c_args, > dependencies: libgit_dependencies, > include_directories: libgit_include_directories, diff --git a/rust/Cargo.toml >b/rust/Cargo.toml new file mode 100644 index 000000000000..ed3d79d7f827 >--- /dev/null >+++ b/rust/Cargo.toml >@@ -0,0 +1,6 @@ >+[workspace] >+members = [ >+ "xdiff", >+ "interop", >+] >+resolver = "2" >diff --git a/rust/interop/Cargo.toml b/rust/interop/Cargo.toml new file mode >100644 index 000000000000..045e3b01cfad >--- /dev/null >+++ b/rust/interop/Cargo.toml >@@ -0,0 +1,14 @@ >+[package] >+name = "interop" >+version = "0.1.0" >+edition = "2021" >+ >+[lib] >+name = "interop" >+path = "src/lib.rs" >+## staticlib to generate xdiff.a for use by gcc ## cdylib (optional) to >+generate xdiff.so for use by gcc ## rlib is required by the rust unit >+tests crate-type = ["staticlib", "rlib"] >+ >+[dependencies] >diff --git a/rust/interop/src/lib.rs b/rust/interop/src/lib.rs new file mode 100644 >index 000000000000..e69de29bb2d1 diff --git a/rust/xdiff/Cargo.toml >b/rust/xdiff/Cargo.toml new file mode 100644 index >000000000000..eb7966aada64 >--- /dev/null >+++ b/rust/xdiff/Cargo.toml >@@ -0,0 +1,15 @@ >+[package] >+name = "xdiff" >+version = "0.1.0" >+edition = "2021" >+ >+[lib] >+name = "xdiff" >+path = "src/lib.rs" >+## staticlib to generate xdiff.a for use by gcc ## cdylib (optional) to >+generate xdiff.so for use by gcc ## rlib is required by the rust unit >+tests crate-type = ["staticlib", "rlib"] >+ >+[dependencies] >+interop = { path = "../interop" } >diff --git a/rust/xdiff/src/lib.rs b/rust/xdiff/src/lib.rs new file mode 100644 index >000000000000..e69de29bb2d1 Does this introduce Rust as a mandatory dependency for git? If so, it cuts out numerous platforms.