slang-rs/slang-sys/build.rs
Lauro Oyen 095c719ff8 Implement ISession and remove ICompileRequest
The ICompileRequest is part of Slang's legacy API, and will be removed
in the future. The ISession and associated interfaces are to be used
instead.
2024-04-05 11:53:27 +02:00

124 lines
3.6 KiB
Rust

extern crate bindgen;
use std::env;
use std::path::{Path, PathBuf};
fn main() {
let slang_dir = env::var("SLANG_DIR")
.map(PathBuf::from)
.expect("Environment variable `SLANG_DIR` should be set to the directory of a Slang installation. \
This directory should contain `slang.h` and a `bin` subdirectory.");
let out_dir = env::var("OUT_DIR")
.map(PathBuf::from)
.expect("Couldn't determine output directory.");
link_libraries(&slang_dir);
bindgen::builder()
.header(slang_dir.join("slang.h").to_str().unwrap())
.clang_arg("-v")
.clang_arg("-xc++")
.clang_arg("-std=c++14")
.allowlist_function("slang_.*")
.allowlist_type("slang.*")
.allowlist_var("SLANG_.*")
.with_codegen_config(
bindgen::CodegenConfig::FUNCTIONS
| bindgen::CodegenConfig::TYPES
| bindgen::CodegenConfig::VARS,
)
.parse_callbacks(Box::new(ParseCallback {}))
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: true,
})
.vtable_generation(true)
.layout_tests(false)
.derive_copy(true)
.generate()
.expect("Couldn't generate bindings.")
.write_to_file(out_dir.join("bindings.rs"))
.expect("Couldn't write bindings.");
}
fn link_libraries(slang_dir: &Path) {
let target_os = env::var("CARGO_CFG_TARGET_OS")
.expect("Couldn't determine target OS.");
let target_arch = env::var("CARGO_CFG_TARGET_ARCH")
.expect("Couldn't determine target architecture.");
let target = match(&*target_os, &*target_arch) {
("windows", "x86") => "windows-x86",
("windows", "x86_64") => "windows-x64",
("windows", "aarch64") => "windows-aarch64",
("linux", "x86_64") => "linux-x64",
("linux", "aarch64") => "linux-aarch64",
("macos", "x86_64") => "macosx-x64",
(os, arch) => panic!("Unsupported OS or architecture: {os} {arch}")
};
let bin_dir = slang_dir.join(format!("bin/{target}/release"));
if !bin_dir.is_dir() {
panic!("
Could not find the target-specific `bin` subdirectory (bin/{target}/release) in the Slang installation directory. \
The Slang installation may not match the target this crate is being compiled for.
")
}
println!("cargo:rustc-link-search=native={}", bin_dir.display());
println!("cargo:rustc-link-lib=dylib=slang");
}
#[derive(Debug)]
struct ParseCallback {}
impl bindgen::callbacks::ParseCallbacks for ParseCallback {
fn enum_variant_name(
&self,
enum_name: Option<&str>,
original_variant_name: &str,
_variant_value: bindgen::callbacks::EnumVariantValue,
) -> Option<String> {
let enum_name = enum_name?;
// Map enum names to the part of their variant names that needs to be trimmed.
// When an enum name is not in this map the code below will try to trim the enum name itself.
let mut map = std::collections::HashMap::new();
map.insert("SlangMatrixLayoutMode", "SlangMatrixLayout");
map.insert("SlangCompileTarget", "Slang");
let trim = map.get(enum_name).unwrap_or(&enum_name);
let new_variant_name = pascal_case_from_snake_case(original_variant_name);
let new_variant_name = new_variant_name.trim_start_matches(trim);
Some(new_variant_name.to_string())
}
}
/// Converts `snake_case` or `SNAKE_CASE` to `PascalCase`.
/// If the input is already in `PascalCase` it will be returned as is.
fn pascal_case_from_snake_case(snake_case: &str) -> String {
let mut result = String::new();
let should_lower = snake_case
.chars()
.filter(|c| c.is_alphabetic())
.all(|c| c.is_uppercase());
for part in snake_case.split('_') {
for (i, c) in part.chars().enumerate() {
if i == 0 {
result.push(c.to_ascii_uppercase());
} else if should_lower {
result.push(c.to_ascii_lowercase());
} else {
result.push(c);
}
}
}
result
}