Skip to content

Commit

Permalink
Import build.rs from franziskus/hacl-sys branch
Browse files Browse the repository at this point in the history
  • Loading branch information
mamonet committed Aug 23, 2023
1 parent 9a40a16 commit 71abeaf
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 174 deletions.
2 changes: 2 additions & 0 deletions sys/libjade/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ log = "0.4"
[build-dependencies]
libc = { version = "0.2", default-features = false }
fs_extra = "1.2"
cc = { version = "1.0", features = ["parallel"] }
libcrux_platform = { path = "../platform" }

[target.'cfg(not(windows))'.build-dependencies]
bindgen = "0.66"
Expand Down
324 changes: 150 additions & 174 deletions sys/libjade/build.rs
Original file line number Diff line number Diff line change
@@ -1,211 +1,184 @@
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod x64_build {
use std::{path::Path, process::Command};
use std::{env, path::Path};

macro_rules! svec {
macro_rules! svec {
($($x:expr),*$(,)?) => (vec![$($x.to_string()),*]);
}

pub fn copy_files(home_path: &Path, out_path: &Path) {
let mut options = fs_extra::dir::CopyOptions::new();
options.overwrite = true;
fs_extra::dir::copy(home_path.join("jazz"), out_path, &options).unwrap();
}
fn copy_files(home_path: &Path, out_path: &Path) {
let mut options = fs_extra::dir::CopyOptions::new();
options.overwrite = true;
fs_extra::dir::copy(home_path.join("jazz"), out_path, &options).unwrap();
}

pub fn append_simd128_flags(flags: &mut Vec<String>) {
// Platform detection
if simd128_support() {
flags.push("-DSIMD128".to_string());
flags.push("-mavx".to_string());
}
}
fn append_simd128_flags(flags: &mut Vec<String>) {
flags.push("-DSIMD128".to_string());
flags.push("-mavx".to_string());
}

pub fn append_simd256_flags(flags: &mut Vec<String>) {
// Platform detection
if simd256_support() {
flags.push("-DSIMD256".to_string());
flags.push("-mavx2".to_string());
}
}
fn append_simd256_flags(flags: &mut Vec<String>) {
flags.push("-DSIMD256".to_string());
flags.push("-mavx2".to_string());
}

#[cfg(not(windows))]
pub fn create_bindings(home_dir: &Path) {
let jazz_dir = home_dir.join("jazz");
let mut clang_args = vec![format!("-I{}", jazz_dir.join("include").display())];
#[cfg(not(windows))]
fn create_bindings(platform: Platform, home_dir: &Path) {
let jazz_dir = home_dir.join("jazz");
let mut clang_args = vec![format!("-I{}", jazz_dir.join("include").display())];
if platform.simd128 {
append_simd128_flags(&mut clang_args);
}
if platform.simd256 {
append_simd256_flags(&mut clang_args);

let bindings = bindgen::Builder::default()
// Header to wrap headers
.header("jazz/include/libjade.h")
// Set include paths for headers
.clang_args(clang_args)
// Allow function we want to have in
.allowlist_function("jade_hash_.*")
.allowlist_var("JADE_HASH_.*")
.allowlist_function("jade_scalarmult_curve25519_.*")
.allowlist_var("JADE_SCALARMULT_CURVE25519_.*")
.allowlist_function("jade_hash_sha3_.*")
.allowlist_var("JADE_HASH_SHA3_.*")
.allowlist_function("jade_onetimeauth_poly1305_.*")
.allowlist_var("JADE_ONETIMEAUTH_POLY1305_.*")
.allowlist_function("jade_stream_chacha_chacha20.*")
.allowlist_var("JADE_STREAM_CHACHA_CHACHA20_.*")
.allowlist_function("jade_kem_kyber_kyber768_.*")
.allowlist_var("JADE_KEM_KYBER_KYBER768_.*")
// Block everything we don't need or define ourselves.
.blocklist_type("__.*")
// Disable tests to avoid warnings and keep it portable
.layout_tests(false)
// Generate bindings
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");

let home_bindings = home_dir.join("src/bindings.rs");
bindings
.write_to_file(home_bindings)
.expect("Couldn't write bindings!");
}

#[cfg(windows)]
pub fn create_bindings(_: &Path) {}

pub fn compile_files(files: &[String], out_path: &Path, args: &[String]) {
let jazz_dir = out_path.join("jazz");
let mut clang_args = vec![format!("-I{}", jazz_dir.join("include").display())];
clang_args.push("-O3".to_string());
clang_args.push("-c".to_string());
clang_args.extend_from_slice(args);

let mut build_cmd = Command::new("clang");
let mut build_args = clang_args;
build_args.extend_from_slice(files);
println!(" >>> {}", out_path.join("jazz").display());
println!(" >>> {}", build_args.join(" "));

build_cmd
.current_dir(out_path.join("jazz"))
.args(&build_args);
println!(" >>> build_cmd: {:?}", build_cmd);
println!(" current dir: {:?}", build_cmd.get_current_dir());

let build_status = build_cmd.status().expect("Failed to run build.");
println!(" >>> build status: {:?}", build_status);
println!(" >>> out {:?}", out_path);
assert!(build_status.success());
}
let bindings = bindgen::Builder::default()
// Header to wrap headers
.header("jazz/include/libjade.h")
// Set include paths for headers
.clang_args(clang_args)
// Allow function we want to have in
.allowlist_function("jade_hash_.*")
.allowlist_var("JADE_HASH_.*")
.allowlist_function("jade_scalarmult_curve25519_.*")
.allowlist_var("JADE_SCALARMULT_CURVE25519_.*")
.allowlist_function("jade_hash_sha3_.*")
.allowlist_var("JADE_HASH_SHA3_.*")
.allowlist_function("jade_onetimeauth_poly1305_.*")
.allowlist_var("JADE_ONETIMEAUTH_POLY1305_.*")
.allowlist_function("jade_stream_chacha_chacha20.*")
.allowlist_var("JADE_STREAM_CHACHA_CHACHA20_.*")
.allowlist_function("jade_kem_kyber_kyber768_.*")
.allowlist_var("JADE_KEM_KYBER_KYBER768_.*")
// Block everything we don't need or define ourselves.
.blocklist_type("__.*")
// Disable tests to avoid warnings and keep it portable
.layout_tests(false)
// Generate bindings
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.use_core()
.generate()
.expect("Unable to generate bindings");

let home_bindings = home_dir.join("src/bindings.rs");
bindings
.write_to_file(home_bindings)
.expect("Couldn't write bindings!");
}

pub fn build(out_path: &Path, cross_target: Option<String>) {
let args = cross_target
.map(|s| match s.as_str() {
// We only support cross compilation here for now.
// We assume that we're using clang and can just add the target
"x86_64-apple-darwin" => svec!["-target", "x86_64-apple-darwin"],
_ => panic!("Unsupported cross compilation target {s}"),
})
.unwrap_or_default();

let files = svec![
"sha256.s",
"x25519_ref.s",
"x25519_mulx.s",
"sha3_224_ref.s",
"sha3_256_ref.s",
"sha3_384_ref.s",
"sha3_512_ref.s",
"chacha20_ref.s",
"poly1305_ref.s",
"kyber_kyber768_ref.s",
];
let mut all_files = files.clone();

// Platform detection
if simd256_support() {
let files256 = svec![
"sha3_224_avx2.s",
"sha3_256_avx2.s",
"sha3_384_avx2.s",
"sha3_512_avx2.s",
"chacha20_avx2.s",
"poly1305_avx2.s",
];
all_files.extend_from_slice(&files256);

let mut simd256_flags = args.clone();
append_simd256_flags(&mut simd256_flags);
compile_files(&files256, out_path, &simd256_flags);
}
if simd128_support() {
let files128 = svec!["chacha20_avx.s", "poly1305_avx.s",];
all_files.extend_from_slice(&files128);
#[cfg(windows)]
fn create_bindings(platform: Platform, _: &Path) {}

let mut simd128_flags = args.clone();
append_simd128_flags(&mut simd128_flags);
compile_files(&files128, out_path, &simd128_flags);
}
fn compile_files(library_name: &str, files: &[String], out_path: &Path, args: &[String]) {
let jazz_dir = out_path.join("jazz");

let mut object_files = vec![];
compile_files(&files, out_path, &args);
for file in all_files {
object_files.push(Path::new(&file).with_extension("o"));
}
let mut build = cc::Build::new();
build
.files(files.iter().map(|fname| jazz_dir.join(fname)))
.warnings_into_errors(true)
.no_default_flags(true);

// Link
let mut build_cmd = Command::new("ar");
build_cmd
.current_dir(out_path.join("jazz"))
.args(&["-r", &out_path.join("libjade.a").display().to_string()])
.args(&object_files);
println!(" >>> build_cmd: {:?}", build_cmd);
println!(" current dir: {:?}", build_cmd.get_current_dir());

let build_status = build_cmd.status().expect("Failed to link.");
println!("{:?}", build_status);
assert!(build_status.success());
build.include(jazz_dir.join("include"));
build.flag("-O3").flag("-c");
for arg in args {
build.flag(arg);
}

// === hardware detection
pub fn simd128_support() -> bool {
std::arch::is_x86_feature_detected!("avx")
build.compile(library_name);
}

fn build(platform: Platform, out_path: &Path, cross_target: Option<String>) {
let args = cross_target
.map(|s| match s.as_str() {
// We only support cross compilation here for now.
"x86_64-apple-darwin" => svec!["-target", "x86_64-apple-darwin"],
_ => panic!("Unsupported cross compilation target {s}"),
})
.unwrap_or_default();

let files = svec![
"sha256.s",
"x25519_ref.s",
"x25519_mulx.s",
"sha3_224_ref.s",
"sha3_256_ref.s",
"sha3_384_ref.s",
"sha3_512_ref.s",
"chacha20_ref.s",
"poly1305_ref.s",
"kyber_kyber768_ref.s",
];
compile_files("libjade.a", &files, out_path, &args);

if platform.simd256 {
let files256 = svec![
"sha3_224_avx2.s",
"sha3_256_avx2.s",
"sha3_384_avx2.s",
"sha3_512_avx2.s",
"chacha20_avx2.s",
"poly1305_avx2.s",
];

let mut simd256_flags = args.clone();
append_simd256_flags(&mut simd256_flags);
compile_files("libjade_256.a", &files256, out_path, &simd256_flags);
}

pub fn simd256_support() -> bool {
std::arch::is_x86_feature_detected!("avx2")
if platform.simd128 {
let files128 = svec!["chacha20_avx.s", "poly1305_avx.s",];

let mut simd128_flags = args.clone();
append_simd128_flags(&mut simd128_flags);
compile_files("libjade_128.a", &files128, out_path, &simd128_flags);
}
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn main() {
use std::{env, path::Path};
use x64_build::*;
#[derive(Debug, Clone, Copy)]
struct Platform {
simd128: bool,
simd256: bool,
}

pub fn main() -> Result<(), u8> {
// Get ENV variables
let home_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let home_path = Path::new(&home_dir);
let out_dir = env::var("OUT_DIR").unwrap();
let out_path = Path::new(&out_dir);
let target = env::var("TARGET").unwrap();
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let host = env::var("HOST").unwrap();

let cross_target = if target != host { Some(target) } else { None };
if cross_target.is_none() && host == "aarch64-apple-darwin" {
panic!("libjade does not support aarch64-apple-darwin");
if target_arch != "x86_64" && target_arch != "x86" {
eprintln!(" ! Only x86 and x64 CPUs are supported !");
return Err(1);
}

if simd128_support() {
println!("cargo:rustc-cfg=simd128");
}
if simd256_support() {
println!("cargo:rustc-cfg=simd256");
}
let cross_target = if target != host {
Some(target.clone())
} else {
None
};

// If cross compiling, we assume to have it all.
let platform = if cross_target.is_some() {
Platform {
simd128: true,
simd256: true,
}
} else {
Platform {
simd128: libcrux_platform::simd128_support(),
simd256: libcrux_platform::simd256_support(),
}
};

// Moving C/ASM code to output to make build easier.
copy_files(home_path, out_path);
eprintln!(" >>> out {:?}", out_path);

// Build the C/ASM files
build(out_path, cross_target);
build(platform, out_path, cross_target);

// Set library name to look up
let library_name = "jade";
Expand All @@ -214,16 +187,19 @@ pub fn main() {
println!("cargo:rerun-if-changed=cs");

// Generate new bindings. This is a no-op on Windows.
create_bindings(home_path);
create_bindings(platform, home_path);

// Link hacl library.
let mode = "static";
println!("cargo:rustc-link-lib={}={}", mode, library_name);
if platform.simd128 {
println!("cargo:rustc-link-lib={}={}", mode, "jade_128");
}
if platform.simd256 {
println!("cargo:rustc-link-lib={}={}", mode, "jade_256");
}
println!("cargo:rustc-link-search=native={}", out_path.display());
println!("cargo:lib={}", out_path.display());
}

#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn main() {
eprintln!("Only x86 and x64 CPUs are supported.");
Ok(())
}

0 comments on commit 71abeaf

Please sign in to comment.