@@ -5,15 +5,66 @@ use std::path::{Path, PathBuf};
55use std:: process:: Command ;
66
77/// Tries to use system libgit2 and emits necessary build script instructions.
8- fn try_system_libgit2 ( ) -> Result < pkg_config:: Library , pkg_config:: Error > {
8+ fn try_system_libgit2 (
9+ experimental_sha256 : bool ,
10+ ) -> Result < pkg_config:: Library , Box < dyn std:: error:: Error > > {
911 let mut cfg = pkg_config:: Config :: new ( ) ;
1012 let range_version = "1.9.2" .."1.10.0" ;
1113
12- let lib = match cfg. range_version ( range_version) . probe ( "libgit2" ) {
13- Ok ( lib) => lib,
14- Err ( e) => {
15- println ! ( "cargo:warning=failed to probe system libgit2: {e}" ) ;
16- return Err ( e) ;
14+ let lib = if experimental_sha256 {
15+ // Determine whether experimental SHA256 object support is enabled.
16+ //
17+ // Given the SHA256 support is ABI-incompatible,
18+ // we take a conservative approach here:
19+ //
20+ // 1. Only accept if the library name has the `-experimental` suffix
21+ // 2. The experimental library must have an `experimental.h` header file
22+ // containing an enabled `GIT_EXPERIMENTAL_SHA256` constant.
23+ //
24+ // See how libgit2 handles experimental features:
25+ // https://github.com/libgit2/libgit2/blob/3ac4c0adb1064bad16a7f980d87e7261753fd07e/cmake/ExperimentalFeatures.cmake
26+ match cfg
27+ . range_version ( range_version. clone ( ) )
28+ . probe ( "libgit2-experimental" )
29+ {
30+ Ok ( lib) => {
31+ let sha256_constant_in_header = lib. include_paths . iter ( ) . any ( |path| {
32+ let header = path. join ( "git2/experimental.h" ) ;
33+ let contents = match std:: fs:: read_to_string ( header) {
34+ Ok ( s) => s,
35+ Err ( _) => return false ,
36+ } ;
37+ if contents. contains ( "#cmakedefine" ) {
38+ // still template
39+ return false ;
40+ }
41+ contents
42+ . lines ( )
43+ . any ( |l| l. starts_with ( "#define GIT_EXPERIMENTAL_SHA256 1" ) )
44+ } ) ;
45+ if sha256_constant_in_header {
46+ println ! ( "cargo:rustc-cfg=libgit2_experimental_sha256" ) ;
47+ lib
48+ } else {
49+ println ! ( "cargo:warning=no GIT_EXPERIMENTAL_SHA256 constant in headers" ) ;
50+ return Err (
51+ "GIT_EXPERIMENTAL_SHA256 wasn't enabled for libgit2-experimental library"
52+ . into ( ) ,
53+ ) ;
54+ }
55+ }
56+ Err ( e) => {
57+ println ! ( "cargo:warning=failed to probe system libgit2-experimental: {e}" ) ;
58+ return Err ( e. into ( ) ) ;
59+ }
60+ }
61+ } else {
62+ match cfg. range_version ( range_version) . probe ( "libgit2" ) {
63+ Ok ( lib) => lib,
64+ Err ( e) => {
65+ println ! ( "cargo:warning=failed to probe system libgit2: {e}" ) ;
66+ return Err ( e. into ( ) ) ;
67+ }
1768 }
1869 } ;
1970
@@ -45,7 +96,7 @@ fn main() {
4596 let forced_no_vendor = env:: var_os ( "LIBGIT2_NO_VENDOR" ) . map_or ( false , |s| s != "0" ) ;
4697
4798 if forced_no_vendor {
48- if try_system_libgit2 ( ) . is_err ( ) {
99+ if try_system_libgit2 ( unstable_sha256 ) . is_err ( ) {
49100 panic ! (
50101 "\
51102 The environment variable `LIBGIT2_NO_VENDOR` has been set but no compatible system libgit2 could be found.
@@ -60,7 +111,7 @@ The build is now aborting. To disable, unset the variable or use `LIBGIT2_NO_VEN
60111
61112 // To use zlib-ng in zlib-compat mode, we have to build libgit2 ourselves.
62113 let try_to_use_system_libgit2 = !vendored && !zlib_ng_compat;
63- if try_to_use_system_libgit2 && try_system_libgit2 ( ) . is_ok ( ) {
114+ if try_to_use_system_libgit2 && try_system_libgit2 ( unstable_sha256 ) . is_ok ( ) {
64115 // using system libgit2 has worked
65116 return ;
66117 }
0 commit comments