bootstrap/core/build_steps/
dist.rs

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