build.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. // Copyright 2015-2016 Brian Smith.
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  10. // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. //! Build the non-Rust components.
  15. // It seems like it would be a good idea to use `log!` for logging, but it
  16. // isn't worth having the external dependencies (one for the `log` crate, and
  17. // another for the concrete logging implementation). Instead we use `eprintln!`
  18. // to log everything to stderr.
  19. // In the `pregenerate_asm_main()` case we don't want to access (Cargo)
  20. // environment variables at all, so avoid `use std::env` here.
  21. use std::{
  22. fs::{self, DirEntry},
  23. path::{Path, PathBuf},
  24. process::Command,
  25. time::SystemTime,
  26. };
  27. const X86: &str = "x86";
  28. const X86_64: &str = "x86_64";
  29. const AARCH64: &str = "aarch64";
  30. const ARM: &str = "arm";
  31. #[rustfmt::skip]
  32. const RING_SRCS: &[(&[&str], &str)] = &[
  33. (&[], "crypto/fipsmodule/aes/aes_nohw.c"),
  34. (&[], "crypto/fipsmodule/bn/montgomery.c"),
  35. (&[], "crypto/fipsmodule/bn/montgomery_inv.c"),
  36. (&[], "crypto/limbs/limbs.c"),
  37. (&[], "crypto/mem.c"),
  38. (&[], "crypto/poly1305/poly1305.c"),
  39. (&[AARCH64, ARM, X86_64, X86], "crypto/crypto.c"),
  40. (&[AARCH64, ARM, X86_64, X86], "crypto/curve25519/curve25519.c"),
  41. (&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/ecp_nistz.c"),
  42. (&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/ecp_nistz256.c"),
  43. (&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/gfp_p256.c"),
  44. (&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/gfp_p384.c"),
  45. (&[X86_64, X86], "crypto/cpu-intel.c"),
  46. (&[X86], "crypto/fipsmodule/aes/asm/aesni-x86.pl"),
  47. (&[X86], "crypto/fipsmodule/aes/asm/vpaes-x86.pl"),
  48. (&[X86], "crypto/fipsmodule/bn/asm/x86-mont.pl"),
  49. (&[X86], "crypto/chacha/asm/chacha-x86.pl"),
  50. (&[X86], "crypto/fipsmodule/ec/asm/ecp_nistz256-x86.pl"),
  51. (&[X86], "crypto/fipsmodule/modes/asm/ghash-x86.pl"),
  52. (&[X86_64], "crypto/fipsmodule/aes/asm/aesni-x86_64.pl"),
  53. (&[X86_64], "crypto/fipsmodule/aes/asm/vpaes-x86_64.pl"),
  54. (&[X86_64], "crypto/fipsmodule/bn/asm/x86_64-mont.pl"),
  55. (&[X86_64], "crypto/fipsmodule/bn/asm/x86_64-mont5.pl"),
  56. (&[X86_64], "crypto/chacha/asm/chacha-x86_64.pl"),
  57. (&[X86_64], "crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl"),
  58. (&[X86_64], "crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl"),
  59. (&[X86_64], "crypto/fipsmodule/modes/asm/ghash-x86_64.pl"),
  60. (&[X86_64], "crypto/poly1305/poly1305_vec.c"),
  61. (&[X86_64], SHA512_X86_64),
  62. (&[X86_64], "crypto/cipher_extra/asm/chacha20_poly1305_x86_64.pl"),
  63. (&[AARCH64, ARM], "crypto/fipsmodule/aes/asm/aesv8-armx.pl"),
  64. (&[AARCH64, ARM], "crypto/fipsmodule/modes/asm/ghashv8-armx.pl"),
  65. (&[ARM], "crypto/fipsmodule/aes/asm/bsaes-armv7.pl"),
  66. (&[ARM], "crypto/fipsmodule/aes/asm/vpaes-armv7.pl"),
  67. (&[ARM], "crypto/fipsmodule/bn/asm/armv4-mont.pl"),
  68. (&[ARM], "crypto/chacha/asm/chacha-armv4.pl"),
  69. (&[ARM], "crypto/curve25519/asm/x25519-asm-arm.S"),
  70. (&[ARM], "crypto/fipsmodule/ec/asm/ecp_nistz256-armv4.pl"),
  71. (&[ARM], "crypto/fipsmodule/modes/asm/ghash-armv4.pl"),
  72. (&[ARM], "crypto/poly1305/poly1305_arm.c"),
  73. (&[ARM], "crypto/poly1305/poly1305_arm_asm.S"),
  74. (&[ARM], "crypto/fipsmodule/sha/asm/sha256-armv4.pl"),
  75. (&[ARM], "crypto/fipsmodule/sha/asm/sha512-armv4.pl"),
  76. (&[AARCH64], "crypto/fipsmodule/aes/asm/vpaes-armv8.pl"),
  77. (&[AARCH64], "crypto/fipsmodule/bn/asm/armv8-mont.pl"),
  78. (&[AARCH64], "crypto/chacha/asm/chacha-armv8.pl"),
  79. (&[AARCH64], "crypto/fipsmodule/ec/asm/ecp_nistz256-armv8.pl"),
  80. (&[AARCH64], "crypto/fipsmodule/modes/asm/ghash-neon-armv8.pl"),
  81. (&[AARCH64], SHA512_ARMV8),
  82. ];
  83. const SHA256_X86_64: &str = "crypto/fipsmodule/sha/asm/sha256-x86_64.pl";
  84. const SHA512_X86_64: &str = "crypto/fipsmodule/sha/asm/sha512-x86_64.pl";
  85. const SHA256_ARMV8: &str = "crypto/fipsmodule/sha/asm/sha256-armv8.pl";
  86. const SHA512_ARMV8: &str = "crypto/fipsmodule/sha/asm/sha512-armv8.pl";
  87. const RING_TEST_SRCS: &[&str] = &[("crypto/constant_time_test.c")];
  88. #[rustfmt::skip]
  89. const RING_INCLUDES: &[&str] =
  90. &[
  91. "crypto/curve25519/curve25519_tables.h",
  92. "crypto/curve25519/internal.h",
  93. "crypto/fipsmodule/bn/internal.h",
  94. "crypto/fipsmodule/ec/ecp_nistz256_table.inl",
  95. "crypto/fipsmodule/ec/ecp_nistz384.inl",
  96. "crypto/fipsmodule/ec/ecp_nistz.h",
  97. "crypto/fipsmodule/ec/ecp_nistz384.h",
  98. "crypto/fipsmodule/ec/ecp_nistz256.h",
  99. "crypto/internal.h",
  100. "crypto/limbs/limbs.h",
  101. "crypto/limbs/limbs.inl",
  102. "crypto/poly1305/internal.h",
  103. "include/GFp/aes.h",
  104. "include/GFp/arm_arch.h",
  105. "include/GFp/base.h",
  106. "include/GFp/check.h",
  107. "include/GFp/cpu.h",
  108. "include/GFp/mem.h",
  109. "include/GFp/poly1305.h",
  110. "include/GFp/type_check.h",
  111. "third_party/fiat/curve25519_32.h",
  112. "third_party/fiat/curve25519_64.h",
  113. ];
  114. #[rustfmt::skip]
  115. const RING_PERL_INCLUDES: &[&str] =
  116. &["crypto/perlasm/arm-xlate.pl",
  117. "crypto/perlasm/x86gas.pl",
  118. "crypto/perlasm/x86nasm.pl",
  119. "crypto/perlasm/x86asm.pl",
  120. "crypto/perlasm/x86_64-xlate.pl"];
  121. const RING_BUILD_FILE: &[&str] = &["build.rs"];
  122. const PREGENERATED: &str = "pregenerated";
  123. fn c_flags(target: &Target) -> &'static [&'static str] {
  124. if target.env != MSVC {
  125. static NON_MSVC_FLAGS: &[&str] = &[
  126. "-std=c1x", // GCC 4.6 requires "c1x" instead of "c11"
  127. "-Wbad-function-cast",
  128. "-Wnested-externs",
  129. "-Wstrict-prototypes",
  130. ];
  131. NON_MSVC_FLAGS
  132. } else {
  133. &[]
  134. }
  135. }
  136. fn cpp_flags(target: &Target) -> &'static [&'static str] {
  137. if target.env != MSVC {
  138. static NON_MSVC_FLAGS: &[&str] = &[
  139. "-pedantic",
  140. "-pedantic-errors",
  141. "-Wall",
  142. "-Wextra",
  143. "-Wcast-align",
  144. "-Wcast-qual",
  145. "-Wconversion",
  146. "-Wenum-compare",
  147. "-Wfloat-equal",
  148. "-Wformat=2",
  149. "-Winline",
  150. "-Winvalid-pch",
  151. "-Wmissing-field-initializers",
  152. "-Wmissing-include-dirs",
  153. "-Wredundant-decls",
  154. "-Wshadow",
  155. "-Wsign-compare",
  156. "-Wsign-conversion",
  157. "-Wundef",
  158. "-Wuninitialized",
  159. "-Wwrite-strings",
  160. "-fno-strict-aliasing",
  161. "-fvisibility=hidden",
  162. ];
  163. NON_MSVC_FLAGS
  164. } else {
  165. static MSVC_FLAGS: &[&str] = &[
  166. "/GS", // Buffer security checks.
  167. "/Gy", // Enable function-level linking.
  168. "/EHsc", // C++ exceptions only, only in C++.
  169. "/GR-", // Disable RTTI.
  170. "/Zc:wchar_t",
  171. "/Zc:forScope",
  172. "/Zc:inline",
  173. "/Zc:rvalueCast",
  174. // Warnings.
  175. "/sdl",
  176. "/Wall",
  177. "/wd4127", // C4127: conditional expression is constant
  178. "/wd4464", // C4464: relative include path contains '..'
  179. "/wd4514", // C4514: <name>: unreferenced inline function has be
  180. "/wd4710", // C4710: function not inlined
  181. "/wd4711", // C4711: function 'function' selected for inline expansion
  182. "/wd4820", // C4820: <struct>: <n> bytes padding added after <name>
  183. "/wd5045", /* C5045: Compiler will insert Spectre mitigation for memory load if
  184. * /Qspectre switch specified */
  185. ];
  186. MSVC_FLAGS
  187. }
  188. }
  189. const LD_FLAGS: &[&str] = &[];
  190. // None means "any OS" or "any target". The first match in sequence order is
  191. // taken.
  192. const ASM_TARGETS: &[(&str, Option<&str>, Option<&str>)] = &[
  193. ("x86_64", Some("ios"), Some("macosx")),
  194. ("x86_64", Some("macos"), Some("macosx")),
  195. ("x86_64", Some(WINDOWS), Some("nasm")),
  196. ("x86_64", None, Some("elf")),
  197. ("aarch64", Some("ios"), Some("ios64")),
  198. ("aarch64", Some("macos"), Some("ios64")),
  199. ("aarch64", None, Some("linux64")),
  200. ("x86", Some(WINDOWS), Some("win32n")),
  201. ("x86", Some("ios"), Some("macosx")),
  202. ("x86", None, Some("elf")),
  203. ("arm", Some("ios"), Some("ios32")),
  204. ("arm", None, Some("linux32")),
  205. ("wasm32", None, None),
  206. ];
  207. const WINDOWS: &str = "windows";
  208. const MSVC: &str = "msvc";
  209. const MSVC_OBJ_OPT: &str = "/Fo";
  210. const MSVC_OBJ_EXT: &str = "obj";
  211. fn main() {
  212. if let Ok(package_name) = std::env::var("CARGO_PKG_NAME") {
  213. if package_name == "ring" {
  214. ring_build_rs_main();
  215. return;
  216. }
  217. }
  218. pregenerate_asm_main();
  219. }
  220. fn ring_build_rs_main() {
  221. use std::env;
  222. let out_dir = env::var("OUT_DIR").unwrap();
  223. let out_dir = PathBuf::from(out_dir);
  224. let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  225. let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  226. let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
  227. let (obj_ext, obj_opt) = if env == MSVC {
  228. (MSVC_OBJ_EXT, MSVC_OBJ_OPT)
  229. } else {
  230. ("o", "-o")
  231. };
  232. let is_git = std::fs::metadata(".git").is_ok();
  233. // Published builds are always release builds.
  234. let is_debug = is_git && env::var("DEBUG").unwrap() != "false";
  235. let target = Target {
  236. arch,
  237. os,
  238. env,
  239. obj_ext,
  240. obj_opt,
  241. is_git,
  242. is_debug,
  243. };
  244. let pregenerated = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join(PREGENERATED);
  245. build_c_code(&target, pregenerated, &out_dir);
  246. check_all_files_tracked()
  247. }
  248. fn pregenerate_asm_main() {
  249. let pregenerated = PathBuf::from(PREGENERATED);
  250. std::fs::create_dir(&pregenerated).unwrap();
  251. let pregenerated_tmp = pregenerated.join("tmp");
  252. std::fs::create_dir(&pregenerated_tmp).unwrap();
  253. for &(target_arch, target_os, perlasm_format) in ASM_TARGETS {
  254. // For Windows, package pregenerated object files instead of
  255. // pregenerated assembly language source files, so that the user
  256. // doesn't need to install the assembler.
  257. let asm_dir = if target_os == Some(WINDOWS) {
  258. &pregenerated_tmp
  259. } else {
  260. &pregenerated
  261. };
  262. if let Some(perlasm_format) = perlasm_format {
  263. let perlasm_src_dsts =
  264. perlasm_src_dsts(&asm_dir, target_arch, target_os, perlasm_format);
  265. perlasm(&perlasm_src_dsts, target_arch, perlasm_format, None);
  266. if target_os == Some(WINDOWS) {
  267. let srcs = asm_srcs(perlasm_src_dsts);
  268. for src in srcs {
  269. let obj_path = obj_path(&pregenerated, &src, MSVC_OBJ_EXT);
  270. run_command(nasm(&src, target_arch, &obj_path));
  271. }
  272. }
  273. }
  274. }
  275. }
  276. struct Target {
  277. arch: String,
  278. os: String,
  279. env: String,
  280. obj_ext: &'static str,
  281. obj_opt: &'static str,
  282. is_git: bool,
  283. is_debug: bool,
  284. }
  285. fn build_c_code(target: &Target, pregenerated: PathBuf, out_dir: &Path) {
  286. #[cfg(not(feature = "wasm32_c"))]
  287. {
  288. if &target.arch == "wasm32" {
  289. return;
  290. }
  291. }
  292. let includes_modified = RING_INCLUDES
  293. .iter()
  294. .chain(RING_BUILD_FILE.iter())
  295. .chain(RING_PERL_INCLUDES.iter())
  296. .map(|f| file_modified(Path::new(*f)))
  297. .max()
  298. .unwrap();
  299. fn is_none_or_equals<T>(opt: Option<T>, other: T) -> bool
  300. where
  301. T: PartialEq,
  302. {
  303. if let Some(value) = opt {
  304. value == other
  305. } else {
  306. true
  307. }
  308. }
  309. let (_, _, perlasm_format) = ASM_TARGETS
  310. .iter()
  311. .find(|entry| {
  312. let &(entry_arch, entry_os, _) = *entry;
  313. entry_arch == target.arch && is_none_or_equals(entry_os, &target.os)
  314. })
  315. .unwrap();
  316. let use_pregenerated = !target.is_git;
  317. let warnings_are_errors = target.is_git;
  318. let asm_dir = if use_pregenerated {
  319. &pregenerated
  320. } else {
  321. out_dir
  322. };
  323. let asm_srcs = if let Some(perlasm_format) = perlasm_format {
  324. let perlasm_src_dsts =
  325. perlasm_src_dsts(asm_dir, &target.arch, Some(&target.os), perlasm_format);
  326. if !use_pregenerated {
  327. perlasm(
  328. &perlasm_src_dsts[..],
  329. &target.arch,
  330. perlasm_format,
  331. Some(includes_modified),
  332. );
  333. }
  334. let mut asm_srcs = asm_srcs(perlasm_src_dsts);
  335. // For Windows we also pregenerate the object files for non-Git builds so
  336. // the user doesn't need to install the assembler. On other platforms we
  337. // assume the C compiler also assembles.
  338. if use_pregenerated && target.os == WINDOWS {
  339. // The pregenerated object files always use ".obj" as the extension,
  340. // even when the C/C++ compiler outputs files with the ".o" extension.
  341. asm_srcs = asm_srcs
  342. .iter()
  343. .map(|src| obj_path(&pregenerated, src.as_path(), "obj"))
  344. .collect::<Vec<_>>();
  345. }
  346. asm_srcs
  347. } else {
  348. Vec::new()
  349. };
  350. let core_srcs = sources_for_arch(&target.arch)
  351. .into_iter()
  352. .filter(|p| !is_perlasm(&p))
  353. .collect::<Vec<_>>();
  354. let test_srcs = RING_TEST_SRCS.iter().map(PathBuf::from).collect::<Vec<_>>();
  355. let libs = [
  356. ("ring-core", &core_srcs[..], &asm_srcs[..]),
  357. ("ring-test", &test_srcs[..], &[]),
  358. ];
  359. // XXX: Ideally, ring-test would only be built for `cargo test`, but Cargo
  360. // can't do that yet.
  361. libs.iter().for_each(|&(lib_name, srcs, additional_srcs)| {
  362. build_library(
  363. &target,
  364. &out_dir,
  365. lib_name,
  366. srcs,
  367. additional_srcs,
  368. warnings_are_errors,
  369. includes_modified,
  370. )
  371. });
  372. println!(
  373. "cargo:rustc-link-search=native={}",
  374. out_dir.to_str().expect("Invalid path")
  375. );
  376. }
  377. fn build_library(
  378. target: &Target,
  379. out_dir: &Path,
  380. lib_name: &str,
  381. srcs: &[PathBuf],
  382. additional_srcs: &[PathBuf],
  383. warnings_are_errors: bool,
  384. includes_modified: SystemTime,
  385. ) {
  386. // Compile all the (dirty) source files into object files.
  387. let objs = additional_srcs
  388. .iter()
  389. .chain(srcs.iter())
  390. .filter(|f| &target.env != "msvc" || f.extension().unwrap().to_str().unwrap() != "S")
  391. .map(|f| compile(f, target, warnings_are_errors, out_dir, includes_modified))
  392. .collect::<Vec<_>>();
  393. // Rebuild the library if necessary.
  394. let lib_path = PathBuf::from(out_dir).join(format!("lib{}.a", lib_name));
  395. if objs
  396. .iter()
  397. .map(Path::new)
  398. .any(|p| need_run(&p, &lib_path, includes_modified))
  399. {
  400. let mut c = cc::Build::new();
  401. for f in LD_FLAGS {
  402. let _ = c.flag(&f);
  403. }
  404. match target.os.as_str() {
  405. "macos" => {
  406. let _ = c.flag("-fPIC");
  407. let _ = c.flag("-Wl,-dead_strip");
  408. }
  409. _ => {
  410. let _ = c.flag("-Wl,--gc-sections");
  411. }
  412. }
  413. for o in objs {
  414. let _ = c.object(o);
  415. }
  416. // Handled below.
  417. let _ = c.cargo_metadata(false);
  418. c.compile(
  419. lib_path
  420. .file_name()
  421. .and_then(|f| f.to_str())
  422. .expect("No filename"),
  423. );
  424. }
  425. // Link the library. This works even when the library doesn't need to be
  426. // rebuilt.
  427. println!("cargo:rustc-link-lib=static={}", lib_name);
  428. }
  429. fn compile(
  430. p: &Path,
  431. target: &Target,
  432. warnings_are_errors: bool,
  433. out_dir: &Path,
  434. includes_modified: SystemTime,
  435. ) -> String {
  436. let ext = p.extension().unwrap().to_str().unwrap();
  437. if ext == "obj" {
  438. p.to_str().expect("Invalid path").into()
  439. } else {
  440. let mut out_path = out_dir.join(p.file_name().unwrap());
  441. assert!(out_path.set_extension(target.obj_ext));
  442. if need_run(&p, &out_path, includes_modified) {
  443. let cmd = if target.os != WINDOWS || ext != "asm" {
  444. cc(p, ext, target, warnings_are_errors, &out_path)
  445. } else {
  446. nasm(p, &target.arch, &out_path)
  447. };
  448. run_command(cmd);
  449. }
  450. out_path.to_str().expect("Invalid path").into()
  451. }
  452. }
  453. fn obj_path(out_dir: &Path, src: &Path, obj_ext: &str) -> PathBuf {
  454. let mut out_path = out_dir.join(src.file_name().unwrap());
  455. assert!(out_path.set_extension(obj_ext));
  456. out_path
  457. }
  458. fn cc(
  459. file: &Path,
  460. ext: &str,
  461. target: &Target,
  462. warnings_are_errors: bool,
  463. out_dir: &Path,
  464. ) -> Command {
  465. let is_musl = target.env.starts_with("musl");
  466. let mut c = cc::Build::new();
  467. let _ = c.include("include");
  468. match ext {
  469. "c" => {
  470. for f in c_flags(target) {
  471. let _ = c.flag(f);
  472. }
  473. }
  474. "S" => (),
  475. e => panic!("Unsupported file extension: {:?}", e),
  476. };
  477. for f in cpp_flags(target) {
  478. let _ = c.flag(&f);
  479. }
  480. if target.os != "none"
  481. && target.os != "redox"
  482. && target.os != "windows"
  483. && target.arch != "wasm32"
  484. {
  485. let _ = c.flag("-fstack-protector");
  486. }
  487. match (target.os.as_str(), target.env.as_str()) {
  488. // ``-gfull`` is required for Darwin's |-dead_strip|.
  489. ("macos", _) => {
  490. let _ = c.flag("-gfull");
  491. }
  492. (_, "msvc") => (),
  493. _ => {
  494. let _ = c.flag("-g3");
  495. }
  496. };
  497. if !target.is_debug {
  498. let _ = c.define("NDEBUG", None);
  499. }
  500. if &target.env == "msvc" {
  501. if std::env::var("OPT_LEVEL").unwrap() == "0" {
  502. let _ = c.flag("/Od"); // Disable optimization for debug builds.
  503. // run-time checking: (s)tack frame, (u)ninitialized variables
  504. let _ = c.flag("/RTCsu");
  505. } else {
  506. let _ = c.flag("/Ox"); // Enable full optimization.
  507. }
  508. }
  509. // Allow cross-compiling without a target sysroot for these targets.
  510. //
  511. // poly1305_vec.c requires <emmintrin.h> which requires <stdlib.h>.
  512. if (target.arch == "wasm32" && target.os == "unknown")
  513. || (target.os == "linux" && is_musl && target.arch != "x86_64")
  514. {
  515. if let Ok(compiler) = c.try_get_compiler() {
  516. // TODO: Expand this to non-clang compilers in 0.17.0 if practical.
  517. if compiler.is_like_clang() {
  518. let _ = c.flag("-nostdlibinc");
  519. let _ = c.define("GFp_NOSTDLIBINC", "1");
  520. }
  521. }
  522. }
  523. if warnings_are_errors {
  524. let flag = if &target.env != "msvc" {
  525. "-Werror"
  526. } else {
  527. "/WX"
  528. };
  529. let _ = c.flag(flag);
  530. }
  531. if is_musl {
  532. // Some platforms enable _FORTIFY_SOURCE by default, but musl
  533. // libc doesn't support it yet. See
  534. // http://wiki.musl-libc.org/wiki/Future_Ideas#Fortify
  535. // http://www.openwall.com/lists/musl/2015/02/04/3
  536. // http://www.openwall.com/lists/musl/2015/06/17/1
  537. let _ = c.flag("-U_FORTIFY_SOURCE");
  538. }
  539. let mut c = c.get_compiler().to_command();
  540. let _ = c
  541. .arg("-c")
  542. .arg(format!(
  543. "{}{}",
  544. target.obj_opt,
  545. out_dir.to_str().expect("Invalid path")
  546. ))
  547. .arg(file);
  548. c
  549. }
  550. fn nasm(file: &Path, arch: &str, out_file: &Path) -> Command {
  551. let oformat = match arch {
  552. "x86_64" => ("win64"),
  553. "x86" => ("win32"),
  554. _ => panic!("unsupported arch: {}", arch),
  555. };
  556. let mut c = Command::new("./target/tools/nasm");
  557. let _ = c
  558. .arg("-o")
  559. .arg(out_file.to_str().expect("Invalid path"))
  560. .arg("-f")
  561. .arg(oformat)
  562. .arg("-Xgnu")
  563. .arg("-gcv8")
  564. .arg(file);
  565. c
  566. }
  567. fn run_command_with_args<S>(command_name: S, args: &[String])
  568. where
  569. S: AsRef<std::ffi::OsStr> + Copy,
  570. {
  571. let mut cmd = Command::new(command_name);
  572. let _ = cmd.args(args);
  573. run_command(cmd)
  574. }
  575. fn run_command(mut cmd: Command) {
  576. eprintln!("running {:?}", cmd);
  577. let status = cmd.status().unwrap_or_else(|e| {
  578. panic!("failed to execute [{:?}]: {}", cmd, e);
  579. });
  580. if !status.success() {
  581. panic!("execution failed");
  582. }
  583. }
  584. fn sources_for_arch(arch: &str) -> Vec<PathBuf> {
  585. RING_SRCS
  586. .iter()
  587. .filter(|&&(archs, _)| archs.is_empty() || archs.contains(&arch))
  588. .map(|&(_, p)| PathBuf::from(p))
  589. .collect::<Vec<_>>()
  590. }
  591. fn perlasm_src_dsts(
  592. out_dir: &Path,
  593. arch: &str,
  594. os: Option<&str>,
  595. perlasm_format: &str,
  596. ) -> Vec<(PathBuf, PathBuf)> {
  597. let srcs = sources_for_arch(arch);
  598. let mut src_dsts = srcs
  599. .iter()
  600. .filter(|p| is_perlasm(p))
  601. .map(|src| (src.clone(), asm_path(out_dir, src, os, perlasm_format)))
  602. .collect::<Vec<_>>();
  603. // Some PerlAsm source files need to be run multiple times with different
  604. // output paths.
  605. {
  606. // Appease the borrow checker.
  607. let mut maybe_synthesize = |concrete, synthesized| {
  608. let concrete_path = PathBuf::from(concrete);
  609. if srcs.contains(&concrete_path) {
  610. let synthesized_path = PathBuf::from(synthesized);
  611. src_dsts.push((
  612. concrete_path,
  613. asm_path(out_dir, &synthesized_path, os, perlasm_format),
  614. ))
  615. }
  616. };
  617. maybe_synthesize(SHA512_X86_64, SHA256_X86_64);
  618. maybe_synthesize(SHA512_ARMV8, SHA256_ARMV8);
  619. }
  620. src_dsts
  621. }
  622. fn asm_srcs(perlasm_src_dsts: Vec<(PathBuf, PathBuf)>) -> Vec<PathBuf> {
  623. perlasm_src_dsts
  624. .into_iter()
  625. .map(|(_src, dst)| dst)
  626. .collect::<Vec<_>>()
  627. }
  628. fn is_perlasm(path: &PathBuf) -> bool {
  629. path.extension().unwrap().to_str().unwrap() == "pl"
  630. }
  631. fn asm_path(out_dir: &Path, src: &Path, os: Option<&str>, perlasm_format: &str) -> PathBuf {
  632. let src_stem = src.file_stem().expect("source file without basename");
  633. let dst_stem = src_stem.to_str().unwrap();
  634. let dst_extension = if os == Some("windows") { "asm" } else { "S" };
  635. let dst_filename = format!("{}-{}.{}", dst_stem, perlasm_format, dst_extension);
  636. out_dir.join(dst_filename)
  637. }
  638. fn perlasm(
  639. src_dst: &[(PathBuf, PathBuf)],
  640. arch: &str,
  641. perlasm_format: &str,
  642. includes_modified: Option<SystemTime>,
  643. ) {
  644. for (src, dst) in src_dst {
  645. if let Some(includes_modified) = includes_modified {
  646. if !need_run(src, dst, includes_modified) {
  647. continue;
  648. }
  649. }
  650. let mut args = Vec::<String>::new();
  651. args.push(src.to_string_lossy().into_owned());
  652. args.push(perlasm_format.to_owned());
  653. if arch == "x86" {
  654. args.push("-fPIC".into());
  655. args.push("-DOPENSSL_IA32_SSE2".into());
  656. }
  657. // Work around PerlAsm issue for ARM and AAarch64 targets by replacing
  658. // back slashes with forward slashes.
  659. let dst = dst
  660. .to_str()
  661. .expect("Could not convert path")
  662. .replace("\\", "/");
  663. args.push(dst);
  664. run_command_with_args(&get_command("PERL_EXECUTABLE", "perl"), &args);
  665. }
  666. }
  667. fn need_run(source: &Path, target: &Path, includes_modified: SystemTime) -> bool {
  668. let s_modified = file_modified(source);
  669. if let Ok(target_metadata) = std::fs::metadata(target) {
  670. let target_modified = target_metadata.modified().unwrap();
  671. s_modified >= target_modified || includes_modified >= target_modified
  672. } else {
  673. // On error fetching metadata for the target file, assume the target
  674. // doesn't exist.
  675. true
  676. }
  677. }
  678. fn file_modified(path: &Path) -> SystemTime {
  679. let path = Path::new(path);
  680. let path_as_str = format!("{:?}", path);
  681. std::fs::metadata(path)
  682. .expect(&path_as_str)
  683. .modified()
  684. .expect("nah")
  685. }
  686. fn get_command(var: &str, default: &str) -> String {
  687. std::env::var(var).unwrap_or_else(|_| default.into())
  688. }
  689. fn check_all_files_tracked() {
  690. for path in &["crypto", "include", "third_party/fiat"] {
  691. walk_dir(&PathBuf::from(path), &is_tracked);
  692. }
  693. }
  694. fn is_tracked(file: &DirEntry) {
  695. let p = file.path();
  696. let cmp = |f| p == PathBuf::from(f);
  697. let tracked = match p.extension().and_then(|p| p.to_str()) {
  698. Some("h") | Some("inl") => RING_INCLUDES.iter().any(cmp),
  699. Some("c") | Some("S") | Some("asm") => {
  700. RING_SRCS.iter().any(|(_, f)| cmp(f)) || RING_TEST_SRCS.iter().any(cmp)
  701. }
  702. Some("pl") => RING_SRCS.iter().any(|(_, f)| cmp(f)) || RING_PERL_INCLUDES.iter().any(cmp),
  703. _ => true,
  704. };
  705. if !tracked {
  706. panic!("{:?} is not tracked in build.rs", p);
  707. }
  708. }
  709. fn walk_dir<F>(dir: &Path, cb: &F)
  710. where
  711. F: Fn(&DirEntry),
  712. {
  713. if dir.is_dir() {
  714. for entry in fs::read_dir(dir).unwrap() {
  715. let entry = entry.unwrap();
  716. let path = entry.path();
  717. if path.is_dir() {
  718. walk_dir(&path, cb);
  719. } else {
  720. cb(&entry);
  721. }
  722. }
  723. }
  724. }