]>
Commit | Line | Data |
---|---|---|
5bcae85e SL |
1 | //! Compilation of native dependencies like LLVM. |
2 | //! | |
3 | //! Native projects like LLVM unfortunately aren't suited just yet for | |
3b2f2976 | 4 | //! compilation in build scripts that Cargo has. This is because the |
5bcae85e SL |
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). | |
7 | //! | |
8 | //! LLVM and compiler-rt are essentially just wired up to everything else to | |
9 | //! ensure that they're always in place if needed. | |
10 | ||
cc61c64b | 11 | use std::env; |
f035d41b | 12 | use std::env::consts::EXE_EXTENSION; |
94222f64 | 13 | use std::ffi::{OsStr, OsString}; |
c30ab7b3 | 14 | use std::fs::{self, File}; |
ba9703b0 | 15 | use std::io; |
2c00a5a8 | 16 | use std::path::{Path, PathBuf}; |
5bcae85e | 17 | use std::process::Command; |
5bcae85e | 18 | |
48663c56 | 19 | use build_helper::{output, t}; |
5bcae85e | 20 | |
0731742a | 21 | use crate::builder::{Builder, RunConfig, ShouldRun, Step}; |
3dfed10e | 22 | use crate::config::TargetSelection; |
dfeec247 | 23 | use crate::util::{self, exe}; |
0731742a | 24 | use crate::GitRepo; |
dfeec247 | 25 | use build_helper::up_to_date; |
5bcae85e | 26 | |
f9f354fc XL |
27 | pub struct Meta { |
28 | stamp: HashStamp, | |
29 | build_llvm_config: PathBuf, | |
30 | out_dir: PathBuf, | |
31 | root: String, | |
32 | } | |
33 | ||
34 | // This returns whether we've already previously built LLVM. | |
35 | // | |
36 | // It's used to avoid busting caches during x.py check -- if we've already built | |
37 | // LLVM, it's fine for us to not try to avoid doing so. | |
38 | // | |
39 | // This will return the llvm-config if it can get it (but it will not build it | |
40 | // if not). | |
41 | pub fn prebuilt_llvm_config( | |
42 | builder: &Builder<'_>, | |
3dfed10e | 43 | target: TargetSelection, |
f9f354fc XL |
44 | ) -> Result<PathBuf, Meta> { |
45 | // If we're using a custom LLVM bail out here, but we can only use a | |
46 | // custom LLVM for the build triple. | |
47 | if let Some(config) = builder.config.target_config.get(&target) { | |
48 | if let Some(ref s) = config.llvm_config { | |
49 | check_llvm_version(builder, s); | |
50 | return Ok(s.to_path_buf()); | |
51 | } | |
52 | } | |
53 | ||
54 | let root = "src/llvm-project/llvm"; | |
55 | let out_dir = builder.llvm_out(target); | |
3dfed10e | 56 | |
f9f354fc | 57 | let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); |
1b1a35ee | 58 | if !builder.config.build.contains("msvc") || builder.ninja() { |
f9f354fc XL |
59 | llvm_config_ret_dir.push("build"); |
60 | } | |
61 | llvm_config_ret_dir.push("bin"); | |
62 | ||
3dfed10e | 63 | let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", builder.config.build)); |
f9f354fc XL |
64 | |
65 | let stamp = out_dir.join("llvm-finished-building"); | |
66 | let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); | |
67 | ||
68 | if builder.config.llvm_skip_rebuild && stamp.path.exists() { | |
69 | builder.info( | |
70 | "Warning: \ | |
71 | Using a potentially stale build of LLVM; \ | |
72 | This may not behave well.", | |
73 | ); | |
74 | return Ok(build_llvm_config); | |
75 | } | |
76 | ||
77 | if stamp.is_done() { | |
78 | if stamp.hash.is_none() { | |
79 | builder.info( | |
80 | "Could not determine the LLVM submodule commit hash. \ | |
81 | Assuming that an LLVM rebuild is not necessary.", | |
82 | ); | |
83 | builder.info(&format!( | |
84 | "To force LLVM to rebuild, remove the file `{}`", | |
85 | stamp.path.display() | |
86 | )); | |
87 | } | |
88 | return Ok(build_llvm_config); | |
89 | } | |
90 | ||
91 | Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() }) | |
92 | } | |
93 | ||
3b2f2976 XL |
94 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
95 | pub struct Llvm { | |
3dfed10e | 96 | pub target: TargetSelection, |
3b2f2976 XL |
97 | } |
98 | ||
99 | impl Step for Llvm { | |
2c00a5a8 XL |
100 | type Output = PathBuf; // path to llvm-config |
101 | ||
3b2f2976 XL |
102 | const ONLY_HOSTS: bool = true; |
103 | ||
9fa01778 | 104 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
dfeec247 | 105 | run.path("src/llvm-project").path("src/llvm-project/llvm").path("src/llvm") |
5bcae85e SL |
106 | } |
107 | ||
9fa01778 | 108 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 109 | run.builder.ensure(Llvm { target: run.target }); |
3b2f2976 | 110 | } |
8bb4bdeb | 111 | |
3b2f2976 | 112 | /// Compile LLVM for `target`. |
9fa01778 | 113 | fn run(self, builder: &Builder<'_>) -> PathBuf { |
3b2f2976 | 114 | let target = self.target; |
3dfed10e XL |
115 | let target_native = if self.target.starts_with("riscv") { |
116 | // RISC-V target triples in Rust is not named the same as C compiler target triples. | |
117 | // This converts Rust RISC-V target triples to C compiler triples. | |
118 | let idx = target.triple.find('-').unwrap(); | |
119 | ||
120 | format!("riscv{}{}", &target.triple[5..7], &target.triple[idx..]) | |
94222f64 XL |
121 | } else if self.target.starts_with("powerpc") && self.target.ends_with("freebsd") { |
122 | // FreeBSD 13 had incompatible ABI changes on all PowerPC platforms. | |
123 | // Set the version suffix to 13.0 so the correct target details are used. | |
124 | format!("{}{}", self.target, "13.0") | |
3dfed10e XL |
125 | } else { |
126 | target.to_string() | |
127 | }; | |
3b2f2976 | 128 | |
f9f354fc XL |
129 | let Meta { stamp, build_llvm_config, out_dir, root } = |
130 | match prebuilt_llvm_config(builder, target) { | |
131 | Ok(p) => return p, | |
132 | Err(m) => m, | |
133 | }; | |
8bb4bdeb | 134 | |
136023e0 | 135 | builder.update_submodule(&Path::new("src").join("llvm-project")); |
1b1a35ee XL |
136 | if builder.config.llvm_link_shared |
137 | && (target.contains("windows") || target.contains("apple-darwin")) | |
138 | { | |
139 | panic!("shared linking to LLVM is not currently supported on {}", target.triple); | |
140 | } | |
141 | ||
e74abb32 | 142 | builder.info(&format!("Building LLVM for {}", target)); |
ba9703b0 | 143 | t!(stamp.remove()); |
83c7162d | 144 | let _time = util::timeit(&builder); |
3b2f2976 | 145 | t!(fs::create_dir_all(&out_dir)); |
5bcae85e | 146 | |
136023e0 | 147 | // https://llvm.org/docs/CMake.html |
83c7162d | 148 | let mut cfg = cmake::Config::new(builder.src.join(root)); |
8bb4bdeb | 149 | |
83c7162d | 150 | let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { |
3b2f2976 XL |
151 | (false, _) => "Debug", |
152 | (true, false) => "Release", | |
153 | (true, true) => "RelWithDebInfo", | |
154 | }; | |
155 | ||
2c00a5a8 XL |
156 | // NOTE: remember to also update `config.toml.example` when changing the |
157 | // defaults! | |
e74abb32 XL |
158 | let llvm_targets = match &builder.config.llvm_targets { |
159 | Some(s) => s, | |
dfeec247 | 160 | None => { |
17df50a5 | 161 | "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\ |
dfeec247 XL |
162 | Sparc;SystemZ;WebAssembly;X86" |
163 | } | |
3b2f2976 XL |
164 | }; |
165 | ||
e74abb32 XL |
166 | let llvm_exp_targets = match builder.config.llvm_experimental_targets { |
167 | Some(ref s) => s, | |
c295e0f8 | 168 | None => "AVR;M68k", |
2c00a5a8 | 169 | }; |
3b2f2976 | 170 | |
dfeec247 | 171 | let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" }; |
94222f64 | 172 | let plugins = if builder.config.llvm_plugins { "ON" } else { "OFF" }; |
3b2f2976 | 173 | |
0531ce1d | 174 | cfg.out_dir(&out_dir) |
dfeec247 XL |
175 | .profile(profile) |
176 | .define("LLVM_ENABLE_ASSERTIONS", assertions) | |
94222f64 | 177 | .define("LLVM_ENABLE_PLUGINS", plugins) |
dfeec247 XL |
178 | .define("LLVM_TARGETS_TO_BUILD", llvm_targets) |
179 | .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets) | |
180 | .define("LLVM_INCLUDE_EXAMPLES", "OFF") | |
dfeec247 XL |
181 | .define("LLVM_INCLUDE_DOCS", "OFF") |
182 | .define("LLVM_INCLUDE_BENCHMARKS", "OFF") | |
94222f64 | 183 | .define("LLVM_INCLUDE_TESTS", "OFF") |
dfeec247 XL |
184 | .define("LLVM_ENABLE_TERMINFO", "OFF") |
185 | .define("LLVM_ENABLE_LIBEDIT", "OFF") | |
186 | .define("LLVM_ENABLE_BINDINGS", "OFF") | |
187 | .define("LLVM_ENABLE_Z3_SOLVER", "OFF") | |
188 | .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) | |
3dfed10e XL |
189 | .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap()) |
190 | .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native); | |
3b2f2976 | 191 | |
c295e0f8 XL |
192 | // Parts of our test suite rely on the `FileCheck` tool, which is built by default in |
193 | // `build/$TARGET/llvm/build/bin` is but *not* then installed to `build/$TARGET/llvm/bin`. | |
194 | // This flag makes sure `FileCheck` is copied in the final binaries directory. | |
195 | cfg.define("LLVM_INSTALL_UTILS", "ON"); | |
196 | ||
94222f64 XL |
197 | if builder.config.llvm_profile_generate { |
198 | cfg.define("LLVM_BUILD_INSTRUMENTED", "IR"); | |
199 | cfg.define("LLVM_BUILD_RUNTIME", "No"); | |
200 | } | |
201 | if let Some(path) = builder.config.llvm_profile_use.as_ref() { | |
202 | cfg.define("LLVM_PROFDATA_FILE", &path); | |
203 | } | |
204 | ||
17df50a5 | 205 | if target != "aarch64-apple-darwin" && !target.contains("windows") { |
f035d41b XL |
206 | cfg.define("LLVM_ENABLE_ZLIB", "ON"); |
207 | } else { | |
f035d41b XL |
208 | cfg.define("LLVM_ENABLE_ZLIB", "OFF"); |
209 | } | |
210 | ||
211 | // Are we compiling for iOS/tvOS? | |
212 | if target.contains("apple-ios") || target.contains("apple-tvos") { | |
213 | // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error. | |
214 | cfg.define("CMAKE_OSX_SYSROOT", "/"); | |
215 | cfg.define("CMAKE_OSX_DEPLOYMENT_TARGET", ""); | |
216 | // Prevent cmake from adding -bundle to CFLAGS automatically, which leads to a compiler error because "-bitcode_bundle" also gets added. | |
217 | cfg.define("LLVM_ENABLE_PLUGINS", "OFF"); | |
218 | // Zlib fails to link properly, leading to a compiler error. | |
219 | cfg.define("LLVM_ENABLE_ZLIB", "OFF"); | |
220 | } | |
221 | ||
e74abb32 | 222 | if builder.config.llvm_thin_lto { |
48663c56 XL |
223 | cfg.define("LLVM_ENABLE_LTO", "Thin"); |
224 | if !target.contains("apple") { | |
dfeec247 | 225 | cfg.define("LLVM_ENABLE_LLD", "ON"); |
48663c56 | 226 | } |
b7449926 XL |
227 | } |
228 | ||
3b2f2976 XL |
229 | // This setting makes the LLVM tools link to the dynamic LLVM library, |
230 | // which saves both memory during parallel links and overall disk space | |
b7449926 XL |
231 | // for the tools. We don't do this on every platform as it doesn't work |
232 | // equally well everywhere. | |
1b1a35ee XL |
233 | // |
234 | // If we're not linking rustc to a dynamic LLVM, though, then don't link | |
235 | // tools to it. | |
236 | if builder.llvm_link_tools_dynamically(target) && builder.config.llvm_link_shared { | |
b7449926 | 237 | cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); |
8faf50e0 XL |
238 | } |
239 | ||
240 | // For distribution we want the LLVM tools to be *statically* linked to libstdc++ | |
f9f354fc | 241 | if builder.config.llvm_tools_enabled { |
e74abb32 | 242 | if !target.contains("msvc") { |
8faf50e0 XL |
243 | if target.contains("apple") { |
244 | cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++"); | |
245 | } else { | |
246 | cfg.define("CMAKE_EXE_LINKER_FLAGS", "-Wl,-Bsymbolic -static-libstdc++"); | |
247 | } | |
248 | } | |
3b2f2976 | 249 | } |
5bcae85e | 250 | |
3dfed10e XL |
251 | if target.starts_with("riscv") { |
252 | // In RISC-V, using C++ atomics require linking to `libatomic` but the LLVM build | |
253 | // system check cannot detect this. Therefore it is set manually here. | |
254 | if !builder.config.llvm_tools_enabled { | |
255 | cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic"); | |
256 | } else { | |
257 | cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic -static-libstdc++"); | |
258 | } | |
259 | cfg.define("CMAKE_SHARED_LINKER_FLAGS", "-latomic"); | |
260 | } | |
261 | ||
7cac9316 | 262 | if target.contains("msvc") { |
3b2f2976 XL |
263 | cfg.define("LLVM_USE_CRT_DEBUG", "MT"); |
264 | cfg.define("LLVM_USE_CRT_RELEASE", "MT"); | |
265 | cfg.define("LLVM_USE_CRT_RELWITHDEBINFO", "MT"); | |
266 | cfg.static_crt(true); | |
7cac9316 | 267 | } |
7cac9316 | 268 | |
3b2f2976 XL |
269 | if target.starts_with("i686") { |
270 | cfg.define("LLVM_BUILD_32_BITS", "ON"); | |
7cac9316 XL |
271 | } |
272 | ||
dc9dc135 XL |
273 | let mut enabled_llvm_projects = Vec::new(); |
274 | ||
275 | if util::forcing_clang_based_tests() { | |
276 | enabled_llvm_projects.push("clang"); | |
277 | enabled_llvm_projects.push("compiler-rt"); | |
278 | } | |
279 | ||
cdc7bbd5 | 280 | if builder.config.llvm_polly { |
29967ef6 XL |
281 | enabled_llvm_projects.push("polly"); |
282 | } | |
283 | ||
94222f64 XL |
284 | if builder.config.llvm_clang { |
285 | enabled_llvm_projects.push("clang"); | |
286 | } | |
287 | ||
f9f354fc XL |
288 | // We want libxml to be disabled. |
289 | // See https://github.com/rust-lang/rust/pull/50104 | |
290 | cfg.define("LLVM_ENABLE_LIBXML2", "OFF"); | |
b7449926 | 291 | |
74b04a01 | 292 | if !enabled_llvm_projects.is_empty() { |
dc9dc135 XL |
293 | enabled_llvm_projects.sort(); |
294 | enabled_llvm_projects.dedup(); | |
295 | cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";")); | |
296 | } | |
297 | ||
83c7162d | 298 | if let Some(num_linkers) = builder.config.llvm_link_jobs { |
3b2f2976 XL |
299 | if num_linkers > 0 { |
300 | cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); | |
301 | } | |
5bcae85e | 302 | } |
5bcae85e | 303 | |
94222f64 XL |
304 | // Workaround for ppc32 lld limitation |
305 | if target == "powerpc-unknown-freebsd" { | |
306 | cfg.define("CMAKE_EXE_LINKER_FLAGS", "-fuse-ld=bfd"); | |
307 | } | |
308 | ||
136023e0 | 309 | // https://llvm.org/docs/HowToCrossCompileLLVM.html |
e74abb32 | 310 | if target != builder.config.build { |
dfeec247 | 311 | builder.ensure(Llvm { target: builder.config.build }); |
3b2f2976 XL |
312 | // FIXME: if the llvm root for the build triple is overridden then we |
313 | // should use llvm-tblgen from there, also should verify that it | |
314 | // actually exists most of the time in normal installs of LLVM. | |
f035d41b XL |
315 | let host_bin = builder.llvm_out(builder.config.build).join("bin"); |
316 | cfg.define("CMAKE_CROSSCOMPILING", "True"); | |
317 | cfg.define("LLVM_TABLEGEN", host_bin.join("llvm-tblgen").with_extension(EXE_EXTENSION)); | |
318 | cfg.define("LLVM_NM", host_bin.join("llvm-nm").with_extension(EXE_EXTENSION)); | |
319 | cfg.define( | |
320 | "LLVM_CONFIG_PATH", | |
321 | host_bin.join("llvm-config").with_extension(EXE_EXTENSION), | |
322 | ); | |
3b2f2976 | 323 | } |
5bcae85e | 324 | |
b7449926 | 325 | if let Some(ref suffix) = builder.config.llvm_version_suffix { |
9fa01778 XL |
326 | // Allow version-suffix="" to not define a version suffix at all. |
327 | if !suffix.is_empty() { | |
328 | cfg.define("LLVM_VERSION_SUFFIX", suffix); | |
329 | } | |
ba9703b0 XL |
330 | } else if builder.config.channel == "dev" { |
331 | // Changes to a version suffix require a complete rebuild of the LLVM. | |
332 | // To avoid rebuilds during a time of version bump, don't include rustc | |
333 | // release number on the dev channel. | |
334 | cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev"); | |
9fa01778 | 335 | } else { |
1b1a35ee | 336 | let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel); |
ba9703b0 | 337 | cfg.define("LLVM_VERSION_SUFFIX", suffix); |
9fa01778 XL |
338 | } |
339 | ||
340 | if let Some(ref linker) = builder.config.llvm_use_linker { | |
341 | cfg.define("LLVM_USE_LINKER", linker); | |
b7449926 XL |
342 | } |
343 | ||
cdc7bbd5 | 344 | if builder.config.llvm_allow_old_toolchain { |
532ac7d7 XL |
345 | cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES"); |
346 | } | |
347 | ||
dfeec247 | 348 | configure_cmake(builder, target, &mut cfg, true); |
3b2f2976 XL |
349 | |
350 | // FIXME: we don't actually need to build all LLVM tools and all LLVM | |
0731742a | 351 | // libraries here, e.g., we just want a few components and a few |
3b2f2976 XL |
352 | // tools. Figure out how to filter them down and only build the right |
353 | // tools and libs on all platforms. | |
83c7162d XL |
354 | |
355 | if builder.config.dry_run { | |
356 | return build_llvm_config; | |
357 | } | |
358 | ||
3b2f2976 XL |
359 | cfg.build(); |
360 | ||
ba9703b0 | 361 | t!(stamp.write()); |
2c00a5a8 XL |
362 | |
363 | build_llvm_config | |
3b2f2976 | 364 | } |
5bcae85e SL |
365 | } |
366 | ||
9fa01778 | 367 | fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { |
83c7162d | 368 | if !builder.config.llvm_version_check { |
dfeec247 | 369 | return; |
5bcae85e SL |
370 | } |
371 | ||
83c7162d XL |
372 | if builder.config.dry_run { |
373 | return; | |
374 | } | |
375 | ||
5bcae85e SL |
376 | let mut cmd = Command::new(llvm_config); |
377 | let version = output(cmd.arg("--version")); | |
dfeec247 | 378 | let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok()); |
8faf50e0 | 379 | if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { |
cdc7bbd5 | 380 | if major >= 10 { |
dfeec247 | 381 | return; |
abe05a73 | 382 | } |
5bcae85e | 383 | } |
cdc7bbd5 | 384 | panic!("\n\nbad LLVM version: {}, need >=10.0\n\n", version) |
5bcae85e SL |
385 | } |
386 | ||
dfeec247 XL |
387 | fn configure_cmake( |
388 | builder: &Builder<'_>, | |
3dfed10e | 389 | target: TargetSelection, |
dfeec247 XL |
390 | cfg: &mut cmake::Config, |
391 | use_compiler_launcher: bool, | |
392 | ) { | |
48663c56 XL |
393 | // Do not print installation messages for up-to-date files. |
394 | // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. | |
395 | cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY"); | |
396 | ||
3dfed10e XL |
397 | // Do not allow the user's value of DESTDIR to influence where |
398 | // LLVM will install itself. LLVM must always be installed in our | |
399 | // own build directories. | |
400 | cfg.env("DESTDIR", ""); | |
401 | ||
1b1a35ee | 402 | if builder.ninja() { |
0531ce1d XL |
403 | cfg.generator("Ninja"); |
404 | } | |
3dfed10e XL |
405 | cfg.target(&target.triple).host(&builder.config.build.triple); |
406 | ||
407 | if target != builder.config.build { | |
408 | if target.contains("netbsd") { | |
409 | cfg.define("CMAKE_SYSTEM_NAME", "NetBSD"); | |
410 | } else if target.contains("freebsd") { | |
411 | cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD"); | |
412 | } else if target.contains("windows") { | |
413 | cfg.define("CMAKE_SYSTEM_NAME", "Windows"); | |
29967ef6 XL |
414 | } else if target.contains("haiku") { |
415 | cfg.define("CMAKE_SYSTEM_NAME", "Haiku"); | |
6a06907d XL |
416 | } else if target.contains("solaris") || target.contains("illumos") { |
417 | cfg.define("CMAKE_SYSTEM_NAME", "SunOS"); | |
3dfed10e XL |
418 | } |
419 | // When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in | |
420 | // that case like CMake we cannot easily determine system version either. | |
421 | // | |
422 | // Since, the LLVM itself makes rather limited use of version checks in | |
423 | // CMakeFiles (and then only in tests), and so far no issues have been | |
424 | // reported, the system version is currently left unset. | |
425 | } | |
0531ce1d XL |
426 | |
427 | let sanitize_cc = |cc: &Path| { | |
428 | if target.contains("msvc") { | |
429 | OsString::from(cc.to_str().unwrap().replace("\\", "/")) | |
430 | } else { | |
431 | cc.as_os_str().to_owned() | |
432 | } | |
433 | }; | |
434 | ||
435 | // MSVC with CMake uses msbuild by default which doesn't respect these | |
436 | // vars that we'd otherwise configure. In that case we just skip this | |
437 | // entirely. | |
1b1a35ee | 438 | if target.contains("msvc") && !builder.ninja() { |
dfeec247 | 439 | return; |
0531ce1d XL |
440 | } |
441 | ||
94b46f34 XL |
442 | let (cc, cxx) = match builder.config.llvm_clang_cl { |
443 | Some(ref cl) => (cl.as_ref(), cl.as_ref()), | |
444 | None => (builder.cc(target), builder.cxx(target).unwrap()), | |
445 | }; | |
0531ce1d XL |
446 | |
447 | // Handle msvc + ninja + ccache specially (this is what the bots use) | |
1b1a35ee | 448 | if target.contains("msvc") && builder.ninja() && builder.config.ccache.is_some() { |
dfeec247 XL |
449 | let mut wrap_cc = env::current_exe().expect("failed to get cwd"); |
450 | wrap_cc.set_file_name("sccache-plus-cl.exe"); | |
451 | ||
452 | cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc)) | |
453 | .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc)); | |
454 | cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap()) | |
3dfed10e | 455 | .env("SCCACHE_TARGET", target.triple) |
dfeec247 XL |
456 | .env("SCCACHE_CC", &cc) |
457 | .env("SCCACHE_CXX", &cxx); | |
458 | ||
459 | // Building LLVM on MSVC can be a little ludicrous at times. We're so far | |
460 | // off the beaten path here that I'm not really sure this is even half | |
461 | // supported any more. Here we're trying to: | |
462 | // | |
463 | // * Build LLVM on MSVC | |
464 | // * Build LLVM with `clang-cl` instead of `cl.exe` | |
465 | // * Build a project with `sccache` | |
466 | // * Build for 32-bit as well | |
467 | // * Build with Ninja | |
468 | // | |
469 | // For `cl.exe` there are different binaries to compile 32/64 bit which | |
470 | // we use but for `clang-cl` there's only one which internally | |
471 | // multiplexes via flags. As a result it appears that CMake's detection | |
472 | // of a compiler's architecture and such on MSVC **doesn't** pass any | |
473 | // custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we | |
474 | // use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which | |
475 | // definitely causes problems since all the env vars are pointing to | |
476 | // 32-bit libraries. | |
477 | // | |
478 | // To hack around this... again... we pass an argument that's | |
479 | // unconditionally passed in the sccache shim. This'll get CMake to | |
480 | // correctly diagnose it's doing a 32-bit compilation and LLVM will | |
481 | // internally configure itself appropriately. | |
482 | if builder.config.llvm_clang_cl.is_some() && target.contains("i686") { | |
483 | cfg.env("SCCACHE_EXTRA_ARGS", "-m32"); | |
484 | } | |
0531ce1d | 485 | } else { |
dfeec247 XL |
486 | // If ccache is configured we inform the build a little differently how |
487 | // to invoke ccache while also invoking our compilers. | |
488 | if use_compiler_launcher { | |
489 | if let Some(ref ccache) = builder.config.ccache { | |
490 | cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache) | |
491 | .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache); | |
492 | } | |
493 | } | |
494 | cfg.define("CMAKE_C_COMPILER", sanitize_cc(cc)) | |
3dfed10e XL |
495 | .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx)) |
496 | .define("CMAKE_ASM_COMPILER", sanitize_cc(cc)); | |
0531ce1d XL |
497 | } |
498 | ||
83c7162d | 499 | cfg.build_arg("-j").build_arg(builder.jobs().to_string()); |
9fa01778 | 500 | let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" "); |
dc9dc135 | 501 | if let Some(ref s) = builder.config.llvm_cflags { |
9fa01778 XL |
502 | cflags.push_str(&format!(" {}", s)); |
503 | } | |
f035d41b XL |
504 | // Some compiler features used by LLVM (such as thread locals) will not work on a min version below iOS 10. |
505 | if target.contains("apple-ios") { | |
506 | if target.contains("86-") { | |
507 | cflags.push_str(" -miphonesimulator-version-min=10.0"); | |
508 | } else { | |
509 | cflags.push_str(" -miphoneos-version-min=10.0"); | |
510 | } | |
511 | } | |
512 | if builder.config.llvm_clang_cl.is_some() { | |
513 | cflags.push_str(&format!(" --target={}", target)) | |
514 | } | |
9fa01778 | 515 | cfg.define("CMAKE_C_FLAGS", cflags); |
b7449926 | 516 | let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" "); |
dfeec247 | 517 | if builder.config.llvm_static_stdcpp && !target.contains("msvc") && !target.contains("netbsd") { |
0731742a | 518 | cxxflags.push_str(" -static-libstdc++"); |
0531ce1d | 519 | } |
9fa01778 XL |
520 | if let Some(ref s) = builder.config.llvm_cxxflags { |
521 | cxxflags.push_str(&format!(" {}", s)); | |
522 | } | |
f035d41b XL |
523 | if builder.config.llvm_clang_cl.is_some() { |
524 | cxxflags.push_str(&format!(" --target={}", target)) | |
525 | } | |
0531ce1d | 526 | cfg.define("CMAKE_CXX_FLAGS", cxxflags); |
83c7162d | 527 | if let Some(ar) = builder.ar(target) { |
0531ce1d XL |
528 | if ar.is_absolute() { |
529 | // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it | |
530 | // tries to resolve this path in the LLVM build directory. | |
531 | cfg.define("CMAKE_AR", sanitize_cc(ar)); | |
532 | } | |
533 | } | |
534 | ||
b7449926 XL |
535 | if let Some(ranlib) = builder.ranlib(target) { |
536 | if ranlib.is_absolute() { | |
537 | // LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it | |
538 | // tries to resolve this path in the LLVM build directory. | |
539 | cfg.define("CMAKE_RANLIB", sanitize_cc(ranlib)); | |
540 | } | |
541 | } | |
542 | ||
9fa01778 XL |
543 | if let Some(ref s) = builder.config.llvm_ldflags { |
544 | cfg.define("CMAKE_SHARED_LINKER_FLAGS", s); | |
545 | cfg.define("CMAKE_MODULE_LINKER_FLAGS", s); | |
546 | cfg.define("CMAKE_EXE_LINKER_FLAGS", s); | |
547 | } | |
548 | ||
0531ce1d | 549 | if env::var_os("SCCACHE_ERROR_LOG").is_some() { |
48663c56 | 550 | cfg.env("RUSTC_LOG", "sccache=warn"); |
0531ce1d XL |
551 | } |
552 | } | |
553 | ||
554 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
555 | pub struct Lld { | |
3dfed10e | 556 | pub target: TargetSelection, |
0531ce1d XL |
557 | } |
558 | ||
559 | impl Step for Lld { | |
560 | type Output = PathBuf; | |
561 | const ONLY_HOSTS: bool = true; | |
562 | ||
9fa01778 XL |
563 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
564 | run.path("src/llvm-project/lld").path("src/tools/lld") | |
0531ce1d XL |
565 | } |
566 | ||
9fa01778 | 567 | fn make_run(run: RunConfig<'_>) { |
0531ce1d XL |
568 | run.builder.ensure(Lld { target: run.target }); |
569 | } | |
570 | ||
f035d41b | 571 | /// Compile LLD for `target`. |
9fa01778 | 572 | fn run(self, builder: &Builder<'_>) -> PathBuf { |
83c7162d XL |
573 | if builder.config.dry_run { |
574 | return PathBuf::from("lld-out-dir-test-gen"); | |
575 | } | |
0531ce1d | 576 | let target = self.target; |
0531ce1d | 577 | |
dfeec247 | 578 | let llvm_config = builder.ensure(Llvm { target: self.target }); |
0531ce1d | 579 | |
83c7162d | 580 | let out_dir = builder.lld_out(target); |
0531ce1d XL |
581 | let done_stamp = out_dir.join("lld-finished-building"); |
582 | if done_stamp.exists() { | |
dfeec247 | 583 | return out_dir; |
0531ce1d XL |
584 | } |
585 | ||
83c7162d XL |
586 | builder.info(&format!("Building LLD for {}", target)); |
587 | let _time = util::timeit(&builder); | |
0531ce1d XL |
588 | t!(fs::create_dir_all(&out_dir)); |
589 | ||
9fa01778 | 590 | let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld")); |
dfeec247 | 591 | configure_cmake(builder, target, &mut cfg, true); |
0531ce1d | 592 | |
94b46f34 XL |
593 | // This is an awful, awful hack. Discovered when we migrated to using |
594 | // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of | |
595 | // tree, will execute `llvm-config --cmakedir` and then tell CMake about | |
596 | // that directory for later processing. Unfortunately if this path has | |
597 | // forward slashes in it (which it basically always does on Windows) | |
598 | // then CMake will hit a syntax error later on as... something isn't | |
599 | // escaped it seems? | |
600 | // | |
601 | // Instead of attempting to fix this problem in upstream CMake and/or | |
602 | // LLVM/LLD we just hack around it here. This thin wrapper will take the | |
603 | // output from llvm-config and replace all instances of `\` with `/` to | |
604 | // ensure we don't hit the same bugs with escaping. It means that you | |
605 | // can't build on a system where your paths require `\` on Windows, but | |
606 | // there's probably a lot of reasons you can't do that other than this. | |
dfeec247 | 607 | let llvm_config_shim = env::current_exe().unwrap().with_file_name("llvm-config-wrapper"); |
f035d41b | 608 | |
0531ce1d | 609 | cfg.out_dir(&out_dir) |
dfeec247 | 610 | .profile("Release") |
f9f354fc | 611 | .env("LLVM_CONFIG_REAL", &llvm_config) |
dfeec247 XL |
612 | .define("LLVM_CONFIG_PATH", llvm_config_shim) |
613 | .define("LLVM_INCLUDE_TESTS", "OFF"); | |
0531ce1d | 614 | |
f9f354fc XL |
615 | // While we're using this horrible workaround to shim the execution of |
616 | // llvm-config, let's just pile on more. I can't seem to figure out how | |
617 | // to build LLD as a standalone project and also cross-compile it at the | |
618 | // same time. It wants a natively executable `llvm-config` to learn | |
619 | // about LLVM, but then it learns about all the host configuration of | |
620 | // LLVM and tries to link to host LLVM libraries. | |
621 | // | |
622 | // To work around that we tell our shim to replace anything with the | |
623 | // build target with the actual target instead. This'll break parts of | |
624 | // LLD though which try to execute host tools, such as llvm-tblgen, so | |
625 | // we specifically tell it where to find those. This is likely super | |
626 | // brittle and will break over time. If anyone knows better how to | |
627 | // cross-compile LLD it would be much appreciated to fix this! | |
628 | if target != builder.config.build { | |
3dfed10e XL |
629 | cfg.env("LLVM_CONFIG_SHIM_REPLACE", &builder.config.build.triple) |
630 | .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target.triple) | |
f035d41b XL |
631 | .define( |
632 | "LLVM_TABLEGEN_EXE", | |
633 | llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION), | |
634 | ); | |
f9f354fc XL |
635 | } |
636 | ||
637 | // Explicitly set C++ standard, because upstream doesn't do so | |
638 | // for standalone builds. | |
639 | cfg.define("CMAKE_CXX_STANDARD", "14"); | |
640 | ||
0531ce1d XL |
641 | cfg.build(); |
642 | ||
643 | t!(File::create(&done_stamp)); | |
644 | out_dir | |
645 | } | |
646 | } | |
647 | ||
3b2f2976 XL |
648 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
649 | pub struct TestHelpers { | |
3dfed10e | 650 | pub target: TargetSelection, |
3b2f2976 XL |
651 | } |
652 | ||
653 | impl Step for TestHelpers { | |
654 | type Output = (); | |
655 | ||
9fa01778 | 656 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
0531ce1d | 657 | run.path("src/test/auxiliary/rust_test_helpers.c") |
5bcae85e SL |
658 | } |
659 | ||
9fa01778 | 660 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 661 | run.builder.ensure(TestHelpers { target: run.target }) |
476ff2be SL |
662 | } |
663 | ||
3b2f2976 | 664 | /// Compiles the `rust_test_helpers.c` library which we used in various |
416331ca | 665 | /// `run-pass` tests for ABI testing. |
9fa01778 | 666 | fn run(self, builder: &Builder<'_>) { |
83c7162d XL |
667 | if builder.config.dry_run { |
668 | return; | |
669 | } | |
1b1a35ee XL |
670 | // The x86_64-fortanix-unknown-sgx target doesn't have a working C |
671 | // toolchain. However, some x86_64 ELF objects can be linked | |
672 | // without issues. Use this hack to compile the test helpers. | |
673 | let target = if self.target == "x86_64-fortanix-unknown-sgx" { | |
674 | TargetSelection::from_user("x86_64-unknown-linux-gnu") | |
675 | } else { | |
676 | self.target | |
677 | }; | |
83c7162d XL |
678 | let dst = builder.test_helpers_out(target); |
679 | let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c"); | |
3b2f2976 | 680 | if up_to_date(&src, &dst.join("librust_test_helpers.a")) { |
dfeec247 | 681 | return; |
3b2f2976 XL |
682 | } |
683 | ||
8faf50e0 | 684 | builder.info("Building test helpers"); |
3b2f2976 | 685 | t!(fs::create_dir_all(&dst)); |
ea8adc8c | 686 | let mut cfg = cc::Build::new(); |
e74abb32 XL |
687 | // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013 |
688 | if target.contains("emscripten") { | |
689 | cfg.pic(false); | |
690 | } | |
3b2f2976 XL |
691 | |
692 | // We may have found various cross-compilers a little differently due to our | |
f035d41b XL |
693 | // extra configuration, so inform cc of these compilers. Note, though, that |
694 | // on MSVC we still need cc's detection of env vars (ugh). | |
3b2f2976 | 695 | if !target.contains("msvc") { |
83c7162d | 696 | if let Some(ar) = builder.ar(target) { |
3b2f2976 XL |
697 | cfg.archiver(ar); |
698 | } | |
83c7162d | 699 | cfg.compiler(builder.cc(target)); |
3b2f2976 | 700 | } |
3b2f2976 | 701 | cfg.cargo_metadata(false) |
dfeec247 | 702 | .out_dir(&dst) |
3dfed10e XL |
703 | .target(&target.triple) |
704 | .host(&builder.config.build.triple) | |
dfeec247 XL |
705 | .opt_level(0) |
706 | .warnings(false) | |
707 | .debug(false) | |
708 | .file(builder.src.join("src/test/auxiliary/rust_test_helpers.c")) | |
709 | .compile("rust_test_helpers"); | |
710 | } | |
711 | } | |
712 | ||
713 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | |
714 | pub struct Sanitizers { | |
3dfed10e | 715 | pub target: TargetSelection, |
dfeec247 XL |
716 | } |
717 | ||
718 | impl Step for Sanitizers { | |
719 | type Output = Vec<SanitizerRuntime>; | |
720 | ||
721 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
722 | run.path("src/llvm-project/compiler-rt").path("src/sanitizers") | |
723 | } | |
724 | ||
725 | fn make_run(run: RunConfig<'_>) { | |
726 | run.builder.ensure(Sanitizers { target: run.target }); | |
727 | } | |
728 | ||
729 | /// Builds sanitizer runtime libraries. | |
730 | fn run(self, builder: &Builder<'_>) -> Self::Output { | |
731 | let compiler_rt_dir = builder.src.join("src/llvm-project/compiler-rt"); | |
732 | if !compiler_rt_dir.exists() { | |
733 | return Vec::new(); | |
734 | } | |
735 | ||
736 | let out_dir = builder.native_dir(self.target).join("sanitizers"); | |
74b04a01 | 737 | let runtimes = supported_sanitizers(&out_dir, self.target, &builder.config.channel); |
dfeec247 XL |
738 | if runtimes.is_empty() { |
739 | return runtimes; | |
740 | } | |
741 | ||
742 | let llvm_config = builder.ensure(Llvm { target: builder.config.build }); | |
743 | if builder.config.dry_run { | |
744 | return runtimes; | |
745 | } | |
746 | ||
ba9703b0 XL |
747 | let stamp = out_dir.join("sanitizers-finished-building"); |
748 | let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); | |
749 | ||
750 | if stamp.is_done() { | |
751 | if stamp.hash.is_none() { | |
752 | builder.info(&format!( | |
753 | "Rebuild sanitizers by removing the file `{}`", | |
754 | stamp.path.display() | |
755 | )); | |
756 | } | |
dfeec247 XL |
757 | return runtimes; |
758 | } | |
759 | ||
760 | builder.info(&format!("Building sanitizers for {}", self.target)); | |
ba9703b0 | 761 | t!(stamp.remove()); |
dfeec247 XL |
762 | let _time = util::timeit(&builder); |
763 | ||
764 | let mut cfg = cmake::Config::new(&compiler_rt_dir); | |
765 | cfg.profile("Release"); | |
3dfed10e | 766 | cfg.define("CMAKE_C_COMPILER_TARGET", self.target.triple); |
dfeec247 XL |
767 | cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF"); |
768 | cfg.define("COMPILER_RT_BUILD_CRT", "OFF"); | |
769 | cfg.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF"); | |
770 | cfg.define("COMPILER_RT_BUILD_PROFILE", "OFF"); | |
771 | cfg.define("COMPILER_RT_BUILD_SANITIZERS", "ON"); | |
772 | cfg.define("COMPILER_RT_BUILD_XRAY", "OFF"); | |
773 | cfg.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON"); | |
774 | cfg.define("COMPILER_RT_USE_LIBCXX", "OFF"); | |
775 | cfg.define("LLVM_CONFIG_PATH", &llvm_config); | |
776 | ||
777 | // On Darwin targets the sanitizer runtimes are build as universal binaries. | |
778 | // Unfortunately sccache currently lacks support to build them successfully. | |
779 | // Disable compiler launcher on Darwin targets to avoid potential issues. | |
780 | let use_compiler_launcher = !self.target.contains("apple-darwin"); | |
781 | configure_cmake(builder, self.target, &mut cfg, use_compiler_launcher); | |
782 | ||
783 | t!(fs::create_dir_all(&out_dir)); | |
784 | cfg.out_dir(out_dir); | |
785 | ||
786 | for runtime in &runtimes { | |
787 | cfg.build_target(&runtime.cmake_target); | |
788 | cfg.build(); | |
789 | } | |
ba9703b0 | 790 | t!(stamp.write()); |
dfeec247 XL |
791 | |
792 | runtimes | |
793 | } | |
794 | } | |
795 | ||
796 | #[derive(Clone, Debug)] | |
797 | pub struct SanitizerRuntime { | |
798 | /// CMake target used to build the runtime. | |
799 | pub cmake_target: String, | |
800 | /// Path to the built runtime library. | |
801 | pub path: PathBuf, | |
802 | /// Library filename that will be used rustc. | |
803 | pub name: String, | |
804 | } | |
805 | ||
806 | /// Returns sanitizers available on a given target. | |
74b04a01 XL |
807 | fn supported_sanitizers( |
808 | out_dir: &Path, | |
3dfed10e | 809 | target: TargetSelection, |
74b04a01 XL |
810 | channel: &str, |
811 | ) -> Vec<SanitizerRuntime> { | |
f035d41b XL |
812 | let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> { |
813 | components | |
3dfed10e | 814 | .iter() |
f035d41b XL |
815 | .map(move |c| SanitizerRuntime { |
816 | cmake_target: format!("clang_rt.{}_{}_dynamic", c, os), | |
817 | path: out_dir | |
818 | .join(&format!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c, os)), | |
819 | name: format!("librustc-{}_rt.{}.dylib", channel, c), | |
820 | }) | |
821 | .collect() | |
822 | }; | |
823 | ||
824 | let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec<SanitizerRuntime> { | |
825 | components | |
3dfed10e | 826 | .iter() |
f035d41b XL |
827 | .map(move |c| SanitizerRuntime { |
828 | cmake_target: format!("clang_rt.{}-{}", c, arch), | |
829 | path: out_dir.join(&format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)), | |
830 | name: format!("librustc-{}_rt.{}.a", channel, c), | |
831 | }) | |
832 | .collect() | |
833 | }; | |
834 | ||
3dfed10e | 835 | match &*target.triple { |
5869c6ff | 836 | "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), |
f035d41b XL |
837 | "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]), |
838 | "aarch64-unknown-linux-gnu" => { | |
6a06907d | 839 | common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"]) |
dfeec247 | 840 | } |
f035d41b XL |
841 | "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), |
842 | "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]), | |
3dfed10e | 843 | "x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]), |
94222f64 XL |
844 | "x86_64-unknown-netbsd" => { |
845 | common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"]) | |
846 | } | |
847 | "x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]), | |
848 | "x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]), | |
dfeec247 | 849 | "x86_64-unknown-linux-gnu" => { |
f035d41b | 850 | common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) |
dfeec247 | 851 | } |
cdc7bbd5 XL |
852 | "x86_64-unknown-linux-musl" => { |
853 | common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) | |
854 | } | |
f035d41b | 855 | _ => Vec::new(), |
3b2f2976 | 856 | } |
5bcae85e | 857 | } |
ba9703b0 XL |
858 | |
859 | struct HashStamp { | |
860 | path: PathBuf, | |
861 | hash: Option<Vec<u8>>, | |
862 | } | |
863 | ||
864 | impl HashStamp { | |
865 | fn new(path: PathBuf, hash: Option<&str>) -> Self { | |
866 | HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) } | |
867 | } | |
868 | ||
869 | fn is_done(&self) -> bool { | |
870 | match fs::read(&self.path) { | |
871 | Ok(h) => self.hash.as_deref().unwrap_or(b"") == h.as_slice(), | |
872 | Err(e) if e.kind() == io::ErrorKind::NotFound => false, | |
873 | Err(e) => { | |
874 | panic!("failed to read stamp file `{}`: {}", self.path.display(), e); | |
875 | } | |
876 | } | |
877 | } | |
878 | ||
879 | fn remove(&self) -> io::Result<()> { | |
880 | match fs::remove_file(&self.path) { | |
881 | Ok(()) => Ok(()), | |
882 | Err(e) => { | |
883 | if e.kind() == io::ErrorKind::NotFound { | |
884 | Ok(()) | |
885 | } else { | |
886 | Err(e) | |
887 | } | |
888 | } | |
889 | } | |
890 | } | |
891 | ||
892 | fn write(&self) -> io::Result<()> { | |
893 | fs::write(&self.path, self.hash.as_deref().unwrap_or(b"")) | |
894 | } | |
895 | } | |
cdc7bbd5 XL |
896 | |
897 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | |
898 | pub struct CrtBeginEnd { | |
899 | pub target: TargetSelection, | |
900 | } | |
901 | ||
902 | impl Step for CrtBeginEnd { | |
903 | type Output = PathBuf; | |
904 | ||
905 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
906 | run.path("src/llvm-project/compiler-rt/lib/crt") | |
907 | } | |
908 | ||
909 | fn make_run(run: RunConfig<'_>) { | |
910 | run.builder.ensure(CrtBeginEnd { target: run.target }); | |
911 | } | |
912 | ||
913 | /// Build crtbegin.o/crtend.o for musl target. | |
914 | fn run(self, builder: &Builder<'_>) -> Self::Output { | |
915 | let out_dir = builder.native_dir(self.target).join("crt"); | |
916 | ||
917 | if builder.config.dry_run { | |
918 | return out_dir; | |
919 | } | |
920 | ||
921 | let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c"); | |
922 | let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c"); | |
923 | if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o")) | |
924 | && up_to_date(&crtend_src, &out_dir.join("crtendS.o")) | |
925 | { | |
926 | return out_dir; | |
927 | } | |
928 | ||
929 | builder.info("Building crtbegin.o and crtend.o"); | |
930 | t!(fs::create_dir_all(&out_dir)); | |
931 | ||
932 | let mut cfg = cc::Build::new(); | |
933 | ||
934 | if let Some(ar) = builder.ar(self.target) { | |
935 | cfg.archiver(ar); | |
936 | } | |
937 | cfg.compiler(builder.cc(self.target)); | |
938 | cfg.cargo_metadata(false) | |
939 | .out_dir(&out_dir) | |
940 | .target(&self.target.triple) | |
941 | .host(&builder.config.build.triple) | |
942 | .warnings(false) | |
943 | .debug(false) | |
944 | .opt_level(3) | |
945 | .file(crtbegin_src) | |
946 | .file(crtend_src); | |
947 | ||
948 | // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt | |
949 | // Currently only consumer of those objects is musl, which use .init_array/.fini_array | |
950 | // instead of .ctors/.dtors | |
951 | cfg.flag("-std=c11") | |
952 | .define("CRT_HAS_INITFINI_ARRAY", None) | |
953 | .define("EH_USE_FRAME_REGISTRY", None); | |
954 | ||
955 | cfg.compile("crt"); | |
956 | ||
957 | t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o"))); | |
958 | t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o"))); | |
959 | out_dir | |
960 | } | |
961 | } | |
94222f64 XL |
962 | |
963 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | |
964 | pub struct Libunwind { | |
965 | pub target: TargetSelection, | |
966 | } | |
967 | ||
968 | impl Step for Libunwind { | |
969 | type Output = PathBuf; | |
970 | ||
971 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
972 | run.path("src/llvm-project/libunwind") | |
973 | } | |
974 | ||
975 | fn make_run(run: RunConfig<'_>) { | |
976 | run.builder.ensure(Libunwind { target: run.target }); | |
977 | } | |
978 | ||
979 | /// Build linunwind.a | |
980 | fn run(self, builder: &Builder<'_>) -> Self::Output { | |
981 | if builder.config.dry_run { | |
982 | return PathBuf::new(); | |
983 | } | |
984 | ||
985 | let out_dir = builder.native_dir(self.target).join("libunwind"); | |
986 | let root = builder.src.join("src/llvm-project/libunwind"); | |
987 | ||
988 | if up_to_date(&root, &out_dir.join("libunwind.a")) { | |
989 | return out_dir; | |
990 | } | |
991 | ||
992 | builder.info(&format!("Building libunwind.a for {}", self.target.triple)); | |
993 | t!(fs::create_dir_all(&out_dir)); | |
994 | ||
995 | let mut cc_cfg = cc::Build::new(); | |
996 | let mut cpp_cfg = cc::Build::new(); | |
997 | ||
998 | cpp_cfg.cpp(true); | |
999 | cpp_cfg.cpp_set_stdlib(None); | |
1000 | cpp_cfg.flag("-nostdinc++"); | |
1001 | cpp_cfg.flag("-fno-exceptions"); | |
1002 | cpp_cfg.flag("-fno-rtti"); | |
1003 | cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); | |
1004 | ||
1005 | for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() { | |
1006 | if let Some(ar) = builder.ar(self.target) { | |
1007 | cfg.archiver(ar); | |
1008 | } | |
1009 | cfg.target(&self.target.triple); | |
1010 | cfg.host(&builder.config.build.triple); | |
1011 | cfg.warnings(false); | |
1012 | cfg.debug(false); | |
1013 | // get_compiler() need set opt_level first. | |
1014 | cfg.opt_level(3); | |
1015 | cfg.flag("-fstrict-aliasing"); | |
1016 | cfg.flag("-funwind-tables"); | |
1017 | cfg.flag("-fvisibility=hidden"); | |
1018 | cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); | |
1019 | cfg.include(root.join("include")); | |
1020 | cfg.cargo_metadata(false); | |
1021 | cfg.out_dir(&out_dir); | |
1022 | ||
1023 | if self.target.contains("x86_64-fortanix-unknown-sgx") { | |
1024 | cfg.static_flag(true); | |
1025 | cfg.flag("-fno-stack-protector"); | |
1026 | cfg.flag("-ffreestanding"); | |
1027 | cfg.flag("-fexceptions"); | |
1028 | ||
1029 | // easiest way to undefine since no API available in cc::Build to undefine | |
1030 | cfg.flag("-U_FORTIFY_SOURCE"); | |
1031 | cfg.define("_FORTIFY_SOURCE", "0"); | |
1032 | cfg.define("RUST_SGX", "1"); | |
1033 | cfg.define("__NO_STRING_INLINES", None); | |
1034 | cfg.define("__NO_MATH_INLINES", None); | |
1035 | cfg.define("_LIBUNWIND_IS_BAREMETAL", None); | |
1036 | cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); | |
1037 | cfg.define("NDEBUG", None); | |
1038 | } | |
1039 | } | |
1040 | ||
1041 | cc_cfg.compiler(builder.cc(self.target)); | |
1042 | if let Ok(cxx) = builder.cxx(self.target) { | |
1043 | cpp_cfg.compiler(cxx); | |
1044 | } else { | |
1045 | cc_cfg.compiler(builder.cc(self.target)); | |
1046 | } | |
1047 | ||
1048 | // Don't set this for clang | |
1049 | // By default, Clang builds C code in GNU C17 mode. | |
1050 | // By default, Clang builds C++ code according to the C++98 standard, | |
1051 | // with many C++11 features accepted as extensions. | |
1052 | if cc_cfg.get_compiler().is_like_gnu() { | |
1053 | cc_cfg.flag("-std=c99"); | |
1054 | } | |
1055 | if cpp_cfg.get_compiler().is_like_gnu() { | |
1056 | cpp_cfg.flag("-std=c++11"); | |
1057 | } | |
1058 | ||
1059 | if self.target.contains("x86_64-fortanix-unknown-sgx") || self.target.contains("musl") { | |
1060 | // use the same GCC C compiler command to compile C++ code so we do not need to setup the | |
1061 | // C++ compiler env variables on the builders. | |
1062 | // Don't set this for clang++, as clang++ is able to compile this without libc++. | |
1063 | if cpp_cfg.get_compiler().is_like_gnu() { | |
1064 | cpp_cfg.cpp(false); | |
1065 | cpp_cfg.compiler(builder.cc(self.target)); | |
1066 | } | |
1067 | } | |
1068 | ||
1069 | let mut c_sources = vec![ | |
1070 | "Unwind-sjlj.c", | |
1071 | "UnwindLevel1-gcc-ext.c", | |
1072 | "UnwindLevel1.c", | |
1073 | "UnwindRegistersRestore.S", | |
1074 | "UnwindRegistersSave.S", | |
1075 | ]; | |
1076 | ||
1077 | let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"]; | |
1078 | let cpp_len = cpp_sources.len(); | |
1079 | ||
1080 | if self.target.contains("x86_64-fortanix-unknown-sgx") { | |
1081 | c_sources.push("UnwindRustSgx.c"); | |
1082 | } | |
1083 | ||
1084 | for src in c_sources { | |
1085 | cc_cfg.file(root.join("src").join(src).canonicalize().unwrap()); | |
1086 | } | |
1087 | ||
1088 | for src in &cpp_sources { | |
1089 | cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap()); | |
1090 | } | |
1091 | ||
1092 | cpp_cfg.compile("unwind-cpp"); | |
1093 | ||
1094 | // FIXME: https://github.com/alexcrichton/cc-rs/issues/545#issuecomment-679242845 | |
1095 | let mut count = 0; | |
1096 | for entry in fs::read_dir(&out_dir).unwrap() { | |
1097 | let file = entry.unwrap().path().canonicalize().unwrap(); | |
1098 | if file.is_file() && file.extension() == Some(OsStr::new("o")) { | |
1099 | // file name starts with "Unwind-EHABI", "Unwind-seh" or "libunwind" | |
1100 | let file_name = file.file_name().unwrap().to_str().expect("UTF-8 file name"); | |
1101 | if cpp_sources.iter().any(|f| file_name.starts_with(&f[..f.len() - 4])) { | |
1102 | cc_cfg.object(&file); | |
1103 | count += 1; | |
1104 | } | |
1105 | } | |
1106 | } | |
1107 | assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir); | |
1108 | ||
1109 | cc_cfg.compile("unwind"); | |
1110 | out_dir | |
1111 | } | |
1112 | } |