@@ -248,3 +248,4 @@ Release/
/git.VC.db
*.dSYM
/contrib/buildsystems/out
+/contrib/libgit-rs/libgit-sys/target
@@ -653,6 +653,8 @@ CURL_CONFIG = curl-config
GCOV = gcov
STRIP = strip
SPATCH = spatch
+LD = ld
+OBJCOPY = objcopy
export TCL_PATH TCLTK_PATH
@@ -2713,6 +2715,7 @@ OBJECTS += $(XDIFF_OBJS)
OBJECTS += $(FUZZ_OBJS)
OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
OBJECTS += $(UNIT_TEST_OBJS)
+OBJECTS += contrib/libgit-rs/libgit-sys/public_symbol_export.o
ifndef NO_CURL
OBJECTS += http.o http-walker.o remote-curl.o
@@ -3720,6 +3723,10 @@ clean: profile-clean coverage-clean cocciclean
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
$(MAKE) -C Documentation/ clean
$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
+ $(RM) -r contrib/libgit-rs/libgit-sys/target
+ $(RM) -r contrib/libgit-rs/libgit-sys/partial_symbol_export.o
+ $(RM) -r contrib/libgit-rs/libgit-sys/hidden_symbol_export.o
+ $(RM) -r contrib/libgit-rs/libgit-sys/libgitpub.a
ifndef NO_PERL
$(RM) -r perl/build/
endif
@@ -3865,3 +3872,12 @@ $(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o \
build-unit-tests: $(UNIT_TEST_PROGS)
unit-tests: $(UNIT_TEST_PROGS) t/helper/test-tool$X
$(MAKE) -C t/ unit-tests
+
+contrib/libgit-rs/libgit-sys/partial_symbol_export.o: contrib/libgit-rs/libgit-sys/public_symbol_export.o libgit.a reftable/libreftable.a xdiff/lib.a
+ $(LD) -r $^ -o $@
+
+contrib/libgit-rs/libgit-sys/hidden_symbol_export.o: contrib/libgit-rs/libgit-sys/partial_symbol_export.o
+ $(OBJCOPY) --localize-hidden $^ $@
+
+contrib/libgit-rs/libgit-sys/libgitpub.a: contrib/libgit-rs/libgit-sys/hidden_symbol_export.o
+ $(AR) $(ARFLAGS) $@ $^
new file mode 100644
@@ -0,0 +1,69 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "cc"
+version = "1.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.158"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+
+[[package]]
+name = "libgit-sys"
+version = "0.1.0"
+dependencies = [
+ "autocfg",
+ "libz-sys",
+ "make-cmd",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "make-cmd"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
new file mode 100644
@@ -0,0 +1,17 @@
+[package]
+name = "libgit-sys"
+version = "0.1.0"
+edition = "2021"
+build = "build.rs"
+links = "gitpub"
+rust-version = "1.63"
+
+[lib]
+path = "src/lib.rs"
+
+[dependencies]
+libz-sys = "1.1.19"
+
+[build-dependencies]
+autocfg = "1.4.0"
+make-cmd = "0.1.0"
new file mode 100644
@@ -0,0 +1,15 @@
+# cgit-info
+
+A small hacky proof-of-concept showing how to provide a Rust FFI for the Git
+library.
+
+## Building
+
+`cargo build` automatically builds and picks up on changes made to both
+the Rust wrapper and git.git code so there is no need to run `make`
+beforehand.
+
+## Running
+
+Assuming you don't make any changes to the Git source, you can just work from
+`contrib/cgit-rs` and use `cargo build` or `cargo run` as usual.
new file mode 100644
@@ -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([
+ "CFLAGS=-fvisibility=hidden",
+ "contrib/libgit-rs/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(())
+}
new file mode 100644
@@ -0,0 +1,21 @@
+// 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-rs/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
new file mode 100644
@@ -0,0 +1,8 @@
+#ifndef PUBLIC_SYMBOL_EXPORT_H
+#define PUBLIC_SYMBOL_EXPORT_H
+
+const char *libgit_user_agent(void);
+
+const char *libgit_user_agent_sanitized(void);
+
+#endif /* PUBLIC_SYMBOL_EXPORT_H */
new file mode 100644
@@ -0,0 +1,46 @@
+#[cfg(has_std__ffi__c_char)]
+use std::ffi::c_char;
+
+#[cfg(not(has_std__ffi__c_char))]
+#[allow(non_camel_case_types)]
+pub type c_char = i8;
+
+extern crate libz_sys;
+
+extern "C" {
+ pub fn libgit_user_agent() -> *const c_char;
+ pub fn libgit_user_agent_sanitized() -> *const c_char;
+}
+
+#[cfg(test)]
+mod tests {
+ use std::ffi::CStr;
+
+ use super::*;
+
+ #[test]
+ fn user_agent_starts_with_git() {
+ let c_str = unsafe { CStr::from_ptr(libgit_user_agent()) };
+ let agent = c_str
+ .to_str()
+ .expect("User agent contains invalid UTF-8 data");
+ assert!(
+ agent.starts_with("git/"),
+ r#"Expected user agent to start with "git/", got: {}"#,
+ agent
+ );
+ }
+
+ #[test]
+ fn sanitized_user_agent_starts_with_git() {
+ let c_str = unsafe { CStr::from_ptr(libgit_user_agent_sanitized()) };
+ let agent = c_str
+ .to_str()
+ .expect("Sanitized user agent contains invalid UTF-8 data");
+ assert!(
+ agent.starts_with("git/"),
+ r#"Expected user agent to start with "git/", got: {}"#,
+ agent
+ );
+ }
+}