Skip to content

Commit

Permalink
build: LIBGIT2_NO_VENDOR to force to use system libgit2
Browse files Browse the repository at this point in the history
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].

[^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
  • Loading branch information
weihanglo committed Jul 11, 2023
1 parent d6d3c0b commit 9eb065e
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 8 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 41 additions & 8 deletions libgit2-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<pkg_config::Library, pkg_config::Error> {
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");
Expand Down

0 comments on commit 9eb065e

Please sign in to comment.