libipt-sys 0.2.4

Bindgen-generated bindings for Intel's libipt (Processor Trace) library
Documentation
use cmake::Config;
use std::env;
use std::path::Path;
use std::process::Command;

const LIBIPT_GIT: &str = "https://github.com/intel/libipt.git";

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let libipt_source = if cfg!(feature = "libipt_master") {
        println!("cargo:warning=`libipt_master` feature enabled, the master branch of libipt from Github will be used.");
        println!(
            "cargo:warning=The usage of this feature is discouraged and can cause build failures"
        );

        let path = Path::new(&out_dir).join("libipt");
        if !path.exists() {
            assert!(
                Command::new("git")
                    .current_dir(&out_dir)
                    .arg("clone")
                    .arg("--branch")
                    .arg("master")
                    .arg("--single-branch")
                    .arg("--depth")
                    .arg("1")
                    .arg(LIBIPT_GIT)
                    .status()
                    .unwrap()
                    .success(),
                "Failed to clone libipt repository"
            );
        } else {
            assert!(
                Command::new("git")
                    .current_dir(&path)
                    .arg("pull")
                    .status()
                    .unwrap()
                    .success(),
                "Failed to pull libipt repository"
            );
        }
        path
    } else {
        Path::new("libipt").to_path_buf()
    };

    check_submodule(&libipt_source);

    let dst = Config::new(&libipt_source)
        .define("BUILD_SHARED_LIBS", "OFF")
        // temporary fix for https://github.com/intel/libipt/issues/114
        .define("CMAKE_POLICY_VERSION_MINIMUM", "3.5")
        .build();

    #[cfg(windows)]
    println!("cargo:rustc-link-lib=static=libipt");
    #[cfg(not(windows))]
    println!("cargo:rustc-link-lib=static=ipt");

    println!(
        "cargo:rustc-link-search=native={}",
        dst.join("lib").to_string_lossy()
    );

    let bindings = bindgen::Builder::default()
        .header(dst.join("include").join("intel-pt.h").to_string_lossy())
        .allowlist_function("pt_.*")
        .allowlist_type("pt_.*")
        .allowlist_var("pt_.*")
        .derive_debug(true)
        .impl_debug(true)
        .derive_eq(true)
        .derive_hash(true)
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate libipt bindings");

    bindings
        .write_to_file(Path::new(&out_dir).join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

fn check_submodule<P: AsRef<Path>>(path: P) {
    let path = path.as_ref();
    if !path.exists()
        || !path
            .read_dir()
            .is_ok_and(|mut content| content.next().is_some())
    {
        let error = format!("{} directory not found or empty", path.display());
        println!("cargo:warning={error}");
        println!(
            "cargo:warning=Hint: Please get the submodules with `git submodule update --init --recursive`"
        );
        panic!("{error}");
    }
}