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