1 //! Compilation of native dependencies like LLVM.
3 //! Native projects like LLVM unfortunately aren't suited just yet for
4 //! compilation in build scripts that Cargo has. This is because the
5 //! compilation takes a *very* long time but also because we don't want to
6 //! compile LLVM 3 times as part of a normal bootstrap (we want it cached).
8 //! LLVM and compiler-rt are essentially just wired up to everything else to
9 //! ensure that they're always in place if needed.
12 use std
::env
::consts
::EXE_EXTENSION
;
13 use std
::ffi
::{OsStr, OsString}
;
14 use std
::fs
::{self, File}
;
16 use std
::path
::{Path, PathBuf}
;
17 use std
::process
::Command
;
19 use crate::builder
::{Builder, RunConfig, ShouldRun, Step}
;
21 use crate::config
::{Config, TargetSelection}
;
22 use crate::util
::get_clang_cl_resource_dir
;
23 use crate::util
::{self, exe, output, t, up_to_date}
;
24 use crate::{CLang, GitRepo}
;
26 use build_helper
::ci
::CiEnv
;
29 pub struct LlvmResult
{
30 /// Path to llvm-config binary.
31 /// NB: This is always the host llvm-config!
32 pub llvm_config
: PathBuf
,
33 /// Path to LLVM cmake directory for the target.
34 pub llvm_cmake_dir
: PathBuf
,
44 // Linker flags to pass to LLVM's CMake invocation.
45 #[derive(Debug, Clone, Default)]
47 // CMAKE_EXE_LINKER_FLAGS
49 // CMAKE_SHARED_LINKER_FLAGS
51 // CMAKE_MODULE_LINKER_FLAGS
56 fn push_all(&mut self, s
: impl AsRef
<OsStr
>) {
60 self.shared
.push(" ");
62 self.module
.push(" ");
67 /// This returns whether we've already previously built LLVM.
69 /// It's used to avoid busting caches during x.py check -- if we've already built
70 /// LLVM, it's fine for us to not try to avoid doing so.
72 /// This will return the llvm-config if it can get it (but it will not build it
74 pub fn prebuilt_llvm_config(
75 builder
: &Builder
<'_
>,
76 target
: TargetSelection
,
77 ) -> Result
<LlvmResult
, Meta
> {
78 builder
.config
.maybe_download_ci_llvm();
80 // If we're using a custom LLVM bail out here, but we can only use a
81 // custom LLVM for the build triple.
82 if let Some(config
) = builder
.config
.target_config
.get(&target
) {
83 if let Some(ref s
) = config
.llvm_config
{
84 check_llvm_version(builder
, s
);
85 let llvm_config
= s
.to_path_buf();
86 let mut llvm_cmake_dir
= llvm_config
.clone();
89 llvm_cmake_dir
.push("lib");
90 llvm_cmake_dir
.push("cmake");
91 llvm_cmake_dir
.push("llvm");
92 return Ok(LlvmResult { llvm_config, llvm_cmake_dir }
);
96 let root
= "src/llvm-project/llvm";
97 let out_dir
= builder
.llvm_out(target
);
99 let mut llvm_config_ret_dir
= builder
.llvm_out(builder
.config
.build
);
100 if !builder
.config
.build
.contains("msvc") || builder
.ninja() {
101 llvm_config_ret_dir
.push("build");
103 llvm_config_ret_dir
.push("bin");
104 let build_llvm_config
= llvm_config_ret_dir
.join(exe("llvm-config", builder
.config
.build
));
105 let llvm_cmake_dir
= out_dir
.join("lib/cmake/llvm");
106 let res
= LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir }
;
108 let stamp
= out_dir
.join("llvm-finished-building");
109 let stamp
= HashStamp
::new(stamp
, builder
.in_tree_llvm_info
.sha());
112 if stamp
.hash
.is_none() {
114 "Could not determine the LLVM submodule commit hash. \
115 Assuming that an LLVM rebuild is not necessary.",
117 builder
.info(&format
!(
118 "To force LLVM to rebuild, remove the file `{}`",
125 Err(Meta { stamp, res, out_dir, root: root.into() }
)
128 /// This retrieves the LLVM sha we *want* to use, according to git history.
129 pub(crate) fn detect_llvm_sha(config
: &Config
, is_git
: bool
) -> String
{
130 let llvm_sha
= if is_git
{
131 let mut rev_list
= config
.git();
133 PathBuf
::from("rev-list"),
134 format
!("--author={}", config
.stage0_metadata
.config
.git_merge_commit_email
).into(),
136 "--first-parent".into(),
139 config
.src
.join("src/llvm-project"),
140 config
.src
.join("src/bootstrap/download-ci-llvm-stamp"),
141 // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
142 config
.src
.join("src/version"),
144 output(&mut rev_list
).trim().to_owned()
145 } else if let Some(info
) = channel
::read_commit_info_file(&config
.src
) {
146 info
.sha
.trim().to_owned()
152 eprintln
!("error: could not find commit hash for downloading LLVM");
153 eprintln
!("help: maybe your repository history is too shallow?");
154 eprintln
!("help: consider disabling `download-ci-llvm`");
155 eprintln
!("help: or fetch enough history to include one upstream commit");
162 /// Returns whether the CI-found LLVM is currently usable.
164 /// This checks both the build triple platform to confirm we're usable at all,
165 /// and then verifies if the current HEAD matches the detected LLVM SHA head,
166 /// in which case LLVM is indicated as not available.
167 pub(crate) fn is_ci_llvm_available(config
: &Config
, asserts
: bool
) -> bool
{
168 // This is currently all tier 1 targets and tier 2 targets with host tools
169 // (since others may not have CI artifacts)
170 // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
171 let supported_platforms
= [
173 ("aarch64-unknown-linux-gnu", false),
174 ("i686-pc-windows-gnu", false),
175 ("i686-pc-windows-msvc", false),
176 ("i686-unknown-linux-gnu", false),
177 ("x86_64-unknown-linux-gnu", true),
178 ("x86_64-apple-darwin", true),
179 ("x86_64-pc-windows-gnu", true),
180 ("x86_64-pc-windows-msvc", true),
181 // tier 2 with host tools
182 ("aarch64-apple-darwin", false),
183 ("aarch64-pc-windows-msvc", false),
184 ("aarch64-unknown-linux-musl", false),
185 ("arm-unknown-linux-gnueabi", false),
186 ("arm-unknown-linux-gnueabihf", false),
187 ("armv7-unknown-linux-gnueabihf", false),
188 ("mips-unknown-linux-gnu", false),
189 ("mips64-unknown-linux-gnuabi64", false),
190 ("mips64el-unknown-linux-gnuabi64", false),
191 ("mipsel-unknown-linux-gnu", false),
192 ("powerpc-unknown-linux-gnu", false),
193 ("powerpc64-unknown-linux-gnu", false),
194 ("powerpc64le-unknown-linux-gnu", false),
195 ("riscv64gc-unknown-linux-gnu", false),
196 ("s390x-unknown-linux-gnu", false),
197 ("x86_64-unknown-freebsd", false),
198 ("x86_64-unknown-illumos", false),
199 ("x86_64-unknown-linux-musl", false),
200 ("x86_64-unknown-netbsd", false),
203 if !supported_platforms
.contains(&(&*config
.build
.triple
, asserts
)) {
204 if asserts
== true || !supported_platforms
.contains(&(&*config
.build
.triple
, true)) {
209 if is_ci_llvm_modified(config
) {
210 eprintln
!("Detected LLVM as non-available: running in CI and modified LLVM in this change");
217 /// Returns true if we're running in CI with modified LLVM (and thus can't download it)
218 pub(crate) fn is_ci_llvm_modified(config
: &Config
) -> bool
{
219 CiEnv
::is_ci() && config
.rust_info
.is_managed_git_subrepository() && {
220 // We assume we have access to git, so it's okay to unconditionally pass
222 let llvm_sha
= detect_llvm_sha(config
, true);
223 let head_sha
= output(config
.git().arg("rev-parse").arg("HEAD"));
224 let head_sha
= head_sha
.trim();
229 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
231 pub target
: TargetSelection
,
235 type Output
= LlvmResult
;
237 const ONLY_HOSTS
: bool
= true;
239 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
240 run
.path("src/llvm-project").path("src/llvm-project/llvm")
243 fn make_run(run
: RunConfig
<'_
>) {
244 run
.builder
.ensure(Llvm { target: run.target }
);
247 /// Compile LLVM for `target`.
248 fn run(self, builder
: &Builder
<'_
>) -> LlvmResult
{
249 let target
= self.target
;
250 let target_native
= if self.target
.starts_with("riscv") {
251 // RISC-V target triples in Rust is not named the same as C compiler target triples.
252 // This converts Rust RISC-V target triples to C compiler triples.
253 let idx
= target
.triple
.find('
-'
).unwrap();
255 format
!("riscv{}{}", &target
.triple
[5..7], &target
.triple
[idx
..])
256 } else if self.target
.starts_with("powerpc") && self.target
.ends_with("freebsd") {
257 // FreeBSD 13 had incompatible ABI changes on all PowerPC platforms.
258 // Set the version suffix to 13.0 so the correct target details are used.
259 format
!("{}{}", self.target
, "13.0")
264 let Meta { stamp, res, out_dir, root }
= match prebuilt_llvm_config(builder
, target
) {
269 builder
.update_submodule(&Path
::new("src").join("llvm-project"));
270 if builder
.llvm_link_shared() && target
.contains("windows") {
271 panic
!("shared linking to LLVM is not currently supported on {}", target
.triple
);
274 builder
.info(&format
!("Building LLVM for {}", target
));
276 let _time
= util
::timeit(&builder
);
277 t
!(fs
::create_dir_all(&out_dir
));
279 // https://llvm.org/docs/CMake.html
280 let mut cfg
= cmake
::Config
::new(builder
.src
.join(root
));
281 let mut ldflags
= LdFlags
::default();
283 let profile
= match (builder
.config
.llvm_optimize
, builder
.config
.llvm_release_debuginfo
) {
284 (false, _
) => "Debug",
285 (true, false) => "Release",
286 (true, true) => "RelWithDebInfo",
289 // NOTE: remember to also update `config.example.toml` when changing the
291 let llvm_targets
= match &builder
.config
.llvm_targets
{
294 "AArch64;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;\
295 Sparc;SystemZ;WebAssembly;X86"
299 let llvm_exp_targets
= match builder
.config
.llvm_experimental_targets
{
304 let assertions
= if builder
.config
.llvm_assertions { "ON" }
else { "OFF" }
;
305 let plugins
= if builder
.config
.llvm_plugins { "ON" }
else { "OFF" }
;
306 let enable_tests
= if builder
.config
.llvm_tests { "ON" }
else { "OFF" }
;
307 let enable_warnings
= if builder
.config
.llvm_enable_warnings { "ON" }
else { "OFF" }
;
309 cfg
.out_dir(&out_dir
)
311 .define("LLVM_ENABLE_ASSERTIONS", assertions
)
312 .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF")
313 .define("LLVM_ENABLE_PLUGINS", plugins
)
314 .define("LLVM_TARGETS_TO_BUILD", llvm_targets
)
315 .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets
)
316 .define("LLVM_INCLUDE_EXAMPLES", "OFF")
317 .define("LLVM_INCLUDE_DOCS", "OFF")
318 .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
319 .define("LLVM_INCLUDE_TESTS", enable_tests
)
320 .define("LLVM_ENABLE_TERMINFO", "OFF")
321 .define("LLVM_ENABLE_LIBEDIT", "OFF")
322 .define("LLVM_ENABLE_BINDINGS", "OFF")
323 .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
324 .define("LLVM_PARALLEL_COMPILE_JOBS", builder
.jobs().to_string())
325 .define("LLVM_TARGET_ARCH", target_native
.split('
-'
).next().unwrap())
326 .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native
)
327 .define("LLVM_ENABLE_WARNINGS", enable_warnings
);
329 // Parts of our test suite rely on the `FileCheck` tool, which is built by default in
330 // `build/$TARGET/llvm/build/bin` is but *not* then installed to `build/$TARGET/llvm/bin`.
331 // This flag makes sure `FileCheck` is copied in the final binaries directory.
332 cfg
.define("LLVM_INSTALL_UTILS", "ON");
334 if builder
.config
.llvm_profile_generate
{
335 cfg
.define("LLVM_BUILD_INSTRUMENTED", "IR");
336 if let Ok(llvm_profile_dir
) = std
::env
::var("LLVM_PROFILE_DIR") {
337 cfg
.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir
);
339 cfg
.define("LLVM_BUILD_RUNTIME", "No");
341 if let Some(path
) = builder
.config
.llvm_profile_use
.as_ref() {
342 cfg
.define("LLVM_PROFDATA_FILE", &path
);
344 if builder
.config
.llvm_bolt_profile_generate
345 || builder
.config
.llvm_bolt_profile_use
.is_some()
347 // Relocations are required for BOLT to work.
348 ldflags
.push_all("-Wl,-q");
351 // Disable zstd to avoid a dependency on libzstd.so.
352 cfg
.define("LLVM_ENABLE_ZSTD", "OFF");
354 if target
!= "aarch64-apple-darwin" && !target
.contains("windows") {
355 cfg
.define("LLVM_ENABLE_ZLIB", "ON");
357 cfg
.define("LLVM_ENABLE_ZLIB", "OFF");
360 // Are we compiling for iOS/tvOS/watchOS?
361 if target
.contains("apple-ios")
362 || target
.contains("apple-tvos")
363 || target
.contains("apple-watchos")
365 // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error.
366 cfg
.define("CMAKE_OSX_SYSROOT", "/");
367 cfg
.define("CMAKE_OSX_DEPLOYMENT_TARGET", "");
368 // Prevent cmake from adding -bundle to CFLAGS automatically, which leads to a compiler error because "-bitcode_bundle" also gets added.
369 cfg
.define("LLVM_ENABLE_PLUGINS", "OFF");
370 // Zlib fails to link properly, leading to a compiler error.
371 cfg
.define("LLVM_ENABLE_ZLIB", "OFF");
374 // This setting makes the LLVM tools link to the dynamic LLVM library,
375 // which saves both memory during parallel links and overall disk space
376 // for the tools. We don't do this on every platform as it doesn't work
377 // equally well everywhere.
378 if builder
.llvm_link_shared() {
379 cfg
.define("LLVM_LINK_LLVM_DYLIB", "ON");
382 if target
.starts_with("riscv") && !target
.contains("freebsd") && !target
.contains("openbsd")
384 // RISC-V GCC erroneously requires linking against
385 // `libatomic` when using 1-byte and 2-byte C++
386 // atomics but the LLVM build system check cannot
387 // detect this. Therefore it is set manually here.
388 // Some BSD uses Clang as its system compiler and
389 // provides no libatomic in its base system so does
391 ldflags
.exe
.push(" -latomic");
392 ldflags
.shared
.push(" -latomic");
395 if target
.contains("msvc") {
396 cfg
.define("LLVM_USE_CRT_DEBUG", "MT");
397 cfg
.define("LLVM_USE_CRT_RELEASE", "MT");
398 cfg
.define("LLVM_USE_CRT_RELWITHDEBINFO", "MT");
399 cfg
.static_crt(true);
402 if target
.starts_with("i686") {
403 cfg
.define("LLVM_BUILD_32_BITS", "ON");
406 let mut enabled_llvm_projects
= Vec
::new();
408 if util
::forcing_clang_based_tests() {
409 enabled_llvm_projects
.push("clang");
410 enabled_llvm_projects
.push("compiler-rt");
413 if builder
.config
.llvm_polly
{
414 enabled_llvm_projects
.push("polly");
417 if builder
.config
.llvm_clang
{
418 enabled_llvm_projects
.push("clang");
421 // We want libxml to be disabled.
422 // See https://github.com/rust-lang/rust/pull/50104
423 cfg
.define("LLVM_ENABLE_LIBXML2", "OFF");
425 if !enabled_llvm_projects
.is_empty() {
426 enabled_llvm_projects
.sort();
427 enabled_llvm_projects
.dedup();
428 cfg
.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects
.join(";"));
431 if let Some(num_linkers
) = builder
.config
.llvm_link_jobs
{
433 cfg
.define("LLVM_PARALLEL_LINK_JOBS", num_linkers
.to_string());
437 // https://llvm.org/docs/HowToCrossCompileLLVM.html
438 if target
!= builder
.config
.build
{
439 let LlvmResult { llvm_config, .. }
=
440 builder
.ensure(Llvm { target: builder.config.build }
);
441 if !builder
.config
.dry_run() {
442 let llvm_bindir
= output(Command
::new(&llvm_config
).arg("--bindir"));
443 let host_bin
= Path
::new(llvm_bindir
.trim());
446 host_bin
.join("llvm-tblgen").with_extension(EXE_EXTENSION
),
448 // LLVM_NM is required for cross compiling using MSVC
449 cfg
.define("LLVM_NM", host_bin
.join("llvm-nm").with_extension(EXE_EXTENSION
));
451 cfg
.define("LLVM_CONFIG_PATH", llvm_config
);
452 if builder
.config
.llvm_clang
{
453 let build_bin
= builder
.llvm_out(builder
.config
.build
).join("build").join("bin");
454 let clang_tblgen
= build_bin
.join("clang-tblgen").with_extension(EXE_EXTENSION
);
455 if !builder
.config
.dry_run() && !clang_tblgen
.exists() {
456 panic
!("unable to find {}", clang_tblgen
.display());
458 cfg
.define("CLANG_TABLEGEN", clang_tblgen
);
462 let llvm_version_suffix
= if let Some(ref suffix
) = builder
.config
.llvm_version_suffix
{
463 // Allow version-suffix="" to not define a version suffix at all.
464 if !suffix
.is_empty() { Some(suffix.to_string()) }
else { None }
465 } else if builder
.config
.channel
== "dev" {
466 // Changes to a version suffix require a complete rebuild of the LLVM.
467 // To avoid rebuilds during a time of version bump, don't include rustc
468 // release number on the dev channel.
469 Some("-rust-dev".to_string())
471 Some(format
!("-rust-{}-{}", builder
.version
, builder
.config
.channel
))
473 if let Some(ref suffix
) = llvm_version_suffix
{
474 cfg
.define("LLVM_VERSION_SUFFIX", suffix
);
477 configure_cmake(builder
, target
, &mut cfg
, true, ldflags
, &[]);
478 configure_llvm(builder
, target
, &mut cfg
);
480 for (key
, val
) in &builder
.config
.llvm_build_config
{
481 cfg
.define(key
, val
);
484 if builder
.config
.dry_run() {
490 // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
491 // libLLVM.dylib will be built. However, llvm-config will still look
492 // for a versioned path like libLLVM-14.dylib. Manually create a symbolic
493 // link to make llvm-config happy.
494 if builder
.llvm_link_shared() && target
.contains("apple-darwin") {
495 let mut cmd
= Command
::new(&res
.llvm_config
);
496 let version
= output(cmd
.arg("--version"));
497 let major
= version
.split('
.'
).next().unwrap();
498 let lib_name
= match llvm_version_suffix
{
499 Some(s
) => format
!("libLLVM-{}{}.dylib", major
, s
),
500 None
=> format
!("libLLVM-{}.dylib", major
),
503 let lib_llvm
= out_dir
.join("build").join("lib").join(lib_name
);
504 if !lib_llvm
.exists() {
505 t
!(builder
.symlink_file("libLLVM.dylib", &lib_llvm
));
515 fn check_llvm_version(builder
: &Builder
<'_
>, llvm_config
: &Path
) {
516 if builder
.config
.dry_run() {
520 let mut cmd
= Command
::new(llvm_config
);
521 let version
= output(cmd
.arg("--version"));
522 let mut parts
= version
.split('
.'
).take(2).filter_map(|s
| s
.parse
::<u32>().ok());
523 if let (Some(major
), Some(_minor
)) = (parts
.next(), parts
.next()) {
528 panic
!("\n\nbad LLVM version: {}, need >=14.0\n\n", version
)
532 builder
: &Builder
<'_
>,
533 target
: TargetSelection
,
534 cfg
: &mut cmake
::Config
,
535 use_compiler_launcher
: bool
,
536 mut ldflags
: LdFlags
,
537 extra_compiler_flags
: &[&str],
539 // Do not print installation messages for up-to-date files.
540 // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
541 cfg
.define("CMAKE_INSTALL_MESSAGE", "LAZY");
543 // Do not allow the user's value of DESTDIR to influence where
544 // LLVM will install itself. LLVM must always be installed in our
545 // own build directories.
546 cfg
.env("DESTDIR", "");
549 cfg
.generator("Ninja");
551 cfg
.target(&target
.triple
).host(&builder
.config
.build
.triple
);
553 if target
!= builder
.config
.build
{
554 cfg
.define("CMAKE_CROSSCOMPILING", "True");
556 if target
.contains("netbsd") {
557 cfg
.define("CMAKE_SYSTEM_NAME", "NetBSD");
558 } else if target
.contains("freebsd") {
559 cfg
.define("CMAKE_SYSTEM_NAME", "FreeBSD");
560 } else if target
.contains("windows") {
561 cfg
.define("CMAKE_SYSTEM_NAME", "Windows");
562 } else if target
.contains("haiku") {
563 cfg
.define("CMAKE_SYSTEM_NAME", "Haiku");
564 } else if target
.contains("solaris") || target
.contains("illumos") {
565 cfg
.define("CMAKE_SYSTEM_NAME", "SunOS");
566 } else if target
.contains("linux") {
567 cfg
.define("CMAKE_SYSTEM_NAME", "Linux");
569 // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in
570 // that case like CMake we cannot easily determine system version either.
572 // Since, the LLVM itself makes rather limited use of version checks in
573 // CMakeFiles (and then only in tests), and so far no issues have been
574 // reported, the system version is currently left unset.
576 if target
.contains("darwin") {
577 // Make sure that CMake does not build universal binaries on macOS.
578 // Explicitly specify the one single target architecture.
579 if target
.starts_with("aarch64") {
580 // macOS uses a different name for building arm64
581 cfg
.define("CMAKE_OSX_ARCHITECTURES", "arm64");
582 } else if target
.starts_with("i686") {
583 // macOS uses a different name for building i386
584 cfg
.define("CMAKE_OSX_ARCHITECTURES", "i386");
586 cfg
.define("CMAKE_OSX_ARCHITECTURES", target
.triple
.split('
-'
).next().unwrap());
591 let sanitize_cc
= |cc
: &Path
| {
592 if target
.contains("msvc") {
593 OsString
::from(cc
.to_str().unwrap().replace("\\", "/"))
595 cc
.as_os_str().to_owned()
599 // MSVC with CMake uses msbuild by default which doesn't respect these
600 // vars that we'd otherwise configure. In that case we just skip this
602 if target
.contains("msvc") && !builder
.ninja() {
606 let (cc
, cxx
) = match builder
.config
.llvm_clang_cl
{
607 Some(ref cl
) => (cl
.as_ref(), cl
.as_ref()),
608 None
=> (builder
.cc(target
), builder
.cxx(target
).unwrap()),
611 // Handle msvc + ninja + ccache specially (this is what the bots use)
612 if target
.contains("msvc") && builder
.ninja() && builder
.config
.ccache
.is_some() {
613 let mut wrap_cc
= env
::current_exe().expect("failed to get cwd");
614 wrap_cc
.set_file_name("sccache-plus-cl.exe");
616 cfg
.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc
))
617 .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc
));
618 cfg
.env("SCCACHE_PATH", builder
.config
.ccache
.as_ref().unwrap())
619 .env("SCCACHE_TARGET", target
.triple
)
620 .env("SCCACHE_CC", &cc
)
621 .env("SCCACHE_CXX", &cxx
);
623 // Building LLVM on MSVC can be a little ludicrous at times. We're so far
624 // off the beaten path here that I'm not really sure this is even half
625 // supported any more. Here we're trying to:
627 // * Build LLVM on MSVC
628 // * Build LLVM with `clang-cl` instead of `cl.exe`
629 // * Build a project with `sccache`
630 // * Build for 32-bit as well
631 // * Build with Ninja
633 // For `cl.exe` there are different binaries to compile 32/64 bit which
634 // we use but for `clang-cl` there's only one which internally
635 // multiplexes via flags. As a result it appears that CMake's detection
636 // of a compiler's architecture and such on MSVC **doesn't** pass any
637 // custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we
638 // use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which
639 // definitely causes problems since all the env vars are pointing to
642 // To hack around this... again... we pass an argument that's
643 // unconditionally passed in the sccache shim. This'll get CMake to
644 // correctly diagnose it's doing a 32-bit compilation and LLVM will
645 // internally configure itself appropriately.
646 if builder
.config
.llvm_clang_cl
.is_some() && target
.contains("i686") {
647 cfg
.env("SCCACHE_EXTRA_ARGS", "-m32");
650 // If ccache is configured we inform the build a little differently how
651 // to invoke ccache while also invoking our compilers.
652 if use_compiler_launcher
{
653 if let Some(ref ccache
) = builder
.config
.ccache
{
654 cfg
.define("CMAKE_C_COMPILER_LAUNCHER", ccache
)
655 .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache
);
658 cfg
.define("CMAKE_C_COMPILER", sanitize_cc(cc
))
659 .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx
))
660 .define("CMAKE_ASM_COMPILER", sanitize_cc(cc
));
663 cfg
.build_arg("-j").build_arg(builder
.jobs().to_string());
664 let mut cflags
: OsString
= builder
.cflags(target
, GitRepo
::Llvm
, CLang
::C
).join(" ").into();
665 if let Some(ref s
) = builder
.config
.llvm_cflags
{
669 // Some compiler features used by LLVM (such as thread locals) will not work on a min version below iOS 10.
670 if target
.contains("apple-ios") {
671 if target
.contains("86-") {
672 cflags
.push(" -miphonesimulator-version-min=10.0");
674 cflags
.push(" -miphoneos-version-min=10.0");
677 if builder
.config
.llvm_clang_cl
.is_some() {
678 cflags
.push(&format
!(" --target={}", target
));
680 for flag
in extra_compiler_flags
{
681 cflags
.push(&format
!(" {}", flag
));
683 cfg
.define("CMAKE_C_FLAGS", cflags
);
684 let mut cxxflags
: OsString
= builder
.cflags(target
, GitRepo
::Llvm
, CLang
::Cxx
).join(" ").into();
685 if let Some(ref s
) = builder
.config
.llvm_cxxflags
{
689 if builder
.config
.llvm_clang_cl
.is_some() {
690 cxxflags
.push(&format
!(" --target={}", target
));
692 for flag
in extra_compiler_flags
{
693 cxxflags
.push(&format
!(" {}", flag
));
695 cfg
.define("CMAKE_CXX_FLAGS", cxxflags
);
696 if let Some(ar
) = builder
.ar(target
) {
697 if ar
.is_absolute() {
698 // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
699 // tries to resolve this path in the LLVM build directory.
700 cfg
.define("CMAKE_AR", sanitize_cc(ar
));
704 if let Some(ranlib
) = builder
.ranlib(target
) {
705 if ranlib
.is_absolute() {
706 // LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it
707 // tries to resolve this path in the LLVM build directory.
708 cfg
.define("CMAKE_RANLIB", sanitize_cc(ranlib
));
712 if let Some(ref flags
) = builder
.config
.llvm_ldflags
{
713 ldflags
.push_all(flags
);
716 if let Some(flags
) = get_var("LDFLAGS", &builder
.config
.build
.triple
, &target
.triple
) {
717 ldflags
.push_all(&flags
);
720 // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
721 // We also do this if the user explicitly requested static libstdc++.
722 if builder
.config
.llvm_static_stdcpp
{
723 if !target
.contains("msvc") && !target
.contains("netbsd") && !target
.contains("solaris") {
724 if target
.contains("apple") || target
.contains("windows") {
725 ldflags
.push_all("-static-libstdc++");
727 ldflags
.push_all("-Wl,-Bsymbolic -static-libstdc++");
732 cfg
.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags
.shared
);
733 cfg
.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags
.module
);
734 cfg
.define("CMAKE_EXE_LINKER_FLAGS", &ldflags
.exe
);
736 if env
::var_os("SCCACHE_ERROR_LOG").is_some() {
737 cfg
.env("RUSTC_LOG", "sccache=warn");
741 fn configure_llvm(builder
: &Builder
<'_
>, target
: TargetSelection
, cfg
: &mut cmake
::Config
) {
742 // ThinLTO is only available when building with LLVM, enabling LLD is required.
743 // Apple's linker ld64 supports ThinLTO out of the box though, so don't use LLD on Darwin.
744 if builder
.config
.llvm_thin_lto
{
745 cfg
.define("LLVM_ENABLE_LTO", "Thin");
746 if !target
.contains("apple") {
747 cfg
.define("LLVM_ENABLE_LLD", "ON");
751 if let Some(ref linker
) = builder
.config
.llvm_use_linker
{
752 cfg
.define("LLVM_USE_LINKER", linker
);
755 if builder
.config
.llvm_allow_old_toolchain
{
756 cfg
.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
760 // Adapted from https://github.com/alexcrichton/cc-rs/blob/fba7feded71ee4f63cfe885673ead6d7b4f2f454/src/lib.rs#L2347-L2365
761 fn get_var(var_base
: &str, host
: &str, target
: &str) -> Option
<OsString
> {
762 let kind
= if host
== target { "HOST" }
else { "TARGET" }
;
763 let target_u
= target
.replace("-", "_");
764 env
::var_os(&format
!("{}_{}", var_base
, target
))
765 .or_else(|| env
::var_os(&format
!("{}_{}", var_base
, target_u
)))
766 .or_else(|| env
::var_os(&format
!("{}_{}", kind
, var_base
)))
767 .or_else(|| env
::var_os(var_base
))
770 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
772 pub target
: TargetSelection
,
776 type Output
= PathBuf
;
777 const ONLY_HOSTS
: bool
= true;
779 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
780 run
.path("src/llvm-project/lld")
783 fn make_run(run
: RunConfig
<'_
>) {
784 run
.builder
.ensure(Lld { target: run.target }
);
787 /// Compile LLD for `target`.
788 fn run(self, builder
: &Builder
<'_
>) -> PathBuf
{
789 if builder
.config
.dry_run() {
790 return PathBuf
::from("lld-out-dir-test-gen");
792 let target
= self.target
;
794 let LlvmResult { llvm_config, llvm_cmake_dir }
= builder
.ensure(Llvm { target }
);
796 // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path
797 // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin`
798 // subfolder. We check if that's the case, and if LLD's binary already exists there next to
799 // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source.
800 let ci_llvm_bin
= llvm_config
.parent().unwrap();
801 if ci_llvm_bin
.is_dir() && ci_llvm_bin
.file_name().unwrap() == "bin" {
802 let lld_path
= ci_llvm_bin
.join(exe("lld", target
));
803 if lld_path
.exists() {
804 // The following steps copying `lld` as `rust-lld` to the sysroot, expect it in the
805 // `bin` subfolder of this step's out dir.
806 return ci_llvm_bin
.parent().unwrap().to_path_buf();
810 let out_dir
= builder
.lld_out(target
);
811 let done_stamp
= out_dir
.join("lld-finished-building");
812 if done_stamp
.exists() {
816 builder
.info(&format
!("Building LLD for {}", target
));
817 let _time
= util
::timeit(&builder
);
818 t
!(fs
::create_dir_all(&out_dir
));
820 let mut cfg
= cmake
::Config
::new(builder
.src
.join("src/llvm-project/lld"));
821 let mut ldflags
= LdFlags
::default();
823 // When building LLD as part of a build with instrumentation on windows, for example
824 // when doing PGO on CI, cmake or clang-cl don't automatically link clang's
825 // profiler runtime in. In that case, we need to manually ask cmake to do it, to avoid
826 // linking errors, much like LLVM's cmake setup does in that situation.
827 if builder
.config
.llvm_profile_generate
&& target
.contains("msvc") {
828 if let Some(clang_cl_path
) = builder
.config
.llvm_clang_cl
.as_ref() {
829 // Find clang's runtime library directory and push that as a search path to the
830 // cmake linker flags.
831 let clang_rt_dir
= get_clang_cl_resource_dir(clang_cl_path
);
832 ldflags
.push_all(&format
!("/libpath:{}", clang_rt_dir
.display()));
836 configure_cmake(builder
, target
, &mut cfg
, true, ldflags
, &[]);
837 configure_llvm(builder
, target
, &mut cfg
);
839 // Re-use the same flags as llvm to control the level of debug information
840 // generated for lld.
841 let profile
= match (builder
.config
.llvm_optimize
, builder
.config
.llvm_release_debuginfo
) {
842 (false, _
) => "Debug",
843 (true, false) => "Release",
844 (true, true) => "RelWithDebInfo",
847 cfg
.out_dir(&out_dir
)
849 .define("LLVM_CMAKE_DIR", llvm_cmake_dir
)
850 .define("LLVM_INCLUDE_TESTS", "OFF");
852 if target
!= builder
.config
.build
{
853 // Use the host llvm-tblgen binary.
856 llvm_config
.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION
),
862 t
!(File
::create(&done_stamp
));
867 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
868 pub struct Sanitizers
{
869 pub target
: TargetSelection
,
872 impl Step
for Sanitizers
{
873 type Output
= Vec
<SanitizerRuntime
>;
875 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
876 run
.alias("sanitizers")
879 fn make_run(run
: RunConfig
<'_
>) {
880 run
.builder
.ensure(Sanitizers { target: run.target }
);
883 /// Builds sanitizer runtime libraries.
884 fn run(self, builder
: &Builder
<'_
>) -> Self::Output
{
885 let compiler_rt_dir
= builder
.src
.join("src/llvm-project/compiler-rt");
886 if !compiler_rt_dir
.exists() {
890 let out_dir
= builder
.native_dir(self.target
).join("sanitizers");
891 let runtimes
= supported_sanitizers(&out_dir
, self.target
, &builder
.config
.channel
);
892 if runtimes
.is_empty() {
896 let LlvmResult { llvm_config, .. }
= builder
.ensure(Llvm { target: builder.config.build }
);
897 if builder
.config
.dry_run() {
901 let stamp
= out_dir
.join("sanitizers-finished-building");
902 let stamp
= HashStamp
::new(stamp
, builder
.in_tree_llvm_info
.sha());
905 if stamp
.hash
.is_none() {
906 builder
.info(&format
!(
907 "Rebuild sanitizers by removing the file `{}`",
914 builder
.info(&format
!("Building sanitizers for {}", self.target
));
916 let _time
= util
::timeit(&builder
);
918 let mut cfg
= cmake
::Config
::new(&compiler_rt_dir
);
919 cfg
.profile("Release");
920 cfg
.define("CMAKE_C_COMPILER_TARGET", self.target
.triple
);
921 cfg
.define("COMPILER_RT_BUILD_BUILTINS", "OFF");
922 cfg
.define("COMPILER_RT_BUILD_CRT", "OFF");
923 cfg
.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF");
924 cfg
.define("COMPILER_RT_BUILD_PROFILE", "OFF");
925 cfg
.define("COMPILER_RT_BUILD_SANITIZERS", "ON");
926 cfg
.define("COMPILER_RT_BUILD_XRAY", "OFF");
927 cfg
.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON");
928 cfg
.define("COMPILER_RT_USE_LIBCXX", "OFF");
929 cfg
.define("LLVM_CONFIG_PATH", &llvm_config
);
931 // On Darwin targets the sanitizer runtimes are build as universal binaries.
932 // Unfortunately sccache currently lacks support to build them successfully.
933 // Disable compiler launcher on Darwin targets to avoid potential issues.
934 let use_compiler_launcher
= !self.target
.contains("apple-darwin");
935 let extra_compiler_flags
: &[&str] =
936 if self.target
.contains("apple") { &["-fembed-bitcode=off"] }
else { &[] }
;
941 use_compiler_launcher
,
943 extra_compiler_flags
,
946 t
!(fs
::create_dir_all(&out_dir
));
947 cfg
.out_dir(out_dir
);
949 for runtime
in &runtimes
{
950 cfg
.build_target(&runtime
.cmake_target
);
959 #[derive(Clone, Debug)]
960 pub struct SanitizerRuntime
{
961 /// CMake target used to build the runtime.
962 pub cmake_target
: String
,
963 /// Path to the built runtime library.
965 /// Library filename that will be used rustc.
969 /// Returns sanitizers available on a given target.
970 fn supported_sanitizers(
972 target
: TargetSelection
,
974 ) -> Vec
<SanitizerRuntime
> {
975 let darwin_libs
= |os
: &str, components
: &[&str]| -> Vec
<SanitizerRuntime
> {
978 .map(move |c
| SanitizerRuntime
{
979 cmake_target
: format
!("clang_rt.{}_{}_dynamic", c
, os
),
981 .join(&format
!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c
, os
)),
982 name
: format
!("librustc-{}_rt.{}.dylib", channel
, c
),
987 let common_libs
= |os
: &str, arch
: &str, components
: &[&str]| -> Vec
<SanitizerRuntime
> {
990 .map(move |c
| SanitizerRuntime
{
991 cmake_target
: format
!("clang_rt.{}-{}", c
, arch
),
992 path
: out_dir
.join(&format
!("build/lib/{}/libclang_rt.{}-{}.a", os
, c
, arch
)),
993 name
: format
!("librustc-{}_rt.{}.a", channel
, c
),
998 match &*target
.triple
{
999 "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1000 "aarch64-apple-ios" => darwin_libs("ios", &["asan", "tsan"]),
1001 "aarch64-apple-ios-sim" => darwin_libs("iossim", &["asan", "tsan"]),
1002 "aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
1003 "aarch64-unknown-linux-gnu" => {
1004 common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
1006 "aarch64-unknown-linux-ohos" => {
1007 common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
1009 "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1010 "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
1011 "x86_64-apple-ios" => darwin_libs("iossim", &["asan", "tsan"]),
1012 "x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]),
1013 "x86_64-unknown-netbsd" => {
1014 common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"])
1016 "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
1017 "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
1018 "x86_64-unknown-linux-gnu" => {
1019 common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
1021 "x86_64-unknown-linux-musl" => {
1022 common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
1024 "s390x-unknown-linux-gnu" => {
1025 common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"])
1027 "s390x-unknown-linux-musl" => {
1028 common_libs("linux", "s390x", &["asan", "lsan", "msan", "tsan"])
1036 hash
: Option
<Vec
<u8>>,
1040 fn new(path
: PathBuf
, hash
: Option
<&str>) -> Self {
1041 HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) }
1044 fn is_done(&self) -> bool
{
1045 match fs
::read(&self.path
) {
1046 Ok(h
) => self.hash
.as_deref().unwrap_or(b
"") == h
.as_slice(),
1047 Err(e
) if e
.kind() == io
::ErrorKind
::NotFound
=> false,
1049 panic
!("failed to read stamp file `{}`: {}", self.path
.display(), e
);
1054 fn remove(&self) -> io
::Result
<()> {
1055 match fs
::remove_file(&self.path
) {
1058 if e
.kind() == io
::ErrorKind
::NotFound
{
1067 fn write(&self) -> io
::Result
<()> {
1068 fs
::write(&self.path
, self.hash
.as_deref().unwrap_or(b
""))
1072 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1073 pub struct CrtBeginEnd
{
1074 pub target
: TargetSelection
,
1077 impl Step
for CrtBeginEnd
{
1078 type Output
= PathBuf
;
1080 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
1081 run
.path("src/llvm-project/compiler-rt/lib/crt")
1084 fn make_run(run
: RunConfig
<'_
>) {
1085 run
.builder
.ensure(CrtBeginEnd { target: run.target }
);
1088 /// Build crtbegin.o/crtend.o for musl target.
1089 fn run(self, builder
: &Builder
<'_
>) -> Self::Output
{
1090 builder
.update_submodule(&Path
::new("src/llvm-project"));
1092 let out_dir
= builder
.native_dir(self.target
).join("crt");
1094 if builder
.config
.dry_run() {
1098 let crtbegin_src
= builder
.src
.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c");
1099 let crtend_src
= builder
.src
.join("src/llvm-project/compiler-rt/lib/crt/crtend.c");
1100 if up_to_date(&crtbegin_src
, &out_dir
.join("crtbegin.o"))
1101 && up_to_date(&crtend_src
, &out_dir
.join("crtendS.o"))
1106 builder
.info("Building crtbegin.o and crtend.o");
1107 t
!(fs
::create_dir_all(&out_dir
));
1109 let mut cfg
= cc
::Build
::new();
1111 if let Some(ar
) = builder
.ar(self.target
) {
1114 cfg
.compiler(builder
.cc(self.target
));
1115 cfg
.cargo_metadata(false)
1117 .target(&self.target
.triple
)
1118 .host(&builder
.config
.build
.triple
)
1125 // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
1126 // Currently only consumer of those objects is musl, which use .init_array/.fini_array
1127 // instead of .ctors/.dtors
1128 cfg
.flag("-std=c11")
1129 .define("CRT_HAS_INITFINI_ARRAY", None
)
1130 .define("EH_USE_FRAME_REGISTRY", None
);
1134 t
!(fs
::copy(out_dir
.join("crtbegin.o"), out_dir
.join("crtbeginS.o")));
1135 t
!(fs
::copy(out_dir
.join("crtend.o"), out_dir
.join("crtendS.o")));
1140 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1141 pub struct Libunwind
{
1142 pub target
: TargetSelection
,
1145 impl Step
for Libunwind
{
1146 type Output
= PathBuf
;
1148 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
1149 run
.path("src/llvm-project/libunwind")
1152 fn make_run(run
: RunConfig
<'_
>) {
1153 run
.builder
.ensure(Libunwind { target: run.target }
);
1156 /// Build linunwind.a
1157 fn run(self, builder
: &Builder
<'_
>) -> Self::Output
{
1158 builder
.update_submodule(&Path
::new("src/llvm-project"));
1160 if builder
.config
.dry_run() {
1161 return PathBuf
::new();
1164 let out_dir
= builder
.native_dir(self.target
).join("libunwind");
1165 let root
= builder
.src
.join("src/llvm-project/libunwind");
1167 if up_to_date(&root
, &out_dir
.join("libunwind.a")) {
1171 builder
.info(&format
!("Building libunwind.a for {}", self.target
.triple
));
1172 t
!(fs
::create_dir_all(&out_dir
));
1174 let mut cc_cfg
= cc
::Build
::new();
1175 let mut cpp_cfg
= cc
::Build
::new();
1178 cpp_cfg
.cpp_set_stdlib(None
);
1179 cpp_cfg
.flag("-nostdinc++");
1180 cpp_cfg
.flag("-fno-exceptions");
1181 cpp_cfg
.flag("-fno-rtti");
1182 cpp_cfg
.flag_if_supported("-fvisibility-global-new-delete-hidden");
1184 for cfg
in [&mut cc_cfg
, &mut cpp_cfg
].iter_mut() {
1185 if let Some(ar
) = builder
.ar(self.target
) {
1188 cfg
.target(&self.target
.triple
);
1189 cfg
.host(&builder
.config
.build
.triple
);
1190 cfg
.warnings(false);
1192 // get_compiler() need set opt_level first.
1194 cfg
.flag("-fstrict-aliasing");
1195 cfg
.flag("-funwind-tables");
1196 cfg
.flag("-fvisibility=hidden");
1197 cfg
.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None
);
1198 cfg
.include(root
.join("include"));
1199 cfg
.cargo_metadata(false);
1200 cfg
.out_dir(&out_dir
);
1202 if self.target
.contains("x86_64-fortanix-unknown-sgx") {
1203 cfg
.static_flag(true);
1204 cfg
.flag("-fno-stack-protector");
1205 cfg
.flag("-ffreestanding");
1206 cfg
.flag("-fexceptions");
1208 // easiest way to undefine since no API available in cc::Build to undefine
1209 cfg
.flag("-U_FORTIFY_SOURCE");
1210 cfg
.define("_FORTIFY_SOURCE", "0");
1211 cfg
.define("RUST_SGX", "1");
1212 cfg
.define("__NO_STRING_INLINES", None
);
1213 cfg
.define("__NO_MATH_INLINES", None
);
1214 cfg
.define("_LIBUNWIND_IS_BAREMETAL", None
);
1215 cfg
.define("__LIBUNWIND_IS_NATIVE_ONLY", None
);
1216 cfg
.define("NDEBUG", None
);
1218 if self.target
.contains("windows") {
1219 cfg
.define("_LIBUNWIND_HIDE_SYMBOLS", "1");
1220 cfg
.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
1224 cc_cfg
.compiler(builder
.cc(self.target
));
1225 if let Ok(cxx
) = builder
.cxx(self.target
) {
1226 cpp_cfg
.compiler(cxx
);
1228 cc_cfg
.compiler(builder
.cc(self.target
));
1231 // Don't set this for clang
1232 // By default, Clang builds C code in GNU C17 mode.
1233 // By default, Clang builds C++ code according to the C++98 standard,
1234 // with many C++11 features accepted as extensions.
1235 if cc_cfg
.get_compiler().is_like_gnu() {
1236 cc_cfg
.flag("-std=c99");
1238 if cpp_cfg
.get_compiler().is_like_gnu() {
1239 cpp_cfg
.flag("-std=c++11");
1242 if self.target
.contains("x86_64-fortanix-unknown-sgx") || self.target
.contains("musl") {
1243 // use the same GCC C compiler command to compile C++ code so we do not need to setup the
1244 // C++ compiler env variables on the builders.
1245 // Don't set this for clang++, as clang++ is able to compile this without libc++.
1246 if cpp_cfg
.get_compiler().is_like_gnu() {
1248 cpp_cfg
.compiler(builder
.cc(self.target
));
1252 let mut c_sources
= vec
![
1254 "UnwindLevel1-gcc-ext.c",
1256 "UnwindRegistersRestore.S",
1257 "UnwindRegistersSave.S",
1260 let cpp_sources
= vec
!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
1261 let cpp_len
= cpp_sources
.len();
1263 if self.target
.contains("x86_64-fortanix-unknown-sgx") {
1264 c_sources
.push("UnwindRustSgx.c");
1267 for src
in c_sources
{
1268 cc_cfg
.file(root
.join("src").join(src
).canonicalize().unwrap());
1271 for src
in &cpp_sources
{
1272 cpp_cfg
.file(root
.join("src").join(src
).canonicalize().unwrap());
1275 cpp_cfg
.compile("unwind-cpp");
1277 // FIXME: https://github.com/alexcrichton/cc-rs/issues/545#issuecomment-679242845
1279 for entry
in fs
::read_dir(&out_dir
).unwrap() {
1280 let file
= entry
.unwrap().path().canonicalize().unwrap();
1281 if file
.is_file() && file
.extension() == Some(OsStr
::new("o")) {
1282 // file name starts with "Unwind-EHABI", "Unwind-seh" or "libunwind"
1283 let file_name
= file
.file_name().unwrap().to_str().expect("UTF-8 file name");
1284 if cpp_sources
.iter().any(|f
| file_name
.starts_with(&f
[..f
.len() - 4])) {
1285 cc_cfg
.object(&file
);
1290 assert_eq
!(cpp_len
, count
, "Can't get object files from {:?}", &out_dir
);
1292 cc_cfg
.compile("unwind");