use anyhow::{anyhow, Result};
use std::{
fs,
path::{self, Path, PathBuf},
};
const ALLOWED_FUNC_PREFIX: &[&str] = &[
"map",
"policy",
"pool",
"prune",
"queue",
"repo",
"repodata",
"selection",
"solv",
"solver",
"testcase",
"transaction",
"dataiterator",
"datamatcher",
"stringpool",
];
fn find_system_libsolv() -> Result<PathBuf> {
let mut conf = pkg_config::Config::new();
let lib = conf.atleast_version("0.7").probe("libsolv")?;
conf.atleast_version("0.7").probe("libsolvext")?;
for inc in lib.include_paths {
if inc.join("solv").is_dir() {
return Ok(inc.join("solv"));
}
}
Err(anyhow!("Error finding libsolv include path"))
}
fn build_libsolv() -> Result<PathBuf> {
println!("cargo:warning=System libsolv not found. Using bundled version.");
let p = path::PathBuf::from("./libsolv/CMakeLists.txt");
if !p.is_file() {
return Err(anyhow!(
"Bundled libsolv not found, please do `git submodule update --init`."
));
}
let out = cmake::Config::new(p.parent().unwrap())
.define("ENABLE_DEBIAN", "ON")
.define("DEBIAN", "ON")
.define("ENABLE_STATIC", "ON")
.define("DISABLE_SHARED", "ON")
.target(&std::env::var("CMAKE_TARGET").unwrap_or(std::env::var("TARGET").unwrap()))
.build();
println!(
"cargo:rustc-link-search=native={}",
out.join("lib").display()
);
println!(
"cargo:rustc-link-search=native={}",
out.join("lib64").display()
);
println!("cargo:rustc-link-lib=static=solv");
println!("cargo:rustc-link-lib=static=solvext");
println!("cargo:rustc-link-lib=z");
Ok(out.join("include/solv"))
}
fn check_solvext_bindings(
include_path: &Path,
builder: bindgen::Builder,
) -> Result<bindgen::Builder> {
let mut builder = builder;
for inc in fs::read_dir(include_path)? {
let inc = inc?;
let name = inc.file_name();
let name = name.to_string_lossy();
if name.starts_with("repo_") && name.ends_with(".h") {
builder = builder.header(inc.path().to_str().unwrap());
}
}
Ok(builder)
}
fn generate_bindings(include_path: &Path) -> Result<()> {
let output = std::env::var("OUT_DIR")?;
let generator = bindgen::Builder::default()
.header(include_path.join("solver.h").to_str().unwrap())
.header(include_path.join("solverdebug.h").to_str().unwrap())
.header(include_path.join("selection.h").to_str().unwrap())
.header(include_path.join("knownid.h").to_str().unwrap())
.whitelist_type("(Id|solv_knownid)")
.whitelist_var(".*")
.whitelist_function(format!("({}).*", ALLOWED_FUNC_PREFIX.join("|")));
check_solvext_bindings(include_path, generator)?
.generate()
.unwrap()
.write_to_file(Path::new(&output).join("bindings.rs"))?;
Ok(())
}
fn main() -> Result<()> {
let include_path = match find_system_libsolv() {
Ok(p) => p,
Err(_) => build_libsolv()?,
};
generate_bindings(&include_path)?;
Ok(())
}