build.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. use std::env;
  2. fn main() {
  3. println!("cargo:rerun-if-changed=build.rs");
  4. let target = env::var("TARGET").unwrap();
  5. let cwd = env::current_dir().unwrap();
  6. println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display());
  7. // Activate libm's unstable features to make full use of Nightly.
  8. println!("cargo:rustc-cfg=feature=\"unstable\"");
  9. // Emscripten's runtime includes all the builtins
  10. if target.contains("emscripten") {
  11. return;
  12. }
  13. // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source
  14. if target.contains("openbsd") {
  15. println!("cargo:rustc-link-search=native=/usr/lib");
  16. println!("cargo:rustc-link-lib=compiler_rt");
  17. return;
  18. }
  19. // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to
  20. // provide them.
  21. if (target.contains("wasm") && !target.contains("wasi"))
  22. || (target.contains("sgx") && target.contains("fortanix"))
  23. || target.contains("-none")
  24. || target.contains("nvptx")
  25. {
  26. println!("cargo:rustc-cfg=feature=\"mem\"");
  27. }
  28. // These targets have hardware unaligned access support.
  29. if target.contains("x86_64")
  30. || target.contains("i686")
  31. || target.contains("aarch64")
  32. || target.contains("bpf")
  33. {
  34. println!("cargo:rustc-cfg=feature=\"mem-unaligned\"");
  35. }
  36. // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the
  37. // target triple. This is usually correct for our built-in targets but can break in presence of
  38. // custom targets, which can have arbitrary names.
  39. let llvm_target = target.split('-').collect::<Vec<_>>();
  40. // Build missing intrinsics from compiler-rt C source code. If we're
  41. // mangling names though we assume that we're also in test mode so we don't
  42. // build anything and we rely on the upstream implementation of compiler-rt
  43. // functions
  44. if !cfg!(feature = "mangled-names") && cfg!(feature = "c") {
  45. // Don't use a C compiler for these targets:
  46. //
  47. // * wasm - clang for wasm is somewhat hard to come by and it's
  48. // unlikely that the C is really that much better than our own Rust.
  49. // * nvptx - everything is bitcode, not compatible with mixed C/Rust
  50. // * riscv - the rust-lang/rust distribution container doesn't have a C
  51. // compiler nor is cc-rs ready for compilation to riscv (at this
  52. // time). This can probably be removed in the future
  53. if !target.contains("wasm") && !target.contains("nvptx") && !target.starts_with("riscv") {
  54. #[cfg(feature = "c")]
  55. c::compile(&llvm_target, &target);
  56. }
  57. }
  58. // To compile intrinsics.rs for thumb targets, where there is no libc
  59. if llvm_target[0].starts_with("thumb") {
  60. println!("cargo:rustc-cfg=thumb")
  61. }
  62. // compiler-rt `cfg`s away some intrinsics for thumbv6m and thumbv8m.base because
  63. // these targets do not have full Thumb-2 support but only original Thumb-1.
  64. // We have to cfg our code accordingly.
  65. if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" {
  66. println!("cargo:rustc-cfg=thumb_1")
  67. }
  68. // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This
  69. // includes the old androideabi. It is deprecated but it is available as a
  70. // rustc target (arm-linux-androideabi).
  71. if llvm_target[0] == "armv4t"
  72. || llvm_target[0] == "armv5te"
  73. || llvm_target.get(2) == Some(&"androideabi")
  74. {
  75. println!("cargo:rustc-cfg=kernel_user_helpers")
  76. }
  77. }
  78. #[cfg(feature = "c")]
  79. mod c {
  80. extern crate cc;
  81. use std::collections::{BTreeMap, HashSet};
  82. use std::env;
  83. use std::fs::File;
  84. use std::io::Write;
  85. use std::path::{Path, PathBuf};
  86. struct Sources {
  87. // SYMBOL -> PATH TO SOURCE
  88. map: BTreeMap<&'static str, &'static str>,
  89. }
  90. impl Sources {
  91. fn new() -> Sources {
  92. Sources {
  93. map: BTreeMap::new(),
  94. }
  95. }
  96. fn extend(&mut self, sources: &[(&'static str, &'static str)]) {
  97. // NOTE Some intrinsics have both a generic implementation (e.g.
  98. // `floatdidf.c`) and an arch optimized implementation
  99. // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized
  100. // implementation and discard the generic implementation. If we don't
  101. // and keep both implementations, the linker will yell at us about
  102. // duplicate symbols!
  103. for (symbol, src) in sources {
  104. if src.contains("/") {
  105. // Arch-optimized implementation (preferred)
  106. self.map.insert(symbol, src);
  107. } else {
  108. // Generic implementation
  109. if !self.map.contains_key(symbol) {
  110. self.map.insert(symbol, src);
  111. }
  112. }
  113. }
  114. }
  115. fn remove(&mut self, symbols: &[&str]) {
  116. for symbol in symbols {
  117. self.map.remove(*symbol).unwrap();
  118. }
  119. }
  120. }
  121. /// Compile intrinsics from the compiler-rt C source code
  122. pub fn compile(llvm_target: &[&str], target: &String) {
  123. let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  124. let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
  125. let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  126. let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
  127. let mut consider_float_intrinsics = true;
  128. let cfg = &mut cc::Build::new();
  129. // AArch64 GCCs exit with an error condition when they encounter any kind of floating point
  130. // code if the `nofp` and/or `nosimd` compiler flags have been set.
  131. //
  132. // Therefore, evaluate if those flags are present and set a boolean that causes any
  133. // compiler-rt intrinsics that contain floating point source to be excluded for this target.
  134. if target_arch == "aarch64" {
  135. let cflags_key = String::from("CFLAGS_") + &(target.to_owned().replace("-", "_"));
  136. if let Ok(cflags_value) = env::var(cflags_key) {
  137. if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") {
  138. consider_float_intrinsics = false;
  139. }
  140. }
  141. }
  142. cfg.warnings(false);
  143. if target_env == "msvc" {
  144. // Don't pull in extra libraries on MSVC
  145. cfg.flag("/Zl");
  146. // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
  147. cfg.define("__func__", Some("__FUNCTION__"));
  148. } else {
  149. // Turn off various features of gcc and such, mostly copying
  150. // compiler-rt's build system already
  151. cfg.flag("-fno-builtin");
  152. cfg.flag("-fvisibility=hidden");
  153. cfg.flag("-ffreestanding");
  154. // Avoid the following warning appearing once **per file**:
  155. // clang: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument]
  156. //
  157. // Note that compiler-rt's build system also checks
  158. //
  159. // `check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)`
  160. //
  161. // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19.
  162. cfg.flag_if_supported("-fomit-frame-pointer");
  163. cfg.define("VISIBILITY_HIDDEN", None);
  164. }
  165. let mut sources = Sources::new();
  166. sources.extend(&[
  167. ("__absvdi2", "absvdi2.c"),
  168. ("__absvsi2", "absvsi2.c"),
  169. ("__addvdi3", "addvdi3.c"),
  170. ("__addvsi3", "addvsi3.c"),
  171. ("apple_versioning", "apple_versioning.c"),
  172. ("__clzdi2", "clzdi2.c"),
  173. ("__clzsi2", "clzsi2.c"),
  174. ("__cmpdi2", "cmpdi2.c"),
  175. ("__ctzdi2", "ctzdi2.c"),
  176. ("__ctzsi2", "ctzsi2.c"),
  177. ("__int_util", "int_util.c"),
  178. ("__mulvdi3", "mulvdi3.c"),
  179. ("__mulvsi3", "mulvsi3.c"),
  180. ("__negdi2", "negdi2.c"),
  181. ("__negvdi2", "negvdi2.c"),
  182. ("__negvsi2", "negvsi2.c"),
  183. ("__paritydi2", "paritydi2.c"),
  184. ("__paritysi2", "paritysi2.c"),
  185. ("__popcountdi2", "popcountdi2.c"),
  186. ("__popcountsi2", "popcountsi2.c"),
  187. ("__subvdi3", "subvdi3.c"),
  188. ("__subvsi3", "subvsi3.c"),
  189. ("__ucmpdi2", "ucmpdi2.c"),
  190. ]);
  191. if consider_float_intrinsics {
  192. sources.extend(&[
  193. ("__divdc3", "divdc3.c"),
  194. ("__divsc3", "divsc3.c"),
  195. ("__divxc3", "divxc3.c"),
  196. ("__extendhfsf2", "extendhfsf2.c"),
  197. ("__muldc3", "muldc3.c"),
  198. ("__mulsc3", "mulsc3.c"),
  199. ("__mulxc3", "mulxc3.c"),
  200. ("__negdf2", "negdf2.c"),
  201. ("__negsf2", "negsf2.c"),
  202. ("__powixf2", "powixf2.c"),
  203. ("__truncdfhf2", "truncdfhf2.c"),
  204. ("__truncdfsf2", "truncdfsf2.c"),
  205. ("__truncsfhf2", "truncsfhf2.c"),
  206. ]);
  207. }
  208. // When compiling in rustbuild (the rust-lang/rust repo) this library
  209. // also needs to satisfy intrinsics that jemalloc or C in general may
  210. // need, so include a few more that aren't typically needed by
  211. // LLVM/Rust.
  212. if cfg!(feature = "rustbuild") {
  213. sources.extend(&[("__ffsdi2", "ffsdi2.c")]);
  214. }
  215. // On iOS and 32-bit OSX these are all just empty intrinsics, no need to
  216. // include them.
  217. if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") {
  218. sources.extend(&[
  219. ("__absvti2", "absvti2.c"),
  220. ("__addvti3", "addvti3.c"),
  221. ("__clzti2", "clzti2.c"),
  222. ("__cmpti2", "cmpti2.c"),
  223. ("__ctzti2", "ctzti2.c"),
  224. ("__ffsti2", "ffsti2.c"),
  225. ("__mulvti3", "mulvti3.c"),
  226. ("__negti2", "negti2.c"),
  227. ("__parityti2", "parityti2.c"),
  228. ("__popcountti2", "popcountti2.c"),
  229. ("__subvti3", "subvti3.c"),
  230. ("__ucmpti2", "ucmpti2.c"),
  231. ]);
  232. if consider_float_intrinsics {
  233. sources.extend(&[("__negvti2", "negvti2.c")]);
  234. }
  235. }
  236. if target_vendor == "apple" {
  237. sources.extend(&[
  238. ("atomic_flag_clear", "atomic_flag_clear.c"),
  239. ("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"),
  240. ("atomic_flag_test_and_set", "atomic_flag_test_and_set.c"),
  241. (
  242. "atomic_flag_test_and_set_explicit",
  243. "atomic_flag_test_and_set_explicit.c",
  244. ),
  245. ("atomic_signal_fence", "atomic_signal_fence.c"),
  246. ("atomic_thread_fence", "atomic_thread_fence.c"),
  247. ]);
  248. }
  249. if target_env == "msvc" {
  250. if target_arch == "x86_64" {
  251. sources.extend(&[
  252. ("__floatdisf", "x86_64/floatdisf.c"),
  253. ("__floatdixf", "x86_64/floatdixf.c"),
  254. ]);
  255. }
  256. } else {
  257. // None of these seem to be used on x86_64 windows, and they've all
  258. // got the wrong ABI anyway, so we want to avoid them.
  259. if target_os != "windows" {
  260. if target_arch == "x86_64" {
  261. sources.extend(&[
  262. ("__floatdisf", "x86_64/floatdisf.c"),
  263. ("__floatdixf", "x86_64/floatdixf.c"),
  264. ("__floatundidf", "x86_64/floatundidf.S"),
  265. ("__floatundisf", "x86_64/floatundisf.S"),
  266. ("__floatundixf", "x86_64/floatundixf.S"),
  267. ]);
  268. }
  269. }
  270. if target_arch == "x86" {
  271. sources.extend(&[
  272. ("__ashldi3", "i386/ashldi3.S"),
  273. ("__ashrdi3", "i386/ashrdi3.S"),
  274. ("__divdi3", "i386/divdi3.S"),
  275. ("__floatdidf", "i386/floatdidf.S"),
  276. ("__floatdisf", "i386/floatdisf.S"),
  277. ("__floatdixf", "i386/floatdixf.S"),
  278. ("__floatundidf", "i386/floatundidf.S"),
  279. ("__floatundisf", "i386/floatundisf.S"),
  280. ("__floatundixf", "i386/floatundixf.S"),
  281. ("__lshrdi3", "i386/lshrdi3.S"),
  282. ("__moddi3", "i386/moddi3.S"),
  283. ("__muldi3", "i386/muldi3.S"),
  284. ("__udivdi3", "i386/udivdi3.S"),
  285. ("__umoddi3", "i386/umoddi3.S"),
  286. ]);
  287. }
  288. }
  289. if target_arch == "arm" && target_os != "ios" && target_env != "msvc" {
  290. sources.extend(&[
  291. ("__aeabi_div0", "arm/aeabi_div0.c"),
  292. ("__aeabi_drsub", "arm/aeabi_drsub.c"),
  293. ("__aeabi_frsub", "arm/aeabi_frsub.c"),
  294. ("__bswapdi2", "arm/bswapdi2.S"),
  295. ("__bswapsi2", "arm/bswapsi2.S"),
  296. ("__clzdi2", "arm/clzdi2.S"),
  297. ("__clzsi2", "arm/clzsi2.S"),
  298. ("__divmodsi4", "arm/divmodsi4.S"),
  299. ("__divsi3", "arm/divsi3.S"),
  300. ("__modsi3", "arm/modsi3.S"),
  301. ("__switch16", "arm/switch16.S"),
  302. ("__switch32", "arm/switch32.S"),
  303. ("__switch8", "arm/switch8.S"),
  304. ("__switchu8", "arm/switchu8.S"),
  305. ("__sync_synchronize", "arm/sync_synchronize.S"),
  306. ("__udivmodsi4", "arm/udivmodsi4.S"),
  307. ("__udivsi3", "arm/udivsi3.S"),
  308. ("__umodsi3", "arm/umodsi3.S"),
  309. ]);
  310. if target_os == "freebsd" {
  311. sources.extend(&[("__clear_cache", "clear_cache.c")]);
  312. }
  313. // First of all aeabi_cdcmp and aeabi_cfcmp are never called by LLVM.
  314. // Second are little-endian only, so build fail on big-endian targets.
  315. // Temporally workaround: exclude these files for big-endian targets.
  316. if !llvm_target[0].starts_with("thumbeb") && !llvm_target[0].starts_with("armeb") {
  317. sources.extend(&[
  318. ("__aeabi_cdcmp", "arm/aeabi_cdcmp.S"),
  319. ("__aeabi_cdcmpeq_check_nan", "arm/aeabi_cdcmpeq_check_nan.c"),
  320. ("__aeabi_cfcmp", "arm/aeabi_cfcmp.S"),
  321. ("__aeabi_cfcmpeq_check_nan", "arm/aeabi_cfcmpeq_check_nan.c"),
  322. ]);
  323. }
  324. }
  325. if llvm_target[0] == "armv7" {
  326. sources.extend(&[
  327. ("__sync_fetch_and_add_4", "arm/sync_fetch_and_add_4.S"),
  328. ("__sync_fetch_and_add_8", "arm/sync_fetch_and_add_8.S"),
  329. ("__sync_fetch_and_and_4", "arm/sync_fetch_and_and_4.S"),
  330. ("__sync_fetch_and_and_8", "arm/sync_fetch_and_and_8.S"),
  331. ("__sync_fetch_and_max_4", "arm/sync_fetch_and_max_4.S"),
  332. ("__sync_fetch_and_max_8", "arm/sync_fetch_and_max_8.S"),
  333. ("__sync_fetch_and_min_4", "arm/sync_fetch_and_min_4.S"),
  334. ("__sync_fetch_and_min_8", "arm/sync_fetch_and_min_8.S"),
  335. ("__sync_fetch_and_nand_4", "arm/sync_fetch_and_nand_4.S"),
  336. ("__sync_fetch_and_nand_8", "arm/sync_fetch_and_nand_8.S"),
  337. ("__sync_fetch_and_or_4", "arm/sync_fetch_and_or_4.S"),
  338. ("__sync_fetch_and_or_8", "arm/sync_fetch_and_or_8.S"),
  339. ("__sync_fetch_and_sub_4", "arm/sync_fetch_and_sub_4.S"),
  340. ("__sync_fetch_and_sub_8", "arm/sync_fetch_and_sub_8.S"),
  341. ("__sync_fetch_and_umax_4", "arm/sync_fetch_and_umax_4.S"),
  342. ("__sync_fetch_and_umax_8", "arm/sync_fetch_and_umax_8.S"),
  343. ("__sync_fetch_and_umin_4", "arm/sync_fetch_and_umin_4.S"),
  344. ("__sync_fetch_and_umin_8", "arm/sync_fetch_and_umin_8.S"),
  345. ("__sync_fetch_and_xor_4", "arm/sync_fetch_and_xor_4.S"),
  346. ("__sync_fetch_and_xor_8", "arm/sync_fetch_and_xor_8.S"),
  347. ]);
  348. }
  349. if llvm_target.last().unwrap().ends_with("eabihf") {
  350. if !llvm_target[0].starts_with("thumbv7em")
  351. && !llvm_target[0].starts_with("thumbv8m.main")
  352. {
  353. // The FPU option chosen for these architectures in cc-rs, ie:
  354. // -mfpu=fpv4-sp-d16 for thumbv7em
  355. // -mfpu=fpv5-sp-d16 for thumbv8m.main
  356. // do not support double precision floating points conversions so the files
  357. // that include such instructions are not included for these targets.
  358. sources.extend(&[
  359. ("__fixdfsivfp", "arm/fixdfsivfp.S"),
  360. ("__fixunsdfsivfp", "arm/fixunsdfsivfp.S"),
  361. ("__floatsidfvfp", "arm/floatsidfvfp.S"),
  362. ("__floatunssidfvfp", "arm/floatunssidfvfp.S"),
  363. ]);
  364. }
  365. sources.extend(&[
  366. ("__fixsfsivfp", "arm/fixsfsivfp.S"),
  367. ("__fixunssfsivfp", "arm/fixunssfsivfp.S"),
  368. ("__floatsisfvfp", "arm/floatsisfvfp.S"),
  369. ("__floatunssisfvfp", "arm/floatunssisfvfp.S"),
  370. ("__floatunssisfvfp", "arm/floatunssisfvfp.S"),
  371. ("__restore_vfp_d8_d15_regs", "arm/restore_vfp_d8_d15_regs.S"),
  372. ("__save_vfp_d8_d15_regs", "arm/save_vfp_d8_d15_regs.S"),
  373. ("__negdf2vfp", "arm/negdf2vfp.S"),
  374. ("__negsf2vfp", "arm/negsf2vfp.S"),
  375. ]);
  376. }
  377. if target_arch == "aarch64" && consider_float_intrinsics {
  378. sources.extend(&[
  379. ("__comparetf2", "comparetf2.c"),
  380. ("__extenddftf2", "extenddftf2.c"),
  381. ("__extendsftf2", "extendsftf2.c"),
  382. ("__fixtfdi", "fixtfdi.c"),
  383. ("__fixtfsi", "fixtfsi.c"),
  384. ("__fixtfti", "fixtfti.c"),
  385. ("__fixunstfdi", "fixunstfdi.c"),
  386. ("__fixunstfsi", "fixunstfsi.c"),
  387. ("__fixunstfti", "fixunstfti.c"),
  388. ("__floatditf", "floatditf.c"),
  389. ("__floatsitf", "floatsitf.c"),
  390. ("__floatunditf", "floatunditf.c"),
  391. ("__floatunsitf", "floatunsitf.c"),
  392. ("__trunctfdf2", "trunctfdf2.c"),
  393. ("__trunctfsf2", "trunctfsf2.c"),
  394. ("__addtf3", "addtf3.c"),
  395. ("__multf3", "multf3.c"),
  396. ("__subtf3", "subtf3.c"),
  397. ("__divtf3", "divtf3.c"),
  398. ("__powitf2", "powitf2.c"),
  399. ("__fe_getround", "fp_mode.c"),
  400. ("__fe_raise_inexact", "fp_mode.c"),
  401. ]);
  402. if target_os != "windows" {
  403. sources.extend(&[("__multc3", "multc3.c")]);
  404. }
  405. }
  406. if target_arch == "mips" {
  407. sources.extend(&[("__bswapsi2", "bswapsi2.c")]);
  408. }
  409. if target_arch == "mips64" {
  410. sources.extend(&[
  411. ("__extenddftf2", "extenddftf2.c"),
  412. ("__netf2", "comparetf2.c"),
  413. ("__addtf3", "addtf3.c"),
  414. ("__multf3", "multf3.c"),
  415. ("__subtf3", "subtf3.c"),
  416. ("__fixtfsi", "fixtfsi.c"),
  417. ("__floatsitf", "floatsitf.c"),
  418. ("__fixunstfsi", "fixunstfsi.c"),
  419. ("__floatunsitf", "floatunsitf.c"),
  420. ("__fe_getround", "fp_mode.c"),
  421. ("__divtf3", "divtf3.c"),
  422. ("__trunctfdf2", "trunctfdf2.c"),
  423. ]);
  424. }
  425. // Remove the assembly implementations that won't compile for the target
  426. if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" {
  427. let mut to_remove = Vec::new();
  428. for (k, v) in sources.map.iter() {
  429. if v.ends_with(".S") {
  430. to_remove.push(*k);
  431. }
  432. }
  433. sources.remove(&to_remove);
  434. // But use some generic implementations where possible
  435. sources.extend(&[("__clzdi2", "clzdi2.c"), ("__clzsi2", "clzsi2.c")])
  436. }
  437. if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" {
  438. sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]);
  439. }
  440. // When compiling the C code we require the user to tell us where the
  441. // source code is, and this is largely done so when we're compiling as
  442. // part of rust-lang/rust we can use the same llvm-project repository as
  443. // rust-lang/rust.
  444. let root = match env::var_os("RUST_COMPILER_RT_ROOT") {
  445. Some(s) => PathBuf::from(s),
  446. None => panic!("RUST_COMPILER_RT_ROOT is not set"),
  447. };
  448. if !root.exists() {
  449. panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display());
  450. }
  451. // Support deterministic builds by remapping the __FILE__ prefix if the
  452. // compiler supports it. This fixes the nondeterminism caused by the
  453. // use of that macro in lib/builtins/int_util.h in compiler-rt.
  454. cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display()));
  455. // Include out-of-line atomics for aarch64, which are all generated by supplying different
  456. // sets of flags to the same source file.
  457. // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430).
  458. let src_dir = root.join("lib/builtins");
  459. if target_arch == "aarch64" && target_env != "msvc" {
  460. // See below for why we're building these as separate libraries.
  461. build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg);
  462. // Some run-time CPU feature detection is necessary, as well.
  463. sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]);
  464. }
  465. let mut added_sources = HashSet::new();
  466. for (sym, src) in sources.map.iter() {
  467. let src = src_dir.join(src);
  468. if added_sources.insert(src.clone()) {
  469. cfg.file(&src);
  470. println!("cargo:rerun-if-changed={}", src.display());
  471. }
  472. println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
  473. }
  474. cfg.compile("libcompiler-rt.a");
  475. }
  476. fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) {
  477. let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
  478. let outlined_atomics_file = builtins_dir.join("aarch64/lse.S");
  479. println!("cargo:rerun-if-changed={}", outlined_atomics_file.display());
  480. cfg.include(&builtins_dir);
  481. for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] {
  482. for size in &[1, 2, 4, 8, 16] {
  483. if *size == 16 && *instruction_type != "cas" {
  484. continue;
  485. }
  486. for (model_number, model_name) in
  487. &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")]
  488. {
  489. // The original compiler-rt build system compiles the same
  490. // source file multiple times with different compiler
  491. // options. Here we do something slightly different: we
  492. // create multiple .S files with the proper #defines and
  493. // then include the original file.
  494. //
  495. // This is needed because the cc crate doesn't allow us to
  496. // override the name of object files and libtool requires
  497. // all objects in an archive to have unique names.
  498. let path =
  499. out_dir.join(format!("lse_{}{}_{}.S", instruction_type, size, model_name));
  500. let mut file = File::create(&path).unwrap();
  501. writeln!(file, "#define L_{}", instruction_type).unwrap();
  502. writeln!(file, "#define SIZE {}", size).unwrap();
  503. writeln!(file, "#define MODEL {}", model_number).unwrap();
  504. writeln!(
  505. file,
  506. "#include \"{}\"",
  507. outlined_atomics_file.canonicalize().unwrap().display()
  508. );
  509. drop(file);
  510. cfg.file(path);
  511. let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name);
  512. println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
  513. }
  514. }
  515. }
  516. }
  517. }