memonitor-sys 0.2.4

Automatically generated bindings for some of memonitor's backends.
Documentation
use bindgen::callbacks::ParseCallbacks;
use bindgen::{Builder, EnumVariation};
use cfg_aliases::cfg_aliases;
use cmake::Config;
use std::env;
use std::fs::read_dir;
use std::path::PathBuf;

fn main() {
    cfg_aliases! {
        apple: { any(target_os = "macos", target_os = "ios", target_os = "dragonfly") },
    }

    let cur_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));

    {
        let log_dir = cur_dir.join("log");
        let mut build = Config::new(log_dir.as_path());
        let lib_out = build.build();
        println!(
            "cargo:rustc-link-search=native={}",
            lib_out.join("lib").display()
        );
        println!("cargo:rustc-link-lib=static=memonitor-log");

        let vk_bindings = Builder::default()
            .header(log_dir.join("include").join("log.h").to_string_lossy())
            .allowlist_function("log_.*")
            .allowlist_type("log_.*")
            .parse_callbacks(Box::new(PrefixRemover::new("log_")))
            .default_enum_style(EnumVariation::Rust {
                non_exhaustive: false,
            })
            .use_core()
            .generate()
            .expect("Failed to generate Log bindings");

        let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

        vk_bindings
            .write_to_file(out_path.join("log_bindings.rs"))
            .expect("Couldn't write bindings");
    }

    #[cfg(feature = "vulkan")]
    {
        let vk_dir = cur_dir.join("vulkan");
        let submodules_dir = vk_dir.join("thirdparty");
        read_dir(submodules_dir.join("Vulkan-Headers"))
            .expect("Could not find Vulkan Headers. Did you forget to initialize submodules?");
        read_dir(submodules_dir.join("volk"))
            .expect("Could not find Volk. Did you forget to initialize submodules?");
        let mut build = Config::new(vk_dir.as_path());

        #[cfg(debug_assertions)]
        {
            build.define("MEMONITOR_VALIDATE", "ON");
        }

        // cmake-rs overrides the standard configured inside CMakeLists for some reason
        let lib_out = build.build();
        println!(
            "cargo:rustc-link-search=native={}",
            lib_out.join("lib").display()
        );
        println!("cargo:rustc-link-lib=static=volk");
        println!("cargo:rustc-link-lib=static=memonitor-vk");

        let vk_bindings = Builder::default()
            .header(vk_dir.join("include").join("memonitor.h").to_string_lossy())
            .allowlist_function("vk_.*")
            .allowlist_type("vk_.*")
            .parse_callbacks(Box::new(PrefixRemover::new("vk_")))
            .default_enum_style(EnumVariation::Rust {
                non_exhaustive: true,
            })
            .use_core()
            .generate()
            .expect("Failed to generate Vulkan bindings");

        let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

        vk_bindings
            .write_to_file(out_path.join("vk_bindings.rs"))
            .expect("Couldn't write bindings");
    }

    #[cfg(all(feature = "cuda", not(apple)))]
    {
        let cuda_dir = cur_dir.join("cuda");
        let mut build = Config::new(cuda_dir.as_path());

        let lib_out = build.build();
        println!(
            "cargo:rustc-link-search=native={}",
            lib_out.join("lib").display()
        );
        println!("cargo:rustc-link-lib=static=memonitor-cuda");

        let cuda_bindings = Builder::default()
            .header(
                cuda_dir
                    .join("include")
                    .join("memonitor.h")
                    .to_string_lossy(),
            )
            .allowlist_function("cu_.*")
            .allowlist_type("cu_.*")
            .parse_callbacks(Box::new(PrefixRemover::new("cu_")))
            .default_enum_style(EnumVariation::Rust {
                non_exhaustive: true,
            })
            .use_core()
            .generate()
            .expect("Failed to generate Cuda bindings");

        let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

        cuda_bindings
            .write_to_file(out_path.join("cuda_bindings.rs"))
            .expect("Couldn't write bindings");
    }
}

#[derive(Debug)]
struct PrefixRemover {
    prefix: String,
}

impl PrefixRemover {
    fn new(prefix: impl ToString) -> Self {
        Self {
            prefix: prefix.to_string(),
        }
    }
}

impl ParseCallbacks for PrefixRemover {
    fn item_name(&self, original_item_name: &str) -> Option<String> {
        original_item_name
            .strip_prefix(&self.prefix)
            .map(move |s| s.to_string())
    }
}