1use std::env::consts::EXE_EXTENSION;
12use std::ffi::{OsStr, OsString};
13use std::path::{Path, PathBuf};
14use std::sync::OnceLock;
15use std::{env, fs};
16
17use build_helper::ci::CiEnv;
18use build_helper::git::get_closest_merge_commit;
19
20use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
21use crate::core::config::{Config, TargetSelection};
22use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
23use crate::utils::exec::command;
24use crate::utils::helpers::{
25 self, exe, get_clang_cl_resource_dir, t, unhashed_basename, up_to_date,
26};
27use crate::{CLang, GitRepo, Kind};
28
29#[derive(Clone)]
30pub struct LlvmResult {
31 pub llvm_config: PathBuf,
34 pub llvm_cmake_dir: PathBuf,
36}
37
38pub struct Meta {
39 stamp: BuildStamp,
40 res: LlvmResult,
41 out_dir: PathBuf,
42 root: String,
43}
44
45pub enum LlvmBuildStatus {
46 AlreadyBuilt(LlvmResult),
47 ShouldBuild(Meta),
48}
49
50impl LlvmBuildStatus {
51 pub fn should_build(&self) -> bool {
52 match self {
53 LlvmBuildStatus::AlreadyBuilt(_) => false,
54 LlvmBuildStatus::ShouldBuild(_) => true,
55 }
56 }
57
58 #[cfg(test)]
59 pub fn llvm_result(&self) -> &LlvmResult {
60 match self {
61 LlvmBuildStatus::AlreadyBuilt(res) => res,
62 LlvmBuildStatus::ShouldBuild(meta) => &meta.res,
63 }
64 }
65}
66
67#[derive(Debug, Clone, Default)]
69struct LdFlags {
70 exe: OsString,
72 shared: OsString,
74 module: OsString,
76}
77
78impl LdFlags {
79 fn push_all(&mut self, s: impl AsRef<OsStr>) {
80 let s = s.as_ref();
81 self.exe.push(" ");
82 self.exe.push(s);
83 self.shared.push(" ");
84 self.shared.push(s);
85 self.module.push(" ");
86 self.module.push(s);
87 }
88}
89
90pub fn prebuilt_llvm_config(
98 builder: &Builder<'_>,
99 target: TargetSelection,
100 handle_submodule_when_needed: bool,
104) -> LlvmBuildStatus {
105 builder.config.maybe_download_ci_llvm();
106
107 if let Some(config) = builder.config.target_config.get(&target) {
110 if let Some(ref s) = config.llvm_config {
111 check_llvm_version(builder, s);
112 let llvm_config = s.to_path_buf();
113 let mut llvm_cmake_dir = llvm_config.clone();
114 llvm_cmake_dir.pop();
115 llvm_cmake_dir.pop();
116 llvm_cmake_dir.push("lib");
117 llvm_cmake_dir.push("cmake");
118 llvm_cmake_dir.push("llvm");
119 return LlvmBuildStatus::AlreadyBuilt(LlvmResult { llvm_config, llvm_cmake_dir });
120 }
121 }
122
123 if handle_submodule_when_needed {
124 builder.config.update_submodule("src/llvm-project");
126 }
127
128 let root = "src/llvm-project/llvm";
129 let out_dir = builder.llvm_out(target);
130
131 let build_llvm_config = if let Some(build_llvm_config) = builder
132 .config
133 .target_config
134 .get(&builder.config.build)
135 .and_then(|config| config.llvm_config.clone())
136 {
137 build_llvm_config
138 } else {
139 let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build);
140 llvm_config_ret_dir.push("bin");
141 llvm_config_ret_dir.join(exe("llvm-config", builder.config.build))
142 };
143
144 let llvm_cmake_dir = out_dir.join("lib/cmake/llvm");
145 let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir };
146
147 static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
148 let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
149 generate_smart_stamp_hash(
150 builder,
151 &builder.config.src.join("src/llvm-project"),
152 builder.in_tree_llvm_info.sha().unwrap_or_default(),
153 )
154 });
155
156 let stamp = BuildStamp::new(&out_dir).with_prefix("llvm").add_stamp(smart_stamp_hash);
157
158 if stamp.is_up_to_date() {
159 if stamp.stamp().is_empty() {
160 builder.info(
161 "Could not determine the LLVM submodule commit hash. \
162 Assuming that an LLVM rebuild is not necessary.",
163 );
164 builder.info(&format!(
165 "To force LLVM to rebuild, remove the file `{}`",
166 stamp.path().display()
167 ));
168 }
169 return LlvmBuildStatus::AlreadyBuilt(res);
170 }
171
172 LlvmBuildStatus::ShouldBuild(Meta { stamp, res, out_dir, root: root.into() })
173}
174
175pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
177 let llvm_sha = if is_git {
178 get_closest_merge_commit(
179 Some(&config.src),
180 &config.git_config(),
181 &[
182 config.src.join("src/llvm-project"),
183 config.src.join("src/bootstrap/download-ci-llvm-stamp"),
184 config.src.join("src/version"),
186 ],
187 )
188 .unwrap()
189 } else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) {
190 info.sha.trim().to_owned()
191 } else {
192 "".to_owned()
193 };
194
195 if llvm_sha.is_empty() {
196 eprintln!("error: could not find commit hash for downloading LLVM");
197 eprintln!("HELP: maybe your repository history is too shallow?");
198 eprintln!("HELP: consider disabling `download-ci-llvm`");
199 eprintln!("HELP: or fetch enough history to include one upstream commit");
200 panic!();
201 }
202
203 llvm_sha
204}
205
206pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
212 let supported_platforms = [
216 ("aarch64-unknown-linux-gnu", false),
218 ("aarch64-apple-darwin", false),
219 ("i686-pc-windows-gnu", false),
220 ("i686-pc-windows-msvc", false),
221 ("i686-unknown-linux-gnu", false),
222 ("x86_64-unknown-linux-gnu", true),
223 ("x86_64-apple-darwin", true),
224 ("x86_64-pc-windows-gnu", true),
225 ("x86_64-pc-windows-msvc", true),
226 ("aarch64-pc-windows-msvc", false),
228 ("aarch64-unknown-linux-musl", false),
229 ("arm-unknown-linux-gnueabi", false),
230 ("arm-unknown-linux-gnueabihf", false),
231 ("armv7-unknown-linux-gnueabihf", false),
232 ("loongarch64-unknown-linux-gnu", false),
233 ("loongarch64-unknown-linux-musl", false),
234 ("mips-unknown-linux-gnu", false),
235 ("mips64-unknown-linux-gnuabi64", false),
236 ("mips64el-unknown-linux-gnuabi64", false),
237 ("mipsel-unknown-linux-gnu", false),
238 ("powerpc-unknown-linux-gnu", false),
239 ("powerpc64-unknown-linux-gnu", false),
240 ("powerpc64le-unknown-linux-gnu", false),
241 ("powerpc64le-unknown-linux-musl", false),
242 ("riscv64gc-unknown-linux-gnu", false),
243 ("s390x-unknown-linux-gnu", false),
244 ("x86_64-unknown-freebsd", false),
245 ("x86_64-unknown-illumos", false),
246 ("x86_64-unknown-linux-musl", false),
247 ("x86_64-unknown-netbsd", false),
248 ];
249
250 if !supported_platforms.contains(&(&*config.build.triple, asserts))
251 && (asserts || !supported_platforms.contains(&(&*config.build.triple, true)))
252 {
253 return false;
254 }
255
256 if is_ci_llvm_modified(config) {
257 eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change");
258 return false;
259 }
260
261 true
262}
263
264pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool {
266 if !CiEnv::is_ci() {
268 return false;
269 }
270
271 if CiEnv::is_rust_lang_managed_ci_job() {
273 assert!(
274 config.in_tree_llvm_info.is_managed_git_subrepository(),
275 "LLVM submodule must be fetched in rust-lang/rust managed CI builders."
276 );
277 }
278 else if !config.in_tree_llvm_info.is_managed_git_subrepository() {
280 return false;
281 }
282
283 let llvm_sha = detect_llvm_sha(config, true);
284 let head_sha = crate::output(
285 helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut(),
286 );
287 let head_sha = head_sha.trim();
288 llvm_sha == head_sha
289}
290
291#[derive(Debug, Clone, Hash, PartialEq, Eq)]
292pub struct Llvm {
293 pub target: TargetSelection,
294}
295
296impl Step for Llvm {
297 type Output = LlvmResult;
298
299 const ONLY_HOSTS: bool = true;
300
301 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
302 run.path("src/llvm-project").path("src/llvm-project/llvm")
303 }
304
305 fn make_run(run: RunConfig<'_>) {
306 run.builder.ensure(Llvm { target: run.target });
307 }
308
309 fn run(self, builder: &Builder<'_>) -> LlvmResult {
311 let target = self.target;
312 let target_native = if self.target.starts_with("riscv") {
313 let idx = target.triple.find('-').unwrap();
316
317 format!("riscv{}{}", &target.triple[5..7], &target.triple[idx..])
318 } else if self.target.starts_with("powerpc") && self.target.ends_with("freebsd") {
319 format!("{}{}", self.target, "13.0")
322 } else {
323 target.to_string()
324 };
325
326 let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target, true) {
328 LlvmBuildStatus::AlreadyBuilt(p) => return p,
329 LlvmBuildStatus::ShouldBuild(m) => m,
330 };
331
332 if builder.llvm_link_shared() && target.is_windows() {
333 panic!("shared linking to LLVM is not currently supported on {}", target.triple);
334 }
335
336 let _guard = builder.msg_unstaged(Kind::Build, "LLVM", target);
337 t!(stamp.remove());
338 let _time = helpers::timeit(builder);
339 t!(fs::create_dir_all(&out_dir));
340
341 let mut cfg = cmake::Config::new(builder.src.join(root));
343 let mut ldflags = LdFlags::default();
344
345 let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
346 (false, _) => "Debug",
347 (true, false) => "Release",
348 (true, true) => "RelWithDebInfo",
349 };
350
351 let llvm_targets = match &builder.config.llvm_targets {
354 Some(s) => s,
355 None => {
356 "AArch64;AMDGPU;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;\
357 Sparc;SystemZ;WebAssembly;X86"
358 }
359 };
360
361 let llvm_exp_targets = match builder.config.llvm_experimental_targets {
362 Some(ref s) => s,
363 None => "AVR;M68k;CSKY;Xtensa",
364 };
365
366 let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" };
367 let plugins = if builder.config.llvm_plugins { "ON" } else { "OFF" };
368 let enable_tests = if builder.config.llvm_tests { "ON" } else { "OFF" };
369 let enable_warnings = if builder.config.llvm_enable_warnings { "ON" } else { "OFF" };
370
371 cfg.out_dir(&out_dir)
372 .profile(profile)
373 .define("LLVM_ENABLE_ASSERTIONS", assertions)
374 .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF")
375 .define("LLVM_ENABLE_PLUGINS", plugins)
376 .define("LLVM_TARGETS_TO_BUILD", llvm_targets)
377 .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets)
378 .define("LLVM_INCLUDE_EXAMPLES", "OFF")
379 .define("LLVM_INCLUDE_DOCS", "OFF")
380 .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
381 .define("LLVM_INCLUDE_TESTS", enable_tests)
382 .define("LLVM_ENABLE_TERMINFO", "OFF")
384 .define("LLVM_ENABLE_LIBEDIT", "OFF")
385 .define("LLVM_ENABLE_BINDINGS", "OFF")
386 .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
387 .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
388 .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
389 .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native)
390 .define("LLVM_ENABLE_WARNINGS", enable_warnings);
391
392 cfg.define("LLVM_INSTALL_UTILS", "ON");
396
397 if builder.config.llvm_profile_generate {
398 cfg.define("LLVM_BUILD_INSTRUMENTED", "IR");
399 if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") {
400 cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir);
401 }
402 cfg.define("LLVM_BUILD_RUNTIME", "No");
403 }
404 if let Some(path) = builder.config.llvm_profile_use.as_ref() {
405 cfg.define("LLVM_PROFDATA_FILE", path);
406 }
407
408 if !target.is_windows() {
410 cfg.define("LLVM_ENABLE_ZLIB", "ON");
411 } else {
412 cfg.define("LLVM_ENABLE_ZLIB", "OFF");
413 }
414
415 if target.contains("apple-ios")
417 || target.contains("apple-tvos")
418 || target.contains("apple-watchos")
419 || target.contains("apple-visionos")
420 {
421 cfg.define("CMAKE_OSX_SYSROOT", "/");
423 cfg.define("CMAKE_OSX_DEPLOYMENT_TARGET", "");
424 cfg.define("LLVM_ENABLE_PLUGINS", "OFF");
426 cfg.define("LLVM_ENABLE_ZLIB", "OFF");
428 }
429
430 if builder.llvm_link_shared() {
435 cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
436 }
437
438 if (target.starts_with("csky")
439 || target.starts_with("riscv")
440 || target.starts_with("sparc-"))
441 && !target.contains("freebsd")
442 && !target.contains("openbsd")
443 && !target.contains("netbsd")
444 {
445 ldflags.exe.push(" -latomic");
454 ldflags.shared.push(" -latomic");
455 }
456
457 if target.starts_with("mips") && target.contains("netbsd") {
458 ldflags.exe.push(" -latomic");
460 ldflags.shared.push(" -latomic");
461 }
462
463 if target.is_msvc() {
464 cfg.define("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded");
465 cfg.static_crt(true);
466 }
467
468 if target.starts_with("i686") {
469 cfg.define("LLVM_BUILD_32_BITS", "ON");
470 }
471
472 let mut enabled_llvm_projects = Vec::new();
473
474 if helpers::forcing_clang_based_tests() {
475 enabled_llvm_projects.push("clang");
476 enabled_llvm_projects.push("compiler-rt");
477 }
478
479 if builder.config.llvm_polly {
480 enabled_llvm_projects.push("polly");
481 }
482
483 if builder.config.llvm_clang {
484 enabled_llvm_projects.push("clang");
485 }
486
487 cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
490
491 if !enabled_llvm_projects.is_empty() {
492 enabled_llvm_projects.sort();
493 enabled_llvm_projects.dedup();
494 cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";"));
495 }
496
497 let mut enabled_llvm_runtimes = Vec::new();
498
499 if builder.config.llvm_offload {
500 enabled_llvm_runtimes.push("offload");
501 enabled_llvm_runtimes.push("openmp");
504 }
505
506 if !enabled_llvm_runtimes.is_empty() {
507 enabled_llvm_runtimes.sort();
508 enabled_llvm_runtimes.dedup();
509 cfg.define("LLVM_ENABLE_RUNTIMES", enabled_llvm_runtimes.join(";"));
510 }
511
512 if let Some(num_linkers) = builder.config.llvm_link_jobs {
513 if num_linkers > 0 {
514 cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
515 }
516 }
517
518 if !builder.is_builder_target(&target) {
520 let LlvmResult { llvm_config, .. } =
521 builder.ensure(Llvm { target: builder.config.build });
522 if !builder.config.dry_run() {
523 let llvm_bindir =
524 command(&llvm_config).arg("--bindir").run_capture_stdout(builder).stdout();
525 let host_bin = Path::new(llvm_bindir.trim());
526 cfg.define(
527 "LLVM_TABLEGEN",
528 host_bin.join("llvm-tblgen").with_extension(EXE_EXTENSION),
529 );
530 cfg.define("LLVM_NM", host_bin.join("llvm-nm").with_extension(EXE_EXTENSION));
532 }
533 cfg.define("LLVM_CONFIG_PATH", llvm_config);
534 if builder.config.llvm_clang {
535 let build_bin = builder.llvm_out(builder.config.build).join("build").join("bin");
536 let clang_tblgen = build_bin.join("clang-tblgen").with_extension(EXE_EXTENSION);
537 if !builder.config.dry_run() && !clang_tblgen.exists() {
538 panic!("unable to find {}", clang_tblgen.display());
539 }
540 cfg.define("CLANG_TABLEGEN", clang_tblgen);
541 }
542 }
543
544 let llvm_version_suffix = if let Some(ref suffix) = builder.config.llvm_version_suffix {
545 if !suffix.is_empty() { Some(suffix.to_string()) } else { None }
547 } else if builder.config.channel == "dev" {
548 Some("-rust-dev".to_string())
552 } else {
553 Some(format!("-rust-{}-{}", builder.version, builder.config.channel))
554 };
555 if let Some(ref suffix) = llvm_version_suffix {
556 cfg.define("LLVM_VERSION_SUFFIX", suffix);
557 }
558
559 configure_cmake(builder, target, &mut cfg, true, ldflags, &[]);
560 configure_llvm(builder, target, &mut cfg);
561
562 for (key, val) in &builder.config.llvm_build_config {
563 cfg.define(key, val);
564 }
565
566 if builder.config.dry_run() {
567 return res;
568 }
569
570 cfg.build();
571
572 let find_llvm_lib_name = |extension| {
574 let major = get_llvm_version_major(builder, &res.llvm_config);
575 match &llvm_version_suffix {
576 Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"),
577 None => format!("libLLVM-{major}.{extension}"),
578 }
579 };
580
581 if builder.llvm_link_shared() && target.contains("apple-darwin") {
587 let lib_name = find_llvm_lib_name("dylib");
588 let lib_llvm = out_dir.join("build").join("lib").join(lib_name);
589 if !lib_llvm.exists() {
590 t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
591 }
592 }
593
594 if builder.llvm_link_shared()
598 && builder.config.llvm_optimize
599 && !builder.config.llvm_release_debuginfo
600 {
601 let lib_name = find_llvm_lib_name("so");
603
604 crate::core::build_steps::compile::strip_debug(
607 builder,
608 target,
609 &out_dir.join("lib").join(&lib_name),
610 );
611 crate::core::build_steps::compile::strip_debug(
612 builder,
613 target,
614 &out_dir.join("build").join("lib").join(&lib_name),
615 );
616 }
617
618 t!(stamp.write());
619
620 res
621 }
622}
623
624pub fn get_llvm_version(builder: &Builder<'_>, llvm_config: &Path) -> String {
625 command(llvm_config).arg("--version").run_capture_stdout(builder).stdout().trim().to_owned()
626}
627
628pub fn get_llvm_version_major(builder: &Builder<'_>, llvm_config: &Path) -> u8 {
629 let version = get_llvm_version(builder, llvm_config);
630 let major_str = version.split_once('.').expect("Failed to parse LLVM version").0;
631 major_str.parse().unwrap()
632}
633
634fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
635 if builder.config.dry_run() {
636 return;
637 }
638
639 let version = get_llvm_version(builder, llvm_config);
640 let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
641 if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
642 if major >= 18 {
643 return;
644 }
645 }
646 panic!("\n\nbad LLVM version: {version}, need >=18\n\n")
647}
648
649fn configure_cmake(
650 builder: &Builder<'_>,
651 target: TargetSelection,
652 cfg: &mut cmake::Config,
653 use_compiler_launcher: bool,
654 mut ldflags: LdFlags,
655 suppressed_compiler_flag_prefixes: &[&str],
656) {
657 cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY");
660
661 cfg.env("DESTDIR", "");
665
666 if builder.ninja() {
667 cfg.generator("Ninja");
668 }
669 cfg.target(&target.triple).host(&builder.config.build.triple);
670
671 if !builder.is_builder_target(&target) {
672 cfg.define("CMAKE_CROSSCOMPILING", "True");
673
674 if target.contains("netbsd") {
675 cfg.define("CMAKE_SYSTEM_NAME", "NetBSD");
676 } else if target.contains("dragonfly") {
677 cfg.define("CMAKE_SYSTEM_NAME", "DragonFly");
678 } else if target.contains("freebsd") {
679 cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD");
680 } else if target.is_windows() {
681 cfg.define("CMAKE_SYSTEM_NAME", "Windows");
682 } else if target.contains("haiku") {
683 cfg.define("CMAKE_SYSTEM_NAME", "Haiku");
684 } else if target.contains("solaris") || target.contains("illumos") {
685 cfg.define("CMAKE_SYSTEM_NAME", "SunOS");
686 } else if target.contains("linux") {
687 cfg.define("CMAKE_SYSTEM_NAME", "Linux");
688 } else {
689 builder.info(&format!(
690 "could not determine CMAKE_SYSTEM_NAME from the target `{target}`, build may fail",
691 ));
692 }
693
694 if target.contains("darwin") {
702 if target.starts_with("aarch64") {
705 cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64");
707 } else if target.starts_with("i686") {
708 cfg.define("CMAKE_OSX_ARCHITECTURES", "i386");
710 } else {
711 cfg.define("CMAKE_OSX_ARCHITECTURES", target.triple.split('-').next().unwrap());
712 }
713 }
714 }
715
716 let sanitize_cc = |cc: &Path| {
717 if target.is_msvc() {
718 OsString::from(cc.to_str().unwrap().replace('\\', "/"))
719 } else {
720 cc.as_os_str().to_owned()
721 }
722 };
723
724 if target.is_msvc() && !builder.ninja() {
728 return;
729 }
730
731 let (cc, cxx) = match builder.config.llvm_clang_cl {
732 Some(ref cl) => (cl.into(), cl.into()),
733 None => (builder.cc(target), builder.cxx(target).unwrap()),
734 };
735
736 if target.is_msvc() && builder.ninja() && builder.config.ccache.is_some() {
738 let mut wrap_cc = env::current_exe().expect("failed to get cwd");
739 wrap_cc.set_file_name("sccache-plus-cl.exe");
740
741 cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc))
742 .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc));
743 cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap())
744 .env("SCCACHE_TARGET", target.triple)
745 .env("SCCACHE_CC", &cc)
746 .env("SCCACHE_CXX", &cxx);
747
748 if builder.config.llvm_clang_cl.is_some() && target.contains("i686") {
772 cfg.env("SCCACHE_EXTRA_ARGS", "-m32");
773 }
774 } else {
775 if use_compiler_launcher {
778 if let Some(ref ccache) = builder.config.ccache {
779 cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache)
780 .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache);
781 }
782 }
783 cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
784 .define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx))
785 .define("CMAKE_ASM_COMPILER", sanitize_cc(&cc));
786 }
787
788 cfg.build_arg("-j").build_arg(builder.jobs().to_string());
789 let mut cflags: OsString = builder
795 .cc_handled_clags(target, CLang::C)
796 .into_iter()
797 .chain(builder.cc_unhandled_cflags(target, GitRepo::Llvm, CLang::C))
798 .filter(|flag| {
799 !suppressed_compiler_flag_prefixes
800 .iter()
801 .any(|suppressed_prefix| flag.starts_with(suppressed_prefix))
802 })
803 .collect::<Vec<String>>()
804 .join(" ")
805 .into();
806 if let Some(ref s) = builder.config.llvm_cflags {
807 cflags.push(" ");
808 cflags.push(s);
809 }
810
811 if builder.config.llvm_clang_cl.is_some() {
812 cflags.push(format!(" --target={target}"));
813 }
814 cfg.define("CMAKE_C_FLAGS", cflags);
815 let mut cxxflags: OsString = builder
816 .cc_handled_clags(target, CLang::Cxx)
817 .into_iter()
818 .chain(builder.cc_unhandled_cflags(target, GitRepo::Llvm, CLang::Cxx))
819 .filter(|flag| {
820 !suppressed_compiler_flag_prefixes
821 .iter()
822 .any(|suppressed_prefix| flag.starts_with(suppressed_prefix))
823 })
824 .collect::<Vec<String>>()
825 .join(" ")
826 .into();
827 if let Some(ref s) = builder.config.llvm_cxxflags {
828 cxxflags.push(" ");
829 cxxflags.push(s);
830 }
831 if builder.config.llvm_clang_cl.is_some() {
832 cxxflags.push(format!(" --target={target}"));
833 }
834 cfg.define("CMAKE_CXX_FLAGS", cxxflags);
835 if let Some(ar) = builder.ar(target) {
836 if ar.is_absolute() {
837 cfg.define("CMAKE_AR", sanitize_cc(&ar));
840 }
841 }
842
843 if let Some(ranlib) = builder.ranlib(target) {
844 if ranlib.is_absolute() {
845 cfg.define("CMAKE_RANLIB", sanitize_cc(&ranlib));
848 }
849 }
850
851 if let Some(ref flags) = builder.config.llvm_ldflags {
852 ldflags.push_all(flags);
853 }
854
855 if let Some(flags) = get_var("LDFLAGS", &builder.config.build.triple, &target.triple) {
856 ldflags.push_all(&flags);
857 }
858
859 if builder.config.llvm_static_stdcpp
862 && !target.is_msvc()
863 && !target.contains("netbsd")
864 && !target.contains("solaris")
865 {
866 if target.contains("apple") || target.is_windows() {
867 ldflags.push_all("-static-libstdc++");
868 } else {
869 ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
870 }
871 }
872
873 cfg.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags.shared);
874 cfg.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags.module);
875 cfg.define("CMAKE_EXE_LINKER_FLAGS", &ldflags.exe);
876
877 if env::var_os("SCCACHE_ERROR_LOG").is_some() {
878 cfg.env("RUSTC_LOG", "sccache=warn");
879 }
880}
881
882fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmake::Config) {
883 if builder.config.llvm_thin_lto {
886 cfg.define("LLVM_ENABLE_LTO", "Thin");
887 if !target.contains("apple") {
888 cfg.define("LLVM_ENABLE_LLD", "ON");
889 }
890 }
891
892 if builder.config.llvm_libzstd {
894 cfg.define("LLVM_ENABLE_ZSTD", "FORCE_ON");
895 cfg.define("LLVM_USE_STATIC_ZSTD", "TRUE");
896 } else {
897 cfg.define("LLVM_ENABLE_ZSTD", "OFF");
898 }
899
900 if let Some(ref linker) = builder.config.llvm_use_linker {
901 cfg.define("LLVM_USE_LINKER", linker);
902 }
903
904 if builder.config.llvm_allow_old_toolchain {
905 cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
906 }
907}
908
909fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
911 let kind = if host == target { "HOST" } else { "TARGET" };
912 let target_u = target.replace('-', "_");
913 env::var_os(format!("{var_base}_{target}"))
914 .or_else(|| env::var_os(format!("{}_{}", var_base, target_u)))
915 .or_else(|| env::var_os(format!("{}_{}", kind, var_base)))
916 .or_else(|| env::var_os(var_base))
917}
918
919#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
920pub struct Enzyme {
921 pub target: TargetSelection,
922}
923
924impl Step for Enzyme {
925 type Output = PathBuf;
926 const ONLY_HOSTS: bool = true;
927
928 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
929 run.path("src/tools/enzyme/enzyme")
930 }
931
932 fn make_run(run: RunConfig<'_>) {
933 run.builder.ensure(Enzyme { target: run.target });
934 }
935
936 fn run(self, builder: &Builder<'_>) -> PathBuf {
938 builder.require_submodule(
939 "src/tools/enzyme",
940 Some("The Enzyme sources are required for autodiff."),
941 );
942 if builder.config.dry_run() {
943 let out_dir = builder.enzyme_out(self.target);
944 return out_dir;
945 }
946 let target = self.target;
947
948 let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: self.target });
949
950 static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
951 let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
952 generate_smart_stamp_hash(
953 builder,
954 &builder.config.src.join("src/tools/enzyme"),
955 builder.enzyme_info.sha().unwrap_or_default(),
956 )
957 });
958
959 let out_dir = builder.enzyme_out(target);
960 let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash);
961
962 if stamp.is_up_to_date() {
963 if stamp.stamp().is_empty() {
964 builder.info(
965 "Could not determine the Enzyme submodule commit hash. \
966 Assuming that an Enzyme rebuild is not necessary.",
967 );
968 builder.info(&format!(
969 "To force Enzyme to rebuild, remove the file `{}`",
970 stamp.path().display()
971 ));
972 }
973 return out_dir;
974 }
975
976 builder.info(&format!("Building Enzyme for {}", target));
977 t!(stamp.remove());
978 let _time = helpers::timeit(builder);
979 t!(fs::create_dir_all(&out_dir));
980
981 builder
982 .config
983 .update_submodule(Path::new("src").join("tools").join("enzyme").to_str().unwrap());
984 let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/"));
985 configure_cmake(builder, target, &mut cfg, true, LdFlags::default(), &[]);
989
990 let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
993 (false, _) => "Debug",
994 (true, false) => "Release",
995 (true, true) => "RelWithDebInfo",
996 };
997
998 cfg.out_dir(&out_dir)
999 .profile(profile)
1000 .env("LLVM_CONFIG_REAL", &llvm_config)
1001 .define("LLVM_ENABLE_ASSERTIONS", "ON")
1002 .define("ENZYME_EXTERNAL_SHARED_LIB", "ON")
1003 .define("ENZYME_RUNPASS", "ON")
1004 .define("LLVM_DIR", builder.llvm_out(target));
1005
1006 cfg.build();
1007
1008 t!(stamp.write());
1009 out_dir
1010 }
1011}
1012
1013#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1014pub struct Lld {
1015 pub target: TargetSelection,
1016}
1017
1018impl Step for Lld {
1019 type Output = PathBuf;
1020 const ONLY_HOSTS: bool = true;
1021
1022 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1023 run.path("src/llvm-project/lld")
1024 }
1025
1026 fn make_run(run: RunConfig<'_>) {
1027 run.builder.ensure(Lld { target: run.target });
1028 }
1029
1030 fn run(self, builder: &Builder<'_>) -> PathBuf {
1032 if builder.config.dry_run() {
1033 return PathBuf::from("lld-out-dir-test-gen");
1034 }
1035 let target = self.target;
1036
1037 let LlvmResult { llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target });
1038
1039 let ci_llvm_bin = llvm_config.parent().unwrap();
1044 if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" {
1045 let lld_path = ci_llvm_bin.join(exe("lld", target));
1046 if lld_path.exists() {
1047 return ci_llvm_bin.parent().unwrap().to_path_buf();
1050 }
1051 }
1052
1053 let out_dir = builder.lld_out(target);
1054
1055 let lld_stamp = BuildStamp::new(&out_dir).with_prefix("lld");
1056 if lld_stamp.path().exists() {
1057 return out_dir;
1058 }
1059
1060 let _guard = builder.msg_unstaged(Kind::Build, "LLD", target);
1061 let _time = helpers::timeit(builder);
1062 t!(fs::create_dir_all(&out_dir));
1063
1064 let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld"));
1065 let mut ldflags = LdFlags::default();
1066
1067 if builder.config.llvm_profile_generate && target.is_msvc() {
1072 if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() {
1073 let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
1076 ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
1077 }
1078 }
1079
1080 if builder.config.rpath_enabled(target)
1092 && helpers::use_host_linker(target)
1093 && builder.config.llvm_link_shared()
1094 && target.contains("linux")
1095 {
1096 ldflags.push_all("-Wl,-rpath,'$ORIGIN/../../../'");
1103 }
1104
1105 configure_cmake(builder, target, &mut cfg, true, ldflags, &[]);
1106 configure_llvm(builder, target, &mut cfg);
1107
1108 let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
1111 (false, _) => "Debug",
1112 (true, false) => "Release",
1113 (true, true) => "RelWithDebInfo",
1114 };
1115
1116 cfg.out_dir(&out_dir)
1117 .profile(profile)
1118 .define("LLVM_CMAKE_DIR", llvm_cmake_dir)
1119 .define("LLVM_INCLUDE_TESTS", "OFF");
1120
1121 if !builder.is_builder_target(&target) {
1122 cfg.define(
1124 "LLVM_TABLEGEN_EXE",
1125 llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION),
1126 );
1127 }
1128
1129 cfg.build();
1130
1131 t!(lld_stamp.write());
1132 out_dir
1133 }
1134}
1135
1136#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1137pub struct Sanitizers {
1138 pub target: TargetSelection,
1139}
1140
1141impl Step for Sanitizers {
1142 type Output = Vec<SanitizerRuntime>;
1143
1144 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1145 run.alias("sanitizers")
1146 }
1147
1148 fn make_run(run: RunConfig<'_>) {
1149 run.builder.ensure(Sanitizers { target: run.target });
1150 }
1151
1152 fn run(self, builder: &Builder<'_>) -> Self::Output {
1154 let compiler_rt_dir = builder.src.join("src/llvm-project/compiler-rt");
1155 if !compiler_rt_dir.exists() {
1156 return Vec::new();
1157 }
1158
1159 let out_dir = builder.native_dir(self.target).join("sanitizers");
1160 let runtimes = supported_sanitizers(&out_dir, self.target, &builder.config.channel);
1161
1162 if builder.config.dry_run() || runtimes.is_empty() {
1163 return runtimes;
1164 }
1165
1166 let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build });
1167
1168 static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
1169 let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
1170 generate_smart_stamp_hash(
1171 builder,
1172 &builder.config.src.join("src/llvm-project/compiler-rt"),
1173 builder.in_tree_llvm_info.sha().unwrap_or_default(),
1174 )
1175 });
1176
1177 let stamp = BuildStamp::new(&out_dir).with_prefix("sanitizers").add_stamp(smart_stamp_hash);
1178
1179 if stamp.is_up_to_date() {
1180 if stamp.stamp().is_empty() {
1181 builder.info(&format!(
1182 "Rebuild sanitizers by removing the file `{}`",
1183 stamp.path().display()
1184 ));
1185 }
1186
1187 return runtimes;
1188 }
1189
1190 let _guard = builder.msg_unstaged(Kind::Build, "sanitizers", self.target);
1191 t!(stamp.remove());
1192 let _time = helpers::timeit(builder);
1193
1194 let mut cfg = cmake::Config::new(&compiler_rt_dir);
1195 cfg.profile("Release");
1196 cfg.define("CMAKE_C_COMPILER_TARGET", self.target.triple);
1197 cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF");
1198 cfg.define("COMPILER_RT_BUILD_CRT", "OFF");
1199 cfg.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF");
1200 cfg.define("COMPILER_RT_BUILD_PROFILE", "OFF");
1201 cfg.define("COMPILER_RT_BUILD_SANITIZERS", "ON");
1202 cfg.define("COMPILER_RT_BUILD_XRAY", "OFF");
1203 cfg.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON");
1204 cfg.define("COMPILER_RT_USE_LIBCXX", "OFF");
1205 cfg.define("LLVM_CONFIG_PATH", &llvm_config);
1206
1207 let use_compiler_launcher = !self.target.contains("apple-darwin");
1211 let suppressed_compiler_flag_prefixes: &[&str] =
1216 if self.target.contains("apple-darwin") { &["-mmacosx-version-min="] } else { &[] };
1217 configure_cmake(
1218 builder,
1219 self.target,
1220 &mut cfg,
1221 use_compiler_launcher,
1222 LdFlags::default(),
1223 suppressed_compiler_flag_prefixes,
1224 );
1225
1226 t!(fs::create_dir_all(&out_dir));
1227 cfg.out_dir(out_dir);
1228
1229 for runtime in &runtimes {
1230 cfg.build_target(&runtime.cmake_target);
1231 cfg.build();
1232 }
1233 t!(stamp.write());
1234
1235 runtimes
1236 }
1237}
1238
1239#[derive(Clone, Debug)]
1240pub struct SanitizerRuntime {
1241 pub cmake_target: String,
1243 pub path: PathBuf,
1245 pub name: String,
1247}
1248
1249fn supported_sanitizers(
1251 out_dir: &Path,
1252 target: TargetSelection,
1253 channel: &str,
1254) -> Vec<SanitizerRuntime> {
1255 let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
1256 components
1257 .iter()
1258 .map(move |c| SanitizerRuntime {
1259 cmake_target: format!("clang_rt.{}_{}_dynamic", c, os),
1260 path: out_dir
1261 .join(format!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c, os)),
1262 name: format!("librustc-{}_rt.{}.dylib", channel, c),
1263 })
1264 .collect()
1265 };
1266
1267 let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec<SanitizerRuntime> {
1268 components
1269 .iter()
1270 .map(move |c| SanitizerRuntime {
1271 cmake_target: format!("clang_rt.{}-{}", c, arch),
1272 path: out_dir.join(format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)),
1273 name: format!("librustc-{}_rt.{}.a", channel, c),
1274 })
1275 .collect()
1276 };
1277
1278 match &*target.triple {
1279 "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1280 "aarch64-apple-ios" => darwin_libs("ios", &["asan", "tsan"]),
1281 "aarch64-apple-ios-sim" => darwin_libs("iossim", &["asan", "tsan"]),
1282 "aarch64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1283 "aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
1284 "aarch64-unknown-linux-gnu" => {
1285 common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
1286 }
1287 "aarch64-unknown-linux-ohos" => {
1288 common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
1289 }
1290 "loongarch64-unknown-linux-gnu" | "loongarch64-unknown-linux-musl" => {
1291 common_libs("linux", "loongarch64", &["asan", "lsan", "msan", "tsan"])
1292 }
1293 "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1294 "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
1295 "x86_64-apple-ios" => darwin_libs("iossim", &["asan", "tsan"]),
1296 "x86_64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1297 "x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]),
1298 "x86_64-unknown-netbsd" => {
1299 common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"])
1300 }
1301 "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
1302 "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
1303 "x86_64-unknown-linux-gnu" => {
1304 common_libs("linux", "x86_64", &["asan", "dfsan", "lsan", "msan", "safestack", "tsan"])
1305 }
1306 "x86_64-unknown-linux-musl" => {
1307 common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
1308 }
1309 "s390x-unknown-linux-gnu" => {
1310 common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"])
1311 }
1312 "s390x-unknown-linux-musl" => {
1313 common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"])
1314 }
1315 "x86_64-unknown-linux-ohos" => {
1316 common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
1317 }
1318 _ => Vec::new(),
1319 }
1320}
1321
1322#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1323pub struct CrtBeginEnd {
1324 pub target: TargetSelection,
1325}
1326
1327impl Step for CrtBeginEnd {
1328 type Output = PathBuf;
1329
1330 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1331 run.path("src/llvm-project/compiler-rt/lib/crt")
1332 }
1333
1334 fn make_run(run: RunConfig<'_>) {
1335 if run.target.needs_crt_begin_end() {
1336 run.builder.ensure(CrtBeginEnd { target: run.target });
1337 }
1338 }
1339
1340 fn run(self, builder: &Builder<'_>) -> Self::Output {
1342 builder.require_submodule(
1343 "src/llvm-project",
1344 Some("The LLVM sources are required for the CRT from `compiler-rt`."),
1345 );
1346
1347 let out_dir = builder.native_dir(self.target).join("crt");
1348
1349 if builder.config.dry_run() {
1350 return out_dir;
1351 }
1352
1353 let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtbegin.c");
1354 let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtend.c");
1355 if up_to_date(&crtbegin_src, &out_dir.join("crtbeginS.o"))
1356 && up_to_date(&crtend_src, &out_dir.join("crtendS.o"))
1357 {
1358 return out_dir;
1359 }
1360
1361 let _guard = builder.msg_unstaged(Kind::Build, "crtbegin.o and crtend.o", self.target);
1362 t!(fs::create_dir_all(&out_dir));
1363
1364 let mut cfg = cc::Build::new();
1365
1366 if let Some(ar) = builder.ar(self.target) {
1367 cfg.archiver(ar);
1368 }
1369 cfg.compiler(builder.cc(self.target));
1370 cfg.cargo_metadata(false)
1371 .out_dir(&out_dir)
1372 .target(&self.target.triple)
1373 .host(&builder.config.build.triple)
1374 .warnings(false)
1375 .debug(false)
1376 .opt_level(3)
1377 .file(crtbegin_src)
1378 .file(crtend_src);
1379
1380 cfg.flag("-std=c11")
1384 .define("CRT_HAS_INITFINI_ARRAY", None)
1385 .define("EH_USE_FRAME_REGISTRY", None);
1386
1387 let objs = cfg.compile_intermediates();
1388 assert_eq!(objs.len(), 2);
1389 for obj in objs {
1390 let base_name = unhashed_basename(&obj);
1391 assert!(base_name == "crtbegin" || base_name == "crtend");
1392 t!(fs::copy(&obj, out_dir.join(format!("{}S.o", base_name))));
1393 t!(fs::rename(&obj, out_dir.join(format!("{}.o", base_name))));
1394 }
1395
1396 out_dir
1397 }
1398}
1399
1400#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1401pub struct Libunwind {
1402 pub target: TargetSelection,
1403}
1404
1405impl Step for Libunwind {
1406 type Output = PathBuf;
1407
1408 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1409 run.path("src/llvm-project/libunwind")
1410 }
1411
1412 fn make_run(run: RunConfig<'_>) {
1413 run.builder.ensure(Libunwind { target: run.target });
1414 }
1415
1416 fn run(self, builder: &Builder<'_>) -> Self::Output {
1418 builder.require_submodule(
1419 "src/llvm-project",
1420 Some("The LLVM sources are required for libunwind."),
1421 );
1422
1423 if builder.config.dry_run() {
1424 return PathBuf::new();
1425 }
1426
1427 let out_dir = builder.native_dir(self.target).join("libunwind");
1428 let root = builder.src.join("src/llvm-project/libunwind");
1429
1430 if up_to_date(&root, &out_dir.join("libunwind.a")) {
1431 return out_dir;
1432 }
1433
1434 let _guard = builder.msg_unstaged(Kind::Build, "libunwind.a", self.target);
1435 t!(fs::create_dir_all(&out_dir));
1436
1437 let mut cc_cfg = cc::Build::new();
1438 let mut cpp_cfg = cc::Build::new();
1439
1440 cpp_cfg.cpp(true);
1441 cpp_cfg.cpp_set_stdlib(None);
1442 cpp_cfg.flag("-nostdinc++");
1443 cpp_cfg.flag("-fno-exceptions");
1444 cpp_cfg.flag("-fno-rtti");
1445 cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
1446
1447 for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
1448 if let Some(ar) = builder.ar(self.target) {
1449 cfg.archiver(ar);
1450 }
1451 cfg.target(&self.target.triple);
1452 cfg.host(&builder.config.build.triple);
1453 cfg.warnings(false);
1454 cfg.debug(false);
1455 cfg.opt_level(3);
1457 cfg.flag("-fstrict-aliasing");
1458 cfg.flag("-funwind-tables");
1459 cfg.flag("-fvisibility=hidden");
1460 cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
1461 cfg.include(root.join("include"));
1462 cfg.cargo_metadata(false);
1463 cfg.out_dir(&out_dir);
1464
1465 if self.target.contains("x86_64-fortanix-unknown-sgx") {
1466 cfg.static_flag(true);
1467 cfg.flag("-fno-stack-protector");
1468 cfg.flag("-ffreestanding");
1469 cfg.flag("-fexceptions");
1470
1471 cfg.flag("-U_FORTIFY_SOURCE");
1473 cfg.define("_FORTIFY_SOURCE", "0");
1474 cfg.define("RUST_SGX", "1");
1475 cfg.define("__NO_STRING_INLINES", None);
1476 cfg.define("__NO_MATH_INLINES", None);
1477 cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
1478 cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
1479 cfg.define("NDEBUG", None);
1480 }
1481 if self.target.is_windows() {
1482 cfg.define("_LIBUNWIND_HIDE_SYMBOLS", "1");
1483 cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
1484 }
1485 }
1486
1487 cc_cfg.compiler(builder.cc(self.target));
1488 if let Ok(cxx) = builder.cxx(self.target) {
1489 cpp_cfg.compiler(cxx);
1490 } else {
1491 cc_cfg.compiler(builder.cc(self.target));
1492 }
1493
1494 if cc_cfg.get_compiler().is_like_gnu() {
1499 cc_cfg.flag("-std=c99");
1500 }
1501 if cpp_cfg.get_compiler().is_like_gnu() {
1502 cpp_cfg.flag("-std=c++11");
1503 }
1504
1505 if self.target.contains("x86_64-fortanix-unknown-sgx") || self.target.contains("musl") {
1506 if cpp_cfg.get_compiler().is_like_gnu() {
1510 cpp_cfg.cpp(false);
1511 cpp_cfg.compiler(builder.cc(self.target));
1512 }
1513 }
1514
1515 let mut c_sources = vec![
1516 "Unwind-sjlj.c",
1517 "UnwindLevel1-gcc-ext.c",
1518 "UnwindLevel1.c",
1519 "UnwindRegistersRestore.S",
1520 "UnwindRegistersSave.S",
1521 ];
1522
1523 let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
1524 let cpp_len = cpp_sources.len();
1525
1526 if self.target.contains("x86_64-fortanix-unknown-sgx") {
1527 c_sources.push("UnwindRustSgx.c");
1528 }
1529
1530 for src in c_sources {
1531 cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
1532 }
1533
1534 for src in &cpp_sources {
1535 cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
1536 }
1537
1538 cpp_cfg.compile("unwind-cpp");
1539
1540 let mut count = 0;
1542 for entry in fs::read_dir(&out_dir).unwrap() {
1543 let file = entry.unwrap().path().canonicalize().unwrap();
1544 if file.is_file() && file.extension() == Some(OsStr::new("o")) {
1545 let base_name = unhashed_basename(&file);
1547 if cpp_sources.iter().any(|f| *base_name == f[..f.len() - 4]) {
1548 cc_cfg.object(&file);
1549 count += 1;
1550 }
1551 }
1552 }
1553 assert_eq!(cpp_len, count, "Can't get object files from {out_dir:?}");
1554
1555 cc_cfg.compile("unwind");
1556 out_dir
1557 }
1558}