From 9e947a327786b5c0c3c05254336916400992edc1 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 7 Feb 2017 23:19:36 +0100 Subject: [PATCH 1/5] Use only build.rs on unix to build the native libraries * Fix #320 I agree to license my contributions to each file under the terms given at the top of each file I changed. --- Cargo.toml | 4 + build.rs | 587 ++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 516 insertions(+), 75 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bd9ccb3c6f..58d0fed14f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -269,6 +269,10 @@ name = "ring" libc = "0.2.20" untrusted = "0.3.2" +[build-dependencies] +gcc = "0.3" +target_build_utils = "0.2" + [target.'cfg(any(target_os = "redox", all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies] lazy_static = "0.2.1" diff --git a/build.rs b/build.rs index 86677a1716..5c88cd8bce 100644 --- a/build.rs +++ b/build.rs @@ -15,7 +15,7 @@ // TODO: Deny `unused_qualifications` after // https://github.com/rust-lang/rust/issues/37345 is fixed. #![allow( - box_pointers, // TODO + // TODO missing_docs, unused_qualifications)] #![deny( @@ -66,101 +66,259 @@ while_true, )] +extern crate gcc; +extern crate target_build_utils; + use std::env; use std::path::{Path, PathBuf}; +use std::fs::{self, DirEntry}; +use target_build_utils::TargetInfo; const LIB_NAME: &'static str = "ring"; -fn main() { - for (key, value) in env::vars() { - println!("{}: {}", key, value); - } +#[cfg_attr(rustfmt, rustfmt_skip)] +const RING_SRC: &'static [&'static str] = + &["crypto/aes/aes.c", + "crypto/bn/add.c", + "crypto/bn/bn.c", + "crypto/bn/cmp.c", + "crypto/bn/convert.c", + "crypto/bn/div.c", + "crypto/bn/exponentiation.c", + "crypto/bn/gcd.c", + "crypto/bn/generic.c", + "crypto/bn/montgomery.c", + "crypto/bn/montgomery_inv.c", + "crypto/bn/mul.c", + "crypto/bn/random.c", + "crypto/bn/shift.c", + "crypto/cipher/e_aes.c", + "crypto/crypto.c", + "crypto/curve25519/curve25519.c", + "crypto/ec/ecp_nistz.c", + "crypto/ec/ecp_nistz256.c", + "crypto/ec/gfp_p256.c", + "crypto/ec/gfp_p384.c", + "crypto/mem.c", + "crypto/modes/gcm.c", + "crypto/rand/sysrand.c", + "crypto/limbs/limbs.c"]; - let out_dir = env::var("OUT_DIR").unwrap(); +const RING_INTEL_SHARED_SRCS: &'static [&'static str] = &["crypto/cpu-intel.c"]; - build_c_code(&out_dir).unwrap(); -} +const RING_X86_SRCS: &'static [&'static str] = + &["crypto/aes/asm/aes-586.pl", + "crypto/aes/asm/aesni-x86.pl", + "crypto/aes/asm/vpaes-x86.pl", + "crypto/bn/asm/x86-mont.pl", + "crypto/chacha/asm/chacha-x86.pl", + "crypto/ec/asm/ecp_nistz256-x86.pl", + "crypto/modes/asm/ghash-x86.pl", + "crypto/poly1305/asm/poly1305-x86.pl", + "crypto/sha/asm/sha256-586.pl", + "crypto/sha/asm/sha512-586.pl"]; -fn build_c_code(out_dir: &str) -> Result<(), std::env::VarError> { - let host_str = try!(env::var("HOST")); - let host_triple = host_str.split('-').collect::>(); +const RING_X86_64_SRC: &'static [&'static str] = + &["crypto/aes/asm/aes-x86_64.pl", + "crypto/aes/asm/aesni-x86_64.pl", + "crypto/aes/asm/bsaes-x86_64.pl", + "crypto/aes/asm/vpaes-x86_64.pl", + "crypto/bn/asm/x86_64-mont.pl", + "crypto/bn/asm/x86_64-mont5.pl", + "crypto/chacha/asm/chacha-x86_64.pl", + "crypto/curve25519/asm/x25519-asm-x86_64.S", + "crypto/curve25519/x25519-x86_64.c", + "crypto/ec/asm/ecp_nistz256-x86_64.pl", + "crypto/ec/asm/p256-x86_64-asm.pl", + "crypto/modes/asm/aesni-gcm-x86_64.pl", + "crypto/modes/asm/ghash-x86_64.pl", + "crypto/poly1305/asm/poly1305-x86_64.pl", + "crypto/sha/asm/sha256-x86_64.pl", + "crypto/sha/asm/sha512-x86_64.pl"]; - let target_str = try!(env::var("TARGET")); - let target_triple = target_str.split('-').collect::>(); +#[cfg_attr(rustfmt, rustfmt_skip)] +const RING_ARM_SHARED_SRCS: &'static [&'static str] = + &["crypto/cpu-arm.c", + "crypto/cpu-arm-linux.c", + "crypto/aes/asm/aesv8-armx.pl", + "crypto/modes/asm/ghashv8-armx.pl"]; - let use_msbuild = host_triple.contains(&"msvc") && - target_triple.contains(&"msvc"); +const RING_ARM_SRCS: &'static [&'static str] = + &["crypto/aes/asm/aes-armv4.pl", + "crypto/aes/asm/bsaes-armv7.pl", + "crypto/bn/asm/armv4-mont.pl", + "crypto/chacha/asm/chacha-armv4.pl", + "crypto/curve25519/asm/x25519-asm-arm.S", + "crypto/ec/asm/ecp_nistz256-armv4.pl", + "crypto/modes/asm/ghash-armv4.pl", + "crypto/poly1305/asm/poly1305-armv4.pl", + "crypto/sha/asm/sha256-armv4.pl", + "crypto/sha/asm/sha512-armv4.pl"]; - let opt_level = try!(env::var("OPT_LEVEL")); - let disable_opt = opt_level == "0"; +const RING_AARCH64_SRCS: &'static [&'static str] = + &["crypto/cpu-aarch64-linux.c", + "crypto/bn/asm/armv8-mont.pl", + "crypto/chacha/asm/chacha-armv8.pl", + "crypto/ec/asm/ecp_nistz256-armv8.pl", + "crypto/poly1305/asm/poly1305-armv8.pl", + "crypto/sha/asm/sha256-armv8.pl", + "crypto/sha/asm/sha512-armv8.pl"]; - let num_jobs = try!(env::var("NUM_JOBS")); +#[cfg_attr(rustfmt, rustfmt_skip)] +const RING_PPC_SRCS: &'static [&'static str] = + &["crypto/aes/asm/aesp8-ppc.pl", + "crypto/cpu-ppc64le.c"]; - // TODO: deal with link-time-optimization flag. +const RING_TEST_SRCS: &'static [&'static str] = + &["crypto/bn/bn_test.cc", + "crypto/constant_time_test.c", + "crypto/test/bn_test_convert.c", + "crypto/test/bn_test_lib.c", + "crypto/test/bn_test_new.c", + "crypto/test/file_test.cc"]; - let lib_path = Path::new(out_dir).join("lib"); +#[cfg_attr(rustfmt, rustfmt_skip)] +const RING_HEADERS: &'static [&'static str] = + &["crypto/poly1305/internal.h", + "crypto/test/scoped_types.h", + "crypto/test/rand.h", + "crypto/curve25519/internal.h", + "crypto/cipher/internal.h", + "crypto/bn/rsaz_exp.h", + "crypto/bn/internal.h", + "crypto/internal.h", + "crypto/rsa/internal.h", + "crypto/modes/internal.h", + "crypto/ec/ecp_nistz.h", + "crypto/ec/ecp_nistz384.h", + "crypto/ec/ecp_nistz256.h", + "crypto/ec/gfp_internal.h", + "crypto/limbs/limbs.h", + "include/openssl/type_check.h", + "include/openssl/mem.h", + "include/openssl/bn.h", + "include/openssl/opensslconf.h", + "include/openssl/arm_arch.h", + "include/openssl/cpu.h", + "include/openssl/rsa.h", + "include/openssl/aes.h", + "include/openssl/base.h", + "include/openssl/err.h"]; - if !use_msbuild { - // Environment variables |CC|, |CXX|, etc. will be inherited from this - // process. - let cmake_build_type = if disable_opt { - "DEBUG" - } else { - "RELWITHDEBINFO" - }; - let args = vec![ - format!("-j{}", num_jobs), - format!("TARGET={}", target_str), - format!("CMAKE_BUILD_TYPE={}", cmake_build_type), - format!("BUILD_PREFIX={}/", out_dir), - ]; - // If $MAKE is given, use it as the make command. If not, use `gmake` - // for BSD systems and `make` for other systems. - let make = env::var_os("MAKE").unwrap_or_else(|| { - let m = if target_triple[2].contains("bsd") { - "gmake" - } else { - "make" - }; - std::ffi::OsString::from(m) - }); - run_command_with_args(&make, &args); - } else { - build_msvc(&target_triple, disable_opt, &num_jobs, lib_path.clone(), - out_dir); - } +const RING_TEST_HEADERS: &'static [&'static str] = + &["crypto/test/bn_test_lib.h", + "crypto/test/file_test.h", + "crypto/test/bn_test_util.h"]; - println!("cargo:rustc-link-search=native={}", lib_path.to_str().unwrap()); - println!("cargo:rustc-link-lib=static={}-core", LIB_NAME); +#[cfg_attr(rustfmt, rustfmt_skip)] +const RING_INLINE_FILES: &'static [&'static str] = + &["crypto/ec/ecp_nistz256_table.inl", + "crypto/ec/ecp_nistz384.inl", + "crypto/ec/gfp_limbs.inl", + "crypto/ec/ecp_nistz384_mul.inl", + "crypto/limbs/limbs.inl"]; - // XXX: Ideally, this would only happen for `cargo test`, but we don't know - // how to do that yet. - println!("cargo:rustc-link-lib=static={}-test", LIB_NAME); - if !use_msbuild { - let libcxx = if target_str.contains("-apple-") || - target_triple[2] == "freebsd" { - "c++" - } else { - "stdc++" - }; - println!("cargo:rustc-flags=-l dylib={}", libcxx); +#[cfg_attr(rustfmt, rustfmt_skip)] +const RING_PERL_INCLUDES: &'static [&'static str] = + &["crypto/sha/asm/sha-x86_64.pl", + "crypto/sha/asm/sha-armv8.pl", + "crypto/perlasm/x86masm.pl", + "crypto/perlasm/x86gas.pl", + "crypto/perlasm/x86nasm.pl", + "crypto/perlasm/x86asm.pl", + "crypto/perlasm/x86_64-xlate.pl", + "crypto/perlasm/arm-xlate.pl", + "crypto/perlasm/ppc-xlate.pl"]; + +const RING_BUILD_FILE: &'static [&'static str] = &["build.rs", + "Makefile", + "mk/top_of_makefile.mk", + "mk/bottom_of_makefile.mk", + "mk/ring.mk"]; + +#[cfg_attr(rustfmt, rustfmt_skip)] +const C_FLAGS: &'static [&'static str] = + &["-std=c1x", + "-Wbad-function-cast", + "-Wmissing-field-initializers", + "-Wmissing-prototypes", + "-Wnested-externs", + "-Wstrict-prototypes"]; + +const CXX_FLAGS: &'static [&'static str] = &["-std=c++0x"]; + +#[cfg_attr(rustfmt, rustfmt_skip)] +const CPP_FLAGS: &'static [&'static str] = + &["-D_XOPEN_SOURCE=700", + "-fpic", + "-fdata-sections", + "-ffunction-sections", + "-pedantic", + "-pedantic-errors", + "-Wall", + "-Werror", + "-Wextra", + "-Wcast-align", + "-Wcast-qual", + "-Wenum-compare", + "-Wfloat-equal", + "-Wformat=2", + "-Winline", + "-Winvalid-pch", + "-Wmissing-declarations", + "-Wmissing-field-initializers", + "-Wmissing-include-dirs", + "-Wredundant-decls", + "-Wshadow", + "-Wsign-compare", + "-Wundef", + "-Wuninitialized", + "-Wwrite-strings", + "-DBORINGSSL_IMPLEMENTATION", + "-fno-strict-aliasing", + "-fvisibility=hidden", + "-Wno-cast-align"]; + +const LD_FLAGS: &'static [&'static str] = &[]; + +fn main() { + for (key, value) in env::vars() { + println!("{}: {}", key, value); } - Ok(()) + let out_dir = env::var("OUT_DIR").unwrap(); + let out_dir = PathBuf::from(out_dir); + + build_c_code(&out_dir); + check_all_files_tracked(); } -fn build_msvc(target_triple: &[&str], disable_opt: bool, num_jobs: &str, - lib_path: PathBuf, out_dir: &str) { - let arch = target_triple[0]; - let (platform, optional_amd64) = match arch { - "i686" => ("Win32", None), +fn build_c_code(out_dir: &PathBuf) { + let target_info = TargetInfo::new().expect("Could not get target"); + let use_msvcbuild = target_info.target_env() == "msvc"; + if use_msvcbuild { + let opt = env::var("OPT_LEVEL").expect("Cargo sets this"); + build_msvc(&target_info, + opt == "0", + &env::var("NUM_JOBS").expect("Cargo sets this"), + out_dir.clone()); + } else { + build_unix(&target_info, out_dir.clone()); + } +} + +fn build_msvc(target_info: &TargetInfo, disable_opt: bool, num_jobs: &str, + lib_path: PathBuf) { + + let (platform, optional_amd64) = match target_info.target_arch() { + "x86" => ("Win32", None), "x86_64" => ("x64", Some("amd64")), - _ => panic!("unexpected ARCH: {}", arch), + arch => panic!("unexpected ARCH: {}", arch), }; fn find_msbuild_exe(program_files_env_var: &str, optional_amd64: Option<&str>) - -> Result { + -> Option { let program_files = env::var(program_files_env_var).unwrap(); let mut msbuild = PathBuf::from(&program_files); msbuild.push("MSBuild"); @@ -170,12 +328,15 @@ fn build_msvc(target_triple: &[&str], disable_opt: bool, num_jobs: &str, msbuild.push(amd64); } msbuild.push("msbuild.exe"); - let _ = try!(std::fs::metadata(&msbuild).map_err(|_| ())); - Ok(msbuild.into_os_string()) + if msbuild.exists() && msbuild.is_file() { + Some(msbuild.into_os_string()) + } else { + None + } } let msbuild = find_msbuild_exe("ProgramFiles", optional_amd64) - .or_else(|_| find_msbuild_exe("ProgramFiles(x86)", optional_amd64)) + .or_else(|| find_msbuild_exe("ProgramFiles(x86)", optional_amd64)) .unwrap(); // .gitignore isn't packaged, so if it exists then this is not a @@ -189,15 +350,16 @@ fn build_msvc(target_triple: &[&str], disable_opt: bool, num_jobs: &str, format!("/m:{}", num_jobs), format!("/p:Platform={}", platform), format!("/p:Configuration={}", configuration), - format!("/p:OutRootDir={}/", out_dir), + format!("/p:OutRootDir={}/", lib_path.to_str().expect("Invalid path")), ]; if !use_prepackaged_asm { let mut asm_args = args.clone(); asm_args.push(String::from("crypto/libring-asm.Windows.vcxproj")); run_command_with_args(&msbuild, &asm_args); } else { + // TODO: rename msvc-ring-asm-i586.lib to msvc-ring-asm-x86.lib let pregenerated_lib_name = - format!("msvc-{}-asm-{}.lib", LIB_NAME, arch); + format!("msvc-{}-asm-{}.lib", LIB_NAME, target_info.target_arch()); let mut pregenerated_lib = PathBuf::from("pregenerated"); pregenerated_lib.push(pregenerated_lib_name); @@ -218,6 +380,154 @@ fn build_msvc(target_triple: &[&str], disable_opt: bool, num_jobs: &str, let mut test_args = args.clone(); test_args.push(String::from("crypto/libring-test.Windows.vcxproj")); run_command_with_args(&msbuild, &test_args); + println!("cargo:rustc-link-search=native={}", lib_path.to_str().unwrap()); + println!("cargo:rustc-link-lib=static={}-core", LIB_NAME); + + // XXX: Ideally, this would only happen for `cargo test`, but we don't know + // how to do that yet. + println!("cargo:rustc-link-lib=static={}-test", LIB_NAME); +} + +fn build_unix(target_info: &TargetInfo, out_dir: PathBuf) { + let mut lib_target = out_dir.clone(); + lib_target.push("libring-core.a"); + let lib_target = lib_target.as_path(); + + let mut test_target = out_dir.clone(); + test_target.push("libring-test.a"); + let test_target = test_target.as_path(); + + let lib_header_change = RING_HEADERS.iter() + .chain(RING_INLINE_FILES.iter()) + .chain(RING_BUILD_FILE.iter()) + .map(Path::new) + .any(|p| need_run(&p, lib_target)); + let test_header_change = RING_TEST_HEADERS.iter() + .map(Path::new) + .any(|p| need_run(&p, test_target)) || + lib_header_change; + + let mut additional = Vec::new(); + let srcs = match target_info.target_arch() { + "x86_64" => vec![RING_X86_64_SRC, RING_INTEL_SHARED_SRCS], + "x86" => vec![RING_X86_SRCS, RING_INTEL_SHARED_SRCS], + "arm" => vec![RING_ARM_SHARED_SRCS, RING_ARM_SRCS], + "aarch64" => vec![RING_ARM_SHARED_SRCS, RING_AARCH64_SRCS], + _ => Vec::new(), + }; + for additional_src in srcs { + for src in additional_src.iter() { + additional.push(make_asm(src, out_dir.clone(), &target_info)); + } + } + + let objs = RING_SRC.iter() + .map(|a| String::from(*a)) + .chain(additional.into_iter()) + .map(|f| compile(&f, &target_info, out_dir.clone(), lib_header_change)) + .collect(); + + build_library(lib_target, objs, target_info); + + // XXX: Ideally, this would only happen for `cargo test`, + // but we don't know how to do that yet. + let test_objs = RING_TEST_SRCS.iter() + .map(|a| String::from(*a)) + .map(|f| { + compile(&f, &target_info, out_dir.clone(), test_header_change) + }) + .collect(); + + build_library(test_target, test_objs, target_info); + + // target_vendor is only set if a nightly version of rustc is used + let libcxx = if target_info.target_vendor() + .map(|v| v == "apple") + .unwrap_or(target_info.target_os() == "macos" || + target_info.target_os() == "ios") || + target_info.target_os() == "freebsd" { + "c++" + } else { + "stdc++" + }; + println!("cargo:rustc-flags=-l dylib={}", libcxx); +} + +fn build_library(target: &Path, objs: Vec, target_info: &TargetInfo) { + if objs.iter() + .map(|f| Path::new(f)) + .any(|p| need_run(&p, target)) { + let mut c = gcc::Config::new(); + + for f in LD_FLAGS { + let _ = c.flag(&f); + } + match target_info.target_os() { + "macos" => { + let _ = c.flag("-fPIC"); + let _ = c.flag("-Wl,-dead_strip"); + }, + _ => { + let _ = c.flag("-Wl,--gc-sections".into()); + }, + } + for o in objs { + let _ = c.object(o); + } + c.compile(target.file_name() + .and_then(|f| f.to_str()) + .expect("No filename")); + } +} + +fn compile(file: &str, target_info: &TargetInfo, mut out_dir: PathBuf, + header_change: bool) + -> String { + let p = Path::new(file); + out_dir.push(p.file_name().expect("There is a filename")); + out_dir.set_extension("o"); + if header_change || need_run(&p, out_dir.as_path()) { + let mut c = gcc::Config::new(); + let _ = c.include("include"); + match p.extension().map(|p| p.to_str()) { + Some(Some("c")) => { + for f in C_FLAGS { + let _ = c.flag(f); + } + }, + Some(Some("cc")) => { + for f in CXX_FLAGS { + let _ = c.flag(f); + } + if target_info.target_os() != "none" { + let _ = c.flag("-fstack-protector"); + } + let _ = match (target_info.target_os(), + target_info.target_arch()) { + ("macos", _) => c.flag("-gfull"), + _ => c.flag("-g3"), + }; + let _ = c.cpp(true); + }, + Some(Some("S")) => {}, + e => panic!("Unsupported filextension: {:?}", e), + }; + for f in CPP_FLAGS { + let _ = c.flag(&f); + } + let mut c = c.get_compiler().to_command(); + let _ = c.arg("-c") + .arg("-o") + .arg(format!("{}", out_dir.to_str().expect("Invalid path"))) + .arg(file); + println!("{:?}", c); + if !c.status() + .expect(&format!("Failed to compile {}", file)) + .success() { + panic!("Failed to compile {}", file) + } + } + out_dir.to_str().expect("Invalid path").into() } fn run_command_with_args(command_name: S, args: &[String]) @@ -236,3 +546,130 @@ fn run_command_with_args(command_name: S, args: &[String]) panic!("{} execution failed", command_name.as_ref().to_str().unwrap()); } } + +fn make_asm(source: &str, mut dst: PathBuf, target_info: &TargetInfo) + -> String { + let p = Path::new(source); + if p.extension().expect("File without extension").to_str() == Some("pl") { + dst.push(p.file_name().expect("File without filename??")); + dst.set_extension("S"); + let r: String = dst.to_str().expect("Could not convert path").into(); + let perl_include_changed = RING_PERL_INCLUDES.iter() + .any(|i| need_run(&Path::new(i), dst.as_path())); + if need_run(&p, dst.as_path()) || perl_include_changed { + let mut args = vec![source.to_owned()]; + match (target_info.target_os(), target_info.target_arch()) { + ("macos", _) => args.push("macosx".into()), + ("ios", "arm") => args.push("ios32".into()), + ("ios", "aarch64") => args.push("ios64".into()), + ("linux", "x86_64") => args.push("elf".into()), + ("linux", "x86") => { + args.push("elf".into()); + args.push("-fPIC".into()); + args.push("-DOPENSSL_IA32_SSE2".into()); + }, + ("linux", "aarch64") | + ("android", "aarch64") => args.push("linux64".into()), + ("linux", "arm") | + ("android", "arm") => args.push("linux32".into()), + ("windows", _) => panic!("Don't run this on windows"), + (e, _) => panic!("{} is unsupported", e), + } + args.push(r.clone()); + run_command_with_args(&get_command("PERL_EXECUTABLE", "perl"), + &args); + } + r + } else { + p.to_str().expect("Could not convert path").into() + } +} + +fn need_run(source: &Path, target: &Path) -> bool { + let s = std::fs::metadata(source); + let t = std::fs::metadata(target); + if s.is_err() || t.is_err() { + true + } else { + match (s.unwrap().modified(), t.unwrap().modified()) { + (Ok(s), Ok(t)) => s >= t, + _ => true, + } + } +} + +fn get_command(var: &str, default: &str) -> String { + env::var(var).unwrap_or(default.into()) +} + + +fn check_all_files_tracked() { + walk_dir(&PathBuf::from("crypto"), &is_tracked); + walk_dir(&PathBuf::from("include"), &is_tracked); + walk_dir(&PathBuf::from("mk"), &is_tracked); +} + + +fn is_tracked(file: &DirEntry) { + let p = file.path(); + let cmp = |f| p == PathBuf::from(f); + let tracked = match p.extension().and_then(|p| p.to_str()) { + Some("h") => { + RING_HEADERS.iter().chain(RING_TEST_HEADERS.iter()).any(cmp) + }, + Some("inl") => RING_INLINE_FILES.iter().any(cmp), + Some("mk") => RING_BUILD_FILE.iter().any(cmp), + Some("c") | Some("cc") => { + RING_SRC.iter() + .chain(RING_AARCH64_SRCS.iter()) + .chain(RING_ARM_SHARED_SRCS.iter()) + .chain(RING_ARM_SRCS.iter()) + .chain(RING_INTEL_SHARED_SRCS.iter()) + .chain(RING_TEST_SRCS.iter()) + .chain(RING_X86_64_SRC.iter()) + .chain(RING_X86_SRCS.iter()) + .chain(RING_PPC_SRCS.iter()) + .any(cmp) + }, + Some("S") => { + RING_AARCH64_SRCS.iter() + .chain(RING_ARM_SHARED_SRCS.iter()) + .chain(RING_ARM_SRCS.iter()) + .chain(RING_INTEL_SHARED_SRCS.iter()) + .chain(RING_X86_64_SRC.iter()) + .chain(RING_X86_SRCS.iter()) + .any(cmp) + }, + Some("pl") => { + RING_AARCH64_SRCS.iter() + .chain(RING_ARM_SHARED_SRCS.iter()) + .chain(RING_ARM_SRCS.iter()) + .chain(RING_INTEL_SHARED_SRCS.iter()) + .chain(RING_X86_64_SRC.iter()) + .chain(RING_X86_SRCS.iter()) + .chain(RING_PPC_SRCS.iter()) + .chain(RING_PERL_INCLUDES.iter()) + .any(cmp) + }, + _ => true, + }; + if !tracked { + panic!("{:?} is not tracked in build.rs", p); + } +} + +fn walk_dir(dir: &Path, cb: &F) + where F: Fn(&DirEntry) +{ + if dir.is_dir() { + for entry in fs::read_dir(dir).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_dir() { + walk_dir(&path, cb); + } else { + cb(&entry); + } + } + } +} From f117dc2de77abe11340f80d15476b800b499534d Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 7 Feb 2017 23:29:00 +0100 Subject: [PATCH 2/5] Build native libraries in parallel I agree to license my contributions to each file under the terms given at the top of each file I changed. --- Cargo.toml | 1 + build.rs | 93 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 59 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 58d0fed14f..1a284abada 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -272,6 +272,7 @@ untrusted = "0.3.2" [build-dependencies] gcc = "0.3" target_build_utils = "0.2" +rayon = "0.6" [target.'cfg(any(target_os = "redox", all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies] lazy_static = "0.2.1" diff --git a/build.rs b/build.rs index 5c88cd8bce..d39ac360b5 100644 --- a/build.rs +++ b/build.rs @@ -15,7 +15,7 @@ // TODO: Deny `unused_qualifications` after // https://github.com/rust-lang/rust/issues/37345 is fixed. #![allow( - // TODO +// TODO missing_docs, unused_qualifications)] #![deny( @@ -68,11 +68,14 @@ extern crate gcc; extern crate target_build_utils; +extern crate rayon; use std::env; use std::path::{Path, PathBuf}; use std::fs::{self, DirEntry}; use target_build_utils::TargetInfo; +use rayon::par_iter::{ParallelIterator, IntoParallelIterator, + IntoParallelRefIterator}; const LIB_NAME: &'static str = "ring"; @@ -289,8 +292,16 @@ fn main() { let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = PathBuf::from(out_dir); - build_c_code(&out_dir); - check_all_files_tracked(); + // copied from gcc + let mut cfg = rayon::Configuration::new(); + if let Ok(amt) = env::var("NUM_JOBS") { + if let Ok(amt) = amt.parse() { + cfg = cfg.set_num_threads(amt); + } + } + rayon::initialize(cfg).unwrap(); + + let _ = rayon::join(check_all_files_tracked, || build_c_code(&out_dir)); } fn build_c_code(out_dir: &PathBuf) { @@ -397,17 +408,16 @@ fn build_unix(target_info: &TargetInfo, out_dir: PathBuf) { test_target.push("libring-test.a"); let test_target = test_target.as_path(); - let lib_header_change = RING_HEADERS.iter() - .chain(RING_INLINE_FILES.iter()) - .chain(RING_BUILD_FILE.iter()) + let lib_header_change = RING_HEADERS.par_iter() + .chain(RING_INLINE_FILES.par_iter()) + .chain(RING_BUILD_FILE.par_iter()) .map(Path::new) .any(|p| need_run(&p, lib_target)); - let test_header_change = RING_TEST_HEADERS.iter() + let test_header_change = RING_TEST_HEADERS.par_iter() .map(Path::new) .any(|p| need_run(&p, test_target)) || lib_header_change; - let mut additional = Vec::new(); let srcs = match target_info.target_arch() { "x86_64" => vec![RING_X86_64_SRC, RING_INTEL_SHARED_SRCS], "x86" => vec![RING_X86_SRCS, RING_INTEL_SHARED_SRCS], @@ -415,30 +425,28 @@ fn build_unix(target_info: &TargetInfo, out_dir: PathBuf) { "aarch64" => vec![RING_ARM_SHARED_SRCS, RING_AARCH64_SRCS], _ => Vec::new(), }; - for additional_src in srcs { - for src in additional_src.iter() { - additional.push(make_asm(src, out_dir.clone(), &target_info)); - } - } - - let objs = RING_SRC.iter() - .map(|a| String::from(*a)) - .chain(additional.into_iter()) - .map(|f| compile(&f, &target_info, out_dir.clone(), lib_header_change)) - .collect(); - build_library(lib_target, objs, target_info); + let additional = srcs.into_par_iter() + .weight_max() + .flat_map(|additional_src| { + additional_src.par_iter() + .map(|src| make_asm(src, out_dir.clone(), &target_info)) + }); + build_library(lib_target, + additional, + RING_SRC, + target_info, + out_dir.clone(), + lib_header_change); // XXX: Ideally, this would only happen for `cargo test`, // but we don't know how to do that yet. - let test_objs = RING_TEST_SRCS.iter() - .map(|a| String::from(*a)) - .map(|f| { - compile(&f, &target_info, out_dir.clone(), test_header_change) - }) - .collect(); - - build_library(test_target, test_objs, target_info); + build_library(test_target, + Vec::new().into_par_iter(), + RING_TEST_SRCS, + target_info, + out_dir.clone(), + test_header_change); // target_vendor is only set if a nightly version of rustc is used let libcxx = if target_info.target_vendor() @@ -453,8 +461,23 @@ fn build_unix(target_info: &TargetInfo, out_dir: PathBuf) { println!("cargo:rustc-flags=-l dylib={}", libcxx); } -fn build_library(target: &Path, objs: Vec, target_info: &TargetInfo) { - if objs.iter() + +fn build_library

