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::bolt
::{instrument_with_bolt_inplace, optimize_library_with_bolt_inplace}
;
20 use crate::builder
::{Builder, RunConfig, ShouldRun, Step}
;
22 use crate::config
::{Config, TargetSelection}
;
23 use crate::util
::get_clang_cl_resource_dir
;
24 use crate::util
::{self, exe, output, t, up_to_date}
;
25 use crate::{CLang, GitRepo}
;
29 build_llvm_config
: PathBuf
,
34 // Linker flags to pass to LLVM's CMake invocation.
35 #[derive(Debug, Clone, Default)]
37 // CMAKE_EXE_LINKER_FLAGS
39 // CMAKE_SHARED_LINKER_FLAGS
41 // CMAKE_MODULE_LINKER_FLAGS
46 fn push_all(&mut self, s
: impl AsRef
<OsStr
>) {
50 self.shared
.push(" ");
52 self.module
.push(" ");
57 // This returns whether we've already previously built LLVM.
59 // It's used to avoid busting caches during x.py check -- if we've already built
60 // LLVM, it's fine for us to not try to avoid doing so.
62 // This will return the llvm-config if it can get it (but it will not build it
64 pub fn prebuilt_llvm_config(
65 builder
: &Builder
<'_
>,
66 target
: TargetSelection
,
67 ) -> Result
<PathBuf
, Meta
> {
68 builder
.config
.maybe_download_ci_llvm();
70 // If we're using a custom LLVM bail out here, but we can only use a
71 // custom LLVM for the build triple.
72 if let Some(config
) = builder
.config
.target_config
.get(&target
) {
73 if let Some(ref s
) = config
.llvm_config
{
74 check_llvm_version(builder
, s
);
75 return Ok(s
.to_path_buf());
79 let root
= "src/llvm-project/llvm";
80 let out_dir
= builder
.llvm_out(target
);
82 let mut llvm_config_ret_dir
= builder
.llvm_out(builder
.config
.build
);
83 if !builder
.config
.build
.contains("msvc") || builder
.ninja() {
84 llvm_config_ret_dir
.push("build");
86 llvm_config_ret_dir
.push("bin");
88 let build_llvm_config
= llvm_config_ret_dir
.join(exe("llvm-config", builder
.config
.build
));
90 let stamp
= out_dir
.join("llvm-finished-building");
91 let stamp
= HashStamp
::new(stamp
, builder
.in_tree_llvm_info
.sha());
93 if builder
.config
.llvm_skip_rebuild
&& stamp
.path
.exists() {
96 Using a potentially stale build of LLVM; \
97 This may not behave well.",
99 return Ok(build_llvm_config
);
103 if stamp
.hash
.is_none() {
105 "Could not determine the LLVM submodule commit hash. \
106 Assuming that an LLVM rebuild is not necessary.",
108 builder
.info(&format
!(
109 "To force LLVM to rebuild, remove the file `{}`",
113 return Ok(build_llvm_config
);
116 Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() }
)
119 /// This retrieves the LLVM sha we *want* to use, according to git history.
120 pub(crate) fn detect_llvm_sha(config
: &Config
, is_git
: bool
) -> String
{
121 let llvm_sha
= if is_git
{
122 let mut rev_list
= config
.git();
124 PathBuf
::from("rev-list"),
125 format
!("--author={}", config
.stage0_metadata
.config
.git_merge_commit_email
).into(),
127 "--first-parent".into(),
130 config
.src
.join("src/llvm-project"),
131 config
.src
.join("src/bootstrap/download-ci-llvm-stamp"),
132 // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
133 config
.src
.join("src/version"),
135 output(&mut rev_list
).trim().to_owned()
136 } else if let Some(info
) = channel
::read_commit_info_file(&config
.src
) {
137 info
.sha
.trim().to_owned()
143 eprintln
!("error: could not find commit hash for downloading LLVM");
144 eprintln
!("help: maybe your repository history is too shallow?");
145 eprintln
!("help: consider disabling `download-ci-llvm`");
146 eprintln
!("help: or fetch enough history to include one upstream commit");
153 /// Returns whether the CI-found LLVM is currently usable.
155 /// This checks both the build triple platform to confirm we're usable at all,
156 /// and then verifies if the current HEAD matches the detected LLVM SHA head,
157 /// in which case LLVM is indicated as not available.
158 pub(crate) fn is_ci_llvm_available(config
: &Config
, asserts
: bool
) -> bool
{
159 // This is currently all tier 1 targets and tier 2 targets with host tools
160 // (since others may not have CI artifacts)
161 // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
162 let supported_platforms
= [
164 "aarch64-unknown-linux-gnu",
165 "i686-pc-windows-gnu",
166 "i686-pc-windows-msvc",
167 "i686-unknown-linux-gnu",
168 "x86_64-unknown-linux-gnu",
169 "x86_64-apple-darwin",
170 "x86_64-pc-windows-gnu",
171 "x86_64-pc-windows-msvc",
172 // tier 2 with host tools
173 "aarch64-apple-darwin",
174 "aarch64-pc-windows-msvc",
175 "aarch64-unknown-linux-musl",
176 "arm-unknown-linux-gnueabi",
177 "arm-unknown-linux-gnueabihf",
178 "armv7-unknown-linux-gnueabihf",
179 "mips-unknown-linux-gnu",
180 "mips64-unknown-linux-gnuabi64",
181 "mips64el-unknown-linux-gnuabi64",
182 "mipsel-unknown-linux-gnu",
183 "powerpc-unknown-linux-gnu",
184 "powerpc64-unknown-linux-gnu",
185 "powerpc64le-unknown-linux-gnu",
186 "riscv64gc-unknown-linux-gnu",
187 "s390x-unknown-linux-gnu",
188 "x86_64-unknown-freebsd",
189 "x86_64-unknown-illumos",
190 "x86_64-unknown-linux-musl",
191 "x86_64-unknown-netbsd",
193 if !supported_platforms
.contains(&&*config
.build
.triple
) {
197 let triple
= &*config
.build
.triple
;
198 if (triple
== "aarch64-unknown-linux-gnu" || triple
.contains("i686")) && asserts
{
199 // No alt builder for aarch64-unknown-linux-gnu today.
203 if crate::util
::CiEnv
::is_ci() {
204 // We assume we have access to git, so it's okay to unconditionally pass
206 let llvm_sha
= detect_llvm_sha(config
, true);
207 let head_sha
= output(config
.git().arg("rev-parse").arg("HEAD"));
208 let head_sha
= head_sha
.trim();
209 if llvm_sha
== head_sha
{
211 "Detected LLVM as non-available: running in CI and modified LLVM in this change"
220 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
222 pub target
: TargetSelection
,
226 type Output
= PathBuf
; // path to llvm-config
228 const ONLY_HOSTS
: bool
= true;
230 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
231 run
.path("src/llvm-project").path("src/llvm-project/llvm")
234 fn make_run(run
: RunConfig
<'_
>) {
235 run
.builder
.ensure(Llvm { target: run.target }
);
238 /// Compile LLVM for `target`.
239 fn run(self, builder
: &Builder
<'_
>) -> PathBuf
{
240 let target
= self.target
;
241 let target_native
= if self.target
.starts_with("riscv") {
242 // RISC-V target triples in Rust is not named the same as C compiler target triples.
243 // This converts Rust RISC-V target triples to C compiler triples.
244 let idx
= target
.triple
.find('
-'
).unwrap();
246 format
!("riscv{}{}", &target
.triple
[5..7], &target
.triple
[idx
..])
247 } else if self.target
.starts_with("powerpc") && self.target
.ends_with("freebsd") {
248 // FreeBSD 13 had incompatible ABI changes on all PowerPC platforms.
249 // Set the version suffix to 13.0 so the correct target details are used.
250 format
!("{}{}", self.target
, "13.0")
255 let Meta { stamp, build_llvm_config, out_dir, root }
=
256 match prebuilt_llvm_config(builder
, target
) {
261 builder
.update_submodule(&Path
::new("src").join("llvm-project"));
262 if builder
.llvm_link_shared() && target
.contains("windows") {
263 panic
!("shared linking to LLVM is not currently supported on {}", target
.triple
);
266 builder
.info(&format
!("Building LLVM for {}", target
));
268 let _time
= util
::timeit(&builder
);
269 t
!(fs
::create_dir_all(&out_dir
));
271 // https://llvm.org/docs/CMake.html
272 let mut cfg
= cmake
::Config
::new(builder
.src
.join(root
));
273 let mut ldflags
= LdFlags
::default();
275 let profile
= match (builder
.config
.llvm_optimize
, builder
.config
.llvm_release_debuginfo
) {
276 (false, _
) => "Debug",
277 (true, false) => "Release",
278 (true, true) => "RelWithDebInfo",
281 // NOTE: remember to also update `config.toml.example` when changing the
283 let llvm_targets
= match &builder
.config
.llvm_targets
{
286 "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
287 Sparc;SystemZ;WebAssembly;X86"
291 let llvm_exp_targets
= match builder
.config
.llvm_experimental_targets
{
296 let assertions
= if builder
.config
.llvm_assertions { "ON" }
else { "OFF" }
;
297 let plugins
= if builder
.config
.llvm_plugins { "ON" }
else { "OFF" }
;
298 let enable_tests
= if builder
.config
.llvm_tests { "ON" }
else { "OFF" }
;
300 cfg
.out_dir(&out_dir
)
302 .define("LLVM_ENABLE_ASSERTIONS", assertions
)
303 .define("LLVM_ENABLE_PLUGINS", plugins
)
304 .define("LLVM_TARGETS_TO_BUILD", llvm_targets
)
305 .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets
)
306 .define("LLVM_INCLUDE_EXAMPLES", "OFF")
307 .define("LLVM_INCLUDE_DOCS", "OFF")
308 .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
309 .define("LLVM_INCLUDE_TESTS", enable_tests
)
310 .define("LLVM_ENABLE_TERMINFO", "OFF")
311 .define("LLVM_ENABLE_LIBEDIT", "OFF")
312 .define("LLVM_ENABLE_BINDINGS", "OFF")
313 .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
314 .define("LLVM_PARALLEL_COMPILE_JOBS", builder
.jobs().to_string())
315 .define("LLVM_TARGET_ARCH", target_native
.split('
-'
).next().unwrap())
316 .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native
);
318 // Parts of our test suite rely on the `FileCheck` tool, which is built by default in
319 // `build/$TARGET/llvm/build/bin` is but *not* then installed to `build/$TARGET/llvm/bin`.
320 // This flag makes sure `FileCheck` is copied in the final binaries directory.
321 cfg
.define("LLVM_INSTALL_UTILS", "ON");
323 if builder
.config
.llvm_profile_generate
{
324 cfg
.define("LLVM_BUILD_INSTRUMENTED", "IR");
325 if let Ok(llvm_profile_dir
) = std
::env
::var("LLVM_PROFILE_DIR") {
326 cfg
.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir
);
328 cfg
.define("LLVM_BUILD_RUNTIME", "No");
330 if let Some(path
) = builder
.config
.llvm_profile_use
.as_ref() {
331 cfg
.define("LLVM_PROFDATA_FILE", &path
);
333 if builder
.config
.llvm_bolt_profile_generate
334 || builder
.config
.llvm_bolt_profile_use
.is_some()
336 // Relocations are required for BOLT to work.
337 ldflags
.push_all("-Wl,-q");
340 // Disable zstd to avoid a dependency on libzstd.so.
341 cfg
.define("LLVM_ENABLE_ZSTD", "OFF");
343 if target
!= "aarch64-apple-darwin" && !target
.contains("windows") {
344 cfg
.define("LLVM_ENABLE_ZLIB", "ON");
346 cfg
.define("LLVM_ENABLE_ZLIB", "OFF");
349 // Are we compiling for iOS/tvOS/watchOS?
350 if target
.contains("apple-ios")
351 || target
.contains("apple-tvos")
352 || target
.contains("apple-watchos")
354 // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error.
355 cfg
.define("CMAKE_OSX_SYSROOT", "/");
356 cfg
.define("CMAKE_OSX_DEPLOYMENT_TARGET", "");
357 // Prevent cmake from adding -bundle to CFLAGS automatically, which leads to a compiler error because "-bitcode_bundle" also gets added.
358 cfg
.define("LLVM_ENABLE_PLUGINS", "OFF");
359 // Zlib fails to link properly, leading to a compiler error.
360 cfg
.define("LLVM_ENABLE_ZLIB", "OFF");
363 // This setting makes the LLVM tools link to the dynamic LLVM library,
364 // which saves both memory during parallel links and overall disk space
365 // for the tools. We don't do this on every platform as it doesn't work
366 // equally well everywhere.
367 if builder
.llvm_link_shared() {
368 cfg
.define("LLVM_LINK_LLVM_DYLIB", "ON");
371 if target
.starts_with("riscv") && !target
.contains("freebsd") && !target
.contains("openbsd")
373 // RISC-V GCC erroneously requires linking against
374 // `libatomic` when using 1-byte and 2-byte C++
375 // atomics but the LLVM build system check cannot
376 // detect this. Therefore it is set manually here.
377 // Some BSD uses Clang as its system compiler and
378 // provides no libatomic in its base system so does
380 ldflags
.exe
.push(" -latomic");
381 ldflags
.shared
.push(" -latomic");
384 if target
.contains("msvc") {
385 cfg
.define("LLVM_USE_CRT_DEBUG", "MT");
386 cfg
.define("LLVM_USE_CRT_RELEASE", "MT");
387 cfg
.define("LLVM_USE_CRT_RELWITHDEBINFO", "MT");
388 cfg
.static_crt(true);
391 if target
.starts_with("i686") {
392 cfg
.define("LLVM_BUILD_32_BITS", "ON");
395 let mut enabled_llvm_projects
= Vec
::new();
397 if util
::forcing_clang_based_tests() {
398 enabled_llvm_projects
.push("clang");
399 enabled_llvm_projects
.push("compiler-rt");
402 if builder
.config
.llvm_polly
{
403 enabled_llvm_projects
.push("polly");
406 if builder
.config
.llvm_clang
{
407 enabled_llvm_projects
.push("clang");
410 // We want libxml to be disabled.
411 // See https://github.com/rust-lang/rust/pull/50104
412 cfg
.define("LLVM_ENABLE_LIBXML2", "OFF");
414 if !enabled_llvm_projects
.is_empty() {
415 enabled_llvm_projects
.sort();
416 enabled_llvm_projects
.dedup();
417 cfg
.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects
.join(";"));
420 if let Some(num_linkers
) = builder
.config
.llvm_link_jobs
{
422 cfg
.define("LLVM_PARALLEL_LINK_JOBS", num_linkers
.to_string());
426 // Workaround for ppc32 lld limitation
427 if target
== "powerpc-unknown-freebsd" {
428 ldflags
.exe
.push(" -fuse-ld=bfd");
431 // https://llvm.org/docs/HowToCrossCompileLLVM.html
432 if target
!= builder
.config
.build
{
433 let llvm_config
= builder
.ensure(Llvm { target: builder.config.build }
);
434 if !builder
.config
.dry_run() {
435 let llvm_bindir
= output(Command
::new(&llvm_config
).arg("--bindir"));
436 let host_bin
= Path
::new(llvm_bindir
.trim());
439 host_bin
.join("llvm-tblgen").with_extension(EXE_EXTENSION
),
441 // LLVM_NM is required for cross compiling using MSVC
442 cfg
.define("LLVM_NM", host_bin
.join("llvm-nm").with_extension(EXE_EXTENSION
));
444 cfg
.define("LLVM_CONFIG_PATH", llvm_config
);
445 if builder
.config
.llvm_clang
{
446 let build_bin
= builder
.llvm_out(builder
.config
.build
).join("build").join("bin");
447 let clang_tblgen
= build_bin
.join("clang-tblgen").with_extension(EXE_EXTENSION
);
448 if !builder
.config
.dry_run() && !clang_tblgen
.exists() {
449 panic
!("unable to find {}", clang_tblgen
.display());
451 cfg
.define("CLANG_TABLEGEN", clang_tblgen
);
455 let llvm_version_suffix
= if let Some(ref suffix
) = builder
.config
.llvm_version_suffix
{
456 // Allow version-suffix="" to not define a version suffix at all.
457 if !suffix
.is_empty() { Some(suffix.to_string()) }
else { None }
458 } else if builder
.config
.channel
== "dev" {
459 // Changes to a version suffix require a complete rebuild of the LLVM.
460 // To avoid rebuilds during a time of version bump, don't include rustc
461 // release number on the dev channel.
462 Some("-rust-dev".to_string())
464 Some(format
!("-rust-{}-{}", builder
.version
, builder
.config
.channel
))
466 if let Some(ref suffix
) = llvm_version_suffix
{
467 cfg
.define("LLVM_VERSION_SUFFIX", suffix
);
470 configure_cmake(builder
, target
, &mut cfg
, true, ldflags
);
471 configure_llvm(builder
, target
, &mut cfg
);
473 for (key
, val
) in &builder
.config
.llvm_build_config
{
474 cfg
.define(key
, val
);
477 // FIXME: we don't actually need to build all LLVM tools and all LLVM
478 // libraries here, e.g., we just want a few components and a few
479 // tools. Figure out how to filter them down and only build the right
480 // tools and libs on all platforms.
482 if builder
.config
.dry_run() {
483 return build_llvm_config
;
488 // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
489 // libLLVM.dylib will be built. However, llvm-config will still look
490 // for a versioned path like libLLVM-14.dylib. Manually create a symbolic
491 // link to make llvm-config happy.
492 if builder
.llvm_link_shared() && target
.contains("apple-darwin") {
493 let mut cmd
= Command
::new(&build_llvm_config
);
494 let version
= output(cmd
.arg("--version"));
495 let major
= version
.split('
.'
).next().unwrap();
496 let lib_name
= match llvm_version_suffix
{
497 Some(s
) => format
!("libLLVM-{}{}.dylib", major
, s
),
498 None
=> format
!("libLLVM-{}.dylib", major
),
501 let lib_llvm
= out_dir
.join("build").join("lib").join(lib_name
);
502 if !lib_llvm
.exists() {
503 t
!(builder
.symlink_file("libLLVM.dylib", &lib_llvm
));
507 // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file
508 // in place. This is fine, because currently we do not support incrementally rebuilding
509 // LLVM after a configuration change, so to rebuild it the build files have to be removed,
510 // which will also remove these modified files.
511 if builder
.config
.llvm_bolt_profile_generate
{
512 instrument_with_bolt_inplace(&get_built_llvm_lib_path(&build_llvm_config
));
514 if let Some(path
) = &builder
.config
.llvm_bolt_profile_use
{
515 optimize_library_with_bolt_inplace(
516 &get_built_llvm_lib_path(&build_llvm_config
),
527 /// Returns path to a built LLVM library (libLLVM.so).
528 /// Assumes that we have built LLVM into a single library file.
529 fn get_built_llvm_lib_path(llvm_config_path
: &Path
) -> PathBuf
{
530 let mut cmd
= Command
::new(llvm_config_path
);
531 cmd
.arg("--libfiles");
532 PathBuf
::from(output(&mut cmd
).trim())
535 fn check_llvm_version(builder
: &Builder
<'_
>, llvm_config
: &Path
) {
536 if !builder
.config
.llvm_version_check
{
540 if builder
.config
.dry_run() {
544 let mut cmd
= Command
::new(llvm_config
);
545 let version
= output(cmd
.arg("--version"));
546 let mut parts
= version
.split('
.'
).take(2).filter_map(|s
| s
.parse
::<u32>().ok());
547 if let (Some(major
), Some(_minor
)) = (parts
.next(), parts
.next()) {
552 panic
!("\n\nbad LLVM version: {}, need >=13.0\n\n", version
)
556 builder
: &Builder
<'_
>,
557 target
: TargetSelection
,
558 cfg
: &mut cmake
::Config
,
559 use_compiler_launcher
: bool
,
560 mut ldflags
: LdFlags
,
562 // Do not print installation messages for up-to-date files.
563 // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
564 cfg
.define("CMAKE_INSTALL_MESSAGE", "LAZY");
566 // Do not allow the user's value of DESTDIR to influence where
567 // LLVM will install itself. LLVM must always be installed in our
568 // own build directories.
569 cfg
.env("DESTDIR", "");
572 cfg
.generator("Ninja");
574 cfg
.target(&target
.triple
).host(&builder
.config
.build
.triple
);
576 if target
!= builder
.config
.build
{
577 cfg
.define("CMAKE_CROSSCOMPILING", "True");
579 if target
.contains("netbsd") {
580 cfg
.define("CMAKE_SYSTEM_NAME", "NetBSD");
581 } else if target
.contains("freebsd") {
582 cfg
.define("CMAKE_SYSTEM_NAME", "FreeBSD");
583 } else if target
.contains("windows") {
584 cfg
.define("CMAKE_SYSTEM_NAME", "Windows");
585 } else if target
.contains("haiku") {
586 cfg
.define("CMAKE_SYSTEM_NAME", "Haiku");
587 } else if target
.contains("solaris") || target
.contains("illumos") {
588 cfg
.define("CMAKE_SYSTEM_NAME", "SunOS");
590 // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in
591 // that case like CMake we cannot easily determine system version either.
593 // Since, the LLVM itself makes rather limited use of version checks in
594 // CMakeFiles (and then only in tests), and so far no issues have been
595 // reported, the system version is currently left unset.
597 if target
.contains("darwin") {
598 // Make sure that CMake does not build universal binaries on macOS.
599 // Explicitly specify the one single target architecture.
600 if target
.starts_with("aarch64") {
601 // macOS uses a different name for building arm64
602 cfg
.define("CMAKE_OSX_ARCHITECTURES", "arm64");
604 cfg
.define("CMAKE_OSX_ARCHITECTURES", target
.triple
.split('
-'
).next().unwrap());
609 let sanitize_cc
= |cc
: &Path
| {
610 if target
.contains("msvc") {
611 OsString
::from(cc
.to_str().unwrap().replace("\\", "/"))
613 cc
.as_os_str().to_owned()
617 // MSVC with CMake uses msbuild by default which doesn't respect these
618 // vars that we'd otherwise configure. In that case we just skip this
620 if target
.contains("msvc") && !builder
.ninja() {
624 let (cc
, cxx
) = match builder
.config
.llvm_clang_cl
{
625 Some(ref cl
) => (cl
.as_ref(), cl
.as_ref()),
626 None
=> (builder
.cc(target
), builder
.cxx(target
).unwrap()),
629 // Handle msvc + ninja + ccache specially (this is what the bots use)
630 if target
.contains("msvc") && builder
.ninja() && builder
.config
.ccache
.is_some() {
631 let mut wrap_cc
= env
::current_exe().expect("failed to get cwd");
632 wrap_cc
.set_file_name("sccache-plus-cl.exe");
634 cfg
.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc
))
635 .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc
));
636 cfg
.env("SCCACHE_PATH", builder
.config
.ccache
.as_ref().unwrap())
637 .env("SCCACHE_TARGET", target
.triple
)
638 .env("SCCACHE_CC", &cc
)
639 .env("SCCACHE_CXX", &cxx
);
641 // Building LLVM on MSVC can be a little ludicrous at times. We're so far
642 // off the beaten path here that I'm not really sure this is even half
643 // supported any more. Here we're trying to:
645 // * Build LLVM on MSVC
646 // * Build LLVM with `clang-cl` instead of `cl.exe`
647 // * Build a project with `sccache`
648 // * Build for 32-bit as well
649 // * Build with Ninja
651 // For `cl.exe` there are different binaries to compile 32/64 bit which
652 // we use but for `clang-cl` there's only one which internally
653 // multiplexes via flags. As a result it appears that CMake's detection
654 // of a compiler's architecture and such on MSVC **doesn't** pass any
655 // custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we
656 // use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which
657 // definitely causes problems since all the env vars are pointing to
660 // To hack around this... again... we pass an argument that's
661 // unconditionally passed in the sccache shim. This'll get CMake to
662 // correctly diagnose it's doing a 32-bit compilation and LLVM will
663 // internally configure itself appropriately.
664 if builder
.config
.llvm_clang_cl
.is_some() && target
.contains("i686") {
665 cfg
.env("SCCACHE_EXTRA_ARGS", "-m32");
668 // If ccache is configured we inform the build a little differently how
669 // to invoke ccache while also invoking our compilers.
670 if use_compiler_launcher
{
671 if let Some(ref ccache
) = builder
.config
.ccache
{
672 cfg
.define("CMAKE_C_COMPILER_LAUNCHER", ccache
)
673 .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache
);
676 cfg
.define("CMAKE_C_COMPILER", sanitize_cc(cc
))
677 .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx
))
678 .define("CMAKE_ASM_COMPILER", sanitize_cc(cc
));
681 cfg
.build_arg("-j").build_arg(builder
.jobs().to_string());
682 let mut cflags
: OsString
= builder
.cflags(target
, GitRepo
::Llvm
, CLang
::C
).join(" ").into();
683 if let Some(ref s
) = builder
.config
.llvm_cflags
{
687 // Some compiler features used by LLVM (such as thread locals) will not work on a min version below iOS 10.
688 if target
.contains("apple-ios") {
689 if target
.contains("86-") {
690 cflags
.push(" -miphonesimulator-version-min=10.0");
692 cflags
.push(" -miphoneos-version-min=10.0");
695 if builder
.config
.llvm_clang_cl
.is_some() {
696 cflags
.push(&format
!(" --target={}", target
));
698 cfg
.define("CMAKE_C_FLAGS", cflags
);
699 let mut cxxflags
: OsString
= builder
.cflags(target
, GitRepo
::Llvm
, CLang
::Cxx
).join(" ").into();
700 if let Some(ref s
) = builder
.config
.llvm_cxxflags
{
704 if builder
.config
.llvm_clang_cl
.is_some() {
705 cxxflags
.push(&format
!(" --target={}", target
));
707 cfg
.define("CMAKE_CXX_FLAGS", cxxflags
);
708 if let Some(ar
) = builder
.ar(target
) {
709 if ar
.is_absolute() {
710 // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
711 // tries to resolve this path in the LLVM build directory.
712 cfg
.define("CMAKE_AR", sanitize_cc(ar
));
716 if let Some(ranlib
) = builder
.ranlib(target
) {
717 if ranlib
.is_absolute() {
718 // LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it
719 // tries to resolve this path in the LLVM build directory.
720 cfg
.define("CMAKE_RANLIB", sanitize_cc(ranlib
));
724 if let Some(ref flags
) = builder
.config
.llvm_ldflags
{
725 ldflags
.push_all(flags
);
728 if let Some(flags
) = get_var("LDFLAGS", &builder
.config
.build
.triple
, &target
.triple
) {
729 ldflags
.push_all(&flags
);
732 // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
733 // We also do this if the user explicitly requested static libstdc++.
734 if builder
.config
.llvm_static_stdcpp
{
735 if !target
.contains("msvc") && !target
.contains("netbsd") && !target
.contains("solaris") {
736 if target
.contains("apple") || target
.contains("windows") {
737 ldflags
.push_all("-static-libstdc++");
739 ldflags
.push_all("-Wl,-Bsymbolic -static-libstdc++");
744 cfg
.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags
.shared
);
745 cfg
.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags
.module
);
746 cfg
.define("CMAKE_EXE_LINKER_FLAGS", &ldflags
.exe
);
748 if env
::var_os("SCCACHE_ERROR_LOG").is_some() {
749 cfg
.env("RUSTC_LOG", "sccache=warn");
753 fn configure_llvm(builder
: &Builder
<'_
>, target
: TargetSelection
, cfg
: &mut cmake
::Config
) {
754 // ThinLTO is only available when building with LLVM, enabling LLD is required.
755 // Apple's linker ld64 supports ThinLTO out of the box though, so don't use LLD on Darwin.
756 if builder
.config
.llvm_thin_lto
{
757 cfg
.define("LLVM_ENABLE_LTO", "Thin");
758 if !target
.contains("apple") {
759 cfg
.define("LLVM_ENABLE_LLD", "ON");
763 if let Some(ref linker
) = builder
.config
.llvm_use_linker
{
764 cfg
.define("LLVM_USE_LINKER", linker
);
767 if builder
.config
.llvm_allow_old_toolchain
{
768 cfg
.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
772 // Adapted from https://github.com/alexcrichton/cc-rs/blob/fba7feded71ee4f63cfe885673ead6d7b4f2f454/src/lib.rs#L2347-L2365
773 fn get_var(var_base
: &str, host
: &str, target
: &str) -> Option
<OsString
> {
774 let kind
= if host
== target { "HOST" }
else { "TARGET" }
;
775 let target_u
= target
.replace("-", "_");
776 env
::var_os(&format
!("{}_{}", var_base
, target
))
777 .or_else(|| env
::var_os(&format
!("{}_{}", var_base
, target_u
)))
778 .or_else(|| env
::var_os(&format
!("{}_{}", kind
, var_base
)))
779 .or_else(|| env
::var_os(var_base
))
782 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
784 pub target
: TargetSelection
,
788 type Output
= PathBuf
;
789 const ONLY_HOSTS
: bool
= true;
791 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
792 run
.path("src/llvm-project/lld")
795 fn make_run(run
: RunConfig
<'_
>) {
796 run
.builder
.ensure(Lld { target: run.target }
);
799 /// Compile LLD for `target`.
800 fn run(self, builder
: &Builder
<'_
>) -> PathBuf
{
801 if builder
.config
.dry_run() {
802 return PathBuf
::from("lld-out-dir-test-gen");
804 let target
= self.target
;
806 let llvm_config
= builder
.ensure(Llvm { target: self.target }
);
808 let out_dir
= builder
.lld_out(target
);
809 let done_stamp
= out_dir
.join("lld-finished-building");
810 if done_stamp
.exists() {
814 builder
.info(&format
!("Building LLD for {}", target
));
815 let _time
= util
::timeit(&builder
);
816 t
!(fs
::create_dir_all(&out_dir
));
818 let mut cfg
= cmake
::Config
::new(builder
.src
.join("src/llvm-project/lld"));
819 let mut ldflags
= LdFlags
::default();
821 // When building LLD as part of a build with instrumentation on windows, for example
822 // when doing PGO on CI, cmake or clang-cl don't automatically link clang's
823 // profiler runtime in. In that case, we need to manually ask cmake to do it, to avoid
824 // linking errors, much like LLVM's cmake setup does in that situation.
825 if builder
.config
.llvm_profile_generate
&& target
.contains("msvc") {
826 if let Some(clang_cl_path
) = builder
.config
.llvm_clang_cl
.as_ref() {
827 // Find clang's runtime library directory and push that as a search path to the
828 // cmake linker flags.
829 let clang_rt_dir
= get_clang_cl_resource_dir(clang_cl_path
);
830 ldflags
.push_all(&format
!("/libpath:{}", clang_rt_dir
.display()));
834 configure_cmake(builder
, target
, &mut cfg
, true, ldflags
);
835 configure_llvm(builder
, target
, &mut cfg
);
837 // This is an awful, awful hack. Discovered when we migrated to using
838 // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of
839 // tree, will execute `llvm-config --cmakedir` and then tell CMake about
840 // that directory for later processing. Unfortunately if this path has
841 // forward slashes in it (which it basically always does on Windows)
842 // then CMake will hit a syntax error later on as... something isn't
845 // Instead of attempting to fix this problem in upstream CMake and/or
846 // LLVM/LLD we just hack around it here. This thin wrapper will take the
847 // output from llvm-config and replace all instances of `\` with `/` to
848 // ensure we don't hit the same bugs with escaping. It means that you
849 // can't build on a system where your paths require `\` on Windows, but
850 // there's probably a lot of reasons you can't do that other than this.
851 let llvm_config_shim
= env
::current_exe().unwrap().with_file_name("llvm-config-wrapper");
853 // Re-use the same flags as llvm to control the level of debug information
854 // generated for lld.
855 let profile
= match (builder
.config
.llvm_optimize
, builder
.config
.llvm_release_debuginfo
) {
856 (false, _
) => "Debug",
857 (true, false) => "Release",
858 (true, true) => "RelWithDebInfo",
861 cfg
.out_dir(&out_dir
)
863 .env("LLVM_CONFIG_REAL", &llvm_config
)
864 .define("LLVM_CONFIG_PATH", llvm_config_shim
)
865 .define("LLVM_INCLUDE_TESTS", "OFF");
867 // While we're using this horrible workaround to shim the execution of
868 // llvm-config, let's just pile on more. I can't seem to figure out how
869 // to build LLD as a standalone project and also cross-compile it at the
870 // same time. It wants a natively executable `llvm-config` to learn
871 // about LLVM, but then it learns about all the host configuration of
872 // LLVM and tries to link to host LLVM libraries.
874 // To work around that we tell our shim to replace anything with the
875 // build target with the actual target instead. This'll break parts of
876 // LLD though which try to execute host tools, such as llvm-tblgen, so
877 // we specifically tell it where to find those. This is likely super
878 // brittle and will break over time. If anyone knows better how to
879 // cross-compile LLD it would be much appreciated to fix this!
880 if target
!= builder
.config
.build
{
881 cfg
.env("LLVM_CONFIG_SHIM_REPLACE", &builder
.config
.build
.triple
)
882 .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target
.triple
)
885 llvm_config
.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION
),
889 // Explicitly set C++ standard, because upstream doesn't do so
890 // for standalone builds.
891 cfg
.define("CMAKE_CXX_STANDARD", "14");
895 t
!(File
::create(&done_stamp
));
900 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
901 pub struct TestHelpers
{
902 pub target
: TargetSelection
,
905 impl Step
for TestHelpers
{
908 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
909 run
.path("src/test/auxiliary/rust_test_helpers.c")
912 fn make_run(run
: RunConfig
<'_
>) {
913 run
.builder
.ensure(TestHelpers { target: run.target }
)
916 /// Compiles the `rust_test_helpers.c` library which we used in various
917 /// `run-pass` tests for ABI testing.
918 fn run(self, builder
: &Builder
<'_
>) {
919 if builder
.config
.dry_run() {
922 // The x86_64-fortanix-unknown-sgx target doesn't have a working C
923 // toolchain. However, some x86_64 ELF objects can be linked
924 // without issues. Use this hack to compile the test helpers.
925 let target
= if self.target
== "x86_64-fortanix-unknown-sgx" {
926 TargetSelection
::from_user("x86_64-unknown-linux-gnu")
930 let dst
= builder
.test_helpers_out(target
);
931 let src
= builder
.src
.join("src/test/auxiliary/rust_test_helpers.c");
932 if up_to_date(&src
, &dst
.join("librust_test_helpers.a")) {
936 builder
.info("Building test helpers");
937 t
!(fs
::create_dir_all(&dst
));
938 let mut cfg
= cc
::Build
::new();
939 // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013
940 if target
.contains("emscripten") {
944 // We may have found various cross-compilers a little differently due to our
945 // extra configuration, so inform cc of these compilers. Note, though, that
946 // on MSVC we still need cc's detection of env vars (ugh).
947 if !target
.contains("msvc") {
948 if let Some(ar
) = builder
.ar(target
) {
951 cfg
.compiler(builder
.cc(target
));
953 cfg
.cargo_metadata(false)
955 .target(&target
.triple
)
956 .host(&builder
.config
.build
.triple
)
960 .file(builder
.src
.join("src/test/auxiliary/rust_test_helpers.c"))
961 .compile("rust_test_helpers");
965 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
966 pub struct Sanitizers
{
967 pub target
: TargetSelection
,
970 impl Step
for Sanitizers
{
971 type Output
= Vec
<SanitizerRuntime
>;
973 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
974 run
.alias("sanitizers")
977 fn make_run(run
: RunConfig
<'_
>) {
978 run
.builder
.ensure(Sanitizers { target: run.target }
);
981 /// Builds sanitizer runtime libraries.
982 fn run(self, builder
: &Builder
<'_
>) -> Self::Output
{
983 let compiler_rt_dir
= builder
.src
.join("src/llvm-project/compiler-rt");
984 if !compiler_rt_dir
.exists() {
988 let out_dir
= builder
.native_dir(self.target
).join("sanitizers");
989 let runtimes
= supported_sanitizers(&out_dir
, self.target
, &builder
.config
.channel
);
990 if runtimes
.is_empty() {
994 let llvm_config
= builder
.ensure(Llvm { target: builder.config.build }
);
995 if builder
.config
.dry_run() {
999 let stamp
= out_dir
.join("sanitizers-finished-building");
1000 let stamp
= HashStamp
::new(stamp
, builder
.in_tree_llvm_info
.sha());
1002 if stamp
.is_done() {
1003 if stamp
.hash
.is_none() {
1004 builder
.info(&format
!(
1005 "Rebuild sanitizers by removing the file `{}`",
1006 stamp
.path
.display()
1012 builder
.info(&format
!("Building sanitizers for {}", self.target
));
1014 let _time
= util
::timeit(&builder
);
1016 let mut cfg
= cmake
::Config
::new(&compiler_rt_dir
);
1017 cfg
.profile("Release");
1018 cfg
.define("CMAKE_C_COMPILER_TARGET", self.target
.triple
);
1019 cfg
.define("COMPILER_RT_BUILD_BUILTINS", "OFF");
1020 cfg
.define("COMPILER_RT_BUILD_CRT", "OFF");
1021 cfg
.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF");
1022 cfg
.define("COMPILER_RT_BUILD_PROFILE", "OFF");
1023 cfg
.define("COMPILER_RT_BUILD_SANITIZERS", "ON");
1024 cfg
.define("COMPILER_RT_BUILD_XRAY", "OFF");
1025 cfg
.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON");
1026 cfg
.define("COMPILER_RT_USE_LIBCXX", "OFF");
1027 cfg
.define("LLVM_CONFIG_PATH", &llvm_config
);
1029 // On Darwin targets the sanitizer runtimes are build as universal binaries.
1030 // Unfortunately sccache currently lacks support to build them successfully.
1031 // Disable compiler launcher on Darwin targets to avoid potential issues.
1032 let use_compiler_launcher
= !self.target
.contains("apple-darwin");
1033 configure_cmake(builder
, self.target
, &mut cfg
, use_compiler_launcher
, LdFlags
::default());
1035 t
!(fs
::create_dir_all(&out_dir
));
1036 cfg
.out_dir(out_dir
);
1038 for runtime
in &runtimes
{
1039 cfg
.build_target(&runtime
.cmake_target
);
1048 #[derive(Clone, Debug)]
1049 pub struct SanitizerRuntime
{
1050 /// CMake target used to build the runtime.
1051 pub cmake_target
: String
,
1052 /// Path to the built runtime library.
1054 /// Library filename that will be used rustc.
1058 /// Returns sanitizers available on a given target.
1059 fn supported_sanitizers(
1061 target
: TargetSelection
,
1063 ) -> Vec
<SanitizerRuntime
> {
1064 let darwin_libs
= |os
: &str, components
: &[&str]| -> Vec
<SanitizerRuntime
> {
1067 .map(move |c
| SanitizerRuntime
{
1068 cmake_target
: format
!("clang_rt.{}_{}_dynamic", c
, os
),
1070 .join(&format
!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c
, os
)),
1071 name
: format
!("librustc-{}_rt.{}.dylib", channel
, c
),
1076 let common_libs
= |os
: &str, arch
: &str, components
: &[&str]| -> Vec
<SanitizerRuntime
> {
1079 .map(move |c
| SanitizerRuntime
{
1080 cmake_target
: format
!("clang_rt.{}-{}", c
, arch
),
1081 path
: out_dir
.join(&format
!("build/lib/{}/libclang_rt.{}-{}.a", os
, c
, arch
)),
1082 name
: format
!("librustc-{}_rt.{}.a", channel
, c
),
1087 match &*target
.triple
{
1088 "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1089 "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
1090 "aarch64-unknown-linux-gnu" => {
1091 common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
1093 "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
1094 "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
1095 "x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]),
1096 "x86_64-unknown-netbsd" => {
1097 common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"])
1099 "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
1100 "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
1101 "x86_64-unknown-linux-gnu" => {
1102 common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
1104 "x86_64-unknown-linux-musl" => {
1105 common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
1113 hash
: Option
<Vec
<u8>>,
1117 fn new(path
: PathBuf
, hash
: Option
<&str>) -> Self {
1118 HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) }
1121 fn is_done(&self) -> bool
{
1122 match fs
::read(&self.path
) {
1123 Ok(h
) => self.hash
.as_deref().unwrap_or(b
"") == h
.as_slice(),
1124 Err(e
) if e
.kind() == io
::ErrorKind
::NotFound
=> false,
1126 panic
!("failed to read stamp file `{}`: {}", self.path
.display(), e
);
1131 fn remove(&self) -> io
::Result
<()> {
1132 match fs
::remove_file(&self.path
) {
1135 if e
.kind() == io
::ErrorKind
::NotFound
{
1144 fn write(&self) -> io
::Result
<()> {
1145 fs
::write(&self.path
, self.hash
.as_deref().unwrap_or(b
""))
1149 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1150 pub struct CrtBeginEnd
{
1151 pub target
: TargetSelection
,
1154 impl Step
for CrtBeginEnd
{
1155 type Output
= PathBuf
;
1157 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
1158 run
.path("src/llvm-project/compiler-rt/lib/crt")
1161 fn make_run(run
: RunConfig
<'_
>) {
1162 run
.builder
.ensure(CrtBeginEnd { target: run.target }
);
1165 /// Build crtbegin.o/crtend.o for musl target.
1166 fn run(self, builder
: &Builder
<'_
>) -> Self::Output
{
1167 let out_dir
= builder
.native_dir(self.target
).join("crt");
1169 if builder
.config
.dry_run() {
1173 let crtbegin_src
= builder
.src
.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c");
1174 let crtend_src
= builder
.src
.join("src/llvm-project/compiler-rt/lib/crt/crtend.c");
1175 if up_to_date(&crtbegin_src
, &out_dir
.join("crtbegin.o"))
1176 && up_to_date(&crtend_src
, &out_dir
.join("crtendS.o"))
1181 builder
.info("Building crtbegin.o and crtend.o");
1182 t
!(fs
::create_dir_all(&out_dir
));
1184 let mut cfg
= cc
::Build
::new();
1186 if let Some(ar
) = builder
.ar(self.target
) {
1189 cfg
.compiler(builder
.cc(self.target
));
1190 cfg
.cargo_metadata(false)
1192 .target(&self.target
.triple
)
1193 .host(&builder
.config
.build
.triple
)
1200 // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
1201 // Currently only consumer of those objects is musl, which use .init_array/.fini_array
1202 // instead of .ctors/.dtors
1203 cfg
.flag("-std=c11")
1204 .define("CRT_HAS_INITFINI_ARRAY", None
)
1205 .define("EH_USE_FRAME_REGISTRY", None
);
1209 t
!(fs
::copy(out_dir
.join("crtbegin.o"), out_dir
.join("crtbeginS.o")));
1210 t
!(fs
::copy(out_dir
.join("crtend.o"), out_dir
.join("crtendS.o")));
1215 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1216 pub struct Libunwind
{
1217 pub target
: TargetSelection
,
1220 impl Step
for Libunwind
{
1221 type Output
= PathBuf
;
1223 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
1224 run
.path("src/llvm-project/libunwind")
1227 fn make_run(run
: RunConfig
<'_
>) {
1228 run
.builder
.ensure(Libunwind { target: run.target }
);
1231 /// Build linunwind.a
1232 fn run(self, builder
: &Builder
<'_
>) -> Self::Output
{
1233 if builder
.config
.dry_run() {
1234 return PathBuf
::new();
1237 let out_dir
= builder
.native_dir(self.target
).join("libunwind");
1238 let root
= builder
.src
.join("src/llvm-project/libunwind");
1240 if up_to_date(&root
, &out_dir
.join("libunwind.a")) {
1244 builder
.info(&format
!("Building libunwind.a for {}", self.target
.triple
));
1245 t
!(fs
::create_dir_all(&out_dir
));
1247 let mut cc_cfg
= cc
::Build
::new();
1248 let mut cpp_cfg
= cc
::Build
::new();
1251 cpp_cfg
.cpp_set_stdlib(None
);
1252 cpp_cfg
.flag("-nostdinc++");
1253 cpp_cfg
.flag("-fno-exceptions");
1254 cpp_cfg
.flag("-fno-rtti");
1255 cpp_cfg
.flag_if_supported("-fvisibility-global-new-delete-hidden");
1257 for cfg
in [&mut cc_cfg
, &mut cpp_cfg
].iter_mut() {
1258 if let Some(ar
) = builder
.ar(self.target
) {
1261 cfg
.target(&self.target
.triple
);
1262 cfg
.host(&builder
.config
.build
.triple
);
1263 cfg
.warnings(false);
1265 // get_compiler() need set opt_level first.
1267 cfg
.flag("-fstrict-aliasing");
1268 cfg
.flag("-funwind-tables");
1269 cfg
.flag("-fvisibility=hidden");
1270 cfg
.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None
);
1271 cfg
.include(root
.join("include"));
1272 cfg
.cargo_metadata(false);
1273 cfg
.out_dir(&out_dir
);
1275 if self.target
.contains("x86_64-fortanix-unknown-sgx") {
1276 cfg
.static_flag(true);
1277 cfg
.flag("-fno-stack-protector");
1278 cfg
.flag("-ffreestanding");
1279 cfg
.flag("-fexceptions");
1281 // easiest way to undefine since no API available in cc::Build to undefine
1282 cfg
.flag("-U_FORTIFY_SOURCE");
1283 cfg
.define("_FORTIFY_SOURCE", "0");
1284 cfg
.define("RUST_SGX", "1");
1285 cfg
.define("__NO_STRING_INLINES", None
);
1286 cfg
.define("__NO_MATH_INLINES", None
);
1287 cfg
.define("_LIBUNWIND_IS_BAREMETAL", None
);
1288 cfg
.define("__LIBUNWIND_IS_NATIVE_ONLY", None
);
1289 cfg
.define("NDEBUG", None
);
1291 if self.target
.contains("windows") {
1292 cfg
.define("_LIBUNWIND_HIDE_SYMBOLS", "1");
1293 cfg
.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
1297 cc_cfg
.compiler(builder
.cc(self.target
));
1298 if let Ok(cxx
) = builder
.cxx(self.target
) {
1299 cpp_cfg
.compiler(cxx
);
1301 cc_cfg
.compiler(builder
.cc(self.target
));
1304 // Don't set this for clang
1305 // By default, Clang builds C code in GNU C17 mode.
1306 // By default, Clang builds C++ code according to the C++98 standard,
1307 // with many C++11 features accepted as extensions.
1308 if cc_cfg
.get_compiler().is_like_gnu() {
1309 cc_cfg
.flag("-std=c99");
1311 if cpp_cfg
.get_compiler().is_like_gnu() {
1312 cpp_cfg
.flag("-std=c++11");
1315 if self.target
.contains("x86_64-fortanix-unknown-sgx") || self.target
.contains("musl") {
1316 // use the same GCC C compiler command to compile C++ code so we do not need to setup the
1317 // C++ compiler env variables on the builders.
1318 // Don't set this for clang++, as clang++ is able to compile this without libc++.
1319 if cpp_cfg
.get_compiler().is_like_gnu() {
1321 cpp_cfg
.compiler(builder
.cc(self.target
));
1325 let mut c_sources
= vec
![
1327 "UnwindLevel1-gcc-ext.c",
1329 "UnwindRegistersRestore.S",
1330 "UnwindRegistersSave.S",
1333 let cpp_sources
= vec
!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
1334 let cpp_len
= cpp_sources
.len();
1336 if self.target
.contains("x86_64-fortanix-unknown-sgx") {
1337 c_sources
.push("UnwindRustSgx.c");
1340 for src
in c_sources
{
1341 cc_cfg
.file(root
.join("src").join(src
).canonicalize().unwrap());
1344 for src
in &cpp_sources
{
1345 cpp_cfg
.file(root
.join("src").join(src
).canonicalize().unwrap());
1348 cpp_cfg
.compile("unwind-cpp");
1350 // FIXME: https://github.com/alexcrichton/cc-rs/issues/545#issuecomment-679242845
1352 for entry
in fs
::read_dir(&out_dir
).unwrap() {
1353 let file
= entry
.unwrap().path().canonicalize().unwrap();
1354 if file
.is_file() && file
.extension() == Some(OsStr
::new("o")) {
1355 // file name starts with "Unwind-EHABI", "Unwind-seh" or "libunwind"
1356 let file_name
= file
.file_name().unwrap().to_str().expect("UTF-8 file name");
1357 if cpp_sources
.iter().any(|f
| file_name
.starts_with(&f
[..f
.len() - 4])) {
1358 cc_cfg
.object(&file
);
1363 assert_eq
!(cpp_len
, count
, "Can't get object files from {:?}", &out_dir
);
1365 cc_cfg
.compile("unwind");