From: "Ezekiel Newren via GitGitGadget" <gitgitgadget@gmail•com>
To: git@vger•kernel.org
Cc: Ezekiel Newren <ezekielnewren@gmail•com>,
Ezekiel Newren <ezekielnewren@gmail•com>
Subject: [PATCH 04/13] build: build Rust with Makefile and Meson
Date: Thu, 27 Nov 2025 01:10:26 +0000 [thread overview]
Message-ID: <a4b79e70c152a8774b59822763045456a8c6b828.1764205835.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2110.git.git.1764205835.gitgitgadget@gmail.com>
From: Ezekiel Newren <ezekielnewren@gmail•com>
Signed-off-by: Ezekiel Newren <ezekielnewren@gmail•com>
---
Makefile | 91 ++++++++++++++++++++++++++++++++++++++-------
meson.build | 63 ++++++++++++++++++++++++++++++-
rust/build-crate.sh | 58 +++++++++++++++++++++++++++++
3 files changed, 197 insertions(+), 15 deletions(-)
create mode 100755 rust/build-crate.sh
diff --git a/Makefile b/Makefile
index 28bc00e648..0aa6b3ae73 100644
--- a/Makefile
+++ b/Makefile
@@ -483,6 +483,14 @@ include shared.mak
# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are
# in /foo/bar/include and /foo/bar/lib directories.
#
+# == Optional Rust support ==
+#
+# Define WITH_RUST=false if you don't want to include features and subsystems
+# written in Rust into Git. For now, Rust is still an optional feature of the
+# build process. With Git 3.0 though, Rust will be mandatory.
+#
+# Building Rust code requires Cargo.
+#
# == SHA-1 and SHA-256 defines ==
#
# === SHA-1 backend ===
@@ -919,9 +927,55 @@ TEST_SHELL_PATH = $(SHELL_PATH)
LIB_FILE = libgit.a
-GITLIBS = common-main.o $(LIB_FILE)
EXTLIBS =
+GIT_BUILD_DIR := $(CURDIR)
+export GIT_BUILD_DIR
+
+RUST_CRATES := gitcore
+.PHONY: rust-compile rust-clean
+
+WITH_RUST ?= true
+ifeq ($(WITH_RUST),true)
+
+ifeq ($(DEBUG), 1)
+ RUST_BUILD_MODE := debug
+else
+ RUST_BUILD_MODE := release
+endif
+
+RUST_LIBS := $(foreach c,$(RUST_CRATES),$(GIT_BUILD_DIR)/lib$(c).a)
+
+rust-compile:
+ @for c in $(RUST_CRATES); do \
+ echo "Building $$c..."; \
+ ./rust/build-crate.sh $(GIT_BUILD_DIR) $(RUST_BUILD_MODE) $$c || exit $$?; \
+ done
+
+rust-clean:
+ $(RM) $(RUST_LIBS) Cargo.lock
+ cargo clean
+
+$(GIT_BUILD_DIR)/lib%.a:
+ echo $(RUST_LIBS)
+ ./rust/build-crate.sh $(GIT_BUILD_DIR) $(RUST_BUILD_MODE) $*
+
+UNAME_S := $(shell uname -s)
+ifeq ($(UNAME_S),Linux)
+ EXTLIBS += -ldl
+endif
+
+else ifeq ($(WITH_RUST),false)
+rust-compile:
+ :
+rust-clean:
+ :
+else
+$(error 'WITH_RUST' must be true or false)
+endif
+
+GITLIBS = common-main.o $(LIB_FILE)
+
GIT_USER_AGENT = git/$(GIT_VERSION)
ifeq ($(wildcard sha1collisiondetection/lib/sha1.h),sha1collisiondetection/lib/sha1.h)
@@ -938,6 +992,11 @@ CC_LD_DYNPATH = -Wl,-rpath,
BASIC_CFLAGS = -I.
BASIC_LDFLAGS =
+ifeq ($(WITH_RUST),true)
+ BASIC_CFLAGS += -DWITH_RUST
+ BASIC_CFLAGS += -fPIE
+endif
+
# library flags
ARFLAGS = rcs
PTHREAD_CFLAGS =
@@ -1303,7 +1362,9 @@ LIB_OBJS += urlmatch.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
+ifeq ($(WITH_RUST),false)
LIB_OBJS += varint.o
+endif
LIB_OBJS += version.o
LIB_OBJS += versioncmp.o
LIB_OBJS += walker.o
@@ -2409,6 +2470,10 @@ endif
# from the dependency list, that would make each entry appear twice.
LIBS = $(filter-out %.o, $(GITLIBS)) $(EXTLIBS)
+ifeq ($(WITH_RUST),true)
+LIBS += $(RUST_LIBS)
+endif
+
BASIC_CFLAGS += $(COMPAT_CFLAGS)
LIB_OBJS += $(COMPAT_OBJS)
@@ -2564,7 +2629,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) rust-compile
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS)
@@ -2889,17 +2954,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) rust-compile
$(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) rust-compile
$(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) rust-compile
$(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) rust-compile
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
@@ -2909,11 +2974,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) rust-compile
$(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) rust-compile
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(LIBS)
@@ -3286,7 +3351,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) rust-compile
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
check-sha1:: t/helper/test-tool$X
@@ -3751,7 +3816,7 @@ cocciclean:
$(RM) -r .build/contrib/coccinelle
$(RM) contrib/coccinelle/*.cocci.patch
-clean: profile-clean coverage-clean cocciclean
+clean: profile-clean coverage-clean cocciclean rust-clean
$(RM) -r .build $(UNIT_TEST_BIN)
$(RM) GIT-TEST-SUITES
$(RM) po/git.pot po/git-core.pot
@@ -3907,13 +3972,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 rust-compile
$(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 rust-compile
$(call mkdir_p_parent_template)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(filter %.a,$^) $(LIBS)
@@ -3932,7 +3997,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 rust-compile
$(call mkdir_p_parent_template)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
diff --git a/meson.build b/meson.build
index 8966596ee8..94ec5e4ac0 100644
--- a/meson.build
+++ b/meson.build
@@ -267,6 +267,55 @@ 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'))
+rust_crates = ['gitcore']
+
+rust_builds = []
+with_rust = get_option('with_rust')
+if with_rust
+ rustc = find_program('rustc', required : false)
+ cargo = find_program('cargo', required : false)
+
+ if not rustc.found() or not cargo.found()
+ error('Rust toolchain not found. Reconfigure with -Dwith_rust=false')
+ endif
+
+ 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_environment = script_environment
+
+ 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() / 'rust' / 'build-crate.sh',
+ meson.current_build_dir(), rust_build_profile, crate,
+ ],
+ install: false,
+ env: rust_environment,
+ )
+ endforeach
+else
+ message('Rust components disabled (-Dwith_rust=false)')
+endif
+
+
compiler = meson.get_compiler('c')
libgit_sources = [
@@ -548,6 +597,10 @@ libgit_sources = [
'xdiff/xutils.c',
]
+if not with_rust
+ libgit_sources += 'varint.c'
+endif
+
libgit_sources += custom_target(
input: 'command-list.txt',
output: 'command-list.h',
@@ -782,6 +835,10 @@ libgit_c_args = [
'-DSHELL_PATH="' + fs.as_posix(target_shell.full_path()) + '"',
]
+if with_rust
+ libgit_c_args += '-DWITH_RUST'
+endif
+
system_attributes = get_option('gitattributes')
if system_attributes != ''
libgit_c_args += '-DETC_GITATTRIBUTES="' + system_attributes + '"'
@@ -1274,6 +1331,7 @@ elif host_machine.system() == 'windows'
]
libgit_dependencies += compiler.find_library('ntdll')
+ libgit_dependencies += compiler.find_library('userenv')
libgit_include_directories += 'compat/win32'
if compiler.get_id() == 'msvc'
libgit_include_directories += 'compat/vcbuild/include'
@@ -1710,14 +1768,15 @@ version_def_h = custom_target(
libgit_sources += version_def_h
libgit = declare_dependency(
- link_with: static_library('git',
+ 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/build-crate.sh b/rust/build-crate.sh
new file mode 100755
index 0000000000..b3debf70e5
--- /dev/null
+++ b/rust/build-crate.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+rustc -vV || exit $?
+cargo --version || exit $?
+
+dir_git_root=${0%/*}
+dir_build=$1
+rust_build_profile=$2
+crate=$3
+
+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
+
+libfile="lib${crate}.a"
+if rustc -vV | grep windows-msvc; then
+ libfile="${crate}.lib"
+ PATH="$(echo $PATH | tr ':' '\n' | grep -Ev "^(/mingw64/bin|/usr/bin)$" | paste -sd: -):/mingw64/bin:/usr/bin"
+fi
+
+CARGO_TARGET_DIR=$dir_git_root/.build/rust/$crate
+export CARGO_TARGET_DIR
+
+cargo clean && pwd && USE_LINKING="false" cargo build -p $crate $rust_args
+
+src=$CARGO_TARGET_DIR/$rust_build_profile/$libfile
+dst=$dir_build/$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
+echo mv $src $dst
+mv $src $dst
--
gitgitgadget
next prev parent reply other threads:[~2025-11-27 1:10 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-27 1:10 [PATCH 00/13] RFC: Convert to Cargo workspace Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 01/13] make: undo Patrick's changes concerning Rust Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 02/13] meson: " Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 03/13] cargo: convert from a crate to a workspace Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` Ezekiel Newren via GitGitGadget [this message]
2025-11-27 1:10 ` [PATCH 05/13] .gitignore: ignore /generated/ Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 06/13] cargo: create crate generate-headers Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 07/13] cargo: create crate link-with-c Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 08/13] rust/gitcore: link with c Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 09/13] varint.h: unsigned char -> uint8_t Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 10/13] make: delete files in generated/ Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 11/13] github-workflows: unify with rust parameters in make and meson Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 12/13] github workflows: install Rust Ezekiel Newren via GitGitGadget
2025-11-27 1:10 ` [PATCH 13/13] rust/build-rust.sh: update dir_git_root variable instantiation Ezekiel Newren via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a4b79e70c152a8774b59822763045456a8c6b828.1764205835.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail$(echo .)com \
--cc=ezekielnewren@gmail$(echo .)com \
--cc=git@vger$(echo .)kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox