Repositories / ocaml-git.git

ocaml-git.git

Clone (read-only): git clone http://git.guha-anderson.com/git/ocaml-git.git

Branch

Vendor static libgit2

Author
Arjun Guha <a.guha@northeastern.edu>
Date
2026-05-03 17:31:30 -0400
Commit
b12eb3f31458e4f73741b47b8938107673cc7b7f
.gitignore
index c914818..2947787 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
 .gradle/
 .build/
 build/
+vendor/libgit2-build/
+vendor/libgit2-install/
 *.kexe
 *.klib
 .kotlin/
.gitmodules
new file mode 100644
index 0000000..44fa6fd
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "vendor/libgit2"]
+	path = vendor/libgit2
+	url = https://github.com/libgit2/libgit2.git
dune-project
index 3aa1234..1249b7c 100644
--- a/dune-project
+++ b/dune-project
@@ -1,6 +1,5 @@
 (lang dune 3.22)
 (name ocaml-git)
-(generate_opam_files true)
 
 (package
  (name ocaml-git)
@@ -8,4 +7,5 @@
  (depends
   (ocaml (>= 5.4))
   dune
+  (conf-cmake :build)
   alcotest))
ocaml-git.opam
index 4020949..faaed88 100644
--- a/ocaml-git.opam
+++ b/ocaml-git.opam
@@ -1,13 +1,15 @@
-# This file is generated by dune, edit dune-project instead
 opam-version: "2.0"
 synopsis: "Small OCaml Git library"
 depends: [
   "ocaml" {>= "5.4"}
   "dune" {>= "3.22"}
+  "conf-cmake" {build}
   "alcotest"
   "odoc" {with-doc}
 ]
 build: [
+  ["sh" "-exc" "if test -f .gitmodules; then git submodule update --init --recursive; fi"]
+  ["sh" "-exc" "LIBGIT2_BUILD_JOBS=%{jobs}% ./scripts/build-vendored-libgit2.sh"]
   ["dune" "subst"] {dev}
   [
     "dune"
scripts/build-vendored-libgit2.sh
new file mode 100755
index 0000000..b60d054
--- /dev/null
+++ b/scripts/build-vendored-libgit2.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+LIBGIT2_SRC="${ROOT}/vendor/libgit2"
+BUILD_DIR="${ROOT}/vendor/libgit2-build"
+INSTALL_DIR="${ROOT}/vendor/libgit2-install"
+
+if [[ ! -f "${LIBGIT2_SRC}/CMakeLists.txt" ]]; then
+  echo "Missing ${LIBGIT2_SRC}. Initialize submodules: git submodule update --init --recursive" >&2
+  exit 1
+fi
+
+JOBS="${LIBGIT2_BUILD_JOBS:-}"
+if [[ -z "${JOBS}" && -n "${OPAMJOBS:-}" ]]; then
+  JOBS="${OPAMJOBS}"
+fi
+if [[ -z "${JOBS}" ]]; then
+  JOBS="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)"
+fi
+
+MARKER="${BUILD_DIR}/.ocaml_git_root"
+if [[ -f "${BUILD_DIR}/CMakeCache.txt" ]]; then
+  if [[ ! -f "${MARKER}" ]] || [[ "$(<"${MARKER}")" != "${ROOT}" ]]; then
+    rm -rf "${BUILD_DIR}"
+  fi
+fi
+
+cmake -S "${LIBGIT2_SRC}" -B "${BUILD_DIR}" \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
+  -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
+  -DBUILD_SHARED_LIBS=OFF \
+  -DBUILD_TESTS=OFF \
+  -DBUILD_CLI=OFF \
+  -DBUILD_EXAMPLES=OFF \
+  -DUSE_HTTPS=OFF \
+  -DUSE_SSH=OFF \
+  -DUSE_GSSAPI=OFF \
+  -DUSE_NTLMCLIENT=OFF \
+  -DUSE_BUNDLED_ZLIB=ON \
+  -DUSE_HTTP_PARSER=builtin \
+  -DREGEX_BACKEND=builtin \
+  -DUSE_ICONV=OFF \
+  -DUSE_SHA1=CollisionDetection \
+  -DUSE_SHA256=Builtin
+
+cmake --build "${BUILD_DIR}" --parallel "${JOBS}"
+rm -rf "${INSTALL_DIR}"
+cmake --install "${BUILD_DIR}"
+printf '%s\n' "${ROOT}" > "${MARKER}"
scripts/gen-libgit2-static-link-sexp.sh
old mode 100644
new mode 100755
index 751b4bd..81f779c
--- a/scripts/gen-libgit2-static-link-sexp.sh
+++ b/scripts/gen-libgit2-static-link-sexp.sh
@@ -1,34 +1,32 @@
 #!/usr/bin/env sh
 set -eu
 
-if ! command -v pkg-config >/dev/null 2>&1; then
-  echo "pkg-config is required to generate libgit2 static link flags" >&2
-  exit 1
+if test "$#" -gt 0; then
+  root="$1"
+else
+  root="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)"
 fi
 
-flags="$(pkg-config --libs --static libgit2)"
-
-printf '('
-for flag in $flags; do
-  case "$flag" in
-  -lgit2) flag="-l:libgit2.a" ;;
-  -lhttp_parser) flag="-l:libhttp_parser.a" ;;
-  -lssh2) flag="-l:libssh2.a" ;;
-  -lssl) flag="-l:libssl.a" ;;
-  -lcrypto) flag="-l:libcrypto.a" ;;
-  -lpcre2-8) flag="-l:libpcre2-8.a" ;;
-  -lz) flag="-l:libz.a" ;;
+if ! test -d "$root/vendor/libgit2-install/lib"; then
+  case "$(pwd)" in
+  */_build/*)
+    workspace_root="${PWD%%/_build/*}"
+    if test -d "$workspace_root/vendor/libgit2-install/lib"; then
+      root="$workspace_root"
+    fi
+    ;;
   esac
-  printf ' "%s"' "$flag"
-done
+fi
 
-# Debian/Ubuntu's libgit2.pc omits GSSAPI from Libs.private even though the
-# static archive references it when HTTP negotiate auth support is enabled.
-# Static Kerberos/GSSAPI archives are not installed by default, and this system
-# also lacks the unversioned linker symlink, so pass the versioned .so path.
-if test -r /usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2; then
-  printf ' "/usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2"'
-else
-  printf ' "-lgssapi_krb5"'
+printf '('
+printf ' "-L%s/vendor/libgit2-install/lib"' "$root"
+if test -n "${OPAM_SWITCH_PREFIX:-}"; then
+  printf ' "-L%s/lib/ocaml-git"' "$OPAM_SWITCH_PREFIX"
+elif command -v opam >/dev/null 2>&1; then
+  libdir="$(opam var lib 2>/dev/null || true)"
+  if test -n "$libdir"; then
+    printf ' "-L%s/ocaml-git"' "$libdir"
+  fi
 fi
+printf ' "-Wl,--start-group" "-l:libgit2.a" "-Wl,--end-group" "-lrt" "-pthread"'
 printf ' )\n'
src/dune
index 5adbc54..df6717f 100644
--- a/src/dune
+++ b/src/dune
@@ -12,7 +12,14 @@
  (no_dynlink)
  (foreign_stubs
   (language c)
-  (names ocaml_git_stubs))
+  (names ocaml_git_stubs)
+  (include_dirs %{project_root}/vendor/libgit2-install/include))
  (c_library_flags
   (:include libgit2_static_link_flags.sexp))
  (libraries unix))
+
+(install
+ (package ocaml-git)
+ (section lib)
+ (files
+  (../vendor/libgit2-install/lib/libgit2.a as libgit2.a)))
vendor/libgit2
new file mode 160000
index 0000000..a418d9d
--- /dev/null
+++ b/vendor/libgit2
@@ -0,0 +1 @@
+Subproject commit a418d9d4ab87bae16b87d8f37143a4687ae0e4b2