use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
const DEFAULT_LIB_DIRS: &[&str] = &["/usr/lib", "/usr/lib64"];
fn main() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
if cfg!(feature = "bundled") {
build_bundled(&out_dir, &manifest_dir);
} else if cfg!(feature = "system") {
setup_system_linking(&manifest_dir);
} else {
panic!("Either 'bundled' or 'system' feature must be enabled");
}
generate_bindings(&manifest_dir, &out_dir);
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=bundled");
println!("cargo:rerun-if-changed=src/mdf_c_wrapper.h");
println!("cargo:rerun-if-changed=src/mdf_c_wrapper.cpp");
println!("cargo:rerun-if-env-changed=VCPKG_ROOT");
println!("cargo:rerun-if-env-changed=VCPKG_DEFAULT_TRIPLET");
println!("cargo:rerun-if-env-changed=CMAKE_GENERATOR");
}
fn is_msvc() -> bool {
cfg!(target_os = "windows") && cfg!(target_env = "msvc")
}
fn is_musl() -> bool {
env::var("CARGO_CFG_TARGET_ENV").is_ok_and(|v| v == "musl")
}
fn get_vcpkg_config() -> Option<(PathBuf, String)> {
let vcpkg_root = PathBuf::from(env::var("VCPKG_ROOT").ok()?);
if !vcpkg_root.exists() {
return None;
}
let triplet = env::var("VCPKG_DEFAULT_TRIPLET").unwrap_or_else(|_| {
let arch = if cfg!(target_arch = "x86_64") {
"x64"
} else {
"x86"
};
format!("{arch}-windows-static-md")
});
Some((vcpkg_root, triplet))
}
fn find_vcpkg_lib(base_name: &str) -> Option<String> {
let (vcpkg_root, triplet) = get_vcpkg_config()?;
let lib_dir = vcpkg_root.join("installed").join(&triplet).join("lib");
let lower = base_name.to_lowercase();
for entry in std::fs::read_dir(&lib_dir).ok()? {
let entry = entry.ok()?;
let fname = entry.file_name();
let name = fname.to_string_lossy();
if name.to_lowercase().contains(&lower) && name.ends_with(".lib") {
return Some(name.trim_end_matches(".lib").to_string());
}
}
None
}
fn apply_cpp_flags(build: &mut cc::Build) {
if is_msvc() {
build
.flag("/std:c++17")
.define("_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", None)
.define("_CRT_SECURE_NO_WARNINGS", None);
} else {
build.flag("-std=c++17").flag("-Wno-overloaded-virtual");
}
}
fn apply_patches(manifest_dir: &Path, bundled_dir: &Path) {
let patches_dir = manifest_dir.join("patches");
if !patches_dir.exists() {
return;
}
let mut patches: Vec<_> = std::fs::read_dir(&patches_dir)
.expect("Failed to read patches directory")
.filter_map(|e| e.ok())
.map(|e| e.path())
.filter(|p| p.extension().is_some_and(|ext| ext == "patch"))
.collect();
patches.sort();
for patch in &patches {
if try_apply_patch(bundled_dir, patch) {
println!(
"Applied patch: {}",
patch.file_name().unwrap().to_string_lossy()
);
}
}
println!("cargo:rerun-if-changed={}", patches_dir.display());
for patch in &patches {
println!("cargo:rerun-if-changed={}", patch.display());
}
}
fn try_apply_patch(bundled_dir: &Path, patch: &Path) -> bool {
if let Ok(output) = Command::new("git")
.current_dir(bundled_dir)
.args(["apply", "--check", "--reverse"])
.arg(patch)
.output()
{
if output.status.success() {
return false; }
let apply = Command::new("git")
.current_dir(bundled_dir)
.args(["apply"])
.arg(patch)
.output()
.expect("Failed to run git apply");
if apply.status.success() {
return true;
}
}
if let Ok(output) = Command::new("patch")
.current_dir(bundled_dir)
.args(["-p1", "--forward", "-s"])
.stdin(std::fs::File::open(patch).expect("Failed to open patch file"))
.output()
{
if output.status.success() {
return true;
}
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
if stderr.contains("Reversed (or previously applied)")
|| stdout.contains("Reversed (or previously applied)")
{
return false;
}
panic!(
"Failed to apply patch {}:\n{}{}",
patch.display(),
stdout,
stderr,
);
}
panic!(
"Neither `git` nor `patch` found. Cannot apply {}",
patch.display()
);
}
fn build_bundled(out_dir: &Path, manifest_dir: &Path) {
let bundled_dir = manifest_dir.join("bundled");
let build_dir = out_dir.join("build");
let install_dir = out_dir.join("install");
std::fs::create_dir_all(&build_dir).expect("Failed to create build directory");
std::fs::create_dir_all(&install_dir).expect("Failed to create install directory");
if !bundled_dir.exists() {
panic!(
"Bundled mdflib source not found at {}. \
Please run: git submodule update --init --recursive \
or download mdflib source to the bundled/ directory",
bundled_dir.display()
);
}
apply_patches(manifest_dir, &bundled_dir);
let mut cmake_config = Command::new("cmake");
cmake_config
.current_dir(&build_dir)
.arg(&bundled_dir)
.arg(format!("-DCMAKE_INSTALL_PREFIX={}", install_dir.display()))
.arg("-DCMAKE_BUILD_TYPE=Release")
.arg("-DBUILD_SHARED_LIBS=OFF")
.arg("-DMDF_BUILD_SHARED_LIB=OFF")
.arg("-DMDF_BUILD_SHARED_LIB_NET=OFF")
.arg("-DMDF_BUILD_TEST=OFF")
.arg("-DMDF_BUILD_DOC=OFF")
.arg("-DMDF_BUILD_TOOLS=OFF")
.arg("-DCMAKE_CXX_STANDARD=17");
if is_msvc() {
if env::var("CMAKE_GENERATOR").map_or(true, |g| g.contains("Visual Studio")) {
if cfg!(target_arch = "x86_64") {
cmake_config.arg("-A").arg("x64");
} else if cfg!(target_arch = "x86") {
cmake_config.arg("-A").arg("Win32");
}
}
if let Some((vcpkg_root, triplet)) = get_vcpkg_config() {
let toolchain = vcpkg_root.join("scripts/buildsystems/vcpkg.cmake");
if toolchain.exists() {
cmake_config.arg(format!("-DCMAKE_TOOLCHAIN_FILE={}", toolchain.display()));
cmake_config.arg(format!("-DVCPKG_TARGET_TRIPLET={triplet}"));
cmake_config.arg("-DVCPKG_MANIFEST_MODE=OFF");
}
}
} else {
cmake_config.arg("-G").arg("Unix Makefiles");
let cc_tool = cc::Build::new().cargo_metadata(false).get_compiler();
let cxx_tool = cc::Build::new()
.cpp(true)
.cargo_metadata(false)
.get_compiler();
cmake_config.arg(format!("-DCMAKE_C_COMPILER={}", cc_tool.path().display()));
cmake_config.arg(format!(
"-DCMAKE_CXX_COMPILER={}",
cxx_tool.path().display()
));
}
add_dependency_hints(&mut cmake_config);
let cmake_output = cmake_config
.output()
.expect("Failed to run CMake configure");
if !cmake_output.status.success() {
eprintln!("CMake configure failed:");
eprintln!("stdout: {}", String::from_utf8_lossy(&cmake_output.stdout));
eprintln!("stderr: {}", String::from_utf8_lossy(&cmake_output.stderr));
panic_with_dependency_errors(&String::from_utf8_lossy(&cmake_output.stderr));
}
let mut cmake_build = Command::new("cmake");
cmake_build
.current_dir(&build_dir)
.arg("--build")
.arg(".")
.arg("--config")
.arg("Release")
.arg("--target")
.arg("install");
if let Ok(jobs) = env::var("NUM_JOBS") {
cmake_build.arg("--parallel").arg(jobs);
} else if let Ok(jobs) = std::thread::available_parallelism() {
cmake_build.arg("--parallel").arg(jobs.get().to_string());
}
let build_output = cmake_build.output().expect("Failed to run CMake build");
if !build_output.status.success() {
panic!(
"CMake build failed:\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&build_output.stdout),
String::from_utf8_lossy(&build_output.stderr)
);
}
let mut cc_build = cc::Build::new();
cc_build
.cpp(true)
.file("src/mdf_c_wrapper.cpp")
.include(install_dir.join("include"))
.include(bundled_dir.join("include"));
let mdf_include = install_dir.join("mdf").join("include");
if mdf_include.exists() {
cc_build.include(&mdf_include);
}
apply_cpp_flags(&mut cc_build);
if is_msvc() {
if let Some((vcpkg_root, triplet)) = get_vcpkg_config() {
let vcpkg_include = vcpkg_root.join("installed").join(&triplet).join("include");
if vcpkg_include.exists() {
cc_build.include(&vcpkg_include);
}
}
}
cc_build.compile("mdf_c_wrapper");
setup_bundled_linking(&install_dir);
}
fn setup_dependencies() {
println!("cargo:rerun-if-env-changed=PKG_CONFIG_PATH");
if is_msvc() {
let zlib_name = find_vcpkg_lib("zlib").unwrap_or_else(|| "zlib".to_string());
let expat_name = find_vcpkg_lib("expat").unwrap_or_else(|| "libexpat".to_string());
setup_dependency("zlib", &zlib_name);
setup_dependency("expat", &expat_name);
} else {
setup_dependency("zlib", "z");
setup_dependency("expat", "expat");
}
}
fn setup_dependency(name: &str, fallback_name: &str) {
let default_lib_dirs = if let Ok(target) = env::var("TARGET") {
let mut dirs = vec![format!("/usr/lib/{target}")];
dirs.extend(DEFAULT_LIB_DIRS.iter().map(|s| s.to_string()));
dirs
} else {
DEFAULT_LIB_DIRS.iter().map(|s| s.to_string()).collect()
};
let upper_name = name.to_uppercase();
println!("cargo:rerun-if-env-changed={upper_name}_LIBRARY");
println!("cargo:rerun-if-env-changed={upper_name}_INCLUDE_DIR");
println!("cargo:rerun-if-env-changed={upper_name}_NO_PKG_CONFIG");
if let Ok(lib_path_str) = env::var(format!("{upper_name}_LIBRARY")) {
println!("Found {name} via {upper_name}_LIBRARY environment variable");
let lib_path = PathBuf::from(&lib_path_str);
if let Some(lib_dir) = lib_path.parent() {
println!("cargo:rustc-link-search=native={}", lib_dir.display());
}
if let Some(lib_name) = lib_path.file_stem() {
let lib_name_str = lib_name.to_string_lossy();
let clean_name = lib_name_str.strip_prefix("lib").unwrap_or(&lib_name_str);
println!("cargo:rustc-link-lib={clean_name}");
}
return;
}
let mut pkg = pkg_config::Config::new();
pkg.statik(true);
if let Ok(lib) = pkg.probe(name) {
println!("Found {name} via pkg-config");
for dir in &lib.link_paths {
println!("cargo:rustc-link-search=native={}", dir.display());
}
let static_name = format!("lib{fallback_name}.a");
let search_dirs: Vec<&Path> = lib
.link_paths
.iter()
.map(|p| p.as_path())
.chain(default_lib_dirs.iter().map(Path::new))
.collect();
let has_static = search_dirs.iter().any(|d| d.join(&static_name).exists());
if has_static {
println!("cargo:rustc-link-lib=static={fallback_name}");
} else {
println!("cargo:rustc-link-lib=dylib={fallback_name}");
}
return;
}
println!(
"cargo:warning={name} not found via pkg-config or environment variables, using system defaults"
);
println!("cargo:rustc-link-lib={fallback_name}");
}
fn add_dependency_hints(cmake_config: &mut Command) {
add_single_dependency_hint(cmake_config, "ZLIB");
add_single_dependency_hint(cmake_config, "EXPAT");
if env::var("ZLIB_LIBRARY").is_err() && env::var("EXPAT_LIBRARY").is_err() {
add_platform_dependency_hints(cmake_config);
}
}
fn add_single_dependency_hint(cmake_config: &mut Command, name: &str) {
if let Ok(lib_path_str) = env::var(format!("{name}_LIBRARY")) {
let lib_path = PathBuf::from(&lib_path_str);
if let Some(lib_dir) = lib_path.parent() {
if let Some(root_dir) = lib_dir.parent() {
cmake_config.arg(format!("-D{}_ROOT={}", name, root_dir.display()));
}
}
cmake_config.arg(format!("-D{name}_LIBRARY={lib_path_str}"));
}
if let Ok(include_path) = env::var(format!("{name}_INCLUDE_DIR")) {
cmake_config.arg(format!("-D{name}_INCLUDE_DIR={include_path}"));
}
}
fn add_platform_dependency_hints(cmake_config: &mut Command) {
if cfg!(target_os = "macos") {
if Path::new("/opt/homebrew/opt/zlib").exists() {
cmake_config.arg("-DZLIB_ROOT=/opt/homebrew/opt");
cmake_config.arg("-DZLIB_LIBRARY=/opt/homebrew/opt/zlib/lib/libz.a");
}
if Path::new("/opt/homebrew/opt/expat").exists() {
cmake_config.arg("-DEXPAT_ROOT=/opt/homebrew/opt");
cmake_config.arg("-DEXPAT_LIBRARY=/opt/homebrew/opt/expat/lib/libexpat.a");
}
if Path::new("/usr/include/zlib.h").exists() {
cmake_config.arg("-DZLIB_ROOT=/usr");
}
if Path::new("/usr/include/expat.h").exists() {
cmake_config.arg("-DEXPAT_ROOT=/usr");
}
} else if cfg!(target_os = "linux") {
if is_musl() {
let search_dirs = musl_lib_search_dirs();
if let Some(inc) = musl_include_dir() {
cmake_config.arg(format!("-DZLIB_INCLUDE_DIR={inc}"));
cmake_config.arg(format!("-DEXPAT_INCLUDE_DIR={inc}"));
}
for lib_dir in &search_dirs {
let zlib = format!("{lib_dir}/libz.a");
if Path::new(&zlib).exists() {
cmake_config.arg(format!("-DZLIB_LIBRARY={zlib}"));
break;
}
}
for lib_dir in &search_dirs {
let expat = format!("{lib_dir}/libexpat.a");
if Path::new(&expat).exists() {
cmake_config.arg(format!("-DEXPAT_LIBRARY={expat}"));
break;
}
}
} else {
if Path::new("/usr/include/zlib.h").exists() {
cmake_config.arg("-DZLIB_ROOT=/usr");
}
if Path::new("/usr/include/expat.h").exists() {
cmake_config.arg("-DEXPAT_ROOT=/usr");
}
if Path::new("/usr/lib/libexpat.a").exists() {
cmake_config.arg("-DEXPAT_LIBRARY=/usr/lib/libexpat.a");
} else if Path::new("/usr/lib/libexpat.so").exists() {
cmake_config.arg("-DEXPAT_LIBRARY=/usr/lib/libexpat.so");
}
if Path::new("/usr/lib/libz.a").exists() {
cmake_config.arg("-DZLIB_LIBRARY=/usr/lib/libz.a");
} else if Path::new("/usr/lib/libz.so").exists() {
cmake_config.arg("-DZLIB_LIBRARY=/usr/lib/libz.so");
}
}
}
}
fn musl_lib_search_dirs() -> Vec<String> {
let mut dirs = Vec::new();
if let Ok(target) = env::var("TARGET") {
if let Some(arch) = target.split('-').next() {
let musl_dir = format!("/usr/lib/{arch}-linux-musl");
if Path::new(&musl_dir).exists() {
dirs.push(musl_dir);
}
}
}
for dir in &["/usr/lib/x86_64-linux-gnu", "/usr/lib"] {
if Path::new(dir).exists() {
dirs.push(dir.to_string());
}
}
dirs
}
fn musl_include_dir() -> Option<String> {
if let Ok(target) = env::var("TARGET") {
if let Some(arch) = target.split('-').next() {
let musl_dir = format!("/usr/include/{arch}-linux-musl");
if Path::new(&musl_dir).exists() {
return Some(musl_dir);
}
}
}
None
}
fn add_gcc_lib_search_path() {
if let Ok(output) = Command::new("g++")
.arg("-print-file-name=libstdc++.a")
.output()
{
if output.status.success() {
let path_str = String::from_utf8_lossy(&output.stdout).trim().to_string();
let path = Path::new(&path_str);
if path.is_absolute() {
if let Some(dir) = path.parent() {
println!("cargo:rustc-link-search=native={}", dir.display());
}
}
}
}
}
fn setup_bundled_linking(install_dir: &Path) {
let lib_dir = install_dir.join("lib");
if lib_dir.exists() {
println!("cargo:rustc-link-search=native={}", lib_dir.display());
}
if install_dir.join("lib64").exists() {
println!(
"cargo:rustc-link-search=native={}",
install_dir.join("lib64").display()
);
}
let mdf_lib_dir = install_dir.join("mdf").join("lib");
if mdf_lib_dir.exists() {
println!("cargo:rustc-link-search=native={}", mdf_lib_dir.display());
}
if is_msvc() {
if let Some((vcpkg_root, triplet)) = get_vcpkg_config() {
let vcpkg_lib = vcpkg_root.join("installed").join(&triplet).join("lib");
if vcpkg_lib.exists() {
println!("cargo:rustc-link-search=native={}", vcpkg_lib.display());
}
}
}
println!("cargo:rustc-link-lib=static=mdf_c_wrapper");
println!("cargo:rustc-link-lib=static=mdf");
setup_dependencies();
if cfg!(target_os = "windows") {
println!("cargo:rustc-link-lib=dylib=user32");
println!("cargo:rustc-link-lib=dylib=kernel32");
println!("cargo:rustc-link-lib=dylib=ws2_32");
println!("cargo:rustc-link-lib=dylib=advapi32");
println!("cargo:rustc-link-lib=dylib=shell32");
println!("cargo:rustc-link-lib=dylib=ole32");
} else if cfg!(target_os = "linux") {
if is_musl() {
println!("cargo:rustc-link-lib=static=stdc++");
for dir in musl_lib_search_dirs() {
println!("cargo:rustc-link-search=native={dir}");
}
add_gcc_lib_search_path();
} else {
println!("cargo:rustc-link-lib=dylib=stdc++");
println!("cargo:rustc-link-lib=dylib=m");
println!("cargo:rustc-link-lib=dylib=pthread");
println!("cargo:rustc-link-lib=dylib=dl");
}
} else if cfg!(target_os = "macos") {
println!("cargo:rustc-link-lib=dylib=c++");
println!("cargo:rustc-link-lib=dylib=System");
println!("cargo:rustc-link-lib=framework=Foundation");
}
}
fn setup_system_linking(_manifest_dir: &Path) {
let mut cc_build = cc::Build::new();
cc_build.cpp(true).file("src/mdf_c_wrapper.cpp");
apply_cpp_flags(&mut cc_build);
if let Ok(library) = pkg_config::Config::new()
.atleast_version("2.3")
.probe("mdflib")
{
for path in library.include_paths {
cc_build.include(path);
}
} else {
println!("cargo:warning=pkg-config failed for mdflib, trying manual discovery");
println!("cargo:rustc-link-lib=mdf");
setup_dependencies();
if cfg!(target_os = "linux") {
if is_musl() {
println!("cargo:rustc-link-lib=static=stdc++");
for dir in musl_lib_search_dirs() {
println!("cargo:rustc-link-search=native={dir}");
}
add_gcc_lib_search_path();
} else {
println!("cargo:rustc-link-lib=dylib=stdc++");
println!("cargo:rustc-link-lib=dylib=m");
println!("cargo:rustc-link-lib=dylib=pthread");
println!("cargo:rustc-link-lib=dylib=dl");
}
cc_build.include("/usr/local/include");
cc_build.include("/usr/include");
} else if cfg!(target_os = "macos") {
println!("cargo:rustc-link-lib=dylib=c++");
println!("cargo:rustc-link-lib=dylib=System");
println!("cargo:rustc-link-lib=framework=Foundation");
cc_build.include("/usr/local/include");
cc_build.include("/opt/homebrew/include");
} else if cfg!(target_os = "windows") {
println!("cargo:rustc-link-lib=dylib=user32");
println!("cargo:rustc-link-lib=dylib=kernel32");
println!("cargo:rustc-link-lib=dylib=ws2_32");
println!("cargo:rustc-link-lib=dylib=advapi32");
println!("cargo:rustc-link-lib=dylib=shell32");
println!("cargo:rustc-link-lib=dylib=ole32");
cc_build.include("C:/Program Files/mdflib/include");
if let Some((vcpkg_root, triplet)) = get_vcpkg_config() {
let vcpkg_include = vcpkg_root.join("installed").join(&triplet).join("include");
let vcpkg_lib = vcpkg_root.join("installed").join(&triplet).join("lib");
if vcpkg_include.exists() {
cc_build.include(&vcpkg_include);
}
if vcpkg_lib.exists() {
println!("cargo:rustc-link-search=native={}", vcpkg_lib.display());
}
}
}
}
cc_build.compile("mdf_c_wrapper");
}
fn generate_bindings(manifest_dir: &Path, out_dir: &Path) {
let wrapper_path = manifest_dir.join("src").join("mdf_c_wrapper.h");
println!("Generating bindings from {}", wrapper_path.display());
let mut bindgen_builder = bindgen::Builder::default()
.header(wrapper_path.to_str().unwrap())
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.clang_arg("-xc++")
.clang_arg("-std=c++17")
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: true,
})
.blocklist_type("std::.*")
.derive_debug(true)
.derive_default(true)
.derive_copy(true)
.derive_eq(true)
.derive_hash(true)
.derive_ord(true)
.derive_partialeq(true)
.derive_partialord(true);
let bundled_include = manifest_dir.join("bundled").join("include");
if bundled_include.exists() {
bindgen_builder = bindgen_builder.clang_arg(format!("-I{}", bundled_include.display()));
}
if let Ok(install_dir) = env::var("OUT_DIR") {
let include_path = PathBuf::from(install_dir).join("install/include");
if include_path.exists() {
bindgen_builder = bindgen_builder.clang_arg(format!("-I{}", include_path.display()));
}
}
if let Ok(zlib_include) = env::var("ZLIB_INCLUDE_DIR") {
bindgen_builder = bindgen_builder.clang_arg(format!("-I{zlib_include}"));
}
if let Ok(expat_include) = env::var("EXPAT_INCLUDE_DIR") {
bindgen_builder = bindgen_builder.clang_arg(format!("-I{expat_include}"));
}
if cfg!(target_os = "macos") {
if Path::new("/opt/homebrew/include").exists() {
bindgen_builder = bindgen_builder.clang_arg("-I/opt/homebrew/include");
}
if let Ok(output) = Command::new("xcrun").args(["--show-sdk-path"]).output() {
if output.status.success() {
let sdk_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
bindgen_builder = bindgen_builder.clang_arg(format!("-I{sdk_path}/usr/include"));
}
}
}
let bindings = bindgen_builder
.generate()
.expect("Unable to generate bindings");
bindings
.write_to_file(out_dir.join("bindings.rs"))
.expect("Couldn't write bindings!");
println!("Successfully generated bindings");
}
fn panic_with_dependency_errors(stderr: &str) {
if stderr.contains("Could NOT find ZLIB") {
eprintln!("\nzlib not found. Please install zlib development libraries:");
print_install_instructions("zlib1g-dev", "zlib-devel");
}
if stderr.contains("Could NOT find EXPAT") {
eprintln!("\nexpat not found. Please install expat development libraries:");
print_install_instructions("libexpat1-dev", "expat-devel");
}
panic!("CMake configuration failed");
}
fn print_install_instructions(debian_pkg: &str, rhel_pkg: &str) {
if cfg!(target_os = "linux") {
eprintln!(" Ubuntu/Debian: sudo apt install {debian_pkg}");
eprintln!(" CentOS/RHEL/Fedora: sudo dnf install {rhel_pkg}");
}
let name = rhel_pkg.split('-').next().unwrap_or("").to_uppercase();
eprintln!("\nAlternatively, set environment variables:");
eprintln!(
" {}_LIBRARY=/path/to/lib{}.so (or .a/.lib)",
name,
rhel_pkg.replace("-devel", "")
);
eprintln!(
" {}_INCLUDE_DIR=/path/to/{}/headers",
name,
rhel_pkg.replace("-devel", "")
);
}