(target: &Path, additional: P, + lib_src: &'static [&'static str], + target_info: &TargetInfo, out_dir: PathBuf, + header_changed: bool) + where P: ParallelIterator +{ + let objs = additional.chain(lib_src.par_iter().map(|a| String::from(*a))) + .weight_max() + .map(|f| compile(&f, &target_info, out_dir.clone(), header_changed)) + .map(|v| vec![v]) + .reduce(Vec::new, + &|mut a: Vec, b: Vec| -> Vec { + a.extend(b.into_iter()); + a + }); + if objs.par_iter() .map(|f| Path::new(f)) .any(|p| need_run(&p, target)) { let mut c = gcc::Config::new(); @@ -602,14 +625,14 @@ fn get_command(var: &str, default: &str) -> String { env::var(var).unwrap_or(default.into()) } - fn check_all_files_tracked() { - walk_dir(&PathBuf::from("crypto"), &is_tracked); - walk_dir(&PathBuf::from("include"), &is_tracked); - walk_dir(&PathBuf::from("mk"), &is_tracked); + let _ = rayon::join(|| { + rayon::join(|| walk_dir(&PathBuf::from("crypto"), &is_tracked), + || walk_dir(&PathBuf::from("include"), &is_tracked)) + }, + || walk_dir(&PathBuf::from("mk"), &is_tracked)); } - fn is_tracked(file: &DirEntry) { let p = file.path(); let cmp = |f| p == PathBuf::from(f); From a36243bca2f032b29359481fa5637dc59245f350 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 7 Feb 2017 23:32:13 +0100 Subject: [PATCH 3/5] We don't need the makefiles anymore I agree to license my contributions to each file under the terms given at the top of each file I changed. --- Makefile | 29 ----- build.rs | 14 +-- mk/bottom_of_makefile.mk | 54 --------- mk/ring.mk | 216 ---------------------------------- mk/top_of_makefile.mk | 245 --------------------------------------- 5 files changed, 3 insertions(+), 555 deletions(-) delete mode 100644 Makefile delete mode 100644 mk/bottom_of_makefile.mk delete mode 100644 mk/ring.mk delete mode 100644 mk/top_of_makefile.mk diff --git a/Makefile b/Makefile deleted file mode 100644 index af975ec0db..0000000000 --- a/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2015 Brian Smith. -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND BRIAN SMITH AND THE AUTHORS DISCLAIM -# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL BRIAN SMITH OR THE AUTHORS -# BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -include mk/top_of_makefile.mk - -RING_PREFIX = - -include mk/ring.mk - -OBJS += \ - $(RING_OBJS) \ - $(NULL) - -LIBS += \ - $(RING_LIBS) \ - $(NULL) - -include mk/bottom_of_makefile.mk diff --git a/build.rs b/build.rs index d39ac360b5..0d47b990eb 100644 --- a/build.rs +++ b/build.rs @@ -233,11 +233,7 @@ const RING_PERL_INCLUDES: &'static [&'static str] = "crypto/perlasm/arm-xlate.pl", "crypto/perlasm/ppc-xlate.pl"]; -const RING_BUILD_FILE: &'static [&'static str] = &["build.rs", - "Makefile", - "mk/top_of_makefile.mk", - "mk/bottom_of_makefile.mk", - "mk/ring.mk"]; +const RING_BUILD_FILE: &'static [&'static str] = &["build.rs"]; #[cfg_attr(rustfmt, rustfmt_skip)] const C_FLAGS: &'static [&'static str] = @@ -626,11 +622,8 @@ fn get_command(var: &str, default: &str) -> String { } fn check_all_files_tracked() { - let _ = rayon::join(|| { - rayon::join(|| walk_dir(&PathBuf::from("crypto"), &is_tracked), - || walk_dir(&PathBuf::from("include"), &is_tracked)) - }, - || walk_dir(&PathBuf::from("mk"), &is_tracked)); + let _ = rayon::join(|| walk_dir(&PathBuf::from("crypto"), &is_tracked), + || walk_dir(&PathBuf::from("include"), &is_tracked)); } fn is_tracked(file: &DirEntry) { @@ -641,7 +634,6 @@ fn is_tracked(file: &DirEntry) { RING_HEADERS.iter().chain(RING_TEST_HEADERS.iter()).any(cmp) }, Some("inl") => RING_INLINE_FILES.iter().any(cmp), - Some("mk") => RING_BUILD_FILE.iter().any(cmp), Some("c") | Some("cc") => { RING_SRC.iter() .chain(RING_AARCH64_SRCS.iter()) diff --git a/mk/bottom_of_makefile.mk b/mk/bottom_of_makefile.mk deleted file mode 100644 index 7263a05fb4..0000000000 --- a/mk/bottom_of_makefile.mk +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2015 Brian Smith. -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND BRIAN SMITH AND THE AUTHORS DISCLAIM -# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL BRIAN SMITH OR THE AUTHORS -# BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -GENERATED = \ - $(EXES) \ - $(OBJS) \ - $(OBJS:.o=.d) \ - $(LIBS) \ - $(OTHER_GENERATED) \ - $(NULL) - -GENERATED_DIRS = $(sort $(dir $(GENERATED))) - -$(GENERATED_DIRS): - mkdir -p $@ - -$(GENERATED) : | $(GENERATED_DIRS) - -# Variants of the built-in GNU Make rules that support targets in $(OBJ_PREFIX) - -%.o: %.S - $(COMPILE.c) $(OUTPUT_OPTION) $< -$(OBJ_PREFIX)%.o: %.S - $(COMPILE.c) $(OUTPUT_OPTION) $< -$(OBJ_PREFIX)%.o: %.c - $(COMPILE.c) $(OUTPUT_OPTION) $< -$(OBJ_PREFIX)%.o: %.cpp - $(COMPILE.cpp) $(OUTPUT_OPTION) $< -$(OBJ_PREFIX)%.o: %.cc - $(COMPILE.cc) $(OUTPUT_OPTION) $< - -.DEFAULT_GOAL := all -.PHONY: all -all: $(GENERATED) - -.PHONY: clean -clean: - $(RM) $(GENERATED) - -# The C/C++ compiler generates dependency info for #includes. - -CPPFLAGS += -MMD --include $(OBJS:.o=.d) diff --git a/mk/ring.mk b/mk/ring.mk deleted file mode 100644 index 44438b220e..0000000000 --- a/mk/ring.mk +++ /dev/null @@ -1,216 +0,0 @@ -# Copyright 2015 Brian Smith. -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND BRIAN SMITH AND THE AUTHORS DISCLAIM -# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL BRIAN SMITH OR THE AUTHORS -# BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -RING_PREFIX ?= ring/ - -RING_CPPFLAGS = -I$(RING_PREFIX)include -D_XOPEN_SOURCE=700 - -RING_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/aes/aes.c \ - crypto/bn/add.c \ - crypto/bn/bn.c \ - crypto/bn/cmp.c \ - crypto/bn/convert.c \ - crypto/bn/div.c \ - crypto/bn/exponentiation.c \ - crypto/bn/gcd.c \ - crypto/bn/generic.c \ - crypto/bn/montgomery.c \ - crypto/bn/montgomery_inv.c \ - crypto/bn/mul.c \ - crypto/bn/random.c \ - crypto/bn/shift.c \ - crypto/cipher/e_aes.c \ - crypto/crypto.c \ - crypto/curve25519/curve25519.c \ - crypto/ec/ecp_nistz.c \ - crypto/ec/ecp_nistz256.c \ - crypto/ec/gfp_p256.c \ - crypto/ec/gfp_p384.c \ - crypto/limbs/limbs.c \ - crypto/mem.c \ - crypto/modes/gcm.c \ - crypto/rand/sysrand.c \ - $(NULL)) \ - $(RING_$(TARGET_ARCH_NORMAL)_SRCS) \ - $(NULL) - -RING_INTEL_SHARED_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/cpu-intel.c \ - $(NULL)) - -# TODO: make all .a files depend on these too. -RING_x86_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/aes/asm/aes-586.pl \ - crypto/aes/asm/aesni-x86.pl \ - crypto/aes/asm/vpaes-x86.pl \ - crypto/bn/asm/x86-mont.pl \ - crypto/chacha/asm/chacha-x86.pl \ - crypto/ec/asm/ecp_nistz256-x86.pl \ - crypto/modes/asm/ghash-x86.pl \ - crypto/poly1305/asm/poly1305-x86.pl \ - crypto/sha/asm/sha256-586.pl \ - crypto/sha/asm/sha512-586.pl \ - $(NULL)) \ - $(RING_INTEL_SHARED_SRCS) \ - $(NULL) - -RING_x86_64_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/aes/asm/aes-x86_64.pl \ - crypto/aes/asm/aesni-x86_64.pl \ - crypto/aes/asm/bsaes-x86_64.pl \ - crypto/aes/asm/vpaes-x86_64.pl \ - crypto/bn/asm/x86_64-mont.pl \ - crypto/bn/asm/x86_64-mont5.pl \ - crypto/chacha/asm/chacha-x86_64.pl \ - crypto/curve25519/asm/x25519-asm-x86_64.S \ - crypto/curve25519/x25519-x86_64.c \ - crypto/ec/asm/ecp_nistz256-x86_64.pl \ - crypto/ec/asm/p256-x86_64-asm.pl \ - crypto/modes/asm/aesni-gcm-x86_64.pl \ - crypto/modes/asm/ghash-x86_64.pl \ - crypto/poly1305/asm/poly1305-x86_64.pl \ - crypto/sha/asm/sha256-x86_64.pl \ - crypto/sha/asm/sha512-x86_64.pl \ - $(NULL)) \ - $(RING_INTEL_SHARED_SRCS) \ - $(NULL) - -RING_ARM_SHARED_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/cpu-arm.c \ - crypto/cpu-arm-linux.c \ - \ - crypto/aes/asm/aesv8-armx.pl \ - crypto/modes/asm/ghashv8-armx.pl \ - $(NULL)) - -RING_arm_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/aes/asm/aes-armv4.pl \ - crypto/aes/asm/bsaes-armv7.pl \ - crypto/bn/asm/armv4-mont.pl \ - crypto/chacha/asm/chacha-armv4.pl \ - crypto/curve25519/asm/x25519-asm-arm.S \ - crypto/ec/asm/ecp_nistz256-armv4.pl \ - crypto/modes/asm/ghash-armv4.pl \ - crypto/poly1305/asm/poly1305-armv4.pl \ - crypto/sha/asm/sha256-armv4.pl \ - crypto/sha/asm/sha512-armv4.pl \ - $(NULL)) \ - $(RING_ARM_SHARED_SRCS) \ - $(NULL) - -RING_aarch64_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/cpu-aarch64-linux.c \ - crypto/bn/asm/armv8-mont.pl \ - crypto/chacha/asm/chacha-armv8.pl \ - crypto/ec/asm/ecp_nistz256-armv8.pl \ - crypto/poly1305/asm/poly1305-armv8.pl \ - crypto/sha/asm/sha256-armv8.pl \ - crypto/sha/asm/sha512-armv8.pl \ - $(NULL)) \ - $(RING_ARM_SHARED_SRCS) \ - $(NULL) - -RING_TEST_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/bn/bn_test.cc \ - crypto/constant_time_test.c \ - crypto/test/bn_test_convert.c \ - crypto/test/bn_test_lib.c \ - crypto/test/bn_test_new.c \ - crypto/test/file_test.cc \ - $(NULL)) - -RING_CORE_OBJS = \ - $(addprefix $(OBJ_PREFIX), \ - $(patsubst %.pl, %.o, \ - $(patsubst %.S, %.o, \ - $(patsubst %.c, %.o, \ - $(RING_SRCS))))) - -RING_TEST_OBJS = \ - $(addprefix $(OBJ_PREFIX), \ - $(patsubst %.c, %.o, \ - $(patsubst %.cc, %.o, \ - $(RING_TEST_SRCS)))) - -RING_CORE_LIB = $(LIB_PREFIX)libring-core.a -RING_TEST_LIB = $(LIB_PREFIX)libring-test.a - -RING_LIBS = \ - $(RING_CORE_LIB) \ - $(RING_TEST_LIB) \ - $(NULL) - -# Recent versions of Linux have the D flag for deterministic builds, but Darwin -# (at least) doesn't. Accroding to Debian's documentation, binutils is built -# with --enable-determnistic-archives by default and we shouldn't need to -# worry about it. -$(RING_CORE_LIB): ARFLAGS = crs -$(RING_CORE_LIB): $(RING_CORE_OBJS) $(RING_PREFIX)mk/ring.mk - $(RM) $@ - $(AR) $(ARFLAGS) $@ $(filter-out $(RING_PREFIX)mk/ring.mk, $^) -$(RING_TEST_LIB): ARFLAGS = crs -$(RING_TEST_LIB): $(RING_TEST_OBJS) $(RING_PREFIX)mk/ring.mk - $(RM) $@ - $(AR) $(ARFLAGS) $@ $(filter-out $(RING_PREFIX)mk/ring.mk, $^) - -RING_OBJS = \ - $(RING_CORE_OBJS) \ - $(RING_TEST_OBJS) \ - $(NULL) - -# TODO: Fix the code so -Wno- overrides are not needed. -$(RING_OBJS) \ -$(NULL): CPPFLAGS += $(RING_CPPFLAGS) \ - -DBORINGSSL_IMPLEMENTATION \ - -fno-strict-aliasing \ - -fvisibility=hidden \ - -Wno-cast-align \ - $(NULL) - -PERLASM_LIB_SRCS = $(addprefix $(RING_PREFIX), \ - crypto/perlasm/arm-xlate.pl \ - crypto/perlasm/x86asm.pl \ - crypto/perlasm/x86gas.pl \ - crypto/perlasm/x86masm.pl \ - crypto/perlasm/x86nasm.pl \ - crypto/perlasm/x86_64-xlate.pl \ - $(NULL)) - -PERL_EXECUTABLE ?= perl - -# The British spelling "flavour" is used for consistency with perlasm's code. -ifeq ($(findstring darwin,$(TARGET_SYS)),darwin) -PERLASM_FLAVOUR ?= macosx -else ifeq ($(TARGET_SYS),ios) -ifeq ($(findstring arm,$(TARGET_ARCH_NORMAL)),arm) -PERLASM_FLAVOUR ?= ios32 -else ifeq ($(TARGET_ARCH_NORMAL),aarch64) -PERLASM_FLAVOUR ?= ios64 -else -PERLASM_FLAVOUR ?= macosx -endif -else ifeq ($(TARGET_ARCH_NORMAL),aarch64) -PERLASM_FLAVOUR ?= linux64 -else ifeq ($(TARGET_ARCH_NORMAL),arm) -PERLASM_FLAVOUR ?= linux32 -else -PERLASM_FLAVOUR ?= elf -endif - -PERLASM_x86_ARGS = -fPIC -DOPENSSL_IA32_SSE2 -PERLASM_ARGS = $(PERLASM_FLAVOUR) $(PERLASM_$(TARGET_ARCH_NORMAL)_ARGS) - -$(OBJ_PREFIX)%.S: %.pl $(PERLASM_LIB_SRCS) - ${PERL_EXECUTABLE} $< $(PERLASM_ARGS) $@ diff --git a/mk/top_of_makefile.mk b/mk/top_of_makefile.mk deleted file mode 100644 index 84b2b72ed8..0000000000 --- a/mk/top_of_makefile.mk +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright 2015 Brian Smith. -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND BRIAN SMITH AND THE AUTHORS DISCLAIM -# ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL BRIAN SMITH OR THE AUTHORS -# BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -.DEFAULT_GOAL := all - -# $(TARGET) must be of the form []---. -# Due to how Rust names platforms the following exceptions are allowed: -# can be omitted for Mac OS X (Darwin) and iOS. -# can be omitted for the Android ABIs (android and androideabi). -# The list of Rust supported platforms is at: -# https://forge.rust-lang.org/platform-support.html -TARGET_WORDS = $(subst -, ,$(TARGET)) -TARGET_ARCH_BASE = $(word 1,$(TARGET_WORDS)) -TARGET_ARCH_NORMAL = \ - $(strip $(if $(findstring arm, $(TARGET_ARCH_BASE)),arm, \ - $(if $(filter i386 i486 i586 i686, \ - $(TARGET_ARCH_BASE)),x86,$(TARGET_ARCH_BASE)))) - -TARGET_VENDOR = $(word 2,$(TARGET_WORDS)) -TARGET_SYS = $(word 3,$(TARGET_WORDS)) -TARGET_ABI = $(word 4,$(TARGET_WORDS)) - -# Match how Rust names targets to our expectations. -ifeq ($(TARGET_ABI),) -# Set ABI when building for Mac OS X and iOS. -ifeq ($(TARGET_VENDOR),apple) -TARGET_ABI = macho -# Set the correct VENDOR, SYS and ABI when building for Android. -else ifeq ($(findstring linux-android,$(TARGET_VENDOR)-$(TARGET_SYS)),linux-android) -TARGET_ABI = $(TARGET_SYS) -TARGET_VENDOR = unknown -TARGET_SYS = linux -endif -endif - -# XXX: Apple's toolchain fails to link when the |-target| arch is "x86_64", -# so just skip -target on Darwin for now. -ifneq ($(TARGET_ARCH_NORMAL)-$(findstring darwin,$(TARGET_SYS)),x86_64-darwin) -ifeq ($(findstring clang,$(CC)),clang) -DEFAULT_TARGET_ARCH = -target "$(TARGET)" -endif -endif - -ifeq ($(TARGET_ARCH_NORMAL),x86) -MARCH = pentium -MINSTR = 32 -else ifeq ($(TARGET_ARCH_NORMAL),x86_64) -MARCH = x86-64 -MINSTR = 64 -else -# TODO: Pass -march and related options. For now, use the default of the -# toolchain's C compiler. -# MARCH = $(subst _,-,$(TARGET_ARCH_BASE)) -endif - -ifeq ($(TARGET_ABI),eabi) -MABI = aapcs -endif - -# Cortex-M0, Cortex-M0+, Cortex-M1: armv6_m -# Cortex-M3: armv7_m -# Cortex-M4, Cortex-M7: armv7e_m -ifeq ($(filter-out armv6_m armv7_m armv7e_m,$(TARGET_ARCH_BASE)),) -MINSTR = thumb -endif - -# Although it isn't mentioned in the GNU Make manual, GNU Make passes -# $(TARGET_ARCH) in its implicit rules. -TARGET_ARCH += $(if $(MCPU),-mcpu=$(MCPU)) \ - $(if $(MARCH),-march=$(MARCH)) \ - $(if $(MABI),-mabi=$(MABI)) \ - $(if $(MINSTR),-m$(MINSTR)) \ - $(NULL) - -ifeq ($(CC),) -$(error You must specify CC) -endif -ifeq ($(CXX),) -$(error You must specify CXX) -endif - -# e.g. "clang-3.6" -COMPILER_NAME ?= $(notdir $(CC)) - -# Generate output to a directory like build/x86_64-unknown-linux-elf-clang-3.6. -BUILD_PREFIX_PRIMARY ?= build -BUILD_PREFIX_SUB ?= $(TARGET)-$(COMPILER_NAME) -BUILD_PREFIX ?= $(BUILD_PREFIX_PRIMARY)/$(BUILD_PREFIX_SUB)/ - -EXE_PREFIX ?= $(BUILD_PREFIX)test/ring/ -OBJ_PREFIX ?= $(BUILD_PREFIX)obj/ -LIB_PREFIX ?= $(BUILD_PREFIX)lib/ - -# GCC 4.6 requires "c1x" and "c++0x" instead of "c11" and "c++11". -CFLAGS_STD ?= -std=c1x -CXXFLAGS_STD ?= -std=c++0x - -CFLAGS += $(CFLAGS_STD) -CXXFLAGS += $(CXXFLAGS_STD) - -# Add flags needed for ios. -ifeq ($(TARGET_SYS),ios) -IOS_MIN_VERSION = 7.0 -ifeq ($(findstring x86,$(TARGET_ARCH_NORMAL)),x86) -IOS_SDK = iphonesimulator -IOS_VERSION_FLAG = -mios-simulator-version-min=$(IOS_MIN_VERSION) -else -IOS_SDK = iphoneos -IOS_VERSION_FLAG = -mios-version-min=$(IOS_MIN_VERSION) -ifeq ($(TARGET_ARCH_BASE),aarch64) -CFLAGS += -arch arm64 -CXXFLAGS += -arch arm64 -else ifeq ($(TARGET_ARCH_BASE),armv7) -CFLAGS += -arch $(TARGET_ARCH_BASE) -mfpu=neon -CXXFLAGS += -arch $(TARGET_ARCH_BASE) -mfpu=neon -else -CFLAGS += -arch $(TARGET_ARCH_BASE) -CXXFLAGS += -arch $(TARGET_ARCH_BASE) -endif -endif -IOS_SDK_PATH = $(shell xcrun --show-sdk-path -sdk $(IOS_SDK)) -CFLAGS += $(DEFAULT_TARGET_ARCH) -isysroot $(IOS_SDK_PATH) $(IOS_VERSION_FLAG) -CXXFLAGS += $(DEFAULT_TARGET_ARCH) -isysroot $(IOS_SDK_PATH) $(IOS_VERSION_FLAG) -endif - -# Always add full debug info and strip dead code. -CPPFLAGS += -fpic -fdata-sections -ffunction-sections -ifeq ($(findstring darwin,$(TARGET_SYS)),darwin) -# |-gfull| is required for Darwin's |-dead_strip|. -CPPFLAGS += -gfull -# libc++ is the default in newer toolchains, but libstdc++ was the default in -# older toolchains. -CXXFLAGS += -stdlib=libc++ -LDFLAGS += -fPIC -Wl,-dead_strip -else -CPPFLAGS += -g3 -LDFLAGS += -Wl,--gc-sections -endif - -ASFLAGS += -Wa,--noexecstack,-gdwarf - -# TODO: link-time optimization. - -# Warnings - -# TODO: -# -fsanitize=undefined \ -# -fsized-deallocation \ -# -Wconversion \ -# -Weverything -Wpessimizing-move, etc. \ -# -Wnormalized \ -# -Wmisleading-indentation \ -# -Wsign-conversion\ -# -Wsized-deallocation \ -# -Wstack-usage=n \ -# -Wsuggest-attribute \ -# -Wsuggest-final-types \ -# -Wsuggest-final-methods \ -# -Wsuggest-override \ -# -Wstrict-overflow=5 \ -# -Wzero-as-null-pointer-constant \ - -# TODO: clang-specific warnings - -# TODO (not in clang): -# -Wlogical-op \ -# -Wmaybe-uninitialized \ -# -Wtrampolines \ -# -Wunsafe-loop-optimizations \ - -# TODO (GCC 4.9+): -# -Wconditionally-supported -# -Wdate-time - -CPPFLAGS += \ - -pedantic -pedantic-errors \ - \ - -Wall -Werror \ - -Wextra \ - \ - -Wcast-align \ - -Wcast-qual \ - -Wenum-compare \ - -Wfloat-equal \ - -Wformat=2 \ - -Winline \ - -Winvalid-pch \ - -Wmissing-declarations \ - -Wmissing-field-initializers \ - -Wmissing-include-dirs \ - -Wredundant-decls \ - -Wshadow \ - -Wsign-compare \ - -Wundef \ - -Wuninitialized \ - -Wwrite-strings \ - $(NULL) - -# XXX: Stack protector causes linking failures for armv7-*-none-eabi and -# it's use seems questionable for that kind of target anyway. -# The launchpad.net arm-none-eabi-gcc toolchain (at least) uses -fshort-enums. -ifneq ($(filter-out none redox,$(TARGET_SYS)),) - CPPFLAGS += -fstack-protector -endif - - -# TODO (not in clang): -# -Wjump-misses-init -# -Wold-style-declaration \ -# -Wold-style-definition -CFLAGS += \ - -Wbad-function-cast \ - -Wmissing-field-initializers \ - -Wmissing-prototypes \ - -Wnested-externs \ - -Wstrict-prototypes \ - $(NULL) - -CMAKE_BUILD_TYPE ?= RELWITHDEBINFO - -# Although we don't use CMake, we use a variable CMAKE_BUILD_TYPE with similar -# semantics to the CMake variable of that name. -ifeq ($(CMAKE_BUILD_TYPE),MINSIZEREL) -CPPFLAGS += -DNDEBUG -Os -else ifeq ($(CMAKE_BUILD_TYPE),RELEASE) -CPPFLAGS += -DNDEBUG -O3 -else ifeq ($(CMAKE_BUILD_TYPE),RELWITHDEBINFO) -CPPFLAGS += -DNDEBUG -O3 -else ifeq ($(CMAKE_BUILD_TYPE),DEBUG) -# Do nothing -# TODO: CPPFLAGS += -Og, but that is only supported with GCC. -else -$(error invalid value for CMAKE_BUILD_TYPE: $(CMAKE_BUILD_TYPE)) -endif From 7787e36d43a36cd6a1c51fe498668795d1053b20 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 7 Feb 2017 23:34:29 +0100 Subject: [PATCH 4/5] Add logic to only run the build script if anything has changed * Track all source, header and make files I agree to license my contributions to each file under the terms given at the top of each file I changed. --- build.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/build.rs b/build.rs index 0d47b990eb..39f6a08830 100644 --- a/build.rs +++ b/build.rs @@ -455,6 +455,7 @@ fn build_unix(target_info: &TargetInfo, out_dir: PathBuf) { "stdc++" }; println!("cargo:rustc-flags=-l dylib={}", libcxx); + print_rerun(); } @@ -688,3 +689,22 @@ fn walk_dir(dir: &Path, cb: &F) } } } + +fn print_rerun() { + for s in RING_ARM_SHARED_SRCS.iter() + .chain(RING_SRC.iter()) + .chain(RING_TEST_SRCS.iter()) + .chain(RING_AARCH64_SRCS.iter()) + .chain(RING_ARM_SRCS.iter()) + .chain(RING_X86_64_SRC.iter()) + .chain(RING_X86_SRCS.iter()) + .chain(RING_INTEL_SHARED_SRCS.iter()) + .chain(RING_PPC_SRCS.iter()) + .chain(RING_HEADERS.iter()) + .chain(RING_TEST_HEADERS.iter()) + .chain(RING_PERL_INCLUDES.iter()) + .chain(RING_INLINE_FILES.iter()) { + println!("cargo:rerun-if-changed={}", s); + } + println!("cargo:rerun-if-changed=build.rs"); +} From 1d2939fdb23b6eb2f44119b55831cd287377db91 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 16 Feb 2017 19:09:22 +0100 Subject: [PATCH 5/5] Minor build script improvements I agree to license my contributions to each file under the terms given at the top of each file I changed. --- Cargo.toml | 5 ++++- build.rs | 29 +++++++++++++++++++---------- mk/travis.sh | 1 - 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1a284abada..36e2e47cad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -270,8 +270,11 @@ libc = "0.2.20" untrusted = "0.3.2" [build-dependencies] +# we do not use the gcc parallel feature because we do the +# parallelism ourself. This gives us a much higher level of +# control about what should be parallised in which way gcc = "0.3" -target_build_utils = "0.2" +target_build_utils = { version = "0.2", default-features = false } rayon = "0.6" [target.'cfg(any(target_os = "redox", all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies] diff --git a/build.rs b/build.rs index 39f6a08830..36ff5bfe7f 100644 --- a/build.rs +++ b/build.rs @@ -15,7 +15,6 @@ // TODO: Deny `unused_qualifications` after // https://github.com/rust-lang/rust/issues/37345 is fixed. #![allow( -// TODO missing_docs, unused_qualifications)] #![deny( @@ -237,13 +236,14 @@ const RING_BUILD_FILE: &'static [&'static str] = &["build.rs"]; #[cfg_attr(rustfmt, rustfmt_skip)] const C_FLAGS: &'static [&'static str] = - &["-std=c1x", + &["-std=c1x", // GCC 4.6 requires "c1x" instead of "c11" "-Wbad-function-cast", "-Wmissing-field-initializers", "-Wmissing-prototypes", "-Wnested-externs", "-Wstrict-prototypes"]; +// GCC 4.6 requires "c++0x" instead of "c++11" const CXX_FLAGS: &'static [&'static str] = &["-std=c++0x"]; #[cfg_attr(rustfmt, rustfmt_skip)] @@ -465,6 +465,7 @@ fn build_library

(target: &Path, additional: P, header_changed: bool) where P: ParallelIterator { + // Compile all the (dirty) source files into object files. let objs = additional.chain(lib_src.par_iter().map(|a| String::from(*a))) .weight_max() .map(|f| compile(&f, &target_info, out_dir.clone(), header_changed)) @@ -474,6 +475,8 @@ fn build_library

(target: &Path, additional: P, a.extend(b.into_iter()); a }); + + //Rebuild the library if necessary. if objs.par_iter() .map(|f| Path::new(f)) .any(|p| need_run(&p, target)) { @@ -519,14 +522,6 @@ fn compile(file: &str, target_info: &TargetInfo, mut out_dir: PathBuf, for f in CXX_FLAGS { let _ = c.flag(f); } - if target_info.target_os() != "none" { - let _ = c.flag("-fstack-protector"); - } - let _ = match (target_info.target_os(), - target_info.target_arch()) { - ("macos", _) => c.flag("-gfull"), - _ => c.flag("-g3"), - }; let _ = c.cpp(true); }, Some(Some("S")) => {}, @@ -535,6 +530,20 @@ fn compile(file: &str, target_info: &TargetInfo, mut out_dir: PathBuf, for f in CPP_FLAGS { let _ = c.flag(&f); } + if target_info.target_os() != "none" && + target_info.target_os() != "redox" { + let _ = c.flag("-fstack-protector"); + } + let _ = match (target_info.target_os(), target_info.target_arch()) { + // ``-gfull`` is required for Darwin's |-dead_strip|. + ("macos", _) => c.flag("-gfull"), + _ => c.flag("-g3"), + }; + if env::var("OPT_LEVEL").unwrap() == "0" { + let _ = c.define("DEBUG", None); + } else { + let _ = c.define("NDEBUG", None); + } let mut c = c.get_compiler().to_command(); let _ = c.arg("-c") .arg("-o") diff --git a/mk/travis.sh b/mk/travis.sh index d8ec8751b3..460903ff47 100755 --- a/mk/travis.sh +++ b/mk/travis.sh @@ -62,7 +62,6 @@ fi $CC_X --version $CXX_X --version -make --version cargo version rustc --version