Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support precompiled library binaries #116

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/Cargo.lock
/target
Cargo.lock
target
35 changes: 32 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
[package]
name = "system-deps"
[workspace]
members = [ "meta" ]
exclude = [ "target" ]

[workspace.package]
version = "7.0.3"
authors = [
"Guillaume Desmottes <[email protected]>",
Expand All @@ -17,16 +20,42 @@ keywords = [
]
edition = "2018"
documentation = "https://docs.rs/system-deps/"

[workspace.dependencies]
system-deps-meta = { path = "./meta" }

[package]
name = "system-deps"
version.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
keywords.workspace = true
edition.workspace = true
documentation.workspace = true
readme = "README.md"

[dependencies]
system-deps-meta = { workspace = true, optional = true }
pkg-config = "0.3.25"
toml = { version = "0.8", default-features = false, features = ["parse"] }
version-compare = "0.2"
heck = "0.5"
cfg-expr = { version = "0.17", features = ["targets"] }

[build-dependencies]
system-deps-meta = { workspace = true, optional = true }

[dev-dependencies]
lazy_static = "1"
system-deps-meta = { workspace = true, features = ["test"] }
itertools = "0.13"
assert_matches = "1.5"
tiny_http = "0.12"

[features]
default = [ ]
# How to do this using resolver v2? Since features are separated
binary = [ "system-deps-meta/binary" ]
gz = [ "system-deps-meta/gz" ]
xz = [ "system-deps-meta/xz" ]
zip = [ "system-deps-meta/zip" ]
32 changes: 32 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pub fn main() {
#[cfg(feature = "binary")]
binary::build().unwrap_or_else(|e| panic!("{}", e));
}

#[cfg(feature = "binary")]
mod binary {
use std::{fs, path::Path};

use system_deps_meta::{
binary::{merge_binary, Paths},
error::{BinaryError, Error},
parse::read_metadata,
BUILD_MANIFEST, BUILD_TARGET_DIR,
};

// Add pkg-config paths to the overrides
pub fn build() -> Result<(), Error> {
// Read metadata from the crate graph
let metadata = read_metadata(BUILD_MANIFEST, "system-deps", merge_binary)?;

// Download the binaries and get their pkg_config paths
let paths: Paths = metadata.into_iter().collect();

// Write the binary paths to a file for later use
let dest = Path::new(BUILD_TARGET_DIR).join("paths.toml");
fs::write(&dest, paths.to_string()?).map_err(BinaryError::InvalidDirectory)?;
println!("cargo:rustc-env=BINARY_PATHS={}", dest.display());

Ok(())
}
}
28 changes: 28 additions & 0 deletions meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "system-deps-meta"
version.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
keywords.workspace = true
edition.workspace = true
documentation.workspace = true

[dependencies]
cargo_metadata = "0.19"
serde = "1.0"
toml = "0.8"
cfg-expr = { version = "0.17", features = ["targets"] }
sha256 = { version = "1.5", optional = true }
attohttpc = { version = "0.28", optional = true }
flate2 = { version = "1.0", optional = true }
xz = { version = "0.1", optional = true }
tar = { version = "0.4", optional = true }
zip = { version = "2.2", optional = true }

[features]
binary = [ "dep:sha256", "dep:attohttpc" ]
gz = [ "dep:flate2", "dep:tar" ]
xz = [ "dep:xz", "dep:tar" ]
zip = [ "dep:zip" ]
test = [ ]
80 changes: 80 additions & 0 deletions meta/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use std::{
env,
path::{Path, PathBuf},
};

/// Environment variable to override the top level `Cargo.toml`.
const MANIFEST_VAR: &str = "SYSTEM_DEPS_BUILD_MANIFEST";

/// Environment variable to override the directory where `system-deps`
/// will store build products such as binary outputs.
const TARGET_VAR: &str = "SYSTEM_DEPS_TARGET_DIR";

/// Try to find the project root using locate-project
fn find_with_cargo(dir: &Path) -> Option<PathBuf> {
let out = std::process::Command::new(env!("CARGO"))
.current_dir(dir)
.arg("locate-project")
.arg("--workspace")
.arg("--message-format=plain")
.output()
.ok()?
.stdout;
if out.is_empty() {
return None;
}
Some(PathBuf::from(std::str::from_utf8(&out).ok()?.trim()))
}

/// Get the manifest from the project directory. This is **not** the directory
/// where `system-deps` is cloned, it should point to the top level `Cargo.toml`
/// file. This is needed to obtain metadata from all of dependencies, including
/// those downstream of the package being compiled.
///
/// If the target directory is not a subfolder of the project it will not be
/// possible to detect it automatically. In this case, the user will be asked
/// to specify the `SYSTEM_DEPS_MANIFEST` variable to point to it.
///
/// See https://github.com/rust-lang/cargo/issues/3946 for updates on first
/// class support for finding the workspace root.
fn manifest() -> PathBuf {
println!("cargo:rerun-if-env-changed={}", MANIFEST_VAR);
if let Ok(root) = env::var(MANIFEST_VAR) {
return PathBuf::from(&root);
}

// When build scripts are invoked, they have one argument pointing to the
// build path of the crate in the target directory. This is different than
// the `OUT_DIR` environment variable, that can point to a target directory
// where the checkout of the dependency is.
let mut dir = PathBuf::from(
std::env::args()
.next()
.expect("There should be cargo arguments for determining the root"),
);
dir.pop();

// Try to find the project with cargo
find_with_cargo(&dir).expect(
"Error determining the cargo root manifest.\n\
Please set `SYSTEM_DEPS_MANIFEST` to the path of your project's Cargo.toml",
)
}

/// Set compile time values for the manifest and target paths, and the compile target.
/// Calculating this in a build script is necessary so that they are only calculated
/// once and every invocation of `system-deps` references the same metadata.
pub fn main() {
let manifest = manifest();
println!("cargo:rerun-if-changed={}", manifest.display());
println!("cargo:rustc-env=BUILD_MANIFEST={}", manifest.display());

let target_dir = env::var(TARGET_VAR).or(env::var("OUT_DIR")).unwrap();
println!("cargo:rerun-if-env-changed={}", TARGET_VAR);
println!("cargo:rustc-env=BUILD_TARGET_DIR={}", target_dir);

println!(
"cargo:rustc-env=TARGET={}",
std::env::var("TARGET").unwrap()
);
}
Loading
Loading