Skip to main content

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#[cfg(feature = "tracing")]
20use tracing::instrument;
21
22use crate::core::build_steps::compile::{
23    get_codegen_backend_file, libgccjit_path_relative_to_cg_dir, normalize_codegen_backend_name,
24};
25use crate::core::build_steps::doc::DocumentationFormat;
26use crate::core::build_steps::gcc::GccTargetPair;
27use crate::core::build_steps::tool::{
28    self, RustcPrivateCompilers, ToolTargetBuildMode, get_tool_target_compiler,
29};
30use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor};
31use crate::core::build_steps::{compile, llvm};
32use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata};
33use crate::core::config::{GccCiMode, TargetSelection};
34use crate::utils::build_stamp::{self, BuildStamp};
35use crate::utils::channel::{self, Info};
36use crate::utils::exec::{BootstrapCommand, command};
37use crate::utils::helpers::{
38    exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit,
39};
40use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
41use crate::{CodegenBackendKind, Compiler, DependencyType, FileType, LLVM_TOOLS, Mode, trace};
42
43pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
44    format!("{}-{}", component, builder.rust_package_vers())
45}
46
47pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf {
48    builder.out.join("dist")
49}
50
51pub fn tmpdir(builder: &Builder<'_>) -> PathBuf {
52    builder.out.join("tmp/dist")
53}
54
55fn should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool {
56    if !builder.config.extended {
57        return false;
58    }
59    builder.config.tools.as_ref().is_none_or(|tools| tools.contains(tool))
60}
61
62#[derive(Debug, Clone, Hash, PartialEq, Eq)]
63pub struct Docs {
64    pub host: TargetSelection,
65}
66
67impl Step for Docs {
68    type Output = Option<GeneratedTarball>;
69
70    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
71        run.alias("rust-docs")
72    }
73
74    fn is_default_step(builder: &Builder<'_>) -> bool {
75        builder.config.docs
76    }
77
78    fn make_run(run: RunConfig<'_>) {
79        run.builder.ensure(Docs { host: run.target });
80    }
81
82    /// Builds the `rust-docs` installer component.
83    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
84        let host = self.host;
85        // FIXME: explicitly enumerate the steps that should be executed here, and gather their
86        // documentation, rather than running all default steps and then read their output
87        // from a shared directory.
88        builder.run_default_doc_steps();
89
90        let dest = "share/doc/rust/html";
91
92        let mut tarball = Tarball::new(builder, "rust-docs", &host.triple);
93        tarball.set_product_name("Rust Documentation");
94        tarball.add_bulk_dir(builder.doc_out(host), dest);
95        tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, FileType::Regular);
96        tarball.add_file(builder.src.join("src/doc/sitemap.txt"), dest, FileType::Regular);
97        Some(tarball.generate())
98    }
99
100    fn metadata(&self) -> Option<StepMetadata> {
101        Some(StepMetadata::dist("docs", self.host))
102    }
103}
104
105/// Builds the `rust-docs-json` installer component.
106/// It contains the documentation of the standard library in JSON format.
107#[derive(Debug, Clone, Hash, PartialEq, Eq)]
108pub struct JsonDocs {
109    build_compiler: Compiler,
110    target: TargetSelection,
111}
112
113impl Step for JsonDocs {
114    type Output = Option<GeneratedTarball>;
115
116    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
117        run.alias("rust-docs-json")
118    }
119
120    fn is_default_step(builder: &Builder<'_>) -> bool {
121        builder.config.docs
122    }
123
124    fn make_run(run: RunConfig<'_>) {
125        run.builder.ensure(JsonDocs {
126            build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
127            target: run.target,
128        });
129    }
130
131    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
132        let target = self.target;
133        let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
134            self.build_compiler,
135            target,
136            DocumentationFormat::Json,
137        ));
138
139        let dest = "share/doc/rust/json";
140
141        let mut tarball = Tarball::new(builder, "rust-docs-json", &target.triple);
142        tarball.set_product_name("Rust Documentation In JSON Format");
143        tarball.is_preview(true);
144        tarball.add_bulk_dir(directory, dest);
145        Some(tarball.generate())
146    }
147
148    fn metadata(&self) -> Option<StepMetadata> {
149        Some(StepMetadata::dist("json-docs", self.target).built_by(self.build_compiler))
150    }
151}
152
153/// Builds the `rustc-docs` installer component.
154/// Apart from the documentation of the `rustc_*` crates, it also includes the documentation of
155/// various in-tree helper tools (bootstrap, build_helper, tidy),
156/// and also rustc_private tools like rustdoc, clippy, miri or rustfmt.
157///
158/// It is currently hosted at <https://doc.rust-lang.org/nightly/nightly-rustc>.
159#[derive(Debug, Clone, Hash, PartialEq, Eq)]
160pub struct RustcDocs {
161    target: TargetSelection,
162}
163
164impl Step for RustcDocs {
165    type Output = GeneratedTarball;
166    const IS_HOST: bool = true;
167
168    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
169        run.alias("rustc-docs")
170    }
171
172    fn is_default_step(builder: &Builder<'_>) -> bool {
173        builder.config.compiler_docs
174    }
175
176    fn make_run(run: RunConfig<'_>) {
177        run.builder.ensure(RustcDocs { target: run.target });
178    }
179
180    fn run(self, builder: &Builder<'_>) -> Self::Output {
181        let target = self.target;
182        builder.run_default_doc_steps();
183
184        let mut tarball = Tarball::new(builder, "rustc-docs", &target.triple);
185        tarball.set_product_name("Rustc Documentation");
186        tarball.add_bulk_dir(builder.compiler_doc_out(target), "share/doc/rust/html/rustc-docs");
187        tarball.generate()
188    }
189}
190
191fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
192    let mut found = Vec::with_capacity(files.len());
193
194    for file in files {
195        let file_path = path.iter().map(|dir| dir.join(file)).find(|p| p.exists());
196
197        if let Some(file_path) = file_path {
198            found.push(file_path);
199        } else {
200            panic!("Could not find '{file}' in {path:?}");
201        }
202    }
203
204    found
205}
206
207fn make_win_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_>) {
208    if builder.config.dry_run() {
209        return;
210    }
211
212    let (bin_path, lib_path) = get_cc_search_dirs(target, builder);
213
214    let compiler = if target == "i686-pc-windows-gnu" {
215        "i686-w64-mingw32-gcc.exe"
216    } else if target == "x86_64-pc-windows-gnu" {
217        "x86_64-w64-mingw32-gcc.exe"
218    } else {
219        "gcc.exe"
220    };
221    let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
222
223    // Libraries necessary to link the windows-gnu toolchains.
224    // System libraries will be preferred if they are available (see #67429).
225    let target_libs = [
226        //MinGW libs
227        "libgcc.a",
228        "libgcc_eh.a",
229        "libgcc_s.a",
230        "libm.a",
231        "libmingw32.a",
232        "libmingwex.a",
233        "libstdc++.a",
234        "libiconv.a",
235        "libmoldname.a",
236        "libpthread.a",
237        // Windows import libs
238        // This *should* contain only the set of libraries necessary to link the standard library,
239        // however we've had problems with people accidentally depending on extra libs being here,
240        // so we can't easily remove entries.
241        "libadvapi32.a",
242        "libbcrypt.a",
243        "libcomctl32.a",
244        "libcomdlg32.a",
245        "libcredui.a",
246        "libcrypt32.a",
247        "libdbghelp.a",
248        "libgdi32.a",
249        "libimagehlp.a",
250        "libiphlpapi.a",
251        "libkernel32.a",
252        "libmsimg32.a",
253        "libmsvcrt.a",
254        "libntdll.a",
255        "libodbc32.a",
256        "libole32.a",
257        "liboleaut32.a",
258        "libopengl32.a",
259        "libpsapi.a",
260        "librpcrt4.a",
261        "libsecur32.a",
262        "libsetupapi.a",
263        "libshell32.a",
264        "libsynchronization.a",
265        "libuser32.a",
266        "libuserenv.a",
267        "libuuid.a",
268        "libwinhttp.a",
269        "libwinmm.a",
270        "libwinspool.a",
271        "libws2_32.a",
272        "libwsock32.a",
273    ];
274
275    //Find mingw artifacts we want to bundle
276    let target_tools = find_files(&target_tools, &bin_path);
277    let target_libs = find_files(&target_libs, &lib_path);
278
279    //Copy platform tools to platform-specific bin directory
280    let plat_target_bin_self_contained_dir =
281        plat_root.join("lib/rustlib").join(target).join("bin/self-contained");
282    fs::create_dir_all(&plat_target_bin_self_contained_dir)
283        .expect("creating plat_target_bin_self_contained_dir failed");
284    for src in target_tools {
285        builder.copy_link_to_folder(&src, &plat_target_bin_self_contained_dir);
286    }
287
288    // Warn windows-gnu users that the bundled GCC cannot compile C files
289    builder.create(
290        &plat_target_bin_self_contained_dir.join("GCC-WARNING.txt"),
291        "gcc.exe contained in this folder cannot be used for compiling C files - it is only \
292         used as a linker. In order to be able to compile projects containing C code use \
293         the GCC provided by MinGW or Cygwin.",
294    );
295
296    //Copy platform libs to platform-specific lib directory
297    let plat_target_lib_self_contained_dir =
298        plat_root.join("lib/rustlib").join(target).join("lib/self-contained");
299    fs::create_dir_all(&plat_target_lib_self_contained_dir)
300        .expect("creating plat_target_lib_self_contained_dir failed");
301    for src in target_libs {
302        builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir);
303    }
304}
305
306fn make_win_llvm_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_>) {
307    if builder.config.dry_run() {
308        return;
309    }
310
311    let (_, lib_path) = get_cc_search_dirs(target, builder);
312
313    // Libraries necessary to link the windows-gnullvm toolchains.
314    // System libraries will be preferred if they are available (see #67429).
315    let target_libs = [
316        // MinGW libs
317        "libunwind.a",
318        "libunwind.dll.a",
319        "libmingw32.a",
320        "libmingwex.a",
321        "libmsvcrt.a",
322        // Windows import libs, remove them once std transitions to raw-dylib
323        "libkernel32.a",
324        "libuser32.a",
325        "libntdll.a",
326        "libuserenv.a",
327        "libws2_32.a",
328        "libdbghelp.a",
329    ];
330
331    //Find mingw artifacts we want to bundle
332    let target_libs = find_files(&target_libs, &lib_path);
333
334    //Copy platform libs to platform-specific lib directory
335    let plat_target_lib_self_contained_dir =
336        plat_root.join("lib/rustlib").join(target).join("lib/self-contained");
337    fs::create_dir_all(&plat_target_lib_self_contained_dir)
338        .expect("creating plat_target_lib_self_contained_dir failed");
339    for src in target_libs {
340        builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir);
341    }
342}
343
344fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder<'_>) {
345    if builder.config.dry_run() {
346        return;
347    }
348
349    let (bin_path, _) = get_cc_search_dirs(target, builder);
350
351    let mut rustc_dlls = vec![];
352    // windows-gnu and windows-gnullvm require different runtime libs
353    if target.is_windows_gnu() {
354        rustc_dlls.push("libwinpthread-1.dll");
355        if target.starts_with("i686-") {
356            rustc_dlls.push("libgcc_s_dw2-1.dll");
357        } else {
358            rustc_dlls.push("libgcc_s_seh-1.dll");
359        }
360    } else if target.is_windows_gnullvm() {
361        rustc_dlls.push("libunwind.dll");
362    } else {
363        panic!("Vendoring of runtime DLLs for `{target}` is not supported`");
364    }
365    let rustc_dlls = find_files(&rustc_dlls, &bin_path);
366
367    // Copy runtime dlls next to rustc.exe
368    let rust_bin_dir = rust_root.join("bin/");
369    fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed");
370    for src in &rustc_dlls {
371        builder.copy_link_to_folder(src, &rust_bin_dir);
372    }
373
374    if builder.config.lld_enabled {
375        // rust-lld.exe also needs runtime dlls
376        let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin");
377        fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed");
378        for src in &rustc_dlls {
379            builder.copy_link_to_folder(src, &rust_target_bin_dir);
380        }
381    }
382}
383
384fn get_cc_search_dirs(
385    target: TargetSelection,
386    builder: &Builder<'_>,
387) -> (Vec<PathBuf>, Vec<PathBuf>) {
388    //Ask gcc where it keeps its stuff
389    let mut cmd = command(builder.cc(target));
390    cmd.arg("-print-search-dirs");
391    let gcc_out = cmd.run_capture_stdout(builder).stdout();
392
393    let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
394    let mut lib_path = Vec::new();
395
396    for line in gcc_out.lines() {
397        let idx = line.find(':').unwrap();
398        let key = &line[..idx];
399        let trim_chars: &[_] = &[' ', '='];
400        let value = env::split_paths(line[(idx + 1)..].trim_start_matches(trim_chars));
401
402        if key == "programs" {
403            bin_path.extend(value);
404        } else if key == "libraries" {
405            lib_path.extend(value);
406        }
407    }
408    (bin_path, lib_path)
409}
410
411/// Builds the `rust-mingw` installer component.
412///
413/// This contains all the bits and pieces to run the MinGW Windows targets
414/// without any extra installed software (e.g., we bundle gcc, libraries, etc.).
415#[derive(Debug, Clone, Hash, PartialEq, Eq)]
416pub struct Mingw {
417    target: TargetSelection,
418}
419
420impl Step for Mingw {
421    type Output = Option<GeneratedTarball>;
422
423    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
424        run.alias("rust-mingw")
425    }
426
427    fn is_default_step(_builder: &Builder<'_>) -> bool {
428        true
429    }
430
431    fn make_run(run: RunConfig<'_>) {
432        run.builder.ensure(Mingw { target: run.target });
433    }
434
435    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
436        let target = self.target;
437        if !target.contains("pc-windows-gnu") || !builder.config.dist_include_mingw_linker {
438            return None;
439        }
440
441        let mut tarball = Tarball::new(builder, "rust-mingw", &target.triple);
442        tarball.set_product_name("Rust MinGW");
443
444        if target.ends_with("pc-windows-gnu") {
445            make_win_dist(tarball.image_dir(), target, builder);
446        } else if target.ends_with("pc-windows-gnullvm") {
447            make_win_llvm_dist(tarball.image_dir(), target, builder);
448        } else {
449            unreachable!();
450        }
451
452        Some(tarball.generate())
453    }
454
455    fn metadata(&self) -> Option<StepMetadata> {
456        Some(StepMetadata::dist("mingw", self.target))
457    }
458}
459
460/// Creates the `rustc` installer component.
461///
462/// This includes:
463/// - The compiler and LLVM.
464/// - Debugger scripts.
465/// - Various helper tools, e.g. LLD or Rust Analyzer proc-macro server (if enabled).
466/// - The licenses of all code used by the compiler.
467///
468/// It does not include any standard library.
469#[derive(Debug, Clone, Hash, PartialEq, Eq)]
470pub struct Rustc {
471    /// This is the compiler that we will *ship* in this dist step.
472    pub target_compiler: Compiler,
473}
474
475impl Step for Rustc {
476    type Output = GeneratedTarball;
477    const IS_HOST: bool = true;
478
479    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
480        run.alias("rustc")
481    }
482
483    fn is_default_step(_builder: &Builder<'_>) -> bool {
484        true
485    }
486
487    fn make_run(run: RunConfig<'_>) {
488        run.builder.ensure(Rustc {
489            target_compiler: run.builder.compiler(run.builder.top_stage, run.target),
490        });
491    }
492
493    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
494        let target_compiler = self.target_compiler;
495        let target = self.target_compiler.host;
496
497        let tarball = Tarball::new(builder, "rustc", &target.triple);
498
499        // Prepare the rustc "image", what will actually end up getting installed
500        prepare_image(builder, target_compiler, tarball.image_dir());
501
502        // On MinGW we've got a few runtime DLL dependencies that we need to
503        // include.
504        // On 32-bit MinGW we're always including a DLL which needs some extra
505        // licenses to distribute. On 64-bit MinGW we don't actually distribute
506        // anything requiring us to distribute a license, but it's likely the
507        // install will *also* include the rust-mingw package, which also needs
508        // licenses, so to be safe we just include it here in all MinGW packages.
509        if target.contains("pc-windows-gnu") && builder.config.dist_include_mingw_linker {
510            runtime_dll_dist(tarball.image_dir(), target, builder);
511            tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
512        }
513
514        return tarball.generate();
515
516        fn prepare_image(builder: &Builder<'_>, target_compiler: Compiler, image: &Path) {
517            let target = target_compiler.host;
518            let src = builder.sysroot(target_compiler);
519
520            // Copy rustc binary
521            t!(fs::create_dir_all(image.join("bin")));
522            builder.cp_link_r(&src.join("bin"), &image.join("bin"));
523
524            // If enabled, copy rustdoc binary
525            if builder
526                .config
527                .tools
528                .as_ref()
529                .is_none_or(|tools| tools.iter().any(|tool| tool == "rustdoc"))
530            {
531                let rustdoc = builder.rustdoc_for_compiler(target_compiler);
532                builder.install(&rustdoc, &image.join("bin"), FileType::Executable);
533            }
534
535            let compilers = RustcPrivateCompilers::from_target_compiler(builder, target_compiler);
536
537            if let Some(ra_proc_macro_srv) = builder.ensure_if_default(
538                tool::RustAnalyzerProcMacroSrv::from_compilers(compilers),
539                builder.kind,
540            ) {
541                let dst = image.join("libexec");
542                builder.install(&ra_proc_macro_srv.tool_path, &dst, FileType::Executable);
543            }
544
545            let libdir_relative = builder.libdir_relative(target_compiler);
546
547            // Copy runtime DLLs needed by the compiler
548            if libdir_relative.to_str() != Some("bin") {
549                let libdir = builder.rustc_libdir(target_compiler);
550                for entry in builder.read_dir(&libdir) {
551                    // A safeguard that we will not ship libgccjit.so from the libdir, in case the
552                    // GCC codegen backend is enabled by default.
553                    // Long-term we should probably split the config options for:
554                    // - Include cg_gcc in the rustc sysroot by default
555                    // - Run dist of a specific codegen backend in `x dist` by default
556                    if is_dylib(&entry.path())
557                        && !entry
558                            .path()
559                            .file_name()
560                            .and_then(|n| n.to_str())
561                            .map(|n| n.contains("libgccjit"))
562                            .unwrap_or(false)
563                    {
564                        // Don't use custom libdir here because ^lib/ will be resolved again
565                        // with installer
566                        builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary);
567                    }
568                }
569            }
570
571            // Copy libLLVM.so to the lib dir as well, if needed. While not
572            // technically needed by rustc itself it's needed by lots of other
573            // components like the llvm tools and LLD. LLD is included below and
574            // tools/LLDB come later, so let's just throw it in the rustc
575            // component for now.
576            maybe_install_llvm_runtime(builder, target, image);
577
578            let dst_dir = image.join("lib/rustlib").join(target).join("bin");
579            t!(fs::create_dir_all(&dst_dir));
580
581            // Copy over lld if it's there
582            if builder.config.lld_enabled {
583                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
584                let rust_lld = exe("rust-lld", target_compiler.host);
585                builder.copy_link(
586                    &src_dir.join(&rust_lld),
587                    &dst_dir.join(&rust_lld),
588                    FileType::Executable,
589                );
590                let self_contained_lld_src_dir = src_dir.join("gcc-ld");
591                let self_contained_lld_dst_dir = dst_dir.join("gcc-ld");
592                t!(fs::create_dir(&self_contained_lld_dst_dir));
593                for name in crate::LLD_FILE_NAMES {
594                    let exe_name = exe(name, target_compiler.host);
595                    builder.copy_link(
596                        &self_contained_lld_src_dir.join(&exe_name),
597                        &self_contained_lld_dst_dir.join(&exe_name),
598                        FileType::Executable,
599                    );
600                }
601            }
602
603            if builder.config.llvm_enabled(target_compiler.host)
604                && builder.config.llvm_tools_enabled
605            {
606                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
607                let llvm_objcopy = exe("llvm-objcopy", target_compiler.host);
608                let rust_objcopy = exe("rust-objcopy", target_compiler.host);
609                builder.copy_link(
610                    &src_dir.join(&llvm_objcopy),
611                    &dst_dir.join(&rust_objcopy),
612                    FileType::Executable,
613                );
614            }
615
616            if builder.tool_enabled("wasm-component-ld") {
617                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
618                let ld = exe("wasm-component-ld", target_compiler.host);
619                builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld), FileType::Executable);
620            }
621
622            // Man pages
623            t!(fs::create_dir_all(image.join("share/man/man1")));
624            let man_src = builder.src.join("src/doc/man");
625            let man_dst = image.join("share/man/man1");
626
627            // don't use our `bootstrap::{copy_internal, cp_r}`, because those try
628            // to hardlink, and we don't want to edit the source templates
629            for file_entry in builder.read_dir(&man_src) {
630                let page_src = file_entry.path();
631                let page_dst = man_dst.join(file_entry.file_name());
632                let src_text = t!(std::fs::read_to_string(&page_src));
633                let new_text = src_text.replace("<INSERT VERSION HERE>", &builder.version);
634                t!(std::fs::write(&page_dst, &new_text));
635                t!(fs::copy(&page_src, &page_dst));
636            }
637
638            // Debugger scripts
639            builder.ensure(DebuggerScripts { sysroot: image.to_owned(), target });
640
641            generate_target_spec_json_schema(builder, image);
642
643            // HTML copyright files
644            let file_list = builder.ensure(super::run::GenerateCopyright);
645            for file in file_list {
646                builder.install(&file, &image.join("share/doc/rust"), FileType::Regular);
647            }
648
649            // README
650            builder.install(
651                &builder.src.join("README.md"),
652                &image.join("share/doc/rust"),
653                FileType::Regular,
654            );
655
656            // The REUSE-managed license files
657            let license = |path: &Path| {
658                builder.install(path, &image.join("share/doc/rust/licenses"), FileType::Regular);
659            };
660            for entry in t!(std::fs::read_dir(builder.src.join("LICENSES"))).flatten() {
661                license(&entry.path());
662            }
663        }
664    }
665
666    fn metadata(&self) -> Option<StepMetadata> {
667        Some(StepMetadata::dist("rustc", self.target_compiler.host))
668    }
669}
670
671fn generate_target_spec_json_schema(builder: &Builder<'_>, sysroot: &Path) {
672    // Since we run rustc in bootstrap, we need to ensure that we use the host compiler.
673    // We do this by using the stage 1 compiler, which is always compiled for the host,
674    // even in a cross build.
675    let stage1_host = builder.compiler(1, builder.host_target);
676    let mut rustc = builder.rustc_cmd(stage1_host).fail_fast();
677    rustc
678        .env("RUSTC_BOOTSTRAP", "1")
679        .args(["--print=target-spec-json-schema", "-Zunstable-options"]);
680    let schema = rustc.run_capture(builder).stdout();
681
682    let schema_dir = tmpdir(builder);
683    t!(fs::create_dir_all(&schema_dir));
684    let schema_file = schema_dir.join("target-spec-json-schema.json");
685    t!(std::fs::write(&schema_file, schema));
686
687    let dst = sysroot.join("etc");
688    t!(fs::create_dir_all(&dst));
689
690    builder.install(&schema_file, &dst, FileType::Regular);
691}
692
693/// Copies debugger scripts for `target` into the given compiler `sysroot`.
694#[derive(Debug, Clone, Hash, PartialEq, Eq)]
695pub struct DebuggerScripts {
696    /// Sysroot of a compiler into which will the debugger scripts be copied to.
697    pub sysroot: PathBuf,
698    pub target: TargetSelection,
699}
700
701impl Step for DebuggerScripts {
702    type Output = ();
703
704    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
705        run.never()
706    }
707
708    fn run(self, builder: &Builder<'_>) {
709        let target = self.target;
710        let sysroot = self.sysroot;
711        let dst = sysroot.join("lib/rustlib/etc");
712        t!(fs::create_dir_all(&dst));
713        let cp_debugger_script = |file: &str| {
714            builder.install(&builder.src.join("src/etc/").join(file), &dst, FileType::Regular);
715        };
716        if target.contains("windows-msvc") {
717            // windbg debugger scripts
718            builder.install(
719                &builder.src.join("src/etc/rust-windbg.cmd"),
720                &sysroot.join("bin"),
721                FileType::Script,
722            );
723
724            cp_debugger_script("natvis/intrinsic.natvis");
725            cp_debugger_script("natvis/liballoc.natvis");
726            cp_debugger_script("natvis/libcore.natvis");
727            cp_debugger_script("natvis/libstd.natvis");
728        }
729
730        cp_debugger_script("rust_types.py");
731
732        // gdb debugger scripts
733        builder.install(
734            &builder.src.join("src/etc/rust-gdb"),
735            &sysroot.join("bin"),
736            FileType::Script,
737        );
738        builder.install(
739            &builder.src.join("src/etc/rust-gdbgui"),
740            &sysroot.join("bin"),
741            FileType::Script,
742        );
743
744        cp_debugger_script("gdb_load_rust_pretty_printers.py");
745        cp_debugger_script("gdb_lookup.py");
746        cp_debugger_script("gdb_providers.py");
747
748        // lldb debugger scripts
749        builder.install(
750            &builder.src.join("src/etc/rust-lldb"),
751            &sysroot.join("bin"),
752            FileType::Script,
753        );
754
755        cp_debugger_script("lldb_lookup.py");
756        cp_debugger_script("lldb_providers.py");
757        cp_debugger_script("lldb_commands")
758    }
759}
760
761fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
762    // The only true set of target libraries came from the build triple, so
763    // let's reduce redundant work by only producing archives from that host.
764    if !builder.config.is_host_target(compiler.host) {
765        builder.info("\tskipping, not a build host");
766        true
767    } else {
768        false
769    }
770}
771
772/// Check that all objects in rlibs for UEFI targets are COFF. This
773/// ensures that the C compiler isn't producing ELF objects, which would
774/// not link correctly with the COFF objects.
775fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &BuildStamp) {
776    if !target.ends_with("-uefi") {
777        return;
778    }
779
780    for (path, _) in builder.read_stamp_file(stamp) {
781        if path.extension() != Some(OsStr::new("rlib")) {
782            continue;
783        }
784
785        let data = t!(fs::read(&path));
786        let data = data.as_slice();
787        let archive = t!(ArchiveFile::parse(data));
788        for member in archive.members() {
789            let member = t!(member);
790            let member_data = t!(member.data(data));
791
792            let is_coff = match object::File::parse(member_data) {
793                Ok(member_file) => member_file.format() == BinaryFormat::Coff,
794                Err(_) => false,
795            };
796
797            if !is_coff {
798                let member_name = String::from_utf8_lossy(member.name());
799                panic!("member {} in {} is not COFF", member_name, path.display());
800            }
801        }
802    }
803}
804
805/// Copy stamped files into an image's `target/lib` directory.
806fn copy_target_libs(
807    builder: &Builder<'_>,
808    target: TargetSelection,
809    image: &Path,
810    stamp: &BuildStamp,
811) {
812    let dst = image.join("lib/rustlib").join(target).join("lib");
813    let self_contained_dst = dst.join("self-contained");
814    t!(fs::create_dir_all(&dst));
815    t!(fs::create_dir_all(&self_contained_dst));
816    for (path, dependency_type) in builder.read_stamp_file(stamp) {
817        if dependency_type == DependencyType::TargetSelfContained {
818            builder.copy_link(
819                &path,
820                &self_contained_dst.join(path.file_name().unwrap()),
821                FileType::NativeLibrary,
822            );
823        } else if dependency_type == DependencyType::Target || builder.config.is_host_target(target)
824        {
825            builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary);
826        }
827    }
828}
829
830/// Builds the standard library (`rust-std`) dist component for a given `target`.
831/// This includes the standard library dynamic library file (e.g. .so/.dll), along with stdlib
832/// .rlibs.
833///
834/// Note that due to uplifting, we actually ship the stage 1 library
835/// (built using the stage1 compiler) even with a stage 2 dist, unless `full-bootstrap` is enabled.
836#[derive(Debug, Clone, Hash, PartialEq, Eq)]
837pub struct Std {
838    /// Compiler that will build the standard library.
839    pub build_compiler: Compiler,
840    pub target: TargetSelection,
841}
842
843impl Std {
844    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
845        Std { build_compiler: builder.compiler_for_std(builder.top_stage), target }
846    }
847}
848
849impl Step for Std {
850    type Output = Option<GeneratedTarball>;
851
852    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
853        run.alias("rust-std")
854    }
855
856    fn is_default_step(_builder: &Builder<'_>) -> bool {
857        true
858    }
859
860    fn make_run(run: RunConfig<'_>) {
861        run.builder.ensure(Std::new(run.builder, run.target));
862    }
863
864    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
865        let build_compiler = self.build_compiler;
866        let target = self.target;
867
868        if skip_host_target_lib(builder, build_compiler) {
869            return None;
870        }
871
872        // It's possible that std was uplifted and thus built with a different build compiler
873        // So we need to read the stamp that was actually generated when std was built
874        let stamp =
875            builder.std(build_compiler, target).expect("Standard library has to be built for dist");
876
877        let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
878        tarball.include_target_in_component_name(true);
879
880        verify_uefi_rlib_format(builder, target, &stamp);
881        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
882
883        Some(tarball.generate())
884    }
885
886    fn metadata(&self) -> Option<StepMetadata> {
887        Some(StepMetadata::dist("std", self.target).built_by(self.build_compiler))
888    }
889}
890
891/// Tarball containing the compiler that gets downloaded and used by
892/// `rust.download-rustc`.
893///
894/// (Don't confuse this with [`RustDev`], without the `c`!)
895#[derive(Debug, Clone, Hash, PartialEq, Eq)]
896pub struct RustcDev {
897    /// The compiler that will build rustc which will be shipped in this component.
898    pub build_compiler: Compiler,
899    pub target: TargetSelection,
900}
901
902impl RustcDev {
903    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
904        Self {
905            // We currently always ship a stage 2 rustc-dev component, so we build it with the
906            // stage 1 compiler. This might change in the future.
907            // The precise stage used here is important, so we hard-code it.
908            build_compiler: builder.compiler(1, builder.config.host_target),
909            target,
910        }
911    }
912}
913
914impl Step for RustcDev {
915    type Output = Option<GeneratedTarball>;
916    const IS_HOST: bool = true;
917
918    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
919        run.alias("rustc-dev")
920    }
921
922    fn is_default_step(_builder: &Builder<'_>) -> bool {
923        true
924    }
925
926    fn make_run(run: RunConfig<'_>) {
927        run.builder.ensure(RustcDev::new(run.builder, run.target));
928    }
929
930    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
931        let build_compiler = self.build_compiler;
932        let target = self.target;
933        if skip_host_target_lib(builder, build_compiler) {
934            return None;
935        }
936
937        // Build the compiler that we will ship
938        builder.ensure(compile::Rustc::new(build_compiler, target));
939
940        let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
941
942        let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);
943        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
944
945        let src_files = &["Cargo.lock"];
946        // This is the reduced set of paths which will become the rustc-dev component
947        // (essentially the compiler crates and all of their path dependencies).
948        copy_src_dirs(
949            builder,
950            &builder.src,
951            // The compiler has a path dependency on proc_macro, so make sure to include it.
952            &["compiler", "library/proc_macro"],
953            &[],
954            &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
955        );
956        for file in src_files {
957            tarball.add_file(
958                builder.src.join(file),
959                "lib/rustlib/rustc-src/rust",
960                FileType::Regular,
961            );
962        }
963
964        Some(tarball.generate())
965    }
966
967    fn metadata(&self) -> Option<StepMetadata> {
968        Some(StepMetadata::dist("rustc-dev", self.target).built_by(self.build_compiler))
969    }
970}
971
972/// The `rust-analysis` component used to create a tarball of save-analysis metadata.
973///
974/// This component has been deprecated and its contents now only include a warning about
975/// its non-availability.
976#[derive(Debug, Clone, Hash, PartialEq, Eq)]
977pub struct Analysis {
978    build_compiler: Compiler,
979    target: TargetSelection,
980}
981
982impl Step for Analysis {
983    type Output = Option<GeneratedTarball>;
984
985    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
986        run.alias("rust-analysis")
987    }
988
989    fn is_default_step(builder: &Builder<'_>) -> bool {
990        should_build_extended_tool(builder, "analysis")
991    }
992
993    fn make_run(run: RunConfig<'_>) {
994        // The step just produces a deprecation notice, so we just hardcode stage 1
995        run.builder.ensure(Analysis {
996            build_compiler: run.builder.compiler(1, run.builder.config.host_target),
997            target: run.target,
998        });
999    }
1000
1001    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1002        let compiler = self.build_compiler;
1003        let target = self.target;
1004        if skip_host_target_lib(builder, compiler) {
1005            return None;
1006        }
1007
1008        let src = builder
1009            .stage_out(compiler, Mode::Std)
1010            .join(target)
1011            .join(builder.cargo_dir(Mode::Std))
1012            .join("deps")
1013            .join("save-analysis");
1014
1015        // Write a file indicating that this component has been removed.
1016        t!(std::fs::create_dir_all(&src));
1017        let mut removed = src.clone();
1018        removed.push("removed.json");
1019        let mut f = t!(std::fs::File::create(removed));
1020        t!(write!(f, r#"{{ "warning": "The `rust-analysis` component has been removed." }}"#));
1021
1022        let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple);
1023        tarball.include_target_in_component_name(true);
1024        tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple));
1025        Some(tarball.generate())
1026    }
1027
1028    fn metadata(&self) -> Option<StepMetadata> {
1029        Some(StepMetadata::dist("analysis", self.target).built_by(self.build_compiler))
1030    }
1031}
1032
1033/// Use the `builder` to make a filtered copy of `base`/X for X in (`src_dirs` - `exclude_dirs`) to
1034/// `dst_dir`.
1035fn copy_src_dirs(
1036    builder: &Builder<'_>,
1037    base: &Path,
1038    src_dirs: &[&str],
1039    exclude_dirs: &[&str],
1040    dst_dir: &Path,
1041) {
1042    // The src directories should be relative to `base`, we depend on them not being absolute
1043    // paths below.
1044    for src_dir in src_dirs {
1045        assert!(Path::new(src_dir).is_relative());
1046    }
1047
1048    // Iterating, filtering and copying a large number of directories can be quite slow.
1049    // Avoid doing it in dry run (and thus also tests).
1050    if builder.config.dry_run() {
1051        return;
1052    }
1053
1054    fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
1055        // The paths are relative, e.g. `llvm-project/...`.
1056        let spath = match path.to_str() {
1057            Some(path) => path,
1058            None => return false,
1059        };
1060        if spath.ends_with('~') || spath.ends_with(".pyc") {
1061            return false;
1062        }
1063        // Normalize slashes
1064        let spath = spath.replace("\\", "/");
1065
1066        static LLVM_PROJECTS: &[&str] = &[
1067            "llvm-project/clang",
1068            "llvm-project/libunwind",
1069            "llvm-project/lld",
1070            "llvm-project/lldb",
1071            "llvm-project/llvm",
1072            "llvm-project/compiler-rt",
1073            "llvm-project/cmake",
1074            "llvm-project/runtimes",
1075            "llvm-project/third-party",
1076        ];
1077        if spath.starts_with("llvm-project") && spath != "llvm-project" {
1078            if !LLVM_PROJECTS.iter().any(|path| spath.starts_with(path)) {
1079                return false;
1080            }
1081
1082            // Keep siphash third-party dependency
1083            if spath.starts_with("llvm-project/third-party")
1084                && spath != "llvm-project/third-party"
1085                && !spath.starts_with("llvm-project/third-party/siphash")
1086            {
1087                return false;
1088            }
1089
1090            if spath.starts_with("llvm-project/llvm/test")
1091                && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
1092            {
1093                return false;
1094            }
1095        }
1096
1097        // Cargo tests use some files like `.gitignore` that we would otherwise exclude.
1098        if spath.starts_with("tools/cargo/tests") {
1099            return true;
1100        }
1101
1102        if !exclude_dirs.is_empty() {
1103            let full_path = Path::new(dir).join(path);
1104            if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
1105                return false;
1106            }
1107        }
1108
1109        static EXCLUDES: &[&str] = &[
1110            "CVS",
1111            "RCS",
1112            "SCCS",
1113            ".git",
1114            ".gitignore",
1115            ".gitmodules",
1116            ".gitattributes",
1117            ".cvsignore",
1118            ".svn",
1119            ".arch-ids",
1120            "{arch}",
1121            "=RELEASE-ID",
1122            "=meta-update",
1123            "=update",
1124            ".bzr",
1125            ".bzrignore",
1126            ".bzrtags",
1127            ".hg",
1128            ".hgignore",
1129            ".hgrags",
1130            "_darcs",
1131        ];
1132
1133        // We want to check if any component of `path` doesn't contain the strings in `EXCLUDES`.
1134        // However, since we traverse directories top-down in `Builder::cp_link_filtered`,
1135        // it is enough to always check only the last component:
1136        // - If the path is a file, we will iterate to it and then check it's filename
1137        // - If the path is a dir, if it's dir name contains an excluded string, we will not even
1138        //   recurse into it.
1139        let last_component = path.iter().next_back().map(|s| s.to_str().unwrap()).unwrap();
1140        !EXCLUDES.contains(&last_component)
1141    }
1142
1143    // Copy the directories using our filter
1144    for item in src_dirs {
1145        let dst = &dst_dir.join(item);
1146        t!(fs::create_dir_all(dst));
1147        builder
1148            .cp_link_filtered(&base.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
1149    }
1150}
1151
1152#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1153pub struct Src;
1154
1155impl Step for Src {
1156    /// The output path of the src installer tarball
1157    type Output = GeneratedTarball;
1158    const IS_HOST: bool = true;
1159
1160    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1161        run.alias("rust-src")
1162    }
1163
1164    fn is_default_step(_builder: &Builder<'_>) -> bool {
1165        true
1166    }
1167
1168    fn make_run(run: RunConfig<'_>) {
1169        run.builder.ensure(Src);
1170    }
1171
1172    /// Creates the `rust-src` installer component
1173    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1174        if !builder.config.dry_run() {
1175            builder.require_submodule("src/llvm-project", None);
1176        }
1177
1178        let tarball = Tarball::new_targetless(builder, "rust-src");
1179
1180        // A lot of tools expect the rust-src component to be entirely in this directory, so if you
1181        // change that (e.g. by adding another directory `lib/rustlib/src/foo` or
1182        // `lib/rustlib/src/rust/foo`), you will need to go around hunting for implicit assumptions
1183        // and fix them...
1184        //
1185        // NOTE: if you update the paths here, you also should update the "virtual" path
1186        // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
1187        let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
1188
1189        // This is the reduced set of paths which will become the rust-src component
1190        // (essentially libstd and all of its path dependencies).
1191        copy_src_dirs(
1192            builder,
1193            &builder.src,
1194            &["library", "src/llvm-project/libunwind"],
1195            &[
1196                // not needed and contains symlinks which rustup currently
1197                // chokes on when unpacking.
1198                "library/backtrace/crates",
1199                // these are 30MB combined and aren't necessary for building
1200                // the standard library.
1201                "library/stdarch/Cargo.toml",
1202                "library/stdarch/crates/stdarch-verify",
1203                "library/stdarch/crates/intrinsic-test",
1204            ],
1205            &dst_src,
1206        );
1207
1208        tarball.generate()
1209    }
1210
1211    fn metadata(&self) -> Option<StepMetadata> {
1212        Some(StepMetadata::dist("src", TargetSelection::default()))
1213    }
1214}
1215
1216/// Tarball for people who want to build rustc and other components from the source.
1217/// Does not contain GPL code, which is separated into `PlainSourceTarballGpl`
1218/// for licensing reasons.
1219#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1220pub struct PlainSourceTarball;
1221
1222impl Step for PlainSourceTarball {
1223    /// Produces the location of the tarball generated
1224    type Output = GeneratedTarball;
1225    const IS_HOST: bool = true;
1226
1227    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1228        run.alias("rustc-src")
1229    }
1230
1231    fn is_default_step(builder: &Builder<'_>) -> bool {
1232        builder.config.rust_dist_src
1233    }
1234
1235    fn make_run(run: RunConfig<'_>) {
1236        run.builder.ensure(PlainSourceTarball);
1237    }
1238
1239    /// Creates the plain source tarball
1240    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1241        let tarball = prepare_source_tarball(
1242            builder,
1243            "src",
1244            &[
1245                // We don't currently use the GCC source code for building any official components,
1246                // it is very big, and has unclear licensing implications due to being GPL licensed.
1247                // We thus exclude it from the source tarball from now.
1248                "src/gcc",
1249            ],
1250        );
1251
1252        let plain_dst_src = tarball.image_dir();
1253        // We keep something in src/gcc because it is a registered submodule,
1254        // and if it misses completely it can cause issues elsewhere
1255        // (see https://github.com/rust-lang/rust/issues/137332).
1256        // We can also let others know why is the source code missing.
1257        if !builder.config.dry_run() {
1258            builder.create_dir(&plain_dst_src.join("src/gcc"));
1259            t!(std::fs::write(
1260                plain_dst_src.join("src/gcc/notice.txt"),
1261                "The GCC source code is not included due to unclear licensing implications\n"
1262            ));
1263        }
1264        tarball.bare()
1265    }
1266}
1267
1268/// Tarball with *all* source code for source builds, including GPL-licensed code.
1269#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1270pub struct PlainSourceTarballGpl;
1271
1272impl Step for PlainSourceTarballGpl {
1273    /// Produces the location of the tarball generated
1274    type Output = GeneratedTarball;
1275    const IS_HOST: bool = true;
1276
1277    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1278        run.alias("rustc-src-gpl")
1279    }
1280
1281    fn is_default_step(builder: &Builder<'_>) -> bool {
1282        builder.config.rust_dist_src
1283    }
1284
1285    fn make_run(run: RunConfig<'_>) {
1286        run.builder.ensure(PlainSourceTarballGpl);
1287    }
1288
1289    /// Creates the plain source tarball
1290    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1291        let tarball = prepare_source_tarball(builder, "src-gpl", &[]);
1292        tarball.bare()
1293    }
1294}
1295
1296fn prepare_source_tarball<'a>(
1297    builder: &'a Builder<'a>,
1298    name: &str,
1299    exclude_dirs: &[&str],
1300) -> Tarball<'a> {
1301    // NOTE: This is a strange component in a lot of ways. It uses `src` as the target, which
1302    // means neither rustup nor rustup-toolchain-install-master know how to download it.
1303    // It also contains symbolic links, unlike other any other dist tarball.
1304    // It's used for distros building rustc from source in a pre-vendored environment.
1305    let mut tarball = Tarball::new(builder, "rustc", name);
1306    tarball.permit_symlinks(true);
1307    let plain_dst_src = tarball.image_dir();
1308
1309    // This is the set of root paths which will become part of the source package
1310    let src_files = [
1311        // tidy-alphabetical-start
1312        ".gitmodules",
1313        "CONTRIBUTING.md",
1314        "COPYRIGHT",
1315        "Cargo.lock",
1316        "Cargo.toml",
1317        "LICENSE-APACHE",
1318        "LICENSE-MIT",
1319        "README.md",
1320        "RELEASES.md",
1321        "REUSE.toml",
1322        "bootstrap.example.toml",
1323        "configure",
1324        "license-metadata.json",
1325        "package.json",
1326        "x",
1327        "x.ps1",
1328        "x.py",
1329        "yarn.lock",
1330        // tidy-alphabetical-end
1331    ];
1332    let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
1333
1334    copy_src_dirs(builder, &builder.src, &src_dirs, exclude_dirs, plain_dst_src);
1335
1336    // Copy the files normally
1337    for item in &src_files {
1338        builder.copy_link(&builder.src.join(item), &plain_dst_src.join(item), FileType::Regular);
1339    }
1340
1341    // Create the version file
1342    builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1343
1344    // Create the files containing git info, to ensure --version outputs the same.
1345    let write_git_info = |info: Option<&Info>, path: &Path| {
1346        if let Some(info) = info {
1347            t!(std::fs::create_dir_all(path));
1348            channel::write_commit_hash_file(path, &info.sha);
1349            channel::write_commit_info_file(path, info);
1350        }
1351    };
1352    write_git_info(builder.rust_info().info(), plain_dst_src);
1353    write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo"));
1354
1355    if builder.config.dist_vendor {
1356        builder.require_and_update_all_submodules();
1357
1358        // Vendor packages that are required by opt-dist to collect PGO profiles.
1359        let pkgs_for_pgo_training =
1360            build_helper::LLVM_PGO_CRATES.iter().chain(build_helper::RUSTC_PGO_CRATES).map(|pkg| {
1361                let mut manifest_path =
1362                    builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks");
1363                manifest_path.push(pkg);
1364                manifest_path.push("Cargo.toml");
1365                manifest_path
1366            });
1367
1368        // Vendor all Cargo dependencies
1369        let vendor = builder.ensure(Vendor {
1370            sync_args: pkgs_for_pgo_training.collect(),
1371            versioned_dirs: true,
1372            root_dir: plain_dst_src.into(),
1373            output_dir: VENDOR_DIR.into(),
1374        });
1375
1376        let cargo_config_dir = plain_dst_src.join(".cargo");
1377        builder.create_dir(&cargo_config_dir);
1378        builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
1379    }
1380
1381    // Delete extraneous directories
1382    // FIXME: if we're managed by git, we should probably instead ask git if the given path
1383    // is managed by it?
1384    for entry in walkdir::WalkDir::new(tarball.image_dir())
1385        .follow_links(true)
1386        .into_iter()
1387        .filter_map(|e| e.ok())
1388    {
1389        if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__")) {
1390            t!(fs::remove_dir_all(entry.path()));
1391        }
1392    }
1393    tarball
1394}
1395
1396#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1397pub struct Cargo {
1398    pub build_compiler: Compiler,
1399    pub target: TargetSelection,
1400}
1401
1402impl Step for Cargo {
1403    type Output = Option<GeneratedTarball>;
1404    const IS_HOST: bool = true;
1405
1406    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1407        run.alias("cargo")
1408    }
1409
1410    fn is_default_step(builder: &Builder<'_>) -> bool {
1411        should_build_extended_tool(builder, "cargo")
1412    }
1413
1414    fn make_run(run: RunConfig<'_>) {
1415        run.builder.ensure(Cargo {
1416            build_compiler: get_tool_target_compiler(
1417                run.builder,
1418                ToolTargetBuildMode::Build(run.target),
1419            ),
1420            target: run.target,
1421        });
1422    }
1423
1424    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1425        let build_compiler = self.build_compiler;
1426        let target = self.target;
1427
1428        let cargo = builder.ensure(tool::Cargo::from_build_compiler(build_compiler, target));
1429        let src = builder.src.join("src/tools/cargo");
1430        let etc = src.join("src/etc");
1431
1432        // Prepare the image directory
1433        let mut tarball = Tarball::new(builder, "cargo", &target.triple);
1434        tarball.set_overlay(OverlayKind::Cargo);
1435
1436        tarball.add_file(&cargo.tool_path, "bin", FileType::Executable);
1437        tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", FileType::Regular);
1438        tarball.add_renamed_file(
1439            etc.join("cargo.bashcomp.sh"),
1440            "etc/bash_completion.d",
1441            "cargo",
1442            FileType::Regular,
1443        );
1444        tarball.add_dir(etc.join("man"), "share/man/man1");
1445        tarball.add_legal_and_readme_to("share/doc/cargo");
1446
1447        Some(tarball.generate())
1448    }
1449
1450    fn metadata(&self) -> Option<StepMetadata> {
1451        Some(StepMetadata::dist("cargo", self.target).built_by(self.build_compiler))
1452    }
1453}
1454
1455/// Distribute the rust-analyzer component, which is used as a LSP by various IDEs.
1456#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1457pub struct RustAnalyzer {
1458    pub compilers: RustcPrivateCompilers,
1459    pub target: TargetSelection,
1460}
1461
1462impl Step for RustAnalyzer {
1463    type Output = Option<GeneratedTarball>;
1464    const IS_HOST: bool = true;
1465
1466    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1467        run.alias("rust-analyzer")
1468    }
1469
1470    fn is_default_step(builder: &Builder<'_>) -> bool {
1471        should_build_extended_tool(builder, "rust-analyzer")
1472    }
1473
1474    fn make_run(run: RunConfig<'_>) {
1475        run.builder.ensure(RustAnalyzer {
1476            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1477            target: run.target,
1478        });
1479    }
1480
1481    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1482        let target = self.target;
1483        let rust_analyzer = builder.ensure(tool::RustAnalyzer::from_compilers(self.compilers));
1484
1485        let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
1486        tarball.set_overlay(OverlayKind::RustAnalyzer);
1487        tarball.is_preview(true);
1488        tarball.add_file(&rust_analyzer.tool_path, "bin", FileType::Executable);
1489        tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
1490        Some(tarball.generate())
1491    }
1492
1493    fn metadata(&self) -> Option<StepMetadata> {
1494        Some(
1495            StepMetadata::dist("rust-analyzer", self.target)
1496                .built_by(self.compilers.build_compiler()),
1497        )
1498    }
1499}
1500
1501#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1502pub struct Clippy {
1503    pub compilers: RustcPrivateCompilers,
1504    pub target: TargetSelection,
1505}
1506
1507impl Step for Clippy {
1508    type Output = Option<GeneratedTarball>;
1509    const IS_HOST: bool = true;
1510
1511    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1512        run.alias("clippy")
1513    }
1514
1515    fn is_default_step(builder: &Builder<'_>) -> bool {
1516        should_build_extended_tool(builder, "clippy")
1517    }
1518
1519    fn make_run(run: RunConfig<'_>) {
1520        run.builder.ensure(Clippy {
1521            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1522            target: run.target,
1523        });
1524    }
1525
1526    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1527        let target = self.target;
1528
1529        // Prepare the image directory
1530        // We expect clippy to build, because we've exited this step above if tool
1531        // state for clippy isn't testing.
1532        let clippy = builder.ensure(tool::Clippy::from_compilers(self.compilers));
1533        let cargoclippy = builder.ensure(tool::CargoClippy::from_compilers(self.compilers));
1534
1535        let mut tarball = Tarball::new(builder, "clippy", &target.triple);
1536        tarball.set_overlay(OverlayKind::Clippy);
1537        tarball.is_preview(true);
1538        tarball.add_file(&clippy.tool_path, "bin", FileType::Executable);
1539        tarball.add_file(&cargoclippy.tool_path, "bin", FileType::Executable);
1540        tarball.add_legal_and_readme_to("share/doc/clippy");
1541        Some(tarball.generate())
1542    }
1543
1544    fn metadata(&self) -> Option<StepMetadata> {
1545        Some(StepMetadata::dist("clippy", self.target).built_by(self.compilers.build_compiler()))
1546    }
1547}
1548
1549#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1550pub struct Miri {
1551    pub compilers: RustcPrivateCompilers,
1552    pub target: TargetSelection,
1553}
1554
1555impl Step for Miri {
1556    type Output = Option<GeneratedTarball>;
1557    const IS_HOST: bool = true;
1558
1559    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1560        run.alias("miri")
1561    }
1562
1563    fn is_default_step(builder: &Builder<'_>) -> bool {
1564        should_build_extended_tool(builder, "miri")
1565    }
1566
1567    fn make_run(run: RunConfig<'_>) {
1568        run.builder.ensure(Miri {
1569            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1570            target: run.target,
1571        });
1572    }
1573
1574    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1575        // This prevents miri from being built for "dist" or "install"
1576        // on the stable/beta channels. It is a nightly-only tool and should
1577        // not be included.
1578        if !builder.build.unstable_features() {
1579            return None;
1580        }
1581
1582        let miri = builder.ensure(tool::Miri::from_compilers(self.compilers));
1583        let cargomiri = builder.ensure(tool::CargoMiri::from_compilers(self.compilers));
1584
1585        let mut tarball = Tarball::new(builder, "miri", &self.target.triple);
1586        tarball.set_overlay(OverlayKind::Miri);
1587        tarball.is_preview(true);
1588        tarball.add_file(&miri.tool_path, "bin", FileType::Executable);
1589        tarball.add_file(&cargomiri.tool_path, "bin", FileType::Executable);
1590        tarball.add_legal_and_readme_to("share/doc/miri");
1591        Some(tarball.generate())
1592    }
1593
1594    fn metadata(&self) -> Option<StepMetadata> {
1595        Some(StepMetadata::dist("miri", self.target).built_by(self.compilers.build_compiler()))
1596    }
1597}
1598
1599#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1600pub struct CraneliftCodegenBackend {
1601    pub compilers: RustcPrivateCompilers,
1602    pub target: TargetSelection,
1603}
1604
1605impl Step for CraneliftCodegenBackend {
1606    type Output = Option<GeneratedTarball>;
1607    const IS_HOST: bool = true;
1608
1609    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1610        run.alias("rustc_codegen_cranelift")
1611    }
1612
1613    fn is_default_step(builder: &Builder<'_>) -> bool {
1614        // We only want to build the cranelift backend in `x dist` if the backend was enabled
1615        // in rust.codegen-backends.
1616        // Sadly, we don't have access to the actual target for which we're disting clif here..
1617        // So we just use the host target.
1618        builder
1619            .config
1620            .enabled_codegen_backends(builder.host_target)
1621            .contains(&CodegenBackendKind::Cranelift)
1622    }
1623
1624    fn make_run(run: RunConfig<'_>) {
1625        run.builder.ensure(CraneliftCodegenBackend {
1626            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1627            target: run.target,
1628        });
1629    }
1630
1631    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1632        // This prevents rustc_codegen_cranelift from being built for "dist"
1633        // or "install" on the stable/beta channels. It is not yet stable and
1634        // should not be included.
1635        if !builder.build.unstable_features() {
1636            return None;
1637        }
1638
1639        let target = self.target;
1640        if !target_supports_cranelift_backend(target) {
1641            builder.info("target not supported by rustc_codegen_cranelift. skipping");
1642            return None;
1643        }
1644
1645        let mut tarball = Tarball::new(builder, "rustc-codegen-cranelift", &target.triple);
1646        tarball.set_overlay(OverlayKind::RustcCodegenCranelift);
1647        tarball.is_preview(true);
1648        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_cranelift");
1649
1650        let compilers = self.compilers;
1651        let stamp = builder.ensure(compile::CraneliftCodegenBackend { compilers });
1652
1653        if builder.config.dry_run() {
1654            return None;
1655        }
1656
1657        add_codegen_backend_to_tarball(builder, &tarball, compilers.target_compiler(), &stamp);
1658
1659        Some(tarball.generate())
1660    }
1661
1662    fn metadata(&self) -> Option<StepMetadata> {
1663        Some(
1664            StepMetadata::dist("rustc_codegen_cranelift", self.target)
1665                .built_by(self.compilers.build_compiler()),
1666        )
1667    }
1668}
1669
1670/// Builds a dist component containing the GCC codegen backend.
1671/// Note that for this backend to work, it must have a set of libgccjit dylibs available
1672/// at runtime.
1673#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1674pub struct GccCodegenBackend {
1675    pub compilers: RustcPrivateCompilers,
1676    pub target: TargetSelection,
1677}
1678
1679impl Step for GccCodegenBackend {
1680    type Output = Option<GeneratedTarball>;
1681    const IS_HOST: bool = true;
1682
1683    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1684        run.alias("rustc_codegen_gcc")
1685    }
1686
1687    fn is_default_step(builder: &Builder<'_>) -> bool {
1688        // We only want to build the gcc backend in `x dist` if the backend was enabled
1689        // in rust.codegen-backends.
1690        // Sadly, we don't have access to the actual target for which we're disting clif here..
1691        // So we just use the host target.
1692        builder
1693            .config
1694            .enabled_codegen_backends(builder.host_target)
1695            .contains(&CodegenBackendKind::Gcc)
1696    }
1697
1698    fn make_run(run: RunConfig<'_>) {
1699        run.builder.ensure(GccCodegenBackend {
1700            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1701            target: run.target,
1702        });
1703    }
1704
1705    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1706        // This prevents rustc_codegen_gcc from being built for "dist"
1707        // or "install" on the stable/beta channels. It is not yet stable and
1708        // should not be included.
1709        if !builder.build.unstable_features() {
1710            return None;
1711        }
1712
1713        let target = self.target;
1714        if target != "x86_64-unknown-linux-gnu" {
1715            builder
1716                .info(&format!("target `{target}` not supported by rustc_codegen_gcc. skipping"));
1717            return None;
1718        }
1719
1720        let mut tarball = Tarball::new(builder, "rustc-codegen-gcc", &target.triple);
1721        tarball.set_overlay(OverlayKind::RustcCodegenGcc);
1722        tarball.is_preview(true);
1723        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_gcc");
1724
1725        let compilers = self.compilers;
1726        let backend = builder.ensure(compile::GccCodegenBackend::for_target(compilers, target));
1727
1728        if builder.config.dry_run() {
1729            return None;
1730        }
1731
1732        add_codegen_backend_to_tarball(
1733            builder,
1734            &tarball,
1735            compilers.target_compiler(),
1736            backend.stamp(),
1737        );
1738
1739        Some(tarball.generate())
1740    }
1741
1742    fn metadata(&self) -> Option<StepMetadata> {
1743        Some(
1744            StepMetadata::dist("rustc_codegen_gcc", self.target)
1745                .built_by(self.compilers.build_compiler()),
1746        )
1747    }
1748}
1749
1750/// Add a codegen backend built for `compiler`, with its artifacts stored in `stamp`, to the given
1751/// `tarball` at the correct place.
1752fn add_codegen_backend_to_tarball(
1753    builder: &Builder<'_>,
1754    tarball: &Tarball<'_>,
1755    compiler: Compiler,
1756    stamp: &BuildStamp,
1757) {
1758    // Get the relative path of where the codegen backend should be stored.
1759    let backends_dst = builder.sysroot_codegen_backends(compiler);
1760    let backends_rel = backends_dst
1761        .strip_prefix(builder.sysroot(compiler))
1762        .unwrap()
1763        .strip_prefix(builder.sysroot_libdir_relative(compiler))
1764        .unwrap();
1765    // Don't use custom libdir here because ^lib/ will be resolved again with installer
1766    let backends_dst = PathBuf::from("lib").join(backends_rel);
1767
1768    let codegen_backend_dylib = get_codegen_backend_file(stamp);
1769    tarball.add_renamed_file(
1770        &codegen_backend_dylib,
1771        &backends_dst,
1772        &normalize_codegen_backend_name(builder, &codegen_backend_dylib),
1773        FileType::NativeLibrary,
1774    );
1775}
1776
1777#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1778pub struct Rustfmt {
1779    pub compilers: RustcPrivateCompilers,
1780    pub target: TargetSelection,
1781}
1782
1783impl Step for Rustfmt {
1784    type Output = Option<GeneratedTarball>;
1785    const IS_HOST: bool = true;
1786
1787    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1788        run.alias("rustfmt")
1789    }
1790
1791    fn is_default_step(builder: &Builder<'_>) -> bool {
1792        should_build_extended_tool(builder, "rustfmt")
1793    }
1794
1795    fn make_run(run: RunConfig<'_>) {
1796        run.builder.ensure(Rustfmt {
1797            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1798            target: run.target,
1799        });
1800    }
1801
1802    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1803        let rustfmt = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
1804        let cargofmt = builder.ensure(tool::Cargofmt::from_compilers(self.compilers));
1805
1806        let mut tarball = Tarball::new(builder, "rustfmt", &self.target.triple);
1807        tarball.set_overlay(OverlayKind::Rustfmt);
1808        tarball.is_preview(true);
1809        tarball.add_file(&rustfmt.tool_path, "bin", FileType::Executable);
1810        tarball.add_file(&cargofmt.tool_path, "bin", FileType::Executable);
1811        tarball.add_legal_and_readme_to("share/doc/rustfmt");
1812        Some(tarball.generate())
1813    }
1814
1815    fn metadata(&self) -> Option<StepMetadata> {
1816        Some(StepMetadata::dist("rustfmt", self.target).built_by(self.compilers.build_compiler()))
1817    }
1818}
1819
1820/// Extended archive that contains the compiler, standard library and a bunch of tools.
1821#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1822pub struct Extended {
1823    build_compiler: Compiler,
1824    target: TargetSelection,
1825}
1826
1827impl Step for Extended {
1828    type Output = ();
1829    const IS_HOST: bool = true;
1830
1831    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1832        run.alias("extended")
1833    }
1834
1835    fn is_default_step(builder: &Builder<'_>) -> bool {
1836        builder.config.extended
1837    }
1838
1839    fn make_run(run: RunConfig<'_>) {
1840        run.builder.ensure(Extended {
1841            build_compiler: run
1842                .builder
1843                .compiler(run.builder.top_stage - 1, run.builder.host_target),
1844            target: run.target,
1845        });
1846    }
1847
1848    /// Creates a combined installer for the specified target in the provided stage.
1849    fn run(self, builder: &Builder<'_>) {
1850        let target = self.target;
1851        builder.info(&format!("Dist extended stage{} ({target})", builder.top_stage));
1852
1853        let mut tarballs = Vec::new();
1854        let mut built_tools = HashSet::new();
1855        macro_rules! add_component {
1856            ($name:expr => $step:expr) => {
1857                if let Some(Some(tarball)) = builder.ensure_if_default($step, Kind::Dist) {
1858                    tarballs.push(tarball);
1859                    built_tools.insert($name);
1860                }
1861            };
1862        }
1863
1864        let rustc_private_compilers =
1865            RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target);
1866        let build_compiler = rustc_private_compilers.build_compiler();
1867        let target_compiler = rustc_private_compilers.target_compiler();
1868
1869        // When rust-std package split from rustc, we needed to ensure that during
1870        // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1871        // the std files during uninstall. To do this ensure that rustc comes
1872        // before rust-std in the list below.
1873        tarballs.push(builder.ensure(Rustc { target_compiler }));
1874        tarballs.push(builder.ensure(Std { build_compiler, target }).expect("missing std"));
1875
1876        if target.is_windows_gnu() || target.is_windows_gnullvm() {
1877            tarballs.push(builder.ensure(Mingw { target }).expect("missing mingw"));
1878        }
1879
1880        add_component!("rust-docs" => Docs { host: target });
1881        // Std stage N is documented with compiler stage N
1882        add_component!("rust-json-docs" => JsonDocs { build_compiler: target_compiler, target });
1883        add_component!("cargo" => Cargo { build_compiler, target });
1884        add_component!("rustfmt" => Rustfmt { compilers: rustc_private_compilers, target });
1885        add_component!("rust-analyzer" => RustAnalyzer { compilers: rustc_private_compilers, target });
1886        add_component!("llvm-components" => LlvmTools { target });
1887        add_component!("clippy" => Clippy { compilers: rustc_private_compilers, target });
1888        add_component!("miri" => Miri { compilers: rustc_private_compilers, target });
1889        add_component!("analysis" => Analysis { build_compiler, target });
1890        add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend {
1891            compilers: rustc_private_compilers,
1892            target
1893        });
1894        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {
1895            build_compiler,
1896            target
1897        });
1898
1899        let etc = builder.src.join("src/etc/installer");
1900
1901        // Avoid producing tarballs during a dry run.
1902        if builder.config.dry_run() {
1903            return;
1904        }
1905
1906        let tarball = Tarball::new(builder, "rust", &target.triple);
1907        let generated = tarball.combine(&tarballs);
1908
1909        let tmp = tmpdir(builder).join("combined-tarball");
1910        let work = generated.work_dir();
1911
1912        let mut license = String::new();
1913        license += &builder.read(&builder.src.join("COPYRIGHT"));
1914        license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1915        license += &builder.read(&builder.src.join("LICENSE-MIT"));
1916        license.push('\n');
1917        license.push('\n');
1918
1919        let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1920        let mut rtf = rtf.to_string();
1921        rtf.push('\n');
1922        for line in license.lines() {
1923            rtf.push_str(line);
1924            rtf.push_str("\\line ");
1925        }
1926        rtf.push('}');
1927
1928        fn filter(contents: &str, marker: &str) -> String {
1929            let start = format!("tool-{marker}-start");
1930            let end = format!("tool-{marker}-end");
1931            let mut lines = Vec::new();
1932            let mut omitted = false;
1933            for line in contents.lines() {
1934                if line.contains(&start) {
1935                    omitted = true;
1936                } else if line.contains(&end) {
1937                    omitted = false;
1938                } else if !omitted {
1939                    lines.push(line);
1940                }
1941            }
1942
1943            lines.join("\n")
1944        }
1945
1946        let xform = |p: &Path| {
1947            let mut contents = t!(fs::read_to_string(p));
1948            for tool in &["miri", "rust-docs"] {
1949                if !built_tools.contains(tool) {
1950                    contents = filter(&contents, tool);
1951                }
1952            }
1953            let ret = tmp.join(p.file_name().unwrap());
1954            t!(fs::write(&ret, &contents));
1955            ret
1956        };
1957
1958        if target.contains("apple-darwin") {
1959            builder.info("building pkg installer");
1960            let pkg = tmp.join("pkg");
1961            let _ = fs::remove_dir_all(&pkg);
1962
1963            let pkgbuild = |component: &str| {
1964                let mut cmd = command("pkgbuild");
1965                cmd.arg("--identifier")
1966                    .arg(format!("org.rust-lang.{component}"))
1967                    .arg("--scripts")
1968                    .arg(pkg.join(component))
1969                    .arg("--nopayload")
1970                    .arg(pkg.join(component).with_extension("pkg"));
1971                cmd.run(builder);
1972            };
1973
1974            let prepare = |name: &str| {
1975                builder.create_dir(&pkg.join(name));
1976                builder.cp_link_r(
1977                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)),
1978                    &pkg.join(name),
1979                );
1980                builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), FileType::Script);
1981                pkgbuild(name);
1982            };
1983            prepare("rustc");
1984            prepare("cargo");
1985            prepare("rust-std");
1986            prepare("rust-analysis");
1987
1988            for tool in &[
1989                "clippy",
1990                "rustfmt",
1991                "rust-analyzer",
1992                "rust-docs",
1993                "miri",
1994                "rustc-codegen-cranelift",
1995            ] {
1996                if built_tools.contains(tool) {
1997                    prepare(tool);
1998                }
1999            }
2000            // create an 'uninstall' package
2001            builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), FileType::Script);
2002            pkgbuild("uninstall");
2003
2004            builder.create_dir(&pkg.join("res"));
2005            builder.create(&pkg.join("res/LICENSE.txt"), &license);
2006            builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), FileType::Regular);
2007            let mut cmd = command("productbuild");
2008            cmd.arg("--distribution")
2009                .arg(xform(&etc.join("pkg/Distribution.xml")))
2010                .arg("--resources")
2011                .arg(pkg.join("res"))
2012                .arg(distdir(builder).join(format!(
2013                    "{}-{}.pkg",
2014                    pkgname(builder, "rust"),
2015                    target.triple
2016                )))
2017                .arg("--package-path")
2018                .arg(&pkg);
2019            let _time = timeit(builder);
2020            cmd.run(builder);
2021        }
2022
2023        if target.is_windows() {
2024            let exe = tmp.join("exe");
2025            let _ = fs::remove_dir_all(&exe);
2026
2027            let prepare = |name: &str| {
2028                builder.create_dir(&exe.join(name));
2029                let dir = if name == "rust-std" || name == "rust-analysis" {
2030                    format!("{}-{}", name, target.triple)
2031                } else if name == "rust-analyzer" {
2032                    "rust-analyzer-preview".to_string()
2033                } else if name == "clippy" {
2034                    "clippy-preview".to_string()
2035                } else if name == "rustfmt" {
2036                    "rustfmt-preview".to_string()
2037                } else if name == "miri" {
2038                    "miri-preview".to_string()
2039                } else if name == "rustc-codegen-cranelift" {
2040                    // FIXME add installer support for cg_clif once it is ready to be distributed on
2041                    // windows.
2042                    unreachable!("cg_clif shouldn't be built for windows");
2043                } else {
2044                    name.to_string()
2045                };
2046                builder.cp_link_r(
2047                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
2048                    &exe.join(name),
2049                );
2050                builder.remove(&exe.join(name).join("manifest.in"));
2051            };
2052            prepare("rustc");
2053            prepare("cargo");
2054            prepare("rust-analysis");
2055            prepare("rust-std");
2056            for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] {
2057                if built_tools.contains(tool) {
2058                    prepare(tool);
2059                }
2060            }
2061            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2062                prepare("rust-mingw");
2063            }
2064
2065            builder.install(&etc.join("gfx/rust-logo.ico"), &exe, FileType::Regular);
2066
2067            // Generate msi installer
2068            let wix_path = env::var_os("WIX")
2069                .expect("`WIX` environment variable must be set for generating MSI installer(s).");
2070            let wix = PathBuf::from(wix_path);
2071            let heat = wix.join("bin/heat.exe");
2072            let candle = wix.join("bin/candle.exe");
2073            let light = wix.join("bin/light.exe");
2074
2075            let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
2076            command(&heat)
2077                .current_dir(&exe)
2078                .arg("dir")
2079                .arg("rustc")
2080                .args(heat_flags)
2081                .arg("-cg")
2082                .arg("RustcGroup")
2083                .arg("-dr")
2084                .arg("Rustc")
2085                .arg("-var")
2086                .arg("var.RustcDir")
2087                .arg("-out")
2088                .arg(exe.join("RustcGroup.wxs"))
2089                .run(builder);
2090            if built_tools.contains("rust-docs") {
2091                command(&heat)
2092                    .current_dir(&exe)
2093                    .arg("dir")
2094                    .arg("rust-docs")
2095                    .args(heat_flags)
2096                    .arg("-cg")
2097                    .arg("DocsGroup")
2098                    .arg("-dr")
2099                    .arg("Docs")
2100                    .arg("-var")
2101                    .arg("var.DocsDir")
2102                    .arg("-out")
2103                    .arg(exe.join("DocsGroup.wxs"))
2104                    .arg("-t")
2105                    .arg(etc.join("msi/squash-components.xsl"))
2106                    .run(builder);
2107            }
2108            command(&heat)
2109                .current_dir(&exe)
2110                .arg("dir")
2111                .arg("cargo")
2112                .args(heat_flags)
2113                .arg("-cg")
2114                .arg("CargoGroup")
2115                .arg("-dr")
2116                .arg("Cargo")
2117                .arg("-var")
2118                .arg("var.CargoDir")
2119                .arg("-out")
2120                .arg(exe.join("CargoGroup.wxs"))
2121                .arg("-t")
2122                .arg(etc.join("msi/remove-duplicates.xsl"))
2123                .run(builder);
2124            command(&heat)
2125                .current_dir(&exe)
2126                .arg("dir")
2127                .arg("rust-std")
2128                .args(heat_flags)
2129                .arg("-cg")
2130                .arg("StdGroup")
2131                .arg("-dr")
2132                .arg("Std")
2133                .arg("-var")
2134                .arg("var.StdDir")
2135                .arg("-out")
2136                .arg(exe.join("StdGroup.wxs"))
2137                .run(builder);
2138            if built_tools.contains("rust-analyzer") {
2139                command(&heat)
2140                    .current_dir(&exe)
2141                    .arg("dir")
2142                    .arg("rust-analyzer")
2143                    .args(heat_flags)
2144                    .arg("-cg")
2145                    .arg("RustAnalyzerGroup")
2146                    .arg("-dr")
2147                    .arg("RustAnalyzer")
2148                    .arg("-var")
2149                    .arg("var.RustAnalyzerDir")
2150                    .arg("-out")
2151                    .arg(exe.join("RustAnalyzerGroup.wxs"))
2152                    .arg("-t")
2153                    .arg(etc.join("msi/remove-duplicates.xsl"))
2154                    .run(builder);
2155            }
2156            if built_tools.contains("clippy") {
2157                command(&heat)
2158                    .current_dir(&exe)
2159                    .arg("dir")
2160                    .arg("clippy")
2161                    .args(heat_flags)
2162                    .arg("-cg")
2163                    .arg("ClippyGroup")
2164                    .arg("-dr")
2165                    .arg("Clippy")
2166                    .arg("-var")
2167                    .arg("var.ClippyDir")
2168                    .arg("-out")
2169                    .arg(exe.join("ClippyGroup.wxs"))
2170                    .arg("-t")
2171                    .arg(etc.join("msi/remove-duplicates.xsl"))
2172                    .run(builder);
2173            }
2174            if built_tools.contains("rustfmt") {
2175                command(&heat)
2176                    .current_dir(&exe)
2177                    .arg("dir")
2178                    .arg("rustfmt")
2179                    .args(heat_flags)
2180                    .arg("-cg")
2181                    .arg("RustFmtGroup")
2182                    .arg("-dr")
2183                    .arg("RustFmt")
2184                    .arg("-var")
2185                    .arg("var.RustFmtDir")
2186                    .arg("-out")
2187                    .arg(exe.join("RustFmtGroup.wxs"))
2188                    .arg("-t")
2189                    .arg(etc.join("msi/remove-duplicates.xsl"))
2190                    .run(builder);
2191            }
2192            if built_tools.contains("miri") {
2193                command(&heat)
2194                    .current_dir(&exe)
2195                    .arg("dir")
2196                    .arg("miri")
2197                    .args(heat_flags)
2198                    .arg("-cg")
2199                    .arg("MiriGroup")
2200                    .arg("-dr")
2201                    .arg("Miri")
2202                    .arg("-var")
2203                    .arg("var.MiriDir")
2204                    .arg("-out")
2205                    .arg(exe.join("MiriGroup.wxs"))
2206                    .arg("-t")
2207                    .arg(etc.join("msi/remove-duplicates.xsl"))
2208                    .run(builder);
2209            }
2210            command(&heat)
2211                .current_dir(&exe)
2212                .arg("dir")
2213                .arg("rust-analysis")
2214                .args(heat_flags)
2215                .arg("-cg")
2216                .arg("AnalysisGroup")
2217                .arg("-dr")
2218                .arg("Analysis")
2219                .arg("-var")
2220                .arg("var.AnalysisDir")
2221                .arg("-out")
2222                .arg(exe.join("AnalysisGroup.wxs"))
2223                .arg("-t")
2224                .arg(etc.join("msi/remove-duplicates.xsl"))
2225                .run(builder);
2226            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2227                command(&heat)
2228                    .current_dir(&exe)
2229                    .arg("dir")
2230                    .arg("rust-mingw")
2231                    .args(heat_flags)
2232                    .arg("-cg")
2233                    .arg("GccGroup")
2234                    .arg("-dr")
2235                    .arg("Gcc")
2236                    .arg("-var")
2237                    .arg("var.GccDir")
2238                    .arg("-out")
2239                    .arg(exe.join("GccGroup.wxs"))
2240                    .run(builder);
2241            }
2242
2243            let candle = |input: &Path| {
2244                let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
2245                let arch = if target.contains("x86_64") { "x64" } else { "x86" };
2246                let mut cmd = command(&candle);
2247                cmd.current_dir(&exe)
2248                    .arg("-nologo")
2249                    .arg("-dRustcDir=rustc")
2250                    .arg("-dCargoDir=cargo")
2251                    .arg("-dStdDir=rust-std")
2252                    .arg("-dAnalysisDir=rust-analysis")
2253                    .arg("-arch")
2254                    .arg(arch)
2255                    .arg("-out")
2256                    .arg(&output)
2257                    .arg(input);
2258                add_env(builder, &mut cmd, target, &built_tools);
2259
2260                if built_tools.contains("clippy") {
2261                    cmd.arg("-dClippyDir=clippy");
2262                }
2263                if built_tools.contains("rustfmt") {
2264                    cmd.arg("-dRustFmtDir=rustfmt");
2265                }
2266                if built_tools.contains("rust-docs") {
2267                    cmd.arg("-dDocsDir=rust-docs");
2268                }
2269                if built_tools.contains("rust-analyzer") {
2270                    cmd.arg("-dRustAnalyzerDir=rust-analyzer");
2271                }
2272                if built_tools.contains("miri") {
2273                    cmd.arg("-dMiriDir=miri");
2274                }
2275                if target.is_windows_gnu() || target.is_windows_gnullvm() {
2276                    cmd.arg("-dGccDir=rust-mingw");
2277                }
2278                cmd.run(builder);
2279            };
2280            candle(&xform(&etc.join("msi/rust.wxs")));
2281            candle(&etc.join("msi/ui.wxs"));
2282            candle(&etc.join("msi/rustwelcomedlg.wxs"));
2283            candle("RustcGroup.wxs".as_ref());
2284            if built_tools.contains("rust-docs") {
2285                candle("DocsGroup.wxs".as_ref());
2286            }
2287            candle("CargoGroup.wxs".as_ref());
2288            candle("StdGroup.wxs".as_ref());
2289            if built_tools.contains("clippy") {
2290                candle("ClippyGroup.wxs".as_ref());
2291            }
2292            if built_tools.contains("rustfmt") {
2293                candle("RustFmtGroup.wxs".as_ref());
2294            }
2295            if built_tools.contains("miri") {
2296                candle("MiriGroup.wxs".as_ref());
2297            }
2298            if built_tools.contains("rust-analyzer") {
2299                candle("RustAnalyzerGroup.wxs".as_ref());
2300            }
2301            candle("AnalysisGroup.wxs".as_ref());
2302
2303            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2304                candle("GccGroup.wxs".as_ref());
2305            }
2306
2307            builder.create(&exe.join("LICENSE.rtf"), &rtf);
2308            builder.install(&etc.join("gfx/banner.bmp"), &exe, FileType::Regular);
2309            builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, FileType::Regular);
2310
2311            builder.info(&format!("building `msi` installer with {light:?}"));
2312            let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
2313            let mut cmd = command(&light);
2314            cmd.arg("-nologo")
2315                .arg("-ext")
2316                .arg("WixUIExtension")
2317                .arg("-ext")
2318                .arg("WixUtilExtension")
2319                .arg("-out")
2320                .arg(exe.join(&filename))
2321                .arg("rust.wixobj")
2322                .arg("ui.wixobj")
2323                .arg("rustwelcomedlg.wixobj")
2324                .arg("RustcGroup.wixobj")
2325                .arg("CargoGroup.wixobj")
2326                .arg("StdGroup.wixobj")
2327                .arg("AnalysisGroup.wixobj")
2328                .current_dir(&exe);
2329
2330            if built_tools.contains("clippy") {
2331                cmd.arg("ClippyGroup.wixobj");
2332            }
2333            if built_tools.contains("rustfmt") {
2334                cmd.arg("RustFmtGroup.wixobj");
2335            }
2336            if built_tools.contains("miri") {
2337                cmd.arg("MiriGroup.wixobj");
2338            }
2339            if built_tools.contains("rust-analyzer") {
2340                cmd.arg("RustAnalyzerGroup.wixobj");
2341            }
2342            if built_tools.contains("rust-docs") {
2343                cmd.arg("DocsGroup.wixobj");
2344            }
2345
2346            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2347                cmd.arg("GccGroup.wixobj");
2348            }
2349            // ICE57 wrongly complains about the shortcuts
2350            cmd.arg("-sice:ICE57");
2351
2352            let _time = timeit(builder);
2353            cmd.run(builder);
2354
2355            if !builder.config.dry_run() {
2356                t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
2357            }
2358        }
2359    }
2360
2361    fn metadata(&self) -> Option<StepMetadata> {
2362        Some(StepMetadata::dist("extended", self.target).built_by(self.build_compiler))
2363    }
2364}
2365
2366fn add_env(
2367    builder: &Builder<'_>,
2368    cmd: &mut BootstrapCommand,
2369    target: TargetSelection,
2370    built_tools: &HashSet<&'static str>,
2371) {
2372    let mut parts = builder.version.split('.');
2373    cmd.env("CFG_RELEASE_INFO", builder.rust_version())
2374        .env("CFG_RELEASE_NUM", &builder.version)
2375        .env("CFG_RELEASE", builder.rust_release())
2376        .env("CFG_VER_MAJOR", parts.next().unwrap())
2377        .env("CFG_VER_MINOR", parts.next().unwrap())
2378        .env("CFG_VER_PATCH", parts.next().unwrap())
2379        .env("CFG_VER_BUILD", "0") // just needed to build
2380        .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
2381        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
2382        .env("CFG_BUILD", target.triple)
2383        .env("CFG_CHANNEL", &builder.config.channel);
2384
2385    if target.is_windows_gnullvm() {
2386        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
2387    } else if target.is_windows_gnu() {
2388        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
2389    } else {
2390        cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
2391    }
2392
2393    // ensure these variables are defined
2394    let mut define_optional_tool = |tool_name: &str, env_name: &str| {
2395        cmd.env(env_name, if built_tools.contains(tool_name) { "1" } else { "0" });
2396    };
2397    define_optional_tool("rustfmt", "CFG_RUSTFMT");
2398    define_optional_tool("clippy", "CFG_CLIPPY");
2399    define_optional_tool("miri", "CFG_MIRI");
2400    define_optional_tool("rust-analyzer", "CFG_RA");
2401}
2402
2403fn install_llvm_file(
2404    builder: &Builder<'_>,
2405    source: &Path,
2406    destination: &Path,
2407    install_symlink: bool,
2408) {
2409    if builder.config.dry_run() {
2410        return;
2411    }
2412
2413    if source.is_symlink() {
2414        // If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the
2415        // symlink, which is what will actually get loaded at runtime.
2416        builder.install(&t!(fs::canonicalize(source)), destination, FileType::NativeLibrary);
2417
2418        let full_dest = destination.join(source.file_name().unwrap());
2419        if install_symlink {
2420            // For download-ci-llvm, also install the symlink, to match what LLVM does. Using a
2421            // symlink is fine here, as this is not a rustup component.
2422            builder.copy_link(source, &full_dest, FileType::NativeLibrary);
2423        } else {
2424            // Otherwise, replace the symlink with an equivalent linker script. This is used when
2425            // projects like miri link against librustc_driver.so. We don't use a symlink, as
2426            // these are not allowed inside rustup components.
2427            let link = t!(fs::read_link(source));
2428            let mut linker_script = t!(fs::File::create(full_dest));
2429            t!(write!(linker_script, "INPUT({})\n", link.display()));
2430
2431            // We also want the linker script to have the same mtime as the source, otherwise it
2432            // can trigger rebuilds.
2433            let meta = t!(fs::metadata(source));
2434            if let Ok(mtime) = meta.modified() {
2435                t!(linker_script.set_modified(mtime));
2436            }
2437        }
2438    } else {
2439        builder.install(source, destination, FileType::NativeLibrary);
2440    }
2441}
2442
2443/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
2444///
2445/// Returns whether the files were actually copied.
2446#[cfg_attr(
2447    feature = "tracing",
2448    instrument(
2449        level = "trace",
2450        name = "maybe_install_llvm",
2451        skip_all,
2452        fields(target = ?target, dst_libdir = ?dst_libdir, install_symlink = install_symlink),
2453    ),
2454)]
2455fn maybe_install_llvm(
2456    builder: &Builder<'_>,
2457    target: TargetSelection,
2458    dst_libdir: &Path,
2459    install_symlink: bool,
2460) -> bool {
2461    // If the LLVM was externally provided, then we don't currently copy
2462    // artifacts into the sysroot. This is not necessarily the right
2463    // choice (in particular, it will require the LLVM dylib to be in
2464    // the linker's load path at runtime), but the common use case for
2465    // external LLVMs is distribution provided LLVMs, and in that case
2466    // they're usually in the standard search path (e.g., /usr/lib) and
2467    // copying them here is going to cause problems as we may end up
2468    // with the wrong files and isn't what distributions want.
2469    //
2470    // This behavior may be revisited in the future though.
2471    //
2472    // NOTE: this intentionally doesn't use `is_rust_llvm`; whether this is patched or not doesn't matter,
2473    // we only care if the shared object itself is managed by bootstrap.
2474    //
2475    // If the LLVM is coming from ourselves (just from CI) though, we
2476    // still want to install it, as it otherwise won't be available.
2477    if builder.config.is_system_llvm(target) {
2478        trace!("system LLVM requested, no install");
2479        return false;
2480    }
2481
2482    // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
2483    // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely
2484    // clear why this is the case, though. llvm-config will emit the versioned
2485    // paths and we don't want those in the sysroot (as we're expecting
2486    // unversioned paths).
2487    if target.contains("apple-darwin") && builder.llvm_link_shared() {
2488        let src_libdir = builder.llvm_out(target).join("lib");
2489        let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2490        if llvm_dylib_path.exists() {
2491            builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary);
2492        }
2493        !builder.config.dry_run()
2494    } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult {
2495        host_llvm_config, ..
2496    }) = llvm::prebuilt_llvm_config(builder, target, true)
2497    {
2498        trace!("LLVM already built, installing LLVM files");
2499        let mut cmd = command(host_llvm_config);
2500        cmd.cached();
2501        cmd.arg("--libfiles");
2502        builder.do_if_verbose(|| println!("running {cmd:?}"));
2503        let files = cmd.run_capture_stdout(builder).stdout();
2504        let build_llvm_out = &builder.llvm_out(builder.config.host_target);
2505        let target_llvm_out = &builder.llvm_out(target);
2506        for file in files.trim_end().split(' ') {
2507            // If we're not using a custom LLVM, make sure we package for the target.
2508            let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
2509                target_llvm_out.join(relative_path)
2510            } else {
2511                PathBuf::from(file)
2512            };
2513            install_llvm_file(builder, &file, dst_libdir, install_symlink);
2514        }
2515        !builder.config.dry_run()
2516    } else {
2517        false
2518    }
2519}
2520
2521/// Maybe add libLLVM.so to the target lib-dir for linking.
2522#[cfg_attr(
2523    feature = "tracing",
2524    instrument(
2525        level = "trace",
2526        name = "maybe_install_llvm_target",
2527        skip_all,
2528        fields(
2529            llvm_link_shared = ?builder.llvm_link_shared(),
2530            target = ?target,
2531            sysroot = ?sysroot,
2532        ),
2533    ),
2534)]
2535pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2536    let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
2537    // We do not need to copy LLVM files into the sysroot if it is not
2538    // dynamically linked; it is already included into librustc_llvm
2539    // statically.
2540    if builder.llvm_link_shared() {
2541        maybe_install_llvm(builder, target, &dst_libdir, false);
2542    }
2543}
2544
2545/// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
2546#[cfg_attr(
2547    feature = "tracing",
2548    instrument(
2549        level = "trace",
2550        name = "maybe_install_llvm_runtime",
2551        skip_all,
2552        fields(
2553            llvm_link_shared = ?builder.llvm_link_shared(),
2554            target = ?target,
2555            sysroot = ?sysroot,
2556        ),
2557    ),
2558)]
2559pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2560    let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler::new(1, target)));
2561    // We do not need to copy LLVM files into the sysroot if it is not
2562    // dynamically linked; it is already included into librustc_llvm
2563    // statically.
2564    if builder.llvm_link_shared() {
2565        maybe_install_llvm(builder, target, &dst_libdir, false);
2566    }
2567}
2568
2569#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2570pub struct LlvmTools {
2571    pub target: TargetSelection,
2572}
2573
2574impl Step for LlvmTools {
2575    type Output = Option<GeneratedTarball>;
2576    const IS_HOST: bool = true;
2577
2578    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2579        let mut run = run.alias("llvm-tools");
2580        for tool in LLVM_TOOLS {
2581            run = run.alias(tool);
2582        }
2583
2584        run
2585    }
2586
2587    fn is_default_step(builder: &Builder<'_>) -> bool {
2588        should_build_extended_tool(builder, "llvm-tools")
2589    }
2590
2591    fn make_run(run: RunConfig<'_>) {
2592        run.builder.ensure(LlvmTools { target: run.target });
2593    }
2594
2595    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2596        fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
2597            let mut tools = vec![];
2598
2599            for path in paths {
2600                let path = path.to_str().unwrap();
2601
2602                // Include all tools if path is 'llvm-tools'.
2603                if path == "llvm-tools" {
2604                    return LLVM_TOOLS.to_owned();
2605                }
2606
2607                for tool in LLVM_TOOLS {
2608                    if path == *tool {
2609                        tools.push(*tool);
2610                    }
2611                }
2612            }
2613
2614            // If no specific tool is requested, include all tools.
2615            if tools.is_empty() {
2616                tools = LLVM_TOOLS.to_owned();
2617            }
2618
2619            tools
2620        }
2621
2622        let target = self.target;
2623
2624        // Run only if a custom llvm-config is not used
2625        if let Some(config) = builder.config.target_config.get(&target)
2626            && !builder.config.llvm_from_ci
2627            && config.llvm_config.is_some()
2628        {
2629            builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
2630            return None;
2631        }
2632
2633        if !builder.config.dry_run() {
2634            builder.require_submodule("src/llvm-project", None);
2635        }
2636
2637        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2638
2639        let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
2640        tarball.set_overlay(OverlayKind::Llvm);
2641        tarball.is_preview(true);
2642
2643        if builder.config.llvm_tools_enabled {
2644            // Prepare the image directory
2645            let src_bindir = builder.llvm_out(target).join("bin");
2646            let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
2647            for tool in tools_to_install(&builder.paths) {
2648                let exe = src_bindir.join(exe(tool, target));
2649                // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
2650                if !exe.exists() && builder.config.llvm_from_ci {
2651                    eprintln!("{} does not exist; skipping copy", exe.display());
2652                    continue;
2653                }
2654
2655                tarball.add_file(&exe, &dst_bindir, FileType::Executable);
2656            }
2657        }
2658
2659        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2660        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2661        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2662        // compiler libraries.
2663        maybe_install_llvm_target(builder, target, tarball.image_dir());
2664
2665        Some(tarball.generate())
2666    }
2667}
2668
2669/// Distributes the `llvm-bitcode-linker` tool so that it can be used by a compiler whose host
2670/// is `target`.
2671#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2672pub struct LlvmBitcodeLinker {
2673    /// The linker will be compiled by this compiler.
2674    pub build_compiler: Compiler,
2675    /// The linker will by usable by rustc on this host.
2676    pub target: TargetSelection,
2677}
2678
2679impl Step for LlvmBitcodeLinker {
2680    type Output = Option<GeneratedTarball>;
2681    const IS_HOST: bool = true;
2682
2683    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2684        run.alias("llvm-bitcode-linker")
2685    }
2686
2687    fn is_default_step(builder: &Builder<'_>) -> bool {
2688        should_build_extended_tool(builder, "llvm-bitcode-linker")
2689    }
2690
2691    fn make_run(run: RunConfig<'_>) {
2692        run.builder.ensure(LlvmBitcodeLinker {
2693            build_compiler: tool::LlvmBitcodeLinker::get_build_compiler_for_target(
2694                run.builder,
2695                run.target,
2696            ),
2697            target: run.target,
2698        });
2699    }
2700
2701    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2702        let target = self.target;
2703
2704        let llbc_linker = builder
2705            .ensure(tool::LlvmBitcodeLinker::from_build_compiler(self.build_compiler, target));
2706
2707        let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
2708
2709        // Prepare the image directory
2710        let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple);
2711        tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
2712        tarball.is_preview(true);
2713
2714        tarball.add_file(&llbc_linker.tool_path, self_contained_bin_dir, FileType::Executable);
2715
2716        Some(tarball.generate())
2717    }
2718}
2719
2720/// Distributes the `enzyme` library so that it can be used by a compiler whose host
2721/// is `target`.
2722#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2723pub struct Enzyme {
2724    /// Enzyme will by usable by rustc on this host.
2725    pub target: TargetSelection,
2726}
2727
2728impl Step for Enzyme {
2729    type Output = Option<GeneratedTarball>;
2730    const IS_HOST: bool = true;
2731
2732    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2733        run.alias("enzyme")
2734    }
2735
2736    fn is_default_step(builder: &Builder<'_>) -> bool {
2737        builder.config.llvm_enzyme
2738    }
2739
2740    fn make_run(run: RunConfig<'_>) {
2741        run.builder.ensure(Enzyme { target: run.target });
2742    }
2743
2744    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2745        // This prevents Enzyme from being built for "dist"
2746        // or "install" on the stable/beta channels. It is not yet stable and
2747        // should not be included.
2748        if !builder.build.unstable_features() {
2749            return None;
2750        }
2751
2752        let target = self.target;
2753
2754        let enzyme = builder.ensure(llvm::Enzyme { target });
2755
2756        let target_libdir = format!("lib/rustlib/{}/lib", target.triple);
2757
2758        // Prepare the image directory
2759        let mut tarball = Tarball::new(builder, "enzyme", &target.triple);
2760        tarball.set_overlay(OverlayKind::Enzyme);
2761        tarball.is_preview(true);
2762
2763        tarball.add_file(enzyme.enzyme_path(), target_libdir, FileType::NativeLibrary);
2764
2765        Some(tarball.generate())
2766    }
2767}
2768
2769/// Tarball intended for internal consumption to ease rustc/std development.
2770///
2771/// Should not be considered stable by end users.
2772///
2773/// In practice, this is the tarball that gets downloaded and used by
2774/// `llvm.download-ci-llvm`.
2775///
2776/// (Don't confuse this with [`RustcDev`], with a `c`!)
2777#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2778pub struct RustDev {
2779    pub target: TargetSelection,
2780}
2781
2782impl Step for RustDev {
2783    type Output = Option<GeneratedTarball>;
2784    const IS_HOST: bool = true;
2785
2786    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2787        run.alias("rust-dev")
2788    }
2789
2790    fn is_default_step(_builder: &Builder<'_>) -> bool {
2791        true
2792    }
2793
2794    fn make_run(run: RunConfig<'_>) {
2795        run.builder.ensure(RustDev { target: run.target });
2796    }
2797
2798    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2799        let target = self.target;
2800
2801        /* run only if llvm-config isn't used */
2802        if let Some(config) = builder.config.target_config.get(&target)
2803            && let Some(ref _s) = config.llvm_config
2804        {
2805            builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
2806            return None;
2807        }
2808
2809        if !builder.config.dry_run() {
2810            builder.require_submodule("src/llvm-project", None);
2811        }
2812
2813        let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
2814        tarball.set_overlay(OverlayKind::Llvm);
2815        // LLVM requires a shared object symlink to exist on some platforms.
2816        tarball.permit_symlinks(true);
2817
2818        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2819
2820        let src_bindir = builder.llvm_out(target).join("bin");
2821        // If updating this, you likely want to change
2822        // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
2823        // will not pick up the extra file until LLVM gets bumped.
2824        // We should include all the build artifacts obtained from a source build,
2825        // so that you can use the downloadable LLVM as if you’ve just run a full source build.
2826        if src_bindir.exists() {
2827            for entry in walkdir::WalkDir::new(&src_bindir) {
2828                let entry = t!(entry);
2829                if entry.file_type().is_file() && !entry.path_is_symlink() {
2830                    let name = entry.file_name().to_str().unwrap();
2831                    tarball.add_file(src_bindir.join(name), "bin", FileType::Executable);
2832                }
2833            }
2834        }
2835
2836        if builder.config.lld_enabled {
2837            // We want to package `lld` to use it with `download-ci-llvm`.
2838            let lld_out = builder.ensure(crate::core::build_steps::llvm::Lld { target });
2839
2840            // We don't build LLD on some platforms, so only add it if it exists
2841            let lld_path = lld_out.join("bin").join(exe("lld", target));
2842            if lld_path.exists() {
2843                tarball.add_file(&lld_path, "bin", FileType::Executable);
2844            }
2845        }
2846
2847        tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable);
2848
2849        // Copy the include directory as well; needed mostly to build
2850        // librustc_llvm properly (e.g., llvm-config.h is in here). But also
2851        // just broadly useful to be able to link against the bundled LLVM.
2852        tarball.add_dir(builder.llvm_out(target).join("include"), "include");
2853
2854        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2855        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2856        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2857        // compiler libraries.
2858        let dst_libdir = tarball.image_dir().join("lib");
2859        maybe_install_llvm(builder, target, &dst_libdir, true);
2860        let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
2861        t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
2862
2863        // Copy the `compiler-rt` source, so that `library/profiler_builtins`
2864        // can potentially use it to build the profiler runtime without needing
2865        // to check out the LLVM submodule.
2866        copy_src_dirs(
2867            builder,
2868            &builder.src.join("src").join("llvm-project"),
2869            &["compiler-rt"],
2870            // The test subdirectory is much larger than the rest of the source,
2871            // and we currently don't use these test files anyway.
2872            &["compiler-rt/test"],
2873            tarball.image_dir(),
2874        );
2875
2876        Some(tarball.generate())
2877    }
2878}
2879
2880/// Tarball intended for internal consumption to ease rustc/std development.
2881///
2882/// It only packages the binaries that were already compiled when bootstrap itself was built.
2883///
2884/// Should not be considered stable by end users.
2885#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2886pub struct Bootstrap {
2887    target: TargetSelection,
2888}
2889
2890impl Step for Bootstrap {
2891    type Output = Option<GeneratedTarball>;
2892
2893    const IS_HOST: bool = true;
2894
2895    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2896        run.alias("bootstrap")
2897    }
2898
2899    fn make_run(run: RunConfig<'_>) {
2900        run.builder.ensure(Bootstrap { target: run.target });
2901    }
2902
2903    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2904        let target = self.target;
2905
2906        let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2907
2908        let bootstrap_outdir = &builder.bootstrap_out;
2909        for file in &["bootstrap", "rustc", "rustdoc"] {
2910            tarball.add_file(
2911                bootstrap_outdir.join(exe(file, target)),
2912                "bootstrap/bin",
2913                FileType::Executable,
2914            );
2915        }
2916
2917        Some(tarball.generate())
2918    }
2919
2920    fn metadata(&self) -> Option<StepMetadata> {
2921        Some(StepMetadata::dist("bootstrap", self.target))
2922    }
2923}
2924
2925/// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
2926/// release process to avoid cloning the monorepo and building stuff.
2927///
2928/// Should not be considered stable by end users.
2929#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2930pub struct BuildManifest {
2931    target: TargetSelection,
2932}
2933
2934impl Step for BuildManifest {
2935    type Output = GeneratedTarball;
2936
2937    const IS_HOST: bool = true;
2938
2939    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2940        run.alias("build-manifest")
2941    }
2942
2943    fn make_run(run: RunConfig<'_>) {
2944        run.builder.ensure(BuildManifest { target: run.target });
2945    }
2946
2947    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
2948        // FIXME: Should BuildManifest actually be built for `self.target`?
2949        // Today CI only builds this step where that matches the host_target so it doesn't matter
2950        // today.
2951        let build_manifest =
2952            builder.ensure(tool::BuildManifest::new(builder, builder.config.host_target));
2953
2954        let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
2955        tarball.add_file(&build_manifest.tool_path, "bin", FileType::Executable);
2956        tarball.generate()
2957    }
2958
2959    fn metadata(&self) -> Option<StepMetadata> {
2960        Some(StepMetadata::dist("build-manifest", self.target))
2961    }
2962}
2963
2964/// Tarball containing artifacts necessary to reproduce the build of rustc.
2965///
2966/// Currently this is the PGO (and possibly BOLT) profile data.
2967///
2968/// Should not be considered stable by end users.
2969#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2970pub struct ReproducibleArtifacts {
2971    target: TargetSelection,
2972}
2973
2974impl Step for ReproducibleArtifacts {
2975    type Output = Option<GeneratedTarball>;
2976    const IS_HOST: bool = true;
2977
2978    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2979        run.alias("reproducible-artifacts")
2980    }
2981
2982    fn is_default_step(_builder: &Builder<'_>) -> bool {
2983        true
2984    }
2985
2986    fn make_run(run: RunConfig<'_>) {
2987        run.builder.ensure(ReproducibleArtifacts { target: run.target });
2988    }
2989
2990    fn run(self, builder: &Builder<'_>) -> Self::Output {
2991        let mut added_anything = false;
2992        let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
2993        if let Some(path) = builder.config.rust_profile_use.as_ref() {
2994            tarball.add_file(path, ".", FileType::Regular);
2995            added_anything = true;
2996        }
2997        if let Some(path) = builder.config.llvm_profile_use.as_ref() {
2998            tarball.add_file(path, ".", FileType::Regular);
2999            added_anything = true;
3000        }
3001        for profile in &builder.config.reproducible_artifacts {
3002            tarball.add_file(profile, ".", FileType::Regular);
3003            added_anything = true;
3004        }
3005        if added_anything { Some(tarball.generate()) } else { None }
3006    }
3007
3008    fn metadata(&self) -> Option<StepMetadata> {
3009        Some(StepMetadata::dist("reproducible-artifacts", self.target))
3010    }
3011}
3012
3013/// Tarball containing a prebuilt version of the libgccjit library,
3014/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
3015/// backend needing a prebuilt libLLVM).
3016///
3017/// This component is used for `download-ci-gcc`.
3018#[derive(Clone, Debug, Eq, Hash, PartialEq)]
3019pub struct GccDev {
3020    target: TargetSelection,
3021}
3022
3023impl Step for GccDev {
3024    type Output = GeneratedTarball;
3025
3026    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3027        run.alias("gcc-dev")
3028    }
3029
3030    fn make_run(run: RunConfig<'_>) {
3031        run.builder.ensure(GccDev { target: run.target });
3032    }
3033
3034    fn run(self, builder: &Builder<'_>) -> Self::Output {
3035        let tarball = Tarball::new(builder, "gcc-dev", &self.target.triple);
3036        let output = builder
3037            .ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) });
3038        tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary);
3039        tarball.generate()
3040    }
3041
3042    fn metadata(&self) -> Option<StepMetadata> {
3043        Some(StepMetadata::dist("gcc-dev", self.target))
3044    }
3045}
3046
3047/// Tarball containing a libgccjit dylib,
3048/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
3049/// backend needing a prebuilt libLLVM).
3050///
3051/// This component is used for distribution through rustup.
3052#[derive(Clone, Debug, Eq, Hash, PartialEq)]
3053pub struct Gcc {
3054    host: TargetSelection,
3055    target: TargetSelection,
3056}
3057
3058impl Step for Gcc {
3059    type Output = Option<GeneratedTarball>;
3060
3061    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3062        run.alias("gcc")
3063    }
3064
3065    fn make_run(run: RunConfig<'_>) {
3066        // GCC is always built for a target pair, (host, target).
3067        // We do not yet support cross-compilation here, so the host target is always inferred to
3068        // be the bootstrap host target.
3069        run.builder.ensure(Gcc { host: run.builder.host_target, target: run.target });
3070    }
3071
3072    fn run(self, builder: &Builder<'_>) -> Self::Output {
3073        // This prevents gcc from being built for "dist"
3074        // or "install" on the stable/beta channels. It is not yet stable and
3075        // should not be included.
3076        if !builder.build.unstable_features() {
3077            return None;
3078        }
3079
3080        let host = self.host;
3081        let target = self.target;
3082        if host != "x86_64-unknown-linux-gnu" {
3083            builder.info(&format!("host target `{host}` not supported by gcc. skipping"));
3084            return None;
3085        }
3086
3087        if builder.config.is_running_on_ci {
3088            assert_eq!(
3089                builder.config.gcc_ci_mode,
3090                GccCiMode::BuildLocally,
3091                "Cannot use gcc.download-ci-gcc when distributing GCC on CI"
3092            );
3093        }
3094
3095        // We need the GCC sources to build GCC and also to add its license and README
3096        // files to the tarball
3097        builder.require_submodule(
3098            "src/gcc",
3099            Some("The src/gcc submodule is required for disting libgccjit"),
3100        );
3101
3102        let target_pair = GccTargetPair::for_target_pair(host, target);
3103        let libgccjit = builder.ensure(super::gcc::Gcc { target_pair });
3104
3105        // We have to include the target name in the component name, so that rustup can somehow
3106        // distinguish that there are multiple gcc components on a given host target.
3107        // So the tarball includes the target name.
3108        let mut tarball = Tarball::new(builder, &format!("gcc-{target}"), &host.triple);
3109        tarball.set_overlay(OverlayKind::Gcc);
3110        tarball.is_preview(true);
3111        tarball.add_legal_and_readme_to("share/doc/gcc");
3112
3113        // The path where to put libgccjit is determined by GccDylibSet.
3114        // However, it requires a Compiler to figure out the path to the codegen backend sysroot.
3115        // We don't really have any compiler here, because we just build libgccjit.
3116        // So we duplicate the logic for determining the CG sysroot here.
3117        let cg_dir = PathBuf::from(format!("lib/rustlib/{host}/codegen-backends"));
3118
3119        // This returns the path to the actual file, but here we need its parent
3120        let rel_libgccjit_path = libgccjit_path_relative_to_cg_dir(&target_pair, &libgccjit);
3121        let path = cg_dir.join(rel_libgccjit_path.parent().unwrap());
3122
3123        tarball.add_file(libgccjit.libgccjit(), path, FileType::NativeLibrary);
3124        Some(tarball.generate())
3125    }
3126
3127    fn metadata(&self) -> Option<StepMetadata> {
3128        Some(StepMetadata::dist(
3129            "gcc",
3130            TargetSelection::from_user(&format!("({}, {})", self.host, self.target)),
3131        ))
3132    }
3133}