use std::env;
use std::path::PathBuf;
const MAINNET_FIELD_ELEMENTS_PER_BLOB: usize = 4096;
const MINIMAL_FIELD_ELEMENTS_PER_BLOB: usize = 4;
fn main() {
let cargo_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let root_dir = cargo_dir
.parent()
.expect("rust dir is nested")
.parent()
.expect("bindings dir is nested");
let field_elements_per_blob = if cfg!(feature = "minimal-spec") {
MINIMAL_FIELD_ELEMENTS_PER_BLOB
} else {
MAINNET_FIELD_ELEMENTS_PER_BLOB
};
eprintln!("Using FIELD_ELEMENTS_PER_BLOB={}", field_elements_per_blob);
// Obtain the header files exposed by blst-bindings' crate.
let blst_headers_dir =
std::env::var_os("DEP_BLST_BINDINGS").expect("BLST exposes header files for bindings");
let c_src_dir = root_dir.join("src");
let mut cc = cc::Build::new();
#[cfg(windows)]
cc.flag("-D_CRT_SECURE_NO_WARNINGS");
cc.include(blst_headers_dir.clone());
cc.warnings(false);
cc.flag(format!("-DFIELD_ELEMENTS_PER_BLOB={}", field_elements_per_blob).as_str());
cc.file(c_src_dir.join("c_kzg_4844.c"));
cc.try_compile("ckzg").expect("Failed to compile ckzg");
// Tell cargo to search for the static blst exposed by the blst-bindings' crate.
println!("cargo:rustc-link-lib=static=blst");
let bindings_out_path = cargo_dir.join("src").join("bindings").join("generated.rs");
let header_file_path = c_src_dir.join("c_kzg_4844.h");
let header_file = header_file_path.to_str().expect("valid header file");
make_bindings(
field_elements_per_blob,
header_file,
&blst_headers_dir.to_string_lossy(),
bindings_out_path,
);
// Finally, tell cargo this provides ckzg
println!("cargo:rustc-link-lib=ckzg");
}
fn make_bindings
(
field_elements_per_blob: usize,
header_path: &str,
blst_headers_dir: &str,
bindings_out_path: P,
) where
P: AsRef,
{
use bindgen::Builder;
#[derive(Debug)]
struct Callbacks;
impl bindgen::callbacks::ParseCallbacks for Callbacks {
fn int_macro(&self, name: &str, _value: i64) -> Option {
match name {
"FIELD_ELEMENTS_PER_BLOB"
| "BYTES_PER_COMMITMENT"
| "BYTES_PER_PROOF"
| "BYTES_PER_FIELD_ELEMENT"
| "BYTES_PER_BLOB" => Some(bindgen::callbacks::IntKind::Custom {
name: "usize",
is_signed: false,
}),
_ => None,
}
}
}
let bindings = Builder::default()
/*
* Header definitions.
*/
// Inject the constant as C code so that the C compiler can use it.
// -D is not supported by bindgen https://github.com/rust-lang/rust-bindgen/issues/2394
.header_contents(
"consts",
&format!("#define FIELD_ELEMENTS_PER_BLOB {field_elements_per_blob}"),
)
.header(header_path)
.clang_args([format!("-I{blst_headers_dir}")])
// Since this is not part of the header file, needs to be allowed explicitly.
.allowlist_var("FIELD_ELEMENTS_PER_BLOB")
// Get bindings only for the header file.
.allowlist_file(".*c_kzg_4844.h")
/*
* Cleanup instructions.
*/
// Remove stdio definitions related to FILE.
.opaque_type("FILE")
// Remove the definition of FILE to use the libc one, which is more convenient.
.blocklist_type("FILE")
// Inject rust code using libc's FILE
.raw_line("use libc::FILE;")
// Do no generate layout tests.
.layout_tests(false)
// Extern functions do not need individual extern blocks.
.merge_extern_blocks(true)
// We implement Drop for this type. Copy is not allowed for types with destructors.
.no_copy("KZGSettings")
/*
* API improvements.
*/
// Do not create individual constants for enum variants.
.rustified_enum("C_KZG_RET")
// Make constants used as sizes `usize`.
.parse_callbacks(Box::new(Callbacks))
// Add PartialEq and Eq impls to types.
.derive_eq(true)
// Blobs are big, we don't want rust to liberally copy them around.
.no_copy("Blob")
// Do not make fields public. If we want to modify them we can create setters/mutable
// getters when necessary.
.default_visibility(bindgen::FieldVisibilityKind::Private)
// Blocklist this type alias to use a custom implementation. If this stops being a type
// alias this line needs to be removed.
.blocklist_type("KZGCommitment")
// Blocklist this type alias to use a custom implementation. If this stops being a type
// alias this line needs to be removed.
.blocklist_type("KZGProof")
/*
* Re-build instructions
*/
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.unwrap();
bindings
.write_to_file(bindings_out_path)
.expect("Failed to write bindings");
}