use std::env;
use std::path::PathBuf;
#[allow(dead_code)]
const LIBYANG_REV: &str = "f302d86cd6083c2bfe16fc2122bc6d4be69ce7a2";
#[allow(dead_code)]
fn wasi_sdk() -> PathBuf {
match env::var("WASI_SDK_PATH") {
Ok(dir) => PathBuf::from(dir),
Err(_) => panic!(
"WASI_SDK_PATH must point to a WASI SDK installation when \
targeting WebAssembly"
),
}
}
#[allow(dead_code)]
fn wasi_clang_include(sdk: &std::path::Path) -> PathBuf {
let versions = sdk.join("lib/clang");
let entry = std::fs::read_dir(&versions)
.unwrap_or_else(|_| {
panic!("no clang headers under {}", versions.display())
})
.filter_map(|entry| entry.ok())
.map(|entry| entry.path().join("include"))
.find(|dir| dir.join("stddef.h").exists());
match entry {
Some(dir) => dir,
None => panic!("no clang builtin headers under {}", versions.display()),
}
}
fn main() {
let dst = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_file = dst.join("libyang5.rs");
let wasm = env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "wasm32";
#[allow(unused_mut, unused_variables)]
let mut include_paths: Vec<PathBuf> = vec![];
#[cfg(feature = "bundled")]
{
use std::path::Path;
use std::process::Command;
if !Path::new("libyang/.git").exists() {
let _ = Command::new("git")
.args(&["submodule", "update", "--init"])
.status();
}
let mut cmake_config = cmake::Config::new("libyang");
cmake_config.define("BUILD_SHARED_LIBS", "OFF"); cmake_config.define("ENABLE_TESTS", "OFF");
cmake_config.define("ENABLE_VALGRIND_TESTS", "OFF");
cmake_config.define("ENABLE_BUILD_TESTS", "OFF");
cmake_config.define("CMAKE_BUILD_TYPE", "Release");
cmake_config.define("CMAKE_POSITION_INDEPENDENT_CODE", "ON");
if wasm {
let sdk = wasi_sdk();
let compat = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
.join("wasi-compat.h");
cmake_config.define("ENABLE_TOOLS", "OFF");
cmake_config.define(
"CMAKE_TOOLCHAIN_FILE",
sdk.join("share/cmake/wasi-sdk-p1.cmake"),
);
cmake_config.define("WASI_SDK_PREFIX", &sdk);
let target = env::var("TARGET").unwrap();
for (var, tool) in [("CC", "clang"), ("CXX", "clang++")] {
let path = sdk.join("bin").join(tool);
env::set_var(format!("{}_{}", var, target), &path);
env::set_var(
format!("{}_{}", var, target.replace('-', "_")),
&path,
);
}
cmake_config.define(
"CMAKE_C_FLAGS",
format!(
"-D_WASI_EMULATED_PTHREAD -include {}",
compat.display()
),
);
cmake_config
.define("CMAKE_EXE_LINKER_FLAGS", "-lwasi-emulated-pthread");
let pcre2_include = env::var("PCRE2_INCLUDE_DIR").expect(
"PCRE2_INCLUDE_DIR must point to the headers of a PCRE2 \
built for the target when targeting WebAssembly",
);
let pcre2_library = env::var("PCRE2_LIBRARY").expect(
"PCRE2_LIBRARY must point to a libpcre2-8 built for the \
target when targeting WebAssembly",
);
cmake_config.define("PCRE2_INCLUDE_DIRS", &pcre2_include);
cmake_config.define("PCRE2_LIBRARIES", &pcre2_library);
let pcre2_library = PathBuf::from(&pcre2_library);
if let Some(dir) = pcre2_library.parent() {
println!("cargo:rustc-link-search=native={}", dir.display());
}
println!("cargo:rustc-link-lib=static=pcre2-8");
println!("cargo:rerun-if-env-changed=WASI_SDK_PATH");
println!("cargo:rerun-if-env-changed=PCRE2_INCLUDE_DIR");
println!("cargo:rerun-if-env-changed=PCRE2_LIBRARY");
println!("cargo:rerun-if-changed=wasi-compat.h");
}
let cmake_dst = cmake_config.build();
include_paths.push(cmake_dst.join("include"));
println!("cargo:root={}", env::var("OUT_DIR").unwrap());
println!("cargo:rustc-link-search=native={}/lib", cmake_dst.display());
println!(
"cargo:rustc-link-search=native={}/lib64",
cmake_dst.display()
);
if !wasm {
if let Err(e) = pkg_config::Config::new().probe("libpcre2-8") {
println!("cargo:warning=failed to find pcre2 library with pkg-config: {}", e);
println!("cargo:warning=attempting to link without pkg-config");
println!("cargo:rustc-link-lib=pcre2-8");
}
}
println!("cargo:rustc-link-lib=static=yang");
if wasm {
let target = env::var("TARGET").unwrap();
println!(
"cargo:rustc-link-search=native={}",
wasi_sdk()
.join("share/wasi-sysroot/lib")
.join(&target)
.display()
);
println!("cargo:rustc-link-lib=static=c-printscan-long-double");
println!("cargo:rustc-link-lib=static=wasi-emulated-pthread");
}
println!("cargo:rerun-if-changed=libyang");
}
#[cfg(feature = "bindgen")]
{
if !wasm && include_paths.is_empty() {
if let Ok(lib) = pkg_config::Config::new().probe("libpcre2-8") {
include_paths.extend(lib.include_paths.clone());
}
if let Ok(lib) = pkg_config::Config::new().probe("libyang") {
include_paths.extend(lib.include_paths.clone());
}
}
println!("cargo:rerun-if-changed=wrapper.h");
let mut builder = bindgen::Builder::default()
.header("wrapper.h")
.derive_default(true)
.default_enum_style(bindgen::EnumVariation::ModuleConsts)
.allowlist_file(".*/libyang/.*\\.h")
.allowlist_function("free")
.blocklist_item("LYPLG_TYPE_DIR")
.blocklist_item("LYPLG_EXT_DIR");
for path in &include_paths {
builder = builder.clang_arg(format!("-I{}", path.display()));
}
if wasm {
let sdk = wasi_sdk();
let sysroot = sdk.join("share/wasi-sysroot");
builder = builder
.clang_arg(format!("--target={}", env::var("TARGET").unwrap()))
.clang_arg(format!("--sysroot={}", sysroot.display()))
.clang_arg(format!("-I{}", wasi_clang_include(&sdk).display()))
.clang_arg("-D_WASI_EMULATED_PTHREAD")
.clang_arg("-fvisibility=default");
}
let bindings = builder
.generate()
.expect("Unable to generate libyang5 bindings");
bindings
.write_to_file(out_file)
.expect("Couldn't write libyang5 bindings!");
}
#[cfg(not(feature = "bindgen"))]
{
let bindings = match wasm {
true => format!("libyang5-{}-wasm32.rs", LIBYANG_REV),
false => format!("libyang5-{}.rs", LIBYANG_REV),
};
let mut pregen_bindings = PathBuf::new();
pregen_bindings.push(env::var("CARGO_MANIFEST_DIR").unwrap());
pregen_bindings.push("pre-generated-bindings");
pregen_bindings.push(bindings);
std::fs::copy(&pregen_bindings, &out_file)
.expect("Unable to copy pre-generated libyang5 bindings");
}
#[cfg(not(feature = "bundled"))]
{
if wasm {
println!("cargo:rustc-link-lib=static=yang");
println!("cargo:rustc-link-lib=static=pcre2-8");
} else if let Err(e) = pkg_config::Config::new().probe("libyang") {
println!(
"cargo:warning=failed to find yang library with pkg-config: {}",
e
);
println!("cargo:warning=attempting to link without pkg-config");
println!("cargo:rustc-link-lib=yang");
}
}
}