From 2392399cc861e692d6d5bf6265eb0f46a19cf9a3 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 11 Jul 2023 00:46:38 +0100 Subject: [PATCH] build: `LIBGIT2_NO_VENDOR` to force to use system libgit2 Specify `LIBGIT2_NO_VENDOR` to force to use system libgit2. Due to the additive nature of Cargo features, if some crate in the dependency graph activates `vendored` feature, there is no way to revert it back. This env var serves as a workaround for this purpose. An alternative is having `no_vendored` feature. We still need to modify `build.rs` to make both `vendored` and `no_vendored` play nice with each other (or bail out as they are mutual-exclusive). However, there is no way to activate a Cargo feature via environment variable (see rust-lang/cargo#4829). Altering environment variables may be the only way to interact with some external build systems. It is also pretty common that people don't want to vendor anything and rather to see the build fail than vendoring. Some prior arts: * `OPENSSL_NO_VENDOR` in `openssl` crate, which serves the exact purpose of `LIBGIT2_NO_VENDOR` [^1]. * Crate `ssh2` has a similar `LIBSSH2_SYS_USE_PKG_CONFIG`, but it doesn't force to do so. It still falls back to vendored lib [^2]. * Crate `curl` has a feature `force-system-lib-on-osx` to trump all others features. It was created primarily for Rust releases [^3]. [^1]: https://github.com/sfackler/rust-openssl/blob/50787ed35bf9efa9dd3cbb1993a2564014b67489/openssl/src/lib.rs#L65 [^2]: https://github.com/alexcrichton/ssh2-rs/blob/d9a1dfac4b8c09c5437eb477606b82aa4f67b092/libssh2-sys/build.rs#L22-L33 [^3]: https://github.com/alexcrichton/curl-rust/blob/431babf1dffe205641793353d3d57fdd36fe8534/curl-sys/build.rs#L15-L20 --- README.md | 5 +++++ libgit2-sys/build.rs | 49 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b4cf4f1e69..816a377fa1 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,11 @@ source for libgit2 is included in the libgit2-sys crate so there's no need to pre-install the libgit2 library, the libgit2-sys crate will figure that and/or build that for you. +You can enable the Cargo feature `vendored-libgit2` to always compile and +statically link to a copy of libgit2. Sometimes the libgit2 on the system is +required to be found and used even when `vendored-libgit2` is activated. In +this case, you shall set the environment variable `LIBGIT2_NO_VENDOR=1`. + ## Building git2-rs ```sh diff --git a/libgit2-sys/build.rs b/libgit2-sys/build.rs index 24df572ef6..fd79e02b57 100644 --- a/libgit2-sys/build.rs +++ b/libgit2-sys/build.rs @@ -4,22 +4,55 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::Command; +/// Tries to use system libgit2 and emits necessary build script instructions. +fn try_system_libgit2() -> Result { + let mut cfg = pkg_config::Config::new(); + match cfg.range_version("1.6.4".."1.7.0").probe("libgit2") { + Ok(lib) => { + for include in &lib.include_paths { + println!("cargo:root={}", include.display()); + } + Ok(lib) + } + Err(e) => { + println!("cargo:warning=failed to probe system libgit2: {e}"); + Err(e) + } + } +} + fn main() { let https = env::var("CARGO_FEATURE_HTTPS").is_ok(); let ssh = env::var("CARGO_FEATURE_SSH").is_ok(); let vendored = env::var("CARGO_FEATURE_VENDORED").is_ok(); let zlib_ng_compat = env::var("CARGO_FEATURE_ZLIB_NG_COMPAT").is_ok(); + // Specify `LIBGIT2_NO_VENDOR` to force to use system libgit2. + // Due to the additive nature of Cargo features, if some crate in the + // dependency graph activates `vendored` feature, there is no way to revert + // it back. This env var serves as a workaround for this purpose. + println!("cargo:rerun-if-env-changed=LIBGIT2_NO_VENDOR"); + let forced_no_vendor = env::var_os("LIBGIT2_NO_VENDOR").map_or(false, |s| s != "0"); + + if forced_no_vendor { + if try_system_libgit2().is_err() { + panic!( + "\ +The environment variable `LIBGIT2_NO_VENDOR` has been set but no compatible system libgit2 could be found. +The build is now aborting. To disable, unset the variable or use `LIBGIT2_NO_VENDOR=0`. +", + ); + } + + // We've reached here, implying we're using system libgit2. + return; + } + // To use zlib-ng in zlib-compat mode, we have to build libgit2 ourselves. let try_to_use_system_libgit2 = !vendored && !zlib_ng_compat; - if try_to_use_system_libgit2 { - let mut cfg = pkg_config::Config::new(); - if let Ok(lib) = cfg.range_version("1.6.4".."1.7.0").probe("libgit2") { - for include in &lib.include_paths { - println!("cargo:root={}", include.display()); - } - return; - } + if try_to_use_system_libgit2 && try_system_libgit2().is_ok() { + // using system libgit2 has worked + return; } println!("cargo:rustc-cfg=libgit2_vendored");