use std::path::PathBuf;
use std::{env, fs};
fn cbindgen_builder() -> cbindgen::Builder {
const AUTOGEN_WARNING: &str =
"/* Automatically generated by `cbindgen`. Not intended for manual editing. */";
cbindgen::Builder::new()
.with_pragma_once(true)
.with_autogen_warning(AUTOGEN_WARNING)
.with_no_includes()
.with_sys_include("cstdint")
.with_parse_deps(true)
.with_parse_include(&[
"sp1-hypercube",
"sp1-primitives",
"p3-koala-bear",
"sp1-core-machine",
"slop-koala-bear",
"sp1-core-executor",
"sp1-recursion-executor",
"sp1-recursion-machine",
])
.with_parse_extra_bindings(&[
"sp1-hypercube",
"p3-koala-bear",
"slop-koala-bear",
"sp1-recursion-executor",
"sp1-recursion-machine",
"sp1-core-machine",
])
.rename_item("KoalaBear", "KoalaBearP3")
.include_item("GlobalInteractionEvent")
.include_item("GlobalCols")
.include_item("MemoryAccessColsChips")
.include_item("Poseidon2Instr")
.include_item("Poseidon2PreprocessedColsWide")
.include_item("Poseidon2Event")
.include_item("SelectInstr")
.include_item("SelectPreprocessedCols")
.include_item("SelectEvent")
.include_item("SelectCols")
.include_item("BaseAluInstr")
.include_item("BaseAluAccessCols")
.include_item("BaseAluEvent")
.include_item("BaseAluValueCols")
.include_item("ExtAluInstr")
.include_item("ExtAluAccessCols")
.include_item("ExtAluEvent")
.include_item("ExtAluValueCols")
.include_item("ExtFeltInstr")
.include_item("ExtFeltEvent")
.include_item("ConvertAccessCols")
.include_item("ConvertValueCols")
.include_item("Poseidon2LinearLayerAccessCols")
.include_item("Poseidon2LinearLayerValueCols")
.include_item("Poseidon2LinearLayerInstr")
.include_item("Poseidon2SBoxInstr")
.include_item("Poseidon2SBoxIo")
.include_item("Poseidon2SBoxAccessCols")
.include_item("Poseidon2SBoxValueCols")
.include_item("NUM_CONVERT_ENTRIES_PER_ROW")
.include_item("NUM_LINEAR_ENTRIES_PER_ROW")
.include_item("NUM_SBOX_ENTRIES_PER_ROW")
.include_item("PERMUTATION_WIDTH")
.include_item("PrefixSumChecksEvent")
.include_item("PrefixSumChecksCols")
.with_namespace("sp1_gpu_sys")
.with_crate(env::var("CARGO_MANIFEST_DIR").unwrap())
}
fn rel_symlink_file<P, Q>(original: P, link: Q)
where
P: AsRef<std::path::Path>,
Q: AsRef<std::path::Path>,
{
#[cfg(unix)]
use std::os::unix::fs::symlink;
#[cfg(windows)]
use std::os::windows::fs::symlink_file as symlink;
let target_dir = link.as_ref().parent().unwrap();
fs::create_dir_all(target_dir).unwrap();
let _ = fs::remove_file(&link);
let relpath = pathdiff::diff_paths(original, target_dir).unwrap();
symlink(relpath, link).unwrap();
}
fn detect_cuda() -> bool {
println!("cargo:rerun-if-env-changed=SP1_CUDA_ENABLED");
if let Ok(val) = env::var("SP1_CUDA_ENABLED") {
match val.to_lowercase().as_str() {
"0" | "false" => return false,
"1" | "true" => return true,
_ => {} }
}
if std::process::Command::new("nvcc")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
{
return true;
}
if env::var("CUDA_PATH").is_ok() {
return true;
}
if std::path::Path::new("/usr/local/cuda/bin/nvcc").exists() {
return true;
}
if std::path::Path::new("/opt/cuda/bin/nvcc").exists() {
return true;
}
false
}
fn main() {
println!("cargo:rerun-if-changed=../../include/");
println!("cargo:rerun-if-changed=../../lib/");
println!("cargo:rerun-if-changed=../../sppark/");
println!("cargo:rerun-if-changed=../../CMakeLists.txt");
println!("cargo:rerun-if-changed=CMakeLists.txt");
println!("cargo:rerun-if-env-changed=PROFILE");
println!("cargo:rerun-if-env-changed=OPT_LEVEL");
println!("cargo:rerun-if-env-changed=DEBUG");
println!("cargo:rerun-if-env-changed=CUDA_ARCHS");
println!("cargo:rerun-if-env-changed=PROFILE_DEBUG_DATA");
let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_include_dir = out_dir.join("include");
const INCLUDE_DIRNAME: &str = "include";
let cbindgen_hpp = "sp1-gpu-cbindgen.hpp";
let header_path = out_include_dir.join(cbindgen_hpp);
match cbindgen_builder().generate() {
Ok(bindings) => {
fs::create_dir_all(&out_include_dir).unwrap();
if bindings.write_to_file(&header_path) {
let mut dir = out_dir.clone();
while !dir.ends_with("target") {
if !dir.pop() {
break;
}
}
if dir.ends_with("target") {
rel_symlink_file(&header_path, dir.join(INCLUDE_DIRNAME).join(cbindgen_hpp));
}
}
}
Err(cbindgen::Error::ParseSyntaxError { .. }) => {
return;
}
Err(e) => panic!("{e:?}"),
}
if !detect_cuda() {
println!("cargo:warning=CUDA not detected, skipping GPU build");
return;
}
let mut cmake_config = cmake::Config::new(".");
cmake_config.define("CMAKE_EXPORT_COMPILE_COMMANDS", "ON");
if let Ok(cuda_archs) = env::var("CUDA_ARCHS") {
cmake_config.define("CUDA_ARCHS", &cuda_archs);
}
cmake_config.define("CBINDGEN_INCLUDE_DIR", out_include_dir.display().to_string());
if let Some(profile_debug_data) = env::var_os("PROFILE_DEBUG_DATA") {
if profile_debug_data == "true" {
cmake_config.define("PROFILE_DEBUG_DATA", "true");
}
}
let profile = env::var("PROFILE").unwrap_or_else(|_| "release".to_string());
if profile == "debug" {
cmake_config.profile("Debug");
} else {
cmake_config.profile("Release");
}
let dst = cmake_config.build();
let compile_commands_src = dst.join("build").join("compile_commands.json");
if compile_commands_src.exists() {
let project_root = crate_dir.join("../..").canonicalize().unwrap();
rel_symlink_file(&compile_commands_src, project_root.join("compile_commands.json"));
}
println!("cargo:rustc-link-search=native={}/../../target/cuda-build/lib", crate_dir.display());
println!("cargo:rustc-link-lib=static=sys-cuda");
if let Ok(cuda_path) = env::var("CUDA_PATH") {
println!("cargo:rustc-link-search=native={cuda_path}/lib64");
println!("cargo:rustc-link-search=native={cuda_path}/lib");
} else {
println!("cargo:rustc-link-search=native=/usr/local/cuda/lib64");
}
println!("cargo:rustc-link-lib=cudart");
println!("cargo:rustc-link-lib=cudadevrt");
println!("cargo:rustc-link-lib=stdc++");
println!("cargo:rustc-link-lib=gomp");
println!("cargo:rustc-link-lib=dl");
println!("cargo:include={}", out_include_dir.display());
}