evercrypt_tiny-sys 0.1.1

A tiny build of EverCrypt's c89-distribution with autogenerated bindings
Documentation
//! A simplified replacement for `make`

use cc::Build;

use crate::{
    config::{Arch, Configuration},
    files::{
        FileList,
        Pattern::{Contains, End, Exact, Start},
        DIST_C89, DIST_KARAMEL_INCLUDE, DIST_KARAMEL_MINIMAL_INCLUDE,
    },
};
use std::{env, fs, path::Path};

/// A simplified replacement for `make`
#[derive(Debug)]
pub struct Make {
    /// The platform configuration
    config: Configuration,
}
impl Make {
    /// Creates a new builder
    pub fn new(config: Configuration) -> Self {
        Self { config }
    }

    /// Builds the library
    pub fn build(&self) {
        // Determine the output directory
        let out_dir = env::var("OUT_DIR").expect("Failed to get target output directory");

        // Create config file
        let config_h_path = Path::new(&out_dir).join("config.h");
        let config_h = self.config_h();
        fs::write(config_h_path, config_h).expect("Failed to create config.h");

        // Gather sources and include paths
        let c_sources = dbg!(self.c_sources());
        let asm_sources = dbg!(self.asm_sources());
        let includes = self.includes();

        // Build the library
        Build::new()
            .include(out_dir)
            .includes(includes)
            .files(c_sources.paths())
            .files(asm_sources.paths())
            .flag_if_supported("-Wno-unused-parameter")
            .flag_if_supported("-Wno-unused-variable")
            .flag_if_supported("-Wno-unused-but-set-variable")
            .flag_if_supported("-Wno-unused-function")
            .flag_if_supported("-Wno-cpp")
            .compile("evercrypt");
    }

    /// Build a config.h
    fn config_h(&self) -> String {
        // Target architecture constant
        let target_arch = match self.config.arch {
            Arch::arm if !self.config.v128 => "#define TARGET_ARCHITECTURE TARGET_ARCHITECTURE_ID_ARM7",
            Arch::arm => "#define TARGET_ARCHITECTURE TARGET_ARCHITECTURE_ID_ARM8",
            Arch::x86 => "#define TARGET_ARCHITECTURE TARGET_ARCHITECTURE_ID_X86",
            Arch::x86_64 => "#define TARGET_ARCHITECTURE TARGET_ARCHITECTURE_ID_X64",
        };
        // Support for compiler intrinsics
        let intrinsics = match self.config.intrinsics {
            true => "#define HACL_CAN_COMPILE_INTRINSICS 1",
            false => "// #define HACL_CAN_COMPILE_INTRINSICS 1",
        };
        // Support for vale
        let vale = match self.config.vale {
            true => "#define HACL_CAN_COMPILE_VALE 1",
            false => "// #define HACL_CAN_COMPILE_VALE 1",
        };
        // Support for inline assembly
        let inline_asm = match self.config.inline_asm {
            true => "#define HACL_CAN_COMPILE_INLINE_ASM 1",
            false => "// #define HACL_CAN_COMPILE_INLINE_ASM 1",
        };
        // 128 bit vector support
        let v128 = match self.config.v128 {
            true => "#define HACL_CAN_COMPILE_VEC128 1",
            false => "#define Lib_IntVector_Intrinsics_vec128 void *",
        };
        // 256 bit vector support
        let v256 = match self.config.v256 {
            true => "#define HACL_CAN_COMPILE_VEC256 1",
            false => "#define Lib_IntVector_Intrinsics_vec256 void *",
        };
        // Support for native 128 bit integer types
        let native_u128 = match self.config.native_u128 {
            true => "#define HACL_CAN_COMPILE_UINT128 1",
            false => "// #define HACL_CAN_COMPILE_UINT128 1",
        };

        // Build header
        let header = format! {
            r#"
            {target_arch}
            {intrinsics}
            {vale}
            {inline_asm}
            {v128}
            {v256}
            {native_u128}
            #define LINUX_NO_EXPLICIT_BZERO 1
            "#
        };
        header.lines().map(|line| format!("{}\n", line.trim())).collect()
    }

    /// Gather all config-specific C source files
    fn c_sources(&self) -> FileList {
        // Collect all sources
        let mut c_sources = FileList::new();
        c_sources.add(DIST_C89, End(".c"));

        // Blacklist x64 assembly files
        if !self.config.vale {
            c_sources.remove(Start("Hacl_HPKE_Curve64_") + End(".c"));
            c_sources.remove(Exact("Hacl_Curve25519_64.c"));
            c_sources.remove(Exact("evercrypt_vale_stubs.c"));
        }
        // Blacklist 128-bit vector arithmetic files
        if !self.config.v128 {
            c_sources.remove(Contains("CP128") + End(".c"));
            c_sources.remove(End("_128.c"));
            c_sources.remove(End("_Vec128.c"));
        }
        // Blacklist 256-bit vector arithmetic files
        if !self.config.v256 {
            c_sources.remove(Contains("CP256") + End(".c"));
            c_sources.remove(End("_256.c"));
            c_sources.remove(End("_Vec256.c"));
        }
        c_sources
    }

    /// Gather all config-specific assembly source files
    fn asm_sources(&self) -> FileList {
        // Collect assembly sources
        let mut asm_sources = FileList::new();
        if self.config.vale {
            // Get target arch or abort if a parameter is unsupported
            let arch = match self.config.arch {
                Arch::x86_64 => "x86_64",
                _ => return asm_sources,
            };

            // Get target OS
            let os = env::var("CARGO_CFG_TARGET_OS").expect("Cannot determine target OS");
            let os_env = env::var("CARGO_CFG_TARGET_ENV").expect("Cannot determine target environment");
            let (os, ext) = match os.as_str() {
                "macos" | "ios" => ("darwin", "S"),
                "linux" => ("linux", "S"),
                "windows" => match os_env.as_str() {
                    "msvc" => ("msvc", "asm"),
                    "gnu" => ("linux", "S"),
                    _ => return asm_sources,
                },
                _ => return asm_sources,
            };

            // Gather files
            let ext = format!("-{arch}-{os}.{ext}");
            asm_sources.add(DIST_C89, End(ext));
        }
        asm_sources
    }

    /// The include paths
    fn includes(&self) -> &'static [&'static str] {
        &[DIST_C89, DIST_KARAMEL_INCLUDE, DIST_KARAMEL_MINIMAL_INCLUDE]
    }
}