Introduce libgit-sys, a Rust wrapper crate that allows Rust code to call
functions in libgit.a. This initial patch defines build rules and an
interface that exposes user agent string getter functions as a proof of
concept. This library can be tested with `cargo test`. In later commits,
a higher-level library containing a more Rust-friendly interface will be
added at `contrib/libgit-rs`.
Symbols in libgit can collide with symbols from other libraries such as
libgit2. We avoid this by first exposing library symbols in
public_symbol_export.[ch]. These symbols are prepended with "libgit_" to
avoid collisions and set to visible using a visibility pragma. In
build.rs, Rust builds contrib/libgit-rs/libgit-sys/libgitpub.a, which also
contains libgit.a and other dependent libraries, with
-fvisibility=hidden to hide all symbols within those libraries that
haven't been exposed with a visibility pragma.
Co-authored-by: Kyle Lippincott <spectral@google.com>
Co-authored-by: Calvin Wan <calvinwan@google.com>
Signed-off-by: Calvin Wan <calvinwan@google.com>
Signed-off-by: Kyle Lippincott <spectral@google.com>
Signed-off-by: Josh Steadmon <steadmon@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Josh Steadmon committedJan 28, 2025 at 14:01 UTCe7f8bf125c078004232e254e71b97226c4fed81b
new file mode 100644index 0000000000..e0623022c3--- /dev/null+++ b/contrib/libgit-sys/Cargo.toml@@ -0,0 +1,19 @@+[package]+name = "libgit-sys"+version = "0.1.0"+edition = "2021"+build = "build.rs"+links = "gitpub"+rust-version = "1.63" # TODO: Once we hit 1.84 or newer, we may want to remove Cargo.lock from+ # version control. See https://lore.kernel.org/git/Z47jgK-oMjFRSslr@tapette.crustytoothpaste.net/+description = "Native bindings to a portion of libgit"++[lib]+path = "src/lib.rs"++[dependencies]+libz-sys = "1.1.19"++[build-dependencies]+autocfg = "1.4.0"+make-cmd = "0.1.0"
contrib/libgit-sys/README.md
+4
new file mode 100644index 0000000000..c061cfcaf5--- /dev/null+++ b/contrib/libgit-sys/README.md@@ -0,0 +1,4 @@+# libgit-sys++A small proof-of-concept crate showing how to provide a Rust FFI to Git+internals.
contrib/libgit-sys/build.rs
+35
new file mode 100644index 0000000000..3ffd80ad91--- /dev/null+++ b/contrib/libgit-sys/build.rs@@ -0,0 +1,35 @@+use std::env;+use std::path::PathBuf;++pub fn main() -> std::io::Result<()> {+ let ac = autocfg::new();+ 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 dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());++ let make_output = make_cmd::gnu_make()+ .env("DEVELOPER", "1")+ .env_remove("PROFILE")+ .current_dir(git_root.clone())+ .args([+ "INCLUDE_LIBGIT_RS=YesPlease",+ "contrib/libgit-sys/libgitpub.a",+ ])+ .output()+ .expect("Make failed to run");+ if !make_output.status.success() {+ panic!(+ "Make failed:\n stdout = {}\n stderr = {}\n",+ String::from_utf8(make_output.stdout).unwrap(),+ String::from_utf8(make_output.stderr).unwrap()+ );+ }+ std::fs::copy(crate_root.join("libgitpub.a"), dst.join("libgitpub.a"))?;+ println!("cargo:rustc-link-search=native={}", dst.display());+ println!("cargo:rustc-link-lib=gitpub");+ println!("cargo:rerun-if-changed={}", git_root.display());++ Ok(())+}
contrib/libgit-sys/public_symbol_export.c
+23
new file mode 100644index 0000000000..4c153c6f0d--- /dev/null+++ b/contrib/libgit-sys/public_symbol_export.c@@ -0,0 +1,23 @@+/*+ * Shim to publicly export Git symbols. These must be renamed so that the+ * original symbols can be hidden. Renaming these with a "libgit_" prefix also+ * avoids conflicts with other libraries such as libgit2.+ */++#include "git-compat-util.h"+#include "contrib/libgit-sys/public_symbol_export.h"+#include "version.h"++#pragma GCC visibility push(default)++const char *libgit_user_agent(void)+{+ return git_user_agent();+}++const char *libgit_user_agent_sanitized(void)+{+ return git_user_agent_sanitized();+}++#pragma GCC visibility pop