1 //! Implementation of the various distribution aspects of the compiler.
2 //!
3 //! This module is responsible for creating tarballs of the standard library,
4 //! compiler, and documentation. This ends up being what we distribute to
5 //! everyone as well.
6 //!
7 //! No tarball is actually created literally in this file, but rather we shell
8 //! out to `rust-installer` still. This may one day be replaced with bits and
9 //! pieces of `rustup.rs`!
10
11 use std::collections::HashSet;
12 use std::env;
13 use std::ffi::OsStr;
14 use std::fs;
15 use std::io::Write;
16 use std::path::{Path, PathBuf};
17 use std::process::Command;
18
19 use object::read::archive::ArchiveFile;
20 use object::BinaryFormat;
21 use sha2::Digest;
22
23 use crate::bolt::{instrument_with_bolt, optimize_with_bolt};
24 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
25 use crate::cache::{Interned, INTERNER};
26 use crate::channel;
27 use crate::compile;
28 use crate::config::TargetSelection;
29 use crate::doc::DocumentationFormat;
30 use crate::llvm;
31 use crate::tarball::{GeneratedTarball, OverlayKind, Tarball};
32 use crate::tool::{self, Tool};
33 use crate::util::{exe, is_dylib, output, t, timeit};
34 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
35
pkgname(builder: &Builder<'_>, component: &str) -> String36 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
37 format!("{}-{}", component, builder.rust_package_vers())
38 }
39
distdir(builder: &Builder<'_>) -> PathBuf40 pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf {
41 builder.out.join("dist")
42 }
43
tmpdir(builder: &Builder<'_>) -> PathBuf44 pub fn tmpdir(builder: &Builder<'_>) -> PathBuf {
45 builder.out.join("tmp/dist")
46 }
47
should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool48 fn should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool {
49 if !builder.config.extended {
50 return false;
51 }
52 builder.config.tools.as_ref().map_or(true, |tools| tools.contains(tool))
53 }
54
55 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
56 pub struct Docs {
57 pub host: TargetSelection,
58 }
59
60 impl Step for Docs {
61 type Output = Option<GeneratedTarball>;
62 const DEFAULT: bool = true;
63
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>64 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
65 let default = run.builder.config.docs;
66 run.alias("rust-docs").default_condition(default)
67 }
68
make_run(run: RunConfig<'_>)69 fn make_run(run: RunConfig<'_>) {
70 run.builder.ensure(Docs { host: run.target });
71 }
72
73 /// Builds the `rust-docs` installer component.
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>74 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
75 let host = self.host;
76 builder.default_doc(&[]);
77
78 let dest = "share/doc/rust/html";
79
80 let mut tarball = Tarball::new(builder, "rust-docs", &host.triple);
81 tarball.set_product_name("Rust Documentation");
82 tarball.add_bulk_dir(&builder.doc_out(host), dest);
83 tarball.add_file(&builder.src.join("src/doc/robots.txt"), dest, 0o644);
84 Some(tarball.generate())
85 }
86 }
87
88 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
89 pub struct JsonDocs {
90 pub host: TargetSelection,
91 }
92
93 impl Step for JsonDocs {
94 type Output = Option<GeneratedTarball>;
95 const DEFAULT: bool = true;
96
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>97 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
98 let default = run.builder.config.docs;
99 run.alias("rust-docs-json").default_condition(default)
100 }
101
make_run(run: RunConfig<'_>)102 fn make_run(run: RunConfig<'_>) {
103 run.builder.ensure(JsonDocs { host: run.target });
104 }
105
106 /// Builds the `rust-docs-json` installer component.
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>107 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
108 let host = self.host;
109 builder.ensure(crate::doc::Std::new(builder.top_stage, host, DocumentationFormat::JSON));
110
111 let dest = "share/doc/rust/json";
112
113 let mut tarball = Tarball::new(builder, "rust-docs-json", &host.triple);
114 tarball.set_product_name("Rust Documentation In JSON Format");
115 tarball.is_preview(true);
116 tarball.add_bulk_dir(&builder.json_doc_out(host), dest);
117 Some(tarball.generate())
118 }
119 }
120
121 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
122 pub struct RustcDocs {
123 pub host: TargetSelection,
124 }
125
126 impl Step for RustcDocs {
127 type Output = Option<GeneratedTarball>;
128 const DEFAULT: bool = true;
129
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>130 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
131 let builder = run.builder;
132 run.alias("rustc-docs").default_condition(builder.config.compiler_docs)
133 }
134
make_run(run: RunConfig<'_>)135 fn make_run(run: RunConfig<'_>) {
136 run.builder.ensure(RustcDocs { host: run.target });
137 }
138
139 /// Builds the `rustc-docs` installer component.
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>140 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
141 let host = self.host;
142 builder.default_doc(&[]);
143
144 let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple);
145 tarball.set_product_name("Rustc Documentation");
146 tarball.add_bulk_dir(&builder.compiler_doc_out(host), "share/doc/rust/html/rustc");
147 Some(tarball.generate())
148 }
149 }
150
find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf>151 fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
152 let mut found = Vec::with_capacity(files.len());
153
154 for file in files {
155 let file_path = path.iter().map(|dir| dir.join(file)).find(|p| p.exists());
156
157 if let Some(file_path) = file_path {
158 found.push(file_path);
159 } else {
160 panic!("Could not find '{}' in {:?}", file, path);
161 }
162 }
163
164 found
165 }
166
make_win_dist( rust_root: &Path, plat_root: &Path, target: TargetSelection, builder: &Builder<'_>, )167 fn make_win_dist(
168 rust_root: &Path,
169 plat_root: &Path,
170 target: TargetSelection,
171 builder: &Builder<'_>,
172 ) {
173 if builder.config.dry_run() {
174 return;
175 }
176
177 //Ask gcc where it keeps its stuff
178 let mut cmd = Command::new(builder.cc(target));
179 cmd.arg("-print-search-dirs");
180 let gcc_out = output(&mut cmd);
181
182 let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
183 let mut lib_path = Vec::new();
184
185 for line in gcc_out.lines() {
186 let idx = line.find(':').unwrap();
187 let key = &line[..idx];
188 let trim_chars: &[_] = &[' ', '='];
189 let value = env::split_paths(line[(idx + 1)..].trim_start_matches(trim_chars));
190
191 if key == "programs" {
192 bin_path.extend(value);
193 } else if key == "libraries" {
194 lib_path.extend(value);
195 }
196 }
197
198 let compiler = if target == "i686-pc-windows-gnu" {
199 "i686-w64-mingw32-gcc.exe"
200 } else if target == "x86_64-pc-windows-gnu" {
201 "x86_64-w64-mingw32-gcc.exe"
202 } else {
203 "gcc.exe"
204 };
205 let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
206 let mut rustc_dlls = vec!["libwinpthread-1.dll"];
207 if target.starts_with("i686-") {
208 rustc_dlls.push("libgcc_s_dw2-1.dll");
209 } else {
210 rustc_dlls.push("libgcc_s_seh-1.dll");
211 }
212
213 // Libraries necessary to link the windows-gnu toolchains.
214 // System libraries will be preferred if they are available (see #67429).
215 let target_libs = [
216 //MinGW libs
217 "libgcc.a",
218 "libgcc_eh.a",
219 "libgcc_s.a",
220 "libm.a",
221 "libmingw32.a",
222 "libmingwex.a",
223 "libstdc++.a",
224 "libiconv.a",
225 "libmoldname.a",
226 "libpthread.a",
227 //Windows import libs
228 //This should contain only the set of libraries necessary to link the standard library.
229 "libadvapi32.a",
230 "libbcrypt.a",
231 "libcomctl32.a",
232 "libcomdlg32.a",
233 "libcredui.a",
234 "libcrypt32.a",
235 "libdbghelp.a",
236 "libgdi32.a",
237 "libimagehlp.a",
238 "libiphlpapi.a",
239 "libkernel32.a",
240 "libmsimg32.a",
241 "libmsvcrt.a",
242 "libntdll.a",
243 "libodbc32.a",
244 "libole32.a",
245 "liboleaut32.a",
246 "libopengl32.a",
247 "libpsapi.a",
248 "librpcrt4.a",
249 "libsecur32.a",
250 "libsetupapi.a",
251 "libshell32.a",
252 "libsynchronization.a",
253 "libuser32.a",
254 "libuserenv.a",
255 "libuuid.a",
256 "libwinhttp.a",
257 "libwinmm.a",
258 "libwinspool.a",
259 "libws2_32.a",
260 "libwsock32.a",
261 ];
262
263 //Find mingw artifacts we want to bundle
264 let target_tools = find_files(&target_tools, &bin_path);
265 let rustc_dlls = find_files(&rustc_dlls, &bin_path);
266 let target_libs = find_files(&target_libs, &lib_path);
267
268 // Copy runtime dlls next to rustc.exe
269 let dist_bin_dir = rust_root.join("bin/");
270 fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
271 for src in rustc_dlls {
272 builder.copy_to_folder(&src, &dist_bin_dir);
273 }
274
275 //Copy platform tools to platform-specific bin directory
276 let target_bin_dir = plat_root
277 .join("lib")
278 .join("rustlib")
279 .join(target.triple)
280 .join("bin")
281 .join("self-contained");
282 fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
283 for src in target_tools {
284 builder.copy_to_folder(&src, &target_bin_dir);
285 }
286
287 // Warn windows-gnu users that the bundled GCC cannot compile C files
288 builder.create(
289 &target_bin_dir.join("GCC-WARNING.txt"),
290 "gcc.exe contained in this folder cannot be used for compiling C files - it is only \
291 used as a linker. In order to be able to compile projects containing C code use \
292 the GCC provided by MinGW or Cygwin.",
293 );
294
295 //Copy platform libs to platform-specific lib directory
296 let target_lib_dir = plat_root
297 .join("lib")
298 .join("rustlib")
299 .join(target.triple)
300 .join("lib")
301 .join("self-contained");
302 fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
303 for src in target_libs {
304 builder.copy_to_folder(&src, &target_lib_dir);
305 }
306 }
307
308 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
309 pub struct Mingw {
310 pub host: TargetSelection,
311 }
312
313 impl Step for Mingw {
314 type Output = Option<GeneratedTarball>;
315 const DEFAULT: bool = true;
316
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>317 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
318 run.alias("rust-mingw")
319 }
320
make_run(run: RunConfig<'_>)321 fn make_run(run: RunConfig<'_>) {
322 run.builder.ensure(Mingw { host: run.target });
323 }
324
325 /// Builds the `rust-mingw` installer component.
326 ///
327 /// This contains all the bits and pieces to run the MinGW Windows targets
328 /// without any extra installed software (e.g., we bundle gcc, libraries, etc).
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>329 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
330 let host = self.host;
331 if !host.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker {
332 return None;
333 }
334
335 let mut tarball = Tarball::new(builder, "rust-mingw", &host.triple);
336 tarball.set_product_name("Rust MinGW");
337
338 // The first argument is a "temporary directory" which is just
339 // thrown away (this contains the runtime DLLs included in the rustc package
340 // above) and the second argument is where to place all the MinGW components
341 // (which is what we want).
342 make_win_dist(&tmpdir(builder), tarball.image_dir(), host, &builder);
343
344 Some(tarball.generate())
345 }
346 }
347
348 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
349 pub struct Rustc {
350 pub compiler: Compiler,
351 }
352
353 impl Step for Rustc {
354 type Output = GeneratedTarball;
355 const DEFAULT: bool = true;
356 const ONLY_HOSTS: bool = true;
357
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>358 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
359 run.alias("rustc")
360 }
361
make_run(run: RunConfig<'_>)362 fn make_run(run: RunConfig<'_>) {
363 run.builder
364 .ensure(Rustc { compiler: run.builder.compiler(run.builder.top_stage, run.target) });
365 }
366
367 /// Creates the `rustc` installer component.
run(self, builder: &Builder<'_>) -> GeneratedTarball368 fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
369 let compiler = self.compiler;
370 let host = self.compiler.host;
371
372 let tarball = Tarball::new(builder, "rustc", &host.triple);
373
374 // Prepare the rustc "image", what will actually end up getting installed
375 prepare_image(builder, compiler, tarball.image_dir());
376
377 // On MinGW we've got a few runtime DLL dependencies that we need to
378 // include. The first argument to this script is where to put these DLLs
379 // (the image we're creating), and the second argument is a junk directory
380 // to ignore all other MinGW stuff the script creates.
381 //
382 // On 32-bit MinGW we're always including a DLL which needs some extra
383 // licenses to distribute. On 64-bit MinGW we don't actually distribute
384 // anything requiring us to distribute a license, but it's likely the
385 // install will *also* include the rust-mingw package, which also needs
386 // licenses, so to be safe we just include it here in all MinGW packages.
387 if host.ends_with("pc-windows-gnu") && builder.config.dist_include_mingw_linker {
388 make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder);
389 tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
390 }
391
392 return tarball.generate();
393
394 fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
395 let host = compiler.host;
396 let src = builder.sysroot(compiler);
397
398 // Copy rustc/rustdoc binaries
399 t!(fs::create_dir_all(image.join("bin")));
400 builder.cp_r(&src.join("bin"), &image.join("bin"));
401
402 if builder
403 .config
404 .tools
405 .as_ref()
406 .map_or(true, |tools| tools.iter().any(|tool| tool == "rustdoc"))
407 {
408 let rustdoc = builder.rustdoc(compiler);
409 builder.install(&rustdoc, &image.join("bin"), 0o755);
410 }
411
412 if let Some(ra_proc_macro_srv) = builder.ensure_if_default(
413 tool::RustAnalyzerProcMacroSrv {
414 compiler: builder.compiler_for(
415 compiler.stage,
416 builder.config.build,
417 compiler.host,
418 ),
419 target: compiler.host,
420 },
421 builder.kind,
422 ) {
423 builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755);
424 }
425
426 let libdir_relative = builder.libdir_relative(compiler);
427
428 // Copy runtime DLLs needed by the compiler
429 if libdir_relative.to_str() != Some("bin") {
430 let libdir = builder.rustc_libdir(compiler);
431 for entry in builder.read_dir(&libdir) {
432 let name = entry.file_name();
433 if let Some(s) = name.to_str() {
434 if is_dylib(s) {
435 // Don't use custom libdir here because ^lib/ will be resolved again
436 // with installer
437 builder.install(&entry.path(), &image.join("lib"), 0o644);
438 }
439 }
440 }
441 }
442
443 // Copy over the codegen backends
444 let backends_src = builder.sysroot_codegen_backends(compiler);
445 let backends_rel = backends_src
446 .strip_prefix(&src)
447 .unwrap()
448 .strip_prefix(builder.sysroot_libdir_relative(compiler))
449 .unwrap();
450 // Don't use custom libdir here because ^lib/ will be resolved again with installer
451 let backends_dst = image.join("lib").join(&backends_rel);
452
453 t!(fs::create_dir_all(&backends_dst));
454 builder.cp_r(&backends_src, &backends_dst);
455
456 // Copy libLLVM.so to the lib dir as well, if needed. While not
457 // technically needed by rustc itself it's needed by lots of other
458 // components like the llvm tools and LLD. LLD is included below and
459 // tools/LLDB come later, so let's just throw it in the rustc
460 // component for now.
461 maybe_install_llvm_runtime(builder, host, image);
462
463 let dst_dir = image.join("lib/rustlib").join(&*host.triple).join("bin");
464 t!(fs::create_dir_all(&dst_dir));
465
466 // Copy over lld if it's there
467 if builder.config.lld_enabled {
468 let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
469 let rust_lld = exe("rust-lld", compiler.host);
470 builder.copy(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
471 // for `-Z gcc-ld=lld`
472 let gcc_lld_src_dir = src_dir.join("gcc-ld");
473 let gcc_lld_dst_dir = dst_dir.join("gcc-ld");
474 t!(fs::create_dir(&gcc_lld_dst_dir));
475 for name in crate::LLD_FILE_NAMES {
476 let exe_name = exe(name, compiler.host);
477 builder
478 .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name));
479 }
480 }
481
482 // Man pages
483 t!(fs::create_dir_all(image.join("share/man/man1")));
484 let man_src = builder.src.join("src/doc/man");
485 let man_dst = image.join("share/man/man1");
486
487 // don't use our `bootstrap::util::{copy, cp_r}`, because those try
488 // to hardlink, and we don't want to edit the source templates
489 for file_entry in builder.read_dir(&man_src) {
490 let page_src = file_entry.path();
491 let page_dst = man_dst.join(file_entry.file_name());
492 let src_text = t!(std::fs::read_to_string(&page_src));
493 let new_text = src_text.replace("<INSERT VERSION HERE>", &builder.version);
494 t!(std::fs::write(&page_dst, &new_text));
495 t!(fs::copy(&page_src, &page_dst));
496 }
497
498 // Debugger scripts
499 builder
500 .ensure(DebuggerScripts { sysroot: INTERNER.intern_path(image.to_owned()), host });
501
502 // Misc license info
503 let cp = |file: &str| {
504 builder.install(&builder.src.join(file), &image.join("share/doc/rust"), 0o644);
505 };
506 cp("COPYRIGHT");
507 cp("LICENSE-APACHE");
508 cp("LICENSE-MIT");
509 cp("README.md");
510 cp("NOTICE");
511 }
512 }
513 }
514
515 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
516 pub struct DebuggerScripts {
517 pub sysroot: Interned<PathBuf>,
518 pub host: TargetSelection,
519 }
520
521 impl Step for DebuggerScripts {
522 type Output = ();
523
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>524 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
525 run.never()
526 }
527
528 /// Copies debugger scripts for `target` into the `sysroot` specified.
run(self, builder: &Builder<'_>)529 fn run(self, builder: &Builder<'_>) {
530 let host = self.host;
531 let sysroot = self.sysroot;
532 let dst = sysroot.join("lib/rustlib/etc");
533 t!(fs::create_dir_all(&dst));
534 let cp_debugger_script = |file: &str| {
535 builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644);
536 };
537 if host.contains("windows-msvc") {
538 // windbg debugger scripts
539 builder.install(
540 &builder.src.join("src/etc/rust-windbg.cmd"),
541 &sysroot.join("bin"),
542 0o755,
543 );
544
545 cp_debugger_script("natvis/intrinsic.natvis");
546 cp_debugger_script("natvis/liballoc.natvis");
547 cp_debugger_script("natvis/libcore.natvis");
548 cp_debugger_script("natvis/libstd.natvis");
549 } else {
550 cp_debugger_script("rust_types.py");
551
552 // gdb debugger scripts
553 builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), 0o755);
554 builder.install(&builder.src.join("src/etc/rust-gdbgui"), &sysroot.join("bin"), 0o755);
555
556 cp_debugger_script("gdb_load_rust_pretty_printers.py");
557 cp_debugger_script("gdb_lookup.py");
558 cp_debugger_script("gdb_providers.py");
559
560 // lldb debugger scripts
561 builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"), 0o755);
562
563 cp_debugger_script("lldb_lookup.py");
564 cp_debugger_script("lldb_providers.py");
565 cp_debugger_script("lldb_commands")
566 }
567 }
568 }
569
skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool570 fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
571 // The only true set of target libraries came from the build triple, so
572 // let's reduce redundant work by only producing archives from that host.
573 if compiler.host != builder.config.build {
574 builder.info("\tskipping, not a build host");
575 true
576 } else {
577 false
578 }
579 }
580
581 /// Check that all objects in rlibs for UEFI targets are COFF. This
582 /// ensures that the C compiler isn't producing ELF objects, which would
583 /// not link correctly with the COFF objects.
verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &Path)584 fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &Path) {
585 if !target.ends_with("-uefi") {
586 return;
587 }
588
589 for (path, _) in builder.read_stamp_file(stamp) {
590 if path.extension() != Some(OsStr::new("rlib")) {
591 continue;
592 }
593
594 let data = t!(fs::read(&path));
595 let data = data.as_slice();
596 let archive = t!(ArchiveFile::parse(data));
597 for member in archive.members() {
598 let member = t!(member);
599 let member_data = t!(member.data(data));
600
601 let is_coff = match object::File::parse(member_data) {
602 Ok(member_file) => member_file.format() == BinaryFormat::Coff,
603 Err(_) => false,
604 };
605
606 if !is_coff {
607 let member_name = String::from_utf8_lossy(member.name());
608 panic!("member {} in {} is not COFF", member_name, path.display());
609 }
610 }
611 }
612 }
613
614 /// Copy stamped files into an image's `target/lib` directory.
copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path)615 fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) {
616 let dst = image.join("lib/rustlib").join(target.triple).join("lib");
617 let self_contained_dst = dst.join("self-contained");
618 t!(fs::create_dir_all(&dst));
619 t!(fs::create_dir_all(&self_contained_dst));
620 for (path, dependency_type) in builder.read_stamp_file(stamp) {
621 if dependency_type == DependencyType::TargetSelfContained {
622 builder.copy(&path, &self_contained_dst.join(path.file_name().unwrap()));
623 } else if dependency_type == DependencyType::Target || builder.config.build == target {
624 builder.copy(&path, &dst.join(path.file_name().unwrap()));
625 }
626 }
627 }
628
629 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
630 pub struct Std {
631 pub compiler: Compiler,
632 pub target: TargetSelection,
633 }
634
635 impl Step for Std {
636 type Output = Option<GeneratedTarball>;
637 const DEFAULT: bool = true;
638
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>639 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
640 run.alias("rust-std")
641 }
642
make_run(run: RunConfig<'_>)643 fn make_run(run: RunConfig<'_>) {
644 run.builder.ensure(Std {
645 compiler: run.builder.compiler_for(
646 run.builder.top_stage,
647 run.builder.config.build,
648 run.target,
649 ),
650 target: run.target,
651 });
652 }
653
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>654 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
655 let compiler = self.compiler;
656 let target = self.target;
657
658 if skip_host_target_lib(builder, compiler) {
659 return None;
660 }
661
662 builder.ensure(compile::Std::new(compiler, target));
663
664 let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
665 tarball.include_target_in_component_name(true);
666
667 let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
668 let stamp = compile::libstd_stamp(builder, compiler_to_use, target);
669 verify_uefi_rlib_format(builder, target, &stamp);
670 copy_target_libs(builder, target, &tarball.image_dir(), &stamp);
671
672 // For std of linux-ohos target,
673 // we want to delete metadata-id from the filename, and add '.dylib' for `libstd` and `libtest`.
674 // After changing the filename,
675 // we modify the dependency of `libtest.dylib.so` from `libstd-{metadata-id}.so` to `libstd.dylib.so`.
676 if target.triple.ends_with("-linux-ohos") {
677 let script = builder.src.join("src/bootstrap/std_rename.sh");
678 Command::new("bash")
679 .arg(script)
680 .arg(&target.triple)
681 .output()
682 .expect("Renaming for std fails.");
683 }
684 Some(tarball.generate())
685 }
686 }
687
688 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
689 pub struct RustcDev {
690 pub compiler: Compiler,
691 pub target: TargetSelection,
692 }
693
694 impl Step for RustcDev {
695 type Output = Option<GeneratedTarball>;
696 const DEFAULT: bool = true;
697 const ONLY_HOSTS: bool = true;
698
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>699 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
700 run.alias("rustc-dev")
701 }
702
make_run(run: RunConfig<'_>)703 fn make_run(run: RunConfig<'_>) {
704 run.builder.ensure(RustcDev {
705 compiler: run.builder.compiler_for(
706 run.builder.top_stage,
707 run.builder.config.build,
708 run.target,
709 ),
710 target: run.target,
711 });
712 }
713
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>714 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
715 let compiler = self.compiler;
716 let target = self.target;
717 if skip_host_target_lib(builder, compiler) {
718 return None;
719 }
720
721 builder.ensure(compile::Rustc::new(compiler, target));
722
723 let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
724
725 let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
726 let stamp = compile::librustc_stamp(builder, compiler_to_use, target);
727 copy_target_libs(builder, target, tarball.image_dir(), &stamp);
728
729 let src_files = &["Cargo.lock"];
730 // This is the reduced set of paths which will become the rustc-dev component
731 // (essentially the compiler crates and all of their path dependencies).
732 copy_src_dirs(
733 builder,
734 &builder.src,
735 &["compiler"],
736 &[],
737 &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
738 );
739 for file in src_files {
740 tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644);
741 }
742
743 Some(tarball.generate())
744 }
745 }
746
747 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
748 pub struct Analysis {
749 pub compiler: Compiler,
750 pub target: TargetSelection,
751 }
752
753 impl Step for Analysis {
754 type Output = Option<GeneratedTarball>;
755 const DEFAULT: bool = true;
756
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>757 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
758 let default = should_build_extended_tool(&run.builder, "analysis");
759 run.alias("rust-analysis").default_condition(default)
760 }
761
make_run(run: RunConfig<'_>)762 fn make_run(run: RunConfig<'_>) {
763 run.builder.ensure(Analysis {
764 // Find the actual compiler (handling the full bootstrap option) which
765 // produced the save-analysis data because that data isn't copied
766 // through the sysroot uplifting.
767 compiler: run.builder.compiler_for(
768 run.builder.top_stage,
769 run.builder.config.build,
770 run.target,
771 ),
772 target: run.target,
773 });
774 }
775
776 /// Creates a tarball of (degenerate) save-analysis metadata, if available.
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>777 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
778 let compiler = self.compiler;
779 let target = self.target;
780 if compiler.host != builder.config.build {
781 return None;
782 }
783
784 let src = builder
785 .stage_out(compiler, Mode::Std)
786 .join(target.triple)
787 .join(builder.cargo_dir())
788 .join("deps")
789 .join("save-analysis");
790
791 // Write a file indicating that this component has been removed.
792 t!(std::fs::create_dir_all(&src));
793 let mut removed = src.clone();
794 removed.push("removed.json");
795 let mut f = t!(std::fs::File::create(removed));
796 t!(write!(f, r#"{{ "warning": "The `rust-analysis` component has been removed." }}"#));
797
798 let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple);
799 tarball.include_target_in_component_name(true);
800 tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple));
801 Some(tarball.generate())
802 }
803 }
804
805 /// Use the `builder` to make a filtered copy of `base`/X for X in (`src_dirs` - `exclude_dirs`) to
806 /// `dst_dir`.
copy_src_dirs( builder: &Builder<'_>, base: &Path, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path, )807 fn copy_src_dirs(
808 builder: &Builder<'_>,
809 base: &Path,
810 src_dirs: &[&str],
811 exclude_dirs: &[&str],
812 dst_dir: &Path,
813 ) {
814 fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
815 let spath = match path.to_str() {
816 Some(path) => path,
817 None => return false,
818 };
819 if spath.ends_with('~') || spath.ends_with(".pyc") {
820 return false;
821 }
822
823 const LLVM_PROJECTS: &[&str] = &[
824 "llvm-project/clang",
825 "llvm-project\\clang",
826 "llvm-project/libunwind",
827 "llvm-project\\libunwind",
828 "llvm-project/lld",
829 "llvm-project\\lld",
830 "llvm-project/lldb",
831 "llvm-project\\lldb",
832 "llvm-project/llvm",
833 "llvm-project\\llvm",
834 "llvm-project/compiler-rt",
835 "llvm-project\\compiler-rt",
836 "llvm-project/cmake",
837 "llvm-project\\cmake",
838 "llvm-project/runtimes",
839 "llvm-project\\runtimes",
840 ];
841 if spath.contains("llvm-project")
842 && !spath.ends_with("llvm-project")
843 && !LLVM_PROJECTS.iter().any(|path| spath.contains(path))
844 {
845 return false;
846 }
847
848 const LLVM_TEST: &[&str] = &["llvm-project/llvm/test", "llvm-project\\llvm\\test"];
849 if LLVM_TEST.iter().any(|path| spath.contains(path))
850 && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
851 {
852 return false;
853 }
854
855 let full_path = Path::new(dir).join(path);
856 if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
857 return false;
858 }
859
860 let excludes = [
861 "CVS",
862 "RCS",
863 "SCCS",
864 ".git",
865 ".gitignore",
866 ".gitmodules",
867 ".gitattributes",
868 ".cvsignore",
869 ".svn",
870 ".arch-ids",
871 "{arch}",
872 "=RELEASE-ID",
873 "=meta-update",
874 "=update",
875 ".bzr",
876 ".bzrignore",
877 ".bzrtags",
878 ".hg",
879 ".hgignore",
880 ".hgrags",
881 "_darcs",
882 ];
883 !path.iter().map(|s| s.to_str().unwrap()).any(|s| excludes.contains(&s))
884 }
885
886 // Copy the directories using our filter
887 for item in src_dirs {
888 let dst = &dst_dir.join(item);
889 t!(fs::create_dir_all(dst));
890 builder.cp_filtered(&base.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
891 }
892 }
893
894 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
895 pub struct Src;
896
897 impl Step for Src {
898 /// The output path of the src installer tarball
899 type Output = GeneratedTarball;
900 const DEFAULT: bool = true;
901 const ONLY_HOSTS: bool = true;
902
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>903 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
904 run.alias("rust-src")
905 }
906
make_run(run: RunConfig<'_>)907 fn make_run(run: RunConfig<'_>) {
908 run.builder.ensure(Src);
909 }
910
911 /// Creates the `rust-src` installer component
run(self, builder: &Builder<'_>) -> GeneratedTarball912 fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
913 builder.update_submodule(&Path::new("src/llvm-project"));
914
915 let tarball = Tarball::new_targetless(builder, "rust-src");
916
917 // A lot of tools expect the rust-src component to be entirely in this directory, so if you
918 // change that (e.g. by adding another directory `lib/rustlib/src/foo` or
919 // `lib/rustlib/src/rust/foo`), you will need to go around hunting for implicit assumptions
920 // and fix them...
921 //
922 // NOTE: if you update the paths here, you also should update the "virtual" path
923 // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
924 let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
925
926 let src_files = ["Cargo.lock"];
927 // This is the reduced set of paths which will become the rust-src component
928 // (essentially libstd and all of its path dependencies).
929 copy_src_dirs(
930 builder,
931 &builder.src,
932 &["library", "src/llvm-project/libunwind"],
933 &[
934 // not needed and contains symlinks which rustup currently
935 // chokes on when unpacking.
936 "library/backtrace/crates",
937 // these are 30MB combined and aren't necessary for building
938 // the standard library.
939 "library/stdarch/Cargo.toml",
940 "library/stdarch/crates/stdarch-verify",
941 "library/stdarch/crates/intrinsic-test",
942 ],
943 &dst_src,
944 );
945 for file in src_files.iter() {
946 builder.copy(&builder.src.join(file), &dst_src.join(file));
947 }
948
949 tarball.generate()
950 }
951 }
952
953 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
954 pub struct PlainSourceTarball;
955
956 impl Step for PlainSourceTarball {
957 /// Produces the location of the tarball generated
958 type Output = GeneratedTarball;
959 const DEFAULT: bool = true;
960 const ONLY_HOSTS: bool = true;
961
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>962 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
963 let builder = run.builder;
964 run.alias("rustc-src").default_condition(builder.config.rust_dist_src)
965 }
966
make_run(run: RunConfig<'_>)967 fn make_run(run: RunConfig<'_>) {
968 run.builder.ensure(PlainSourceTarball);
969 }
970
971 /// Creates the plain source tarball
run(self, builder: &Builder<'_>) -> GeneratedTarball972 fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
973 // NOTE: This is a strange component in a lot of ways. It uses `src` as the target, which
974 // means neither rustup nor rustup-toolchain-install-master know how to download it.
975 // It also contains symbolic links, unlike other any other dist tarball.
976 // It's used for distros building rustc from source in a pre-vendored environment.
977 let mut tarball = Tarball::new(builder, "rustc", "src");
978 tarball.permit_symlinks(true);
979 let plain_dst_src = tarball.image_dir();
980
981 // This is the set of root paths which will become part of the source package
982 let src_files = [
983 "COPYRIGHT",
984 "LICENSE-APACHE",
985 "LICENSE-MIT",
986 "CONTRIBUTING.md",
987 "README.md",
988 "RELEASES.md",
989 "configure",
990 "x.py",
991 "config.example.toml",
992 "Cargo.toml",
993 "Cargo.lock",
994 ".gitmodules",
995 ];
996 let src_dirs = ["src", "compiler", "library", "tests"];
997
998 copy_src_dirs(builder, &builder.src, &src_dirs, &[], &plain_dst_src);
999
1000 // Copy the files normally
1001 for item in &src_files {
1002 builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
1003 }
1004
1005 // Create the version file
1006 builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1007 if let Some(info) = builder.rust_info().info() {
1008 channel::write_commit_hash_file(&plain_dst_src, &info.sha);
1009 channel::write_commit_info_file(&plain_dst_src, info);
1010 }
1011
1012 // If we're building from git sources, we need to vendor a complete distribution.
1013 if builder.rust_info().is_managed_git_subrepository() {
1014 // Ensure we have the submodules checked out.
1015 builder.update_submodule(Path::new("src/tools/cargo"));
1016 builder.update_submodule(Path::new("src/tools/rust-analyzer"));
1017
1018 // Vendor all Cargo dependencies
1019 let mut cmd = Command::new(&builder.initial_cargo);
1020 cmd.arg("vendor")
1021 .arg("--sync")
1022 .arg(builder.src.join("./src/tools/cargo/Cargo.toml"))
1023 .arg("--sync")
1024 .arg(builder.src.join("./src/tools/rust-analyzer/Cargo.toml"))
1025 .arg("--sync")
1026 .arg(builder.src.join("./compiler/rustc_codegen_cranelift/Cargo.toml"))
1027 .arg("--sync")
1028 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
1029 // Will read the libstd Cargo.toml
1030 // which uses the unstable `public-dependency` feature.
1031 .env("RUSTC_BOOTSTRAP", "1")
1032 .current_dir(&plain_dst_src);
1033
1034 let config = if !builder.config.dry_run() {
1035 t!(String::from_utf8(t!(cmd.output()).stdout))
1036 } else {
1037 String::new()
1038 };
1039
1040 let cargo_config_dir = plain_dst_src.join(".cargo");
1041 builder.create_dir(&cargo_config_dir);
1042 builder.create(&cargo_config_dir.join("config.toml"), &config);
1043 }
1044
1045 tarball.bare()
1046 }
1047 }
1048
1049 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1050 pub struct Cargo {
1051 pub compiler: Compiler,
1052 pub target: TargetSelection,
1053 }
1054
1055 impl Step for Cargo {
1056 type Output = Option<GeneratedTarball>;
1057 const DEFAULT: bool = true;
1058 const ONLY_HOSTS: bool = true;
1059
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1060 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1061 let default = should_build_extended_tool(&run.builder, "cargo");
1062 run.alias("cargo").default_condition(default)
1063 }
1064
make_run(run: RunConfig<'_>)1065 fn make_run(run: RunConfig<'_>) {
1066 run.builder.ensure(Cargo {
1067 compiler: run.builder.compiler_for(
1068 run.builder.top_stage,
1069 run.builder.config.build,
1070 run.target,
1071 ),
1072 target: run.target,
1073 });
1074 }
1075
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>1076 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1077 let compiler = self.compiler;
1078 let target = self.target;
1079
1080 let cargo = builder.ensure(tool::Cargo { compiler, target });
1081 let src = builder.src.join("src/tools/cargo");
1082 let etc = src.join("src/etc");
1083
1084 // Prepare the image directory
1085 let mut tarball = Tarball::new(builder, "cargo", &target.triple);
1086 tarball.set_overlay(OverlayKind::Cargo);
1087
1088 tarball.add_file(&cargo, "bin", 0o755);
1089 tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
1090 tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo");
1091 tarball.add_dir(etc.join("man"), "share/man/man1");
1092 tarball.add_legal_and_readme_to("share/doc/cargo");
1093
1094 for dirent in fs::read_dir(cargo.parent().unwrap()).expect("read_dir") {
1095 let dirent = dirent.expect("read dir entry");
1096 if dirent.file_name().to_str().expect("utf8").starts_with("cargo-credential-") {
1097 tarball.add_file(&dirent.path(), "libexec", 0o755);
1098 }
1099 }
1100
1101 Some(tarball.generate())
1102 }
1103 }
1104
1105 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1106 pub struct Rls {
1107 pub compiler: Compiler,
1108 pub target: TargetSelection,
1109 }
1110
1111 impl Step for Rls {
1112 type Output = Option<GeneratedTarball>;
1113 const ONLY_HOSTS: bool = true;
1114 const DEFAULT: bool = true;
1115
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1116 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1117 let default = should_build_extended_tool(&run.builder, "rls");
1118 run.alias("rls").default_condition(default)
1119 }
1120
make_run(run: RunConfig<'_>)1121 fn make_run(run: RunConfig<'_>) {
1122 run.builder.ensure(Rls {
1123 compiler: run.builder.compiler_for(
1124 run.builder.top_stage,
1125 run.builder.config.build,
1126 run.target,
1127 ),
1128 target: run.target,
1129 });
1130 }
1131
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>1132 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1133 let compiler = self.compiler;
1134 let target = self.target;
1135
1136 let rls = builder
1137 .ensure(tool::Rls { compiler, target, extra_features: Vec::new() })
1138 .expect("rls expected to build");
1139
1140 let mut tarball = Tarball::new(builder, "rls", &target.triple);
1141 tarball.set_overlay(OverlayKind::RLS);
1142 tarball.is_preview(true);
1143 tarball.add_file(rls, "bin", 0o755);
1144 tarball.add_legal_and_readme_to("share/doc/rls");
1145 Some(tarball.generate())
1146 }
1147 }
1148
1149 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1150 pub struct RustAnalyzer {
1151 pub compiler: Compiler,
1152 pub target: TargetSelection,
1153 }
1154
1155 impl Step for RustAnalyzer {
1156 type Output = Option<GeneratedTarball>;
1157 const DEFAULT: bool = true;
1158 const ONLY_HOSTS: bool = true;
1159
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1160 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1161 let default = should_build_extended_tool(&run.builder, "rust-analyzer");
1162 run.alias("rust-analyzer").default_condition(default)
1163 }
1164
make_run(run: RunConfig<'_>)1165 fn make_run(run: RunConfig<'_>) {
1166 run.builder.ensure(RustAnalyzer {
1167 compiler: run.builder.compiler_for(
1168 run.builder.top_stage,
1169 run.builder.config.build,
1170 run.target,
1171 ),
1172 target: run.target,
1173 });
1174 }
1175
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>1176 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1177 let compiler = self.compiler;
1178 let target = self.target;
1179
1180 let rust_analyzer = builder
1181 .ensure(tool::RustAnalyzer { compiler, target })
1182 .expect("rust-analyzer always builds");
1183
1184 let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
1185 tarball.set_overlay(OverlayKind::RustAnalyzer);
1186 tarball.is_preview(true);
1187 tarball.add_file(rust_analyzer, "bin", 0o755);
1188 tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
1189 Some(tarball.generate())
1190 }
1191 }
1192
1193 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1194 pub struct Clippy {
1195 pub compiler: Compiler,
1196 pub target: TargetSelection,
1197 }
1198
1199 impl Step for Clippy {
1200 type Output = Option<GeneratedTarball>;
1201 const DEFAULT: bool = true;
1202 const ONLY_HOSTS: bool = true;
1203
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1204 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1205 let default = should_build_extended_tool(&run.builder, "clippy");
1206 run.alias("clippy").default_condition(default)
1207 }
1208
make_run(run: RunConfig<'_>)1209 fn make_run(run: RunConfig<'_>) {
1210 run.builder.ensure(Clippy {
1211 compiler: run.builder.compiler_for(
1212 run.builder.top_stage,
1213 run.builder.config.build,
1214 run.target,
1215 ),
1216 target: run.target,
1217 });
1218 }
1219
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>1220 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1221 let compiler = self.compiler;
1222 let target = self.target;
1223
1224 // Prepare the image directory
1225 // We expect clippy to build, because we've exited this step above if tool
1226 // state for clippy isn't testing.
1227 let clippy = builder
1228 .ensure(tool::Clippy { compiler, target, extra_features: Vec::new() })
1229 .expect("clippy expected to build - essential tool");
1230 let cargoclippy = builder
1231 .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() })
1232 .expect("clippy expected to build - essential tool");
1233
1234 let mut tarball = Tarball::new(builder, "clippy", &target.triple);
1235 tarball.set_overlay(OverlayKind::Clippy);
1236 tarball.is_preview(true);
1237 tarball.add_file(clippy, "bin", 0o755);
1238 tarball.add_file(cargoclippy, "bin", 0o755);
1239 tarball.add_legal_and_readme_to("share/doc/clippy");
1240 Some(tarball.generate())
1241 }
1242 }
1243
1244 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1245 pub struct Miri {
1246 pub compiler: Compiler,
1247 pub target: TargetSelection,
1248 }
1249
1250 impl Step for Miri {
1251 type Output = Option<GeneratedTarball>;
1252 const DEFAULT: bool = true;
1253 const ONLY_HOSTS: bool = true;
1254
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1255 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1256 let default = should_build_extended_tool(&run.builder, "miri");
1257 run.alias("miri").default_condition(default)
1258 }
1259
make_run(run: RunConfig<'_>)1260 fn make_run(run: RunConfig<'_>) {
1261 run.builder.ensure(Miri {
1262 compiler: run.builder.compiler_for(
1263 run.builder.top_stage,
1264 run.builder.config.build,
1265 run.target,
1266 ),
1267 target: run.target,
1268 });
1269 }
1270
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>1271 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1272 // This prevents miri from being built for "dist" or "install"
1273 // on the stable/beta channels. It is a nightly-only tool and should
1274 // not be included.
1275 if !builder.build.unstable_features() {
1276 return None;
1277 }
1278 let compiler = self.compiler;
1279 let target = self.target;
1280
1281 let miri = builder.ensure(tool::Miri { compiler, target, extra_features: Vec::new() })?;
1282 let cargomiri =
1283 builder.ensure(tool::CargoMiri { compiler, target, extra_features: Vec::new() })?;
1284
1285 let mut tarball = Tarball::new(builder, "miri", &target.triple);
1286 tarball.set_overlay(OverlayKind::Miri);
1287 tarball.is_preview(true);
1288 tarball.add_file(miri, "bin", 0o755);
1289 tarball.add_file(cargomiri, "bin", 0o755);
1290 tarball.add_legal_and_readme_to("share/doc/miri");
1291 Some(tarball.generate())
1292 }
1293 }
1294
1295 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1296 pub struct Rustfmt {
1297 pub compiler: Compiler,
1298 pub target: TargetSelection,
1299 }
1300
1301 impl Step for Rustfmt {
1302 type Output = Option<GeneratedTarball>;
1303 const DEFAULT: bool = true;
1304 const ONLY_HOSTS: bool = true;
1305
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1306 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1307 let default = should_build_extended_tool(&run.builder, "rustfmt");
1308 run.alias("rustfmt").default_condition(default)
1309 }
1310
make_run(run: RunConfig<'_>)1311 fn make_run(run: RunConfig<'_>) {
1312 run.builder.ensure(Rustfmt {
1313 compiler: run.builder.compiler_for(
1314 run.builder.top_stage,
1315 run.builder.config.build,
1316 run.target,
1317 ),
1318 target: run.target,
1319 });
1320 }
1321
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>1322 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1323 let compiler = self.compiler;
1324 let target = self.target;
1325
1326 let rustfmt = builder
1327 .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() })
1328 .expect("rustfmt expected to build - essential tool");
1329 let cargofmt = builder
1330 .ensure(tool::Cargofmt { compiler, target, extra_features: Vec::new() })
1331 .expect("cargo fmt expected to build - essential tool");
1332 let mut tarball = Tarball::new(builder, "rustfmt", &target.triple);
1333 tarball.set_overlay(OverlayKind::Rustfmt);
1334 tarball.is_preview(true);
1335 tarball.add_file(rustfmt, "bin", 0o755);
1336 tarball.add_file(cargofmt, "bin", 0o755);
1337 tarball.add_legal_and_readme_to("share/doc/rustfmt");
1338 Some(tarball.generate())
1339 }
1340 }
1341
1342 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1343 pub struct RustDemangler {
1344 pub compiler: Compiler,
1345 pub target: TargetSelection,
1346 }
1347
1348 impl Step for RustDemangler {
1349 type Output = Option<GeneratedTarball>;
1350 const DEFAULT: bool = true;
1351 const ONLY_HOSTS: bool = true;
1352
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1353 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1354 // While other tools use `should_build_extended_tool` to decide whether to be run by
1355 // default or not, `rust-demangler` must be build when *either* it's enabled as a tool like
1356 // the other ones or if `profiler = true`. Because we don't know the target at this stage
1357 // we run the step by default when only `extended = true`, and decide whether to actually
1358 // run it or not later.
1359 let default = run.builder.config.extended;
1360 run.alias("rust-demangler").default_condition(default)
1361 }
1362
make_run(run: RunConfig<'_>)1363 fn make_run(run: RunConfig<'_>) {
1364 run.builder.ensure(RustDemangler {
1365 compiler: run.builder.compiler_for(
1366 run.builder.top_stage,
1367 run.builder.config.build,
1368 run.target,
1369 ),
1370 target: run.target,
1371 });
1372 }
1373
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>1374 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1375 let compiler = self.compiler;
1376 let target = self.target;
1377
1378 // Only build this extended tool if explicitly included in `tools`, or if `profiler = true`
1379 let condition = should_build_extended_tool(builder, "rust-demangler")
1380 || builder.config.profiler_enabled(target);
1381 if builder.config.extended && !condition {
1382 return None;
1383 }
1384
1385 let rust_demangler = builder
1386 .ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() })
1387 .expect("rust-demangler expected to build - in-tree tool");
1388
1389 // Prepare the image directory
1390 let mut tarball = Tarball::new(builder, "rust-demangler", &target.triple);
1391 tarball.set_overlay(OverlayKind::RustDemangler);
1392 tarball.is_preview(true);
1393 tarball.add_file(&rust_demangler, "bin", 0o755);
1394 tarball.add_legal_and_readme_to("share/doc/rust-demangler");
1395 Some(tarball.generate())
1396 }
1397 }
1398
1399 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1400 pub struct Extended {
1401 stage: u32,
1402 host: TargetSelection,
1403 target: TargetSelection,
1404 }
1405
1406 impl Step for Extended {
1407 type Output = ();
1408 const DEFAULT: bool = true;
1409 const ONLY_HOSTS: bool = true;
1410
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>1411 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1412 let builder = run.builder;
1413 run.alias("extended").default_condition(builder.config.extended)
1414 }
1415
make_run(run: RunConfig<'_>)1416 fn make_run(run: RunConfig<'_>) {
1417 run.builder.ensure(Extended {
1418 stage: run.builder.top_stage,
1419 host: run.builder.config.build,
1420 target: run.target,
1421 });
1422 }
1423
1424 /// Creates a combined installer for the specified target in the provided stage.
run(self, builder: &Builder<'_>)1425 fn run(self, builder: &Builder<'_>) {
1426 let target = self.target;
1427 let stage = self.stage;
1428 let compiler = builder.compiler_for(self.stage, self.host, self.target);
1429
1430 builder.info(&format!("Dist extended stage{} ({})", compiler.stage, target));
1431
1432 let mut tarballs = Vec::new();
1433 let mut built_tools = HashSet::new();
1434 macro_rules! add_component {
1435 ($name:expr => $step:expr) => {
1436 if let Some(tarball) = builder.ensure_if_default($step, Kind::Dist) {
1437 tarballs.push(tarball);
1438 built_tools.insert($name);
1439 }
1440 };
1441 }
1442
1443 // When rust-std package split from rustc, we needed to ensure that during
1444 // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1445 // the std files during uninstall. To do this ensure that rustc comes
1446 // before rust-std in the list below.
1447 tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) }));
1448 tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std"));
1449
1450 if target.ends_with("windows-gnu") {
1451 tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw"));
1452 }
1453
1454 add_component!("rust-docs" => Docs { host: target });
1455 add_component!("rust-json-docs" => JsonDocs { host: target });
1456 add_component!("rust-demangler"=> RustDemangler { compiler, target });
1457 add_component!("cargo" => Cargo { compiler, target });
1458 add_component!("rustfmt" => Rustfmt { compiler, target });
1459 add_component!("rls" => Rls { compiler, target });
1460 add_component!("rust-analyzer" => RustAnalyzer { compiler, target });
1461 add_component!("llvm-components" => LlvmTools { target });
1462 add_component!("clippy" => Clippy { compiler, target });
1463 add_component!("miri" => Miri { compiler, target });
1464 add_component!("analysis" => Analysis { compiler, target });
1465
1466 let etc = builder.src.join("src/etc/installer");
1467
1468 // Avoid producing tarballs during a dry run.
1469 if builder.config.dry_run() {
1470 return;
1471 }
1472
1473 let tarball = Tarball::new(builder, "rust", &target.triple);
1474 let generated = tarball.combine(&tarballs);
1475
1476 let tmp = tmpdir(builder).join("combined-tarball");
1477 let work = generated.work_dir();
1478
1479 let mut license = String::new();
1480 license += &builder.read(&builder.src.join("COPYRIGHT"));
1481 license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1482 license += &builder.read(&builder.src.join("LICENSE-MIT"));
1483 license.push('\n');
1484 license.push('\n');
1485
1486 let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1487 let mut rtf = rtf.to_string();
1488 rtf.push('\n');
1489 for line in license.lines() {
1490 rtf.push_str(line);
1491 rtf.push_str("\\line ");
1492 }
1493 rtf.push('}');
1494
1495 fn filter(contents: &str, marker: &str) -> String {
1496 let start = format!("tool-{}-start", marker);
1497 let end = format!("tool-{}-end", marker);
1498 let mut lines = Vec::new();
1499 let mut omitted = false;
1500 for line in contents.lines() {
1501 if line.contains(&start) {
1502 omitted = true;
1503 } else if line.contains(&end) {
1504 omitted = false;
1505 } else if !omitted {
1506 lines.push(line);
1507 }
1508 }
1509
1510 lines.join("\n")
1511 }
1512
1513 let xform = |p: &Path| {
1514 let mut contents = t!(fs::read_to_string(p));
1515 for tool in &["rust-demangler", "miri", "rust-docs"] {
1516 if !built_tools.contains(tool) {
1517 contents = filter(&contents, tool);
1518 }
1519 }
1520 let ret = tmp.join(p.file_name().unwrap());
1521 t!(fs::write(&ret, &contents));
1522 ret
1523 };
1524
1525 if target.contains("apple-darwin") {
1526 builder.info("building pkg installer");
1527 let pkg = tmp.join("pkg");
1528 let _ = fs::remove_dir_all(&pkg);
1529
1530 let pkgbuild = |component: &str| {
1531 let mut cmd = Command::new("pkgbuild");
1532 cmd.arg("--identifier")
1533 .arg(format!("org.rust-lang.{}", component))
1534 .arg("--scripts")
1535 .arg(pkg.join(component))
1536 .arg("--nopayload")
1537 .arg(pkg.join(component).with_extension("pkg"));
1538 builder.run(&mut cmd);
1539 };
1540
1541 let prepare = |name: &str| {
1542 builder.create_dir(&pkg.join(name));
1543 builder.cp_r(
1544 &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)),
1545 &pkg.join(name),
1546 );
1547 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
1548 pkgbuild(name);
1549 };
1550 prepare("rustc");
1551 prepare("rust-std");
1552 prepare("clippy");
1553 for tool in &["rust-docs", "rust-demangler", "miri", "cargo", "rust-analysis", "rust-analyzer"] {
1554 if built_tools.contains(tool) {
1555 prepare(tool);
1556 }
1557 }
1558 // create an 'uninstall' package
1559 builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1560 pkgbuild("uninstall");
1561
1562 builder.create_dir(&pkg.join("res"));
1563 builder.create(&pkg.join("res/LICENSE.txt"), &license);
1564 builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1565 let mut cmd = Command::new("productbuild");
1566 cmd.arg("--distribution")
1567 .arg(xform(&etc.join("pkg/Distribution.xml")))
1568 .arg("--resources")
1569 .arg(pkg.join("res"))
1570 .arg(distdir(builder).join(format!(
1571 "{}-{}.pkg",
1572 pkgname(builder, "rust"),
1573 target.triple
1574 )))
1575 .arg("--package-path")
1576 .arg(&pkg);
1577 let _time = timeit(builder);
1578 builder.run(&mut cmd);
1579 }
1580
1581 if target.contains("windows") {
1582 let exe = tmp.join("exe");
1583 let _ = fs::remove_dir_all(&exe);
1584
1585 let prepare = |name: &str| {
1586 builder.create_dir(&exe.join(name));
1587 let dir = if name == "rust-std" || name == "rust-analysis" {
1588 format!("{}-{}", name, target.triple)
1589 } else if name == "rust-analyzer" {
1590 "rust-analyzer-preview".to_string()
1591 } else if name == "clippy" {
1592 "clippy-preview".to_string()
1593 } else if name == "rust-demangler" {
1594 "rust-demangler-preview".to_string()
1595 } else if name == "miri" {
1596 "miri-preview".to_string()
1597 } else {
1598 name.to_string()
1599 };
1600 builder.cp_r(
1601 &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
1602 &exe.join(name),
1603 );
1604 builder.remove(&exe.join(name).join("manifest.in"));
1605 };
1606 prepare("rustc");
1607 prepare("cargo");
1608 prepare("rust-analysis");
1609 prepare("rust-std");
1610 for tool in &["clippy", "rust-analyzer", "rust-docs", "rust-demangler", "miri"] {
1611 if built_tools.contains(tool) {
1612 prepare(tool);
1613 }
1614 }
1615 if target.ends_with("windows-gnu") {
1616 prepare("rust-mingw");
1617 }
1618
1619 builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1620
1621 // Generate msi installer
1622 let wix_path = env::var_os("WIX")
1623 .expect("`WIX` environment variable must be set for generating MSI installer(s).");
1624 let wix = PathBuf::from(wix_path);
1625 let heat = wix.join("bin/heat.exe");
1626 let candle = wix.join("bin/candle.exe");
1627 let light = wix.join("bin/light.exe");
1628
1629 let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1630 builder.run(
1631 Command::new(&heat)
1632 .current_dir(&exe)
1633 .arg("dir")
1634 .arg("rustc")
1635 .args(&heat_flags)
1636 .arg("-cg")
1637 .arg("RustcGroup")
1638 .arg("-dr")
1639 .arg("Rustc")
1640 .arg("-var")
1641 .arg("var.RustcDir")
1642 .arg("-out")
1643 .arg(exe.join("RustcGroup.wxs")),
1644 );
1645 if built_tools.contains("rust-docs") {
1646 builder.run(
1647 Command::new(&heat)
1648 .current_dir(&exe)
1649 .arg("dir")
1650 .arg("rust-docs")
1651 .args(&heat_flags)
1652 .arg("-cg")
1653 .arg("DocsGroup")
1654 .arg("-dr")
1655 .arg("Docs")
1656 .arg("-var")
1657 .arg("var.DocsDir")
1658 .arg("-out")
1659 .arg(exe.join("DocsGroup.wxs"))
1660 .arg("-t")
1661 .arg(etc.join("msi/squash-components.xsl")),
1662 );
1663 }
1664 builder.run(
1665 Command::new(&heat)
1666 .current_dir(&exe)
1667 .arg("dir")
1668 .arg("cargo")
1669 .args(&heat_flags)
1670 .arg("-cg")
1671 .arg("CargoGroup")
1672 .arg("-dr")
1673 .arg("Cargo")
1674 .arg("-var")
1675 .arg("var.CargoDir")
1676 .arg("-out")
1677 .arg(exe.join("CargoGroup.wxs"))
1678 .arg("-t")
1679 .arg(etc.join("msi/remove-duplicates.xsl")),
1680 );
1681 builder.run(
1682 Command::new(&heat)
1683 .current_dir(&exe)
1684 .arg("dir")
1685 .arg("rust-std")
1686 .args(&heat_flags)
1687 .arg("-cg")
1688 .arg("StdGroup")
1689 .arg("-dr")
1690 .arg("Std")
1691 .arg("-var")
1692 .arg("var.StdDir")
1693 .arg("-out")
1694 .arg(exe.join("StdGroup.wxs")),
1695 );
1696 if built_tools.contains("rust-analyzer") {
1697 builder.run(
1698 Command::new(&heat)
1699 .current_dir(&exe)
1700 .arg("dir")
1701 .arg("rust-analyzer")
1702 .args(&heat_flags)
1703 .arg("-cg")
1704 .arg("RustAnalyzerGroup")
1705 .arg("-dr")
1706 .arg("RustAnalyzer")
1707 .arg("-var")
1708 .arg("var.RustAnalyzerDir")
1709 .arg("-out")
1710 .arg(exe.join("RustAnalyzerGroup.wxs"))
1711 .arg("-t")
1712 .arg(etc.join("msi/remove-duplicates.xsl")),
1713 );
1714 }
1715 if built_tools.contains("clippy") {
1716 builder.run(
1717 Command::new(&heat)
1718 .current_dir(&exe)
1719 .arg("dir")
1720 .arg("clippy")
1721 .args(&heat_flags)
1722 .arg("-cg")
1723 .arg("ClippyGroup")
1724 .arg("-dr")
1725 .arg("Clippy")
1726 .arg("-var")
1727 .arg("var.ClippyDir")
1728 .arg("-out")
1729 .arg(exe.join("ClippyGroup.wxs"))
1730 .arg("-t")
1731 .arg(etc.join("msi/remove-duplicates.xsl")),
1732 );
1733 }
1734 if built_tools.contains("rust-demangler") {
1735 builder.run(
1736 Command::new(&heat)
1737 .current_dir(&exe)
1738 .arg("dir")
1739 .arg("rust-demangler")
1740 .args(&heat_flags)
1741 .arg("-cg")
1742 .arg("RustDemanglerGroup")
1743 .arg("-dr")
1744 .arg("RustDemangler")
1745 .arg("-var")
1746 .arg("var.RustDemanglerDir")
1747 .arg("-out")
1748 .arg(exe.join("RustDemanglerGroup.wxs"))
1749 .arg("-t")
1750 .arg(etc.join("msi/remove-duplicates.xsl")),
1751 );
1752 }
1753 if built_tools.contains("miri") {
1754 builder.run(
1755 Command::new(&heat)
1756 .current_dir(&exe)
1757 .arg("dir")
1758 .arg("miri")
1759 .args(&heat_flags)
1760 .arg("-cg")
1761 .arg("MiriGroup")
1762 .arg("-dr")
1763 .arg("Miri")
1764 .arg("-var")
1765 .arg("var.MiriDir")
1766 .arg("-out")
1767 .arg(exe.join("MiriGroup.wxs"))
1768 .arg("-t")
1769 .arg(etc.join("msi/remove-duplicates.xsl")),
1770 );
1771 }
1772 builder.run(
1773 Command::new(&heat)
1774 .current_dir(&exe)
1775 .arg("dir")
1776 .arg("rust-analysis")
1777 .args(&heat_flags)
1778 .arg("-cg")
1779 .arg("AnalysisGroup")
1780 .arg("-dr")
1781 .arg("Analysis")
1782 .arg("-var")
1783 .arg("var.AnalysisDir")
1784 .arg("-out")
1785 .arg(exe.join("AnalysisGroup.wxs"))
1786 .arg("-t")
1787 .arg(etc.join("msi/remove-duplicates.xsl")),
1788 );
1789 if target.ends_with("windows-gnu") {
1790 builder.run(
1791 Command::new(&heat)
1792 .current_dir(&exe)
1793 .arg("dir")
1794 .arg("rust-mingw")
1795 .args(&heat_flags)
1796 .arg("-cg")
1797 .arg("GccGroup")
1798 .arg("-dr")
1799 .arg("Gcc")
1800 .arg("-var")
1801 .arg("var.GccDir")
1802 .arg("-out")
1803 .arg(exe.join("GccGroup.wxs")),
1804 );
1805 }
1806
1807 let candle = |input: &Path| {
1808 let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
1809 let arch = if target.contains("x86_64") { "x64" } else { "x86" };
1810 let mut cmd = Command::new(&candle);
1811 cmd.current_dir(&exe)
1812 .arg("-nologo")
1813 .arg("-dRustcDir=rustc")
1814 .arg("-dCargoDir=cargo")
1815 .arg("-dStdDir=rust-std")
1816 .arg("-dAnalysisDir=rust-analysis")
1817 .arg("-arch")
1818 .arg(&arch)
1819 .arg("-out")
1820 .arg(&output)
1821 .arg(&input);
1822 add_env(builder, &mut cmd, target);
1823
1824 if built_tools.contains("clippy") {
1825 cmd.arg("-dClippyDir=clippy");
1826 }
1827 if built_tools.contains("rust-docs") {
1828 cmd.arg("-dDocsDir=rust-docs");
1829 }
1830 if built_tools.contains("rust-demangler") {
1831 cmd.arg("-dRustDemanglerDir=rust-demangler");
1832 }
1833 if built_tools.contains("rust-analyzer") {
1834 cmd.arg("-dRustAnalyzerDir=rust-analyzer");
1835 }
1836 if built_tools.contains("miri") {
1837 cmd.arg("-dMiriDir=miri");
1838 }
1839 if target.ends_with("windows-gnu") {
1840 cmd.arg("-dGccDir=rust-mingw");
1841 }
1842 builder.run(&mut cmd);
1843 };
1844 candle(&xform(&etc.join("msi/rust.wxs")));
1845 candle(&etc.join("msi/ui.wxs"));
1846 candle(&etc.join("msi/rustwelcomedlg.wxs"));
1847 candle("RustcGroup.wxs".as_ref());
1848 if built_tools.contains("rust-docs") {
1849 candle("DocsGroup.wxs".as_ref());
1850 }
1851 candle("CargoGroup.wxs".as_ref());
1852 candle("StdGroup.wxs".as_ref());
1853 if built_tools.contains("clippy") {
1854 candle("ClippyGroup.wxs".as_ref());
1855 }
1856 if built_tools.contains("miri") {
1857 candle("MiriGroup.wxs".as_ref());
1858 }
1859 if built_tools.contains("rust-demangler") {
1860 candle("RustDemanglerGroup.wxs".as_ref());
1861 }
1862 if built_tools.contains("rust-analyzer") {
1863 candle("RustAnalyzerGroup.wxs".as_ref());
1864 }
1865 candle("AnalysisGroup.wxs".as_ref());
1866
1867 if target.ends_with("windows-gnu") {
1868 candle("GccGroup.wxs".as_ref());
1869 }
1870
1871 builder.create(&exe.join("LICENSE.rtf"), &rtf);
1872 builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1873 builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1874
1875 builder.info(&format!("building `msi` installer with {:?}", light));
1876 let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
1877 let mut cmd = Command::new(&light);
1878 cmd.arg("-nologo")
1879 .arg("-ext")
1880 .arg("WixUIExtension")
1881 .arg("-ext")
1882 .arg("WixUtilExtension")
1883 .arg("-out")
1884 .arg(exe.join(&filename))
1885 .arg("rust.wixobj")
1886 .arg("ui.wixobj")
1887 .arg("rustwelcomedlg.wixobj")
1888 .arg("RustcGroup.wixobj")
1889 .arg("CargoGroup.wixobj")
1890 .arg("StdGroup.wixobj")
1891 .arg("AnalysisGroup.wixobj")
1892 .current_dir(&exe);
1893
1894 if built_tools.contains("clippy") {
1895 cmd.arg("ClippyGroup.wixobj");
1896 }
1897 if built_tools.contains("miri") {
1898 cmd.arg("MiriGroup.wixobj");
1899 }
1900 if built_tools.contains("rust-analyzer") {
1901 cmd.arg("RustAnalyzerGroup.wixobj");
1902 }
1903 if built_tools.contains("rust-demangler") {
1904 cmd.arg("RustDemanglerGroup.wixobj");
1905 }
1906 if built_tools.contains("rust-docs") {
1907 cmd.arg("DocsGroup.wixobj");
1908 }
1909
1910 if target.ends_with("windows-gnu") {
1911 cmd.arg("GccGroup.wixobj");
1912 }
1913 // ICE57 wrongly complains about the shortcuts
1914 cmd.arg("-sice:ICE57");
1915
1916 let _time = timeit(builder);
1917 builder.run(&mut cmd);
1918
1919 if !builder.config.dry_run() {
1920 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
1921 }
1922 }
1923 }
1924 }
1925
add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection)1926 fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
1927 let mut parts = builder.version.split('.');
1928 cmd.env("CFG_RELEASE_INFO", builder.rust_version())
1929 .env("CFG_RELEASE_NUM", &builder.version)
1930 .env("CFG_RELEASE", builder.rust_release())
1931 .env("CFG_VER_MAJOR", parts.next().unwrap())
1932 .env("CFG_VER_MINOR", parts.next().unwrap())
1933 .env("CFG_VER_PATCH", parts.next().unwrap())
1934 .env("CFG_VER_BUILD", "0") // just needed to build
1935 .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
1936 .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
1937 .env("CFG_BUILD", target.triple)
1938 .env("CFG_CHANNEL", &builder.config.channel);
1939
1940 if target.contains("windows-gnullvm") {
1941 cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
1942 } else if target.contains("windows-gnu") {
1943 cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
1944 } else {
1945 cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
1946 }
1947 }
1948
install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path)1949 fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
1950 if builder.config.dry_run() {
1951 return;
1952 }
1953
1954 // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file.
1955 // This is not done in-place so that the built LLVM files are not "tainted" with BOLT.
1956 // We perform the instrumentation/optimization here, on the fly, just before they are being
1957 // packaged into some destination directory.
1958 let postprocessed = if builder.config.llvm_bolt_profile_generate {
1959 builder.ensure(BoltInstrument::new(source.to_path_buf()))
1960 } else if let Some(path) = &builder.config.llvm_bolt_profile_use {
1961 builder.ensure(BoltOptimize::new(source.to_path_buf(), path.into()))
1962 } else {
1963 source.to_path_buf()
1964 };
1965
1966 builder.install(&postprocessed, destination, 0o644);
1967 }
1968
1969 /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
1970 ///
1971 /// Returns whether the files were actually copied.
maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool1972 fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
1973 if let Some(config) = builder.config.target_config.get(&target) {
1974 if config.llvm_config.is_some() && !builder.config.llvm_from_ci {
1975 // If the LLVM was externally provided, then we don't currently copy
1976 // artifacts into the sysroot. This is not necessarily the right
1977 // choice (in particular, it will require the LLVM dylib to be in
1978 // the linker's load path at runtime), but the common use case for
1979 // external LLVMs is distribution provided LLVMs, and in that case
1980 // they're usually in the standard search path (e.g., /usr/lib) and
1981 // copying them here is going to cause problems as we may end up
1982 // with the wrong files and isn't what distributions want.
1983 //
1984 // This behavior may be revisited in the future though.
1985 //
1986 // If the LLVM is coming from ourselves (just from CI) though, we
1987 // still want to install it, as it otherwise won't be available.
1988 return false;
1989 }
1990 }
1991
1992 // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
1993 // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely
1994 // clear why this is the case, though. llvm-config will emit the versioned
1995 // paths and we don't want those in the sysroot (as we're expecting
1996 // unversioned paths).
1997 if target.contains("apple-darwin") && builder.llvm_link_shared() {
1998 let src_libdir = builder.llvm_out(target).join("lib");
1999 let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2000 if llvm_dylib_path.exists() {
2001 builder.install(&llvm_dylib_path, dst_libdir, 0o644);
2002 }
2003 !builder.config.dry_run()
2004 } else if let Ok(llvm::LlvmResult { llvm_config, .. }) =
2005 llvm::prebuilt_llvm_config(builder, target)
2006 {
2007 let mut cmd = Command::new(llvm_config);
2008 cmd.arg("--libfiles");
2009 builder.verbose(&format!("running {:?}", cmd));
2010 let files = if builder.config.dry_run() { "".into() } else { output(&mut cmd) };
2011 let build_llvm_out = &builder.llvm_out(builder.config.build);
2012 let target_llvm_out = &builder.llvm_out(target);
2013 for file in files.trim_end().split(' ') {
2014 // If we're not using a custom LLVM, make sure we package for the target.
2015 let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
2016 target_llvm_out.join(relative_path)
2017 } else {
2018 PathBuf::from(file)
2019 };
2020 install_llvm_file(builder, &file, dst_libdir);
2021 }
2022 !builder.config.dry_run()
2023 } else {
2024 false
2025 }
2026 }
2027
2028 /// Maybe add libLLVM.so to the target lib-dir for linking.
maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path)2029 pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2030 let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib");
2031 // We do not need to copy LLVM files into the sysroot if it is not
2032 // dynamically linked; it is already included into librustc_llvm
2033 // statically.
2034 if builder.llvm_link_shared() {
2035 maybe_install_llvm(builder, target, &dst_libdir);
2036 }
2037 }
2038
2039 /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path)2040 pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2041 let dst_libdir =
2042 sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
2043 // We do not need to copy LLVM files into the sysroot if it is not
2044 // dynamically linked; it is already included into librustc_llvm
2045 // statically.
2046 if builder.llvm_link_shared() {
2047 maybe_install_llvm(builder, target, &dst_libdir);
2048 }
2049 }
2050
2051 /// Creates an output path to a BOLT-manipulated artifact for the given `file`.
2052 /// The hash of the file is used to make sure that we don't mix BOLT artifacts amongst different
2053 /// files with the same name.
2054 ///
2055 /// We need to keep the file-name the same though, to make sure that copying the manipulated file
2056 /// to a directory will not change the final file path.
create_bolt_output_path(builder: &Builder<'_>, file: &Path, hash: &str) -> PathBuf2057 fn create_bolt_output_path(builder: &Builder<'_>, file: &Path, hash: &str) -> PathBuf {
2058 let directory = builder.out.join("bolt").join(hash);
2059 t!(fs::create_dir_all(&directory));
2060 directory.join(file.file_name().unwrap())
2061 }
2062
2063 /// Instrument the provided file with BOLT.
2064 /// Returns a path to the instrumented artifact.
2065 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2066 pub struct BoltInstrument {
2067 file: PathBuf,
2068 hash: String,
2069 }
2070
2071 impl BoltInstrument {
new(file: PathBuf) -> Self2072 fn new(file: PathBuf) -> Self {
2073 let mut hasher = sha2::Sha256::new();
2074 hasher.update(t!(fs::read(&file)));
2075 let hash = hex::encode(hasher.finalize().as_slice());
2076
2077 Self { file, hash }
2078 }
2079 }
2080
2081 impl Step for BoltInstrument {
2082 type Output = PathBuf;
2083
2084 const ONLY_HOSTS: bool = false;
2085 const DEFAULT: bool = false;
2086
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>2087 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2088 run.never()
2089 }
2090
run(self, builder: &Builder<'_>) -> PathBuf2091 fn run(self, builder: &Builder<'_>) -> PathBuf {
2092 if builder.build.config.dry_run() {
2093 return self.file.clone();
2094 }
2095
2096 if builder.build.config.llvm_from_ci {
2097 println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
2098 }
2099
2100 println!("Instrumenting {} with BOLT", self.file.display());
2101
2102 let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
2103 if !output_path.is_file() {
2104 instrument_with_bolt(&self.file, &output_path);
2105 }
2106 output_path
2107 }
2108 }
2109
2110 /// Optimize the provided file with BOLT.
2111 /// Returns a path to the optimized artifact.
2112 ///
2113 /// The hash is stored in the step to make sure that we don't optimize the same file
2114 /// twice (even under different file paths).
2115 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2116 pub struct BoltOptimize {
2117 file: PathBuf,
2118 profile: PathBuf,
2119 hash: String,
2120 }
2121
2122 impl BoltOptimize {
new(file: PathBuf, profile: PathBuf) -> Self2123 fn new(file: PathBuf, profile: PathBuf) -> Self {
2124 let mut hasher = sha2::Sha256::new();
2125 hasher.update(t!(fs::read(&file)));
2126 hasher.update(t!(fs::read(&profile)));
2127 let hash = hex::encode(hasher.finalize().as_slice());
2128
2129 Self { file, profile, hash }
2130 }
2131 }
2132
2133 impl Step for BoltOptimize {
2134 type Output = PathBuf;
2135
2136 const ONLY_HOSTS: bool = false;
2137 const DEFAULT: bool = false;
2138
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>2139 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2140 run.never()
2141 }
2142
run(self, builder: &Builder<'_>) -> PathBuf2143 fn run(self, builder: &Builder<'_>) -> PathBuf {
2144 if builder.build.config.dry_run() {
2145 return self.file.clone();
2146 }
2147
2148 if builder.build.config.llvm_from_ci {
2149 println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
2150 }
2151
2152 println!("Optimizing {} with BOLT", self.file.display());
2153
2154 let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
2155 if !output_path.is_file() {
2156 optimize_with_bolt(&self.file, &self.profile, &output_path);
2157 }
2158 output_path
2159 }
2160 }
2161
2162 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2163 pub struct LlvmTools {
2164 pub target: TargetSelection,
2165 }
2166
2167 impl Step for LlvmTools {
2168 type Output = Option<GeneratedTarball>;
2169 const ONLY_HOSTS: bool = true;
2170 const DEFAULT: bool = true;
2171
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>2172 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2173 let default = should_build_extended_tool(&run.builder, "llvm-tools");
2174 // FIXME: allow using the names of the tools themselves?
2175 run.alias("llvm-tools").default_condition(default)
2176 }
2177
make_run(run: RunConfig<'_>)2178 fn make_run(run: RunConfig<'_>) {
2179 run.builder.ensure(LlvmTools { target: run.target });
2180 }
2181
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>2182 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2183 let target = self.target;
2184
2185 /* run only if llvm-config isn't used */
2186 if let Some(config) = builder.config.target_config.get(&target) {
2187 if let Some(ref _s) = config.llvm_config {
2188 builder.info(&format!("Skipping LlvmTools ({}): external LLVM", target));
2189 return None;
2190 }
2191 }
2192
2193 builder.ensure(crate::llvm::Llvm { target });
2194
2195 let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
2196 tarball.set_overlay(OverlayKind::LLVM);
2197 tarball.is_preview(true);
2198
2199 // Prepare the image directory
2200 let src_bindir = builder.llvm_out(target).join("bin");
2201 let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
2202 for tool in LLVM_TOOLS {
2203 let exe = src_bindir.join(exe(tool, target));
2204 tarball.add_file(&exe, &dst_bindir, 0o755);
2205 }
2206
2207 // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2208 // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2209 // of `rustc-dev` to support the inherited `-lLLVM` when using the
2210 // compiler libraries.
2211 maybe_install_llvm_target(builder, target, tarball.image_dir());
2212
2213 Some(tarball.generate())
2214 }
2215 }
2216
2217 // Tarball intended for internal consumption to ease rustc/std development.
2218 //
2219 // Should not be considered stable by end users.
2220 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2221 pub struct RustDev {
2222 pub target: TargetSelection,
2223 }
2224
2225 impl Step for RustDev {
2226 type Output = Option<GeneratedTarball>;
2227 const DEFAULT: bool = true;
2228 const ONLY_HOSTS: bool = true;
2229
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>2230 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2231 run.alias("rust-dev")
2232 }
2233
make_run(run: RunConfig<'_>)2234 fn make_run(run: RunConfig<'_>) {
2235 run.builder.ensure(RustDev { target: run.target });
2236 }
2237
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>2238 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2239 let target = self.target;
2240
2241 /* run only if llvm-config isn't used */
2242 if let Some(config) = builder.config.target_config.get(&target) {
2243 if let Some(ref _s) = config.llvm_config {
2244 builder.info(&format!("Skipping RustDev ({}): external LLVM", target));
2245 return None;
2246 }
2247 }
2248
2249 let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
2250 tarball.set_overlay(OverlayKind::LLVM);
2251
2252 builder.ensure(crate::llvm::Llvm { target });
2253
2254 // We want to package `lld` to use it with `download-ci-llvm`.
2255 builder.ensure(crate::llvm::Lld { target });
2256
2257 let src_bindir = builder.llvm_out(target).join("bin");
2258 // If updating this list, you likely want to change
2259 // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
2260 // will not pick up the extra file until LLVM gets bumped.
2261 for bin in &[
2262 "llvm-config",
2263 "llvm-ar",
2264 "llvm-objdump",
2265 "llvm-profdata",
2266 "llvm-bcanalyzer",
2267 "llvm-cov",
2268 "llvm-dwp",
2269 "llvm-nm",
2270 "llvm-dwarfdump",
2271 "llvm-dis",
2272 "llvm-tblgen",
2273 ] {
2274 tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
2275 }
2276
2277 // We don't build LLD on some platforms, so only add it if it exists
2278 let lld_path = builder.lld_out(target).join("bin").join(exe("lld", target));
2279 if lld_path.exists() {
2280 tarball.add_file(lld_path, "bin", 0o755);
2281 }
2282
2283 tarball.add_file(&builder.llvm_filecheck(target), "bin", 0o755);
2284
2285 // Copy the include directory as well; needed mostly to build
2286 // librustc_llvm properly (e.g., llvm-config.h is in here). But also
2287 // just broadly useful to be able to link against the bundled LLVM.
2288 tarball.add_dir(&builder.llvm_out(target).join("include"), "include");
2289
2290 // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2291 // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2292 // of `rustc-dev` to support the inherited `-lLLVM` when using the
2293 // compiler libraries.
2294 let dst_libdir = tarball.image_dir().join("lib");
2295 maybe_install_llvm(builder, target, &dst_libdir);
2296 let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
2297 t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
2298
2299 Some(tarball.generate())
2300 }
2301 }
2302
2303 // Tarball intended for internal consumption to ease rustc/std development.
2304 //
2305 // Should not be considered stable by end users.
2306 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2307 pub struct Bootstrap {
2308 pub target: TargetSelection,
2309 }
2310
2311 impl Step for Bootstrap {
2312 type Output = Option<GeneratedTarball>;
2313 const DEFAULT: bool = false;
2314 const ONLY_HOSTS: bool = true;
2315
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>2316 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2317 run.alias("bootstrap")
2318 }
2319
make_run(run: RunConfig<'_>)2320 fn make_run(run: RunConfig<'_>) {
2321 run.builder.ensure(Bootstrap { target: run.target });
2322 }
2323
run(self, builder: &Builder<'_>) -> Option<GeneratedTarball>2324 fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2325 let target = self.target;
2326
2327 let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2328
2329 let bootstrap_outdir = &builder.bootstrap_out;
2330 for file in &["bootstrap", "rustc", "rustdoc", "sccache-plus-cl"] {
2331 tarball.add_file(bootstrap_outdir.join(exe(file, target)), "bootstrap/bin", 0o755);
2332 }
2333
2334 Some(tarball.generate())
2335 }
2336 }
2337
2338 /// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
2339 /// release process to avoid cloning the monorepo and building stuff.
2340 ///
2341 /// Should not be considered stable by end users.
2342 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2343 pub struct BuildManifest {
2344 pub target: TargetSelection,
2345 }
2346
2347 impl Step for BuildManifest {
2348 type Output = GeneratedTarball;
2349 const DEFAULT: bool = false;
2350 const ONLY_HOSTS: bool = true;
2351
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>2352 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2353 run.alias("build-manifest")
2354 }
2355
make_run(run: RunConfig<'_>)2356 fn make_run(run: RunConfig<'_>) {
2357 run.builder.ensure(BuildManifest { target: run.target });
2358 }
2359
run(self, builder: &Builder<'_>) -> GeneratedTarball2360 fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
2361 let build_manifest = builder.tool_exe(Tool::BuildManifest);
2362
2363 let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
2364 tarball.add_file(&build_manifest, "bin", 0o755);
2365 tarball.generate()
2366 }
2367 }
2368
2369 /// Tarball containing artifacts necessary to reproduce the build of rustc.
2370 ///
2371 /// Currently this is the PGO profile data.
2372 ///
2373 /// Should not be considered stable by end users.
2374 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2375 pub struct ReproducibleArtifacts {
2376 pub target: TargetSelection,
2377 }
2378
2379 impl Step for ReproducibleArtifacts {
2380 type Output = Option<GeneratedTarball>;
2381 const DEFAULT: bool = true;
2382 const ONLY_HOSTS: bool = true;
2383
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>2384 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2385 run.alias("reproducible-artifacts")
2386 }
2387
make_run(run: RunConfig<'_>)2388 fn make_run(run: RunConfig<'_>) {
2389 run.builder.ensure(ReproducibleArtifacts { target: run.target });
2390 }
2391
run(self, builder: &Builder<'_>) -> Self::Output2392 fn run(self, builder: &Builder<'_>) -> Self::Output {
2393 let mut added_anything = false;
2394 let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
2395 if let Some(path) = builder.config.rust_profile_use.as_ref() {
2396 tarball.add_file(path, ".", 0o644);
2397 added_anything = true;
2398 }
2399 if let Some(path) = builder.config.llvm_profile_use.as_ref() {
2400 tarball.add_file(path, ".", 0o644);
2401 added_anything = true;
2402 }
2403 if let Some(path) = builder.config.llvm_bolt_profile_use.as_ref() {
2404 tarball.add_file(path, ".", 0o644);
2405 added_anything = true;
2406 }
2407 if added_anything { Some(tarball.generate()) } else { None }
2408 }
2409 }
2410