git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC PATCH v1 2/4] libgit-sys: add symlink to git repo root and clean after build

From
Josh Steadmon <steadmon@google.com>
Date
Mar 18, 2025, 23:24 UTC
Message-ID
<d592a3c2e3f56aa4f6915a07307a2ed349296272.1742339107.git.josh@steadmon.net>
In-Reply-To
<cover.1742339107.git.josh@steadmon.net>

Unlike `cargo build`, `cargo package` does not get access to the entire Git repo containing a Rust crate. Instead, it prepares a directory starting from the crate root (potentially excluding files, such as those not under version control, or explicity excluded in the Cargo.toml file).

This means that the current method of building the libgit-sys crate does not work with `cargo package`, as it tries to execute the Makefile from "../.." relative to the crate root.

Fix this by adding a `git-src` symlink in the crate that points to the Git repository root. `cargo package` will flatten this to a copy of the Git repo, excluding non-version-controlled files, any explicitly-excluded files, and trees that contain a Cargo.toml file (this prevents infinite recursion on the symlink).

We can then execute the Makefile under the flattened git-src directory from our build.rs script. However, this exposes a second problem; Cargo will check that the build script does not add, delete, or modify any source files. This means that after we copy our libgitpub.a dependency to the output directory, we must run `make clean` to remove the object files we created during the build process.

Unfortunately, there is not a way to determine from the build.rs script whether we're running `cargo build` vs. `cargo package`, so now any build of the libgit-sys crate will result in cleaning the Git worktree.

A potential alternative is to make an additional temporary copy of the worktree and run the Makefile there. This would avoid removing build artifacts in the worktree at the cost of copying MBs worth of source files to a temporary directory. Perhaps hardlinking instead of making a full copy would help here, but that might be less portable.

Signed-off-by: Josh Steadmon <steadmon@google.com>
---
 Makefile                    |  6 ++++++
 contrib/libgit-sys/build.rs | 21 ++++++++++++++++++++-
 contrib/libgit-sys/git-src  |  1 +
 3 files changed, 27 insertions(+), 1 deletion(-)
 create mode 120000 contrib/libgit-sys/git-src
diff --git a/Makefile b/Makefile
index 52eed88dde..e7d8786e4e 100644
--- a/Makefile
+++ b/Makefile
@@ -420,6 +420,10 @@ include shared.mak
 # Define INCLUDE_LIBGIT_RS if you want `make all` and `make test` to build and
 # test the Rust crates in contrib/libgit-sys and contrib/libgit-rs.
 #
+# Define PRESERVE_LIBGIT_TARGET to prevent `make clean` from removing the Cargo
+# output directories for libgit-sys and libgit-rs. This is mainly for use in the
+# Cargo build scripts.
+#
 # === Optional library: libintl ===
 #
 # Define NO_GETTEXT if you don't want Git output to be translated.
@@ -3761,7 +3765,9 @@ clean: profile-clean coverage-clean cocciclean
 	$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
 	$(MAKE) -C Documentation/ clean
 	$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
+ifndef PRESERVE_LIBGIT_TARGET
 	$(RM) -r contrib/libgit-sys/target contrib/libgit-rs/target
+endif
 	$(RM) contrib/libgitpub/partial_symbol_export.o
 	$(RM) contrib/libgitpub/hidden_symbol_export.o
 	$(RM) contrib/libgitpub/libgitpub.a
diff --git a/contrib/libgit-sys/build.rs b/contrib/libgit-sys/build.rs
index e0d979c196..9d586d272d 100644
--- a/contrib/libgit-sys/build.rs
+++ b/contrib/libgit-sys/build.rs
@@ -6,7 +6,7 @@ pub fn main() -> std::io::Result<()> {
     ac.emit_has_path("std::ffi::c_char");
 
     let crate_root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
-    let git_root = crate_root.join("../..");
+    let git_root = crate_root.join("git-src");
     let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
 
     let make_output = make_cmd::gnu_make()
@@ -31,5 +31,24 @@ pub fn main() -> std::io::Result<()> {
     println!("cargo:rustc-link-lib=gitpub");
     println!("cargo:rerun-if-changed={}", git_root.display());
 
+    let make_output = make_cmd::gnu_make()
+        .env("DEVELOPER", "1")
+        .env_remove("PROFILE")
+        .current_dir(git_root.clone())
+        .args([
+            "INCLUDE_LIBGIT_RS=YesPlease",
+            "PRESERVE_LIBGIT_TARGET=YesPlease",
+            "clean",
+        ])
+        .output()
+        .expect("`make clean` failed to run");
+    if !make_output.status.success() {
+        panic!(
+            "`make clean` failed:\n  stdout = {}\n  stderr = {}\n",
+            String::from_utf8(make_output.stdout).unwrap(),
+            String::from_utf8(make_output.stderr).unwrap()
+        );
+    }
+
     Ok(())
 }
diff --git a/contrib/libgit-sys/git-src b/contrib/libgit-sys/git-src
new file mode 120000
index 0000000000..c25bddb6dd
--- /dev/null
+++ b/contrib/libgit-sys/git-src
@@ -0,0 +1 @@
+../..
\ No newline at end of file
-- 
2.49.0.rc1.451.g8f38331e32-goog
Previous: Josh SteadmonNext: Josh Steadmon
Message 3 of 21 in “Fix `cargo package` for libgit-sys”
  1. 0/4 Fix `cargo package` for libgit-sysJosh Steadmon, Mar 18, 2025
  2. 1/4 libgitpub: move to separate contrib/ directoryJosh Steadmon, Mar 18, 2025
  3. 2/4 libgit-sys: add symlink to git repo root and clean after buildJosh Steadmon, Mar 18, 2025
  4. Josh SteadmonMar 19, 2025
  5. Phillip WoodMar 20, 2025
  6. Josh SteadmonMar 21, 2025
  7. 3/4 libgit-sys: parallelize build with Cargo's jobserverJosh Steadmon, Mar 18, 2025
  8. 4/4 libgit-sys: exclude unnecessary directories in git-srcJosh Steadmon, Mar 18, 2025
  9. 0/5 Fix `cargo package` for libgit-sysJosh Steadmon, Mar 21, 2025
  10. 1/5 libgitpub: move to separate contrib/ directoryJosh Steadmon, Mar 21, 2025
  11. 2/5 libgit-sys: add symlink to git repo root and build out of treeJosh Steadmon, Mar 21, 2025
  12. Eric SunshineMar 23, 2025
  13. Junio C HamanoMar 24, 2025
  14. Josh SteadmonMar 25, 2025
  15. Junio C HamanoMar 25, 2025
  16. Josh SteadmonMar 27, 2025
  17. Junio C HamanoMar 29, 2025
  18. Johannes SchindelinMar 31, 2025
  19. 3/5 libgit-sys: parallelize build with Cargo's jobserverJosh Steadmon, Mar 21, 2025
  20. 4/5 libgit-sys: exclude unnecessary directories in git-srcJosh Steadmon, Mar 21, 2025
  21. 5/5 libgit-{sys,rs}: add license and description fieldsJosh Steadmon, Mar 21, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.