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        cp_debugger_script("lldb_commands")
764    }
765}
766
767fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
768    // The only true set of target libraries came from the build triple, so
769    // let's reduce redundant work by only producing archives from that host.
770    if !builder.config.is_host_target(compiler.host) {
771        builder.info("\tskipping, not a build host");
772        true
773    } else {
774        false
775    }
776}
777
778/// Check that all objects in rlibs for UEFI targets are COFF. This
779/// ensures that the C compiler isn't producing ELF objects, which would
780/// not link correctly with the COFF objects.
781fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &BuildStamp) {
782    if !target.ends_with("-uefi") {
783        return;
784    }
785
786    for (path, _) in builder.read_stamp_file(stamp) {
787        if path.extension() != Some(OsStr::new("rlib")) {
788            continue;
789        }
790
791        let data = t!(fs::read(&path));
792        let data = data.as_slice();
793        let archive = t!(ArchiveFile::parse(data));
794        for member in archive.members() {
795            let member = t!(member);
796            let member_data = t!(member.data(data));
797
798            let is_coff = match object::File::parse(member_data) {
799                Ok(member_file) => member_file.format() == BinaryFormat::Coff,
800                Err(_) => false,
801            };
802
803            if !is_coff {
804                let member_name = String::from_utf8_lossy(member.name());
805                panic!("member {} in {} is not COFF", member_name, path.display());
806            }
807        }
808    }
809}
810
811/// Copy stamped files into an image's `target/lib` directory.
812fn copy_target_libs(
813    builder: &Builder<'_>,
814    target: TargetSelection,
815    image: &Path,
816    stamp: &BuildStamp,
817) {
818    let dst = image.join("lib/rustlib").join(target).join("lib");
819    let self_contained_dst = dst.join("self-contained");
820    t!(fs::create_dir_all(&dst));
821    t!(fs::create_dir_all(&self_contained_dst));
822    for (path, dependency_type) in builder.read_stamp_file(stamp) {
823        if dependency_type == DependencyType::TargetSelfContained {
824            builder.copy_link(
825                &path,
826                &self_contained_dst.join(path.file_name().unwrap()),
827                FileType::NativeLibrary,
828            );
829        } else if dependency_type == DependencyType::Target || builder.config.is_host_target(target)
830        {
831            builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary);
832        }
833    }
834}
835
836/// Builds the standard library (`rust-std`) dist component for a given `target`.
837/// This includes the standard library dynamic library file (e.g. .so/.dll), along with stdlib
838/// .rlibs.
839///
840/// Note that due to uplifting, we actually ship the stage 1 library
841/// (built using the stage1 compiler) even with a stage 2 dist, unless `full-bootstrap` is enabled.
842#[derive(Debug, Clone, Hash, PartialEq, Eq)]
843pub struct Std {
844    /// Compiler that will build the standard library.
845    pub build_compiler: Compiler,
846    pub target: TargetSelection,
847}
848
849impl Std {
850    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
851        Std { build_compiler: builder.compiler_for_std(builder.top_stage), target }
852    }
853}
854
855impl Step for Std {
856    type Output = Option<GeneratedTarball>;
857
858    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
859        run.alias("rust-std")
860    }
861
862    fn is_default_step(_builder: &Builder<'_>) -> bool {
863        true
864    }
865
866    fn make_run(run: RunConfig<'_>) {
867        run.builder.ensure(Std::new(run.builder, run.target));
868    }
869
870    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
871        let build_compiler = self.build_compiler;
872        let target = self.target;
873
874        if skip_host_target_lib(builder, build_compiler) {
875            return None;
876        }
877
878        // It's possible that std was uplifted and thus built with a different build compiler
879        // So we need to read the stamp that was actually generated when std was built
880        let stamp =
881            builder.std(build_compiler, target).expect("Standard library has to be built for dist");
882
883        let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
884        tarball.include_target_in_component_name(true);
885
886        verify_uefi_rlib_format(builder, target, &stamp);
887        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
888
889        Some(tarball.generate())
890    }
891
892    fn metadata(&self) -> Option<StepMetadata> {
893        Some(StepMetadata::dist("std", self.target).built_by(self.build_compiler))
894    }
895}
896
897/// Tarball containing the compiler that gets downloaded and used by
898/// `rust.download-rustc`.
899///
900/// (Don't confuse this with [`RustDev`], without the `c`!)
901#[derive(Debug, Clone, Hash, PartialEq, Eq)]
902pub struct RustcDev {
903    /// The compiler that will build rustc which will be shipped in this component.
904    pub build_compiler: Compiler,
905    pub target: TargetSelection,
906}
907
908impl RustcDev {
909    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
910        Self {
911            // We currently always ship a stage 2 rustc-dev component, so we build it with the
912            // stage 1 compiler. This might change in the future.
913            // The precise stage used here is important, so we hard-code it.
914            build_compiler: builder.compiler(1, builder.config.host_target),
915            target,
916        }
917    }
918}
919
920impl Step for RustcDev {
921    type Output = Option<GeneratedTarball>;
922    const IS_HOST: bool = true;
923
924    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
925        run.alias("rustc-dev")
926    }
927
928    fn is_default_step(_builder: &Builder<'_>) -> bool {
929        true
930    }
931
932    fn make_run(run: RunConfig<'_>) {
933        run.builder.ensure(RustcDev::new(run.builder, run.target));
934    }
935
936    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
937        let build_compiler = self.build_compiler;
938        let target = self.target;
939        if skip_host_target_lib(builder, build_compiler) {
940            return None;
941        }
942
943        // Build the compiler that we will ship
944        builder.ensure(compile::Rustc::new(build_compiler, target));
945
946        let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
947
948        let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);
949        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
950
951        let src_files = &["Cargo.lock"];
952        // This is the reduced set of paths which will become the rustc-dev component
953        // (essentially the compiler crates and all of their path dependencies).
954        copy_src_dirs(
955            builder,
956            &builder.src,
957            // The compiler has a path dependency on proc_macro, so make sure to include it.
958            &["compiler", "library/proc_macro"],
959            &[],
960            &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
961        );
962        for file in src_files {
963            tarball.add_file(
964                builder.src.join(file),
965                "lib/rustlib/rustc-src/rust",
966                FileType::Regular,
967            );
968        }
969
970        Some(tarball.generate())
971    }
972
973    fn metadata(&self) -> Option<StepMetadata> {
974        Some(StepMetadata::dist("rustc-dev", self.target).built_by(self.build_compiler))
975    }
976}
977
978/// The `rust-analysis` component used to create a tarball of save-analysis metadata.
979///
980/// This component has been deprecated and its contents now only include a warning about
981/// its non-availability.
982#[derive(Debug, Clone, Hash, PartialEq, Eq)]
983pub struct Analysis {
984    build_compiler: Compiler,
985    target: TargetSelection,
986}
987
988impl Step for Analysis {
989    type Output = Option<GeneratedTarball>;
990
991    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
992        run.alias("rust-analysis")
993    }
994
995    fn is_default_step(builder: &Builder<'_>) -> bool {
996        should_build_extended_tool(builder, "analysis")
997    }
998
999    fn make_run(run: RunConfig<'_>) {
1000        // The step just produces a deprecation notice, so we just hardcode stage 1
1001        run.builder.ensure(Analysis {
1002            build_compiler: run.builder.compiler(1, run.builder.config.host_target),
1003            target: run.target,
1004        });
1005    }
1006
1007    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1008        let compiler = self.build_compiler;
1009        let target = self.target;
1010        if skip_host_target_lib(builder, compiler) {
1011            return None;
1012        }
1013
1014        let src = builder
1015            .stage_out(compiler, Mode::Std)
1016            .join(target)
1017            .join(builder.cargo_dir(Mode::Std))
1018            .join("deps")
1019            .join("save-analysis");
1020
1021        // Write a file indicating that this component has been removed.
1022        t!(std::fs::create_dir_all(&src));
1023        let mut removed = src.clone();
1024        removed.push("removed.json");
1025        let mut f = t!(std::fs::File::create(removed));
1026        t!(write!(f, r#"{{ "warning": "The `rust-analysis` component has been removed." }}"#));
1027
1028        let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple);
1029        tarball.include_target_in_component_name(true);
1030        tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple));
1031        Some(tarball.generate())
1032    }
1033
1034    fn metadata(&self) -> Option<StepMetadata> {
1035        Some(StepMetadata::dist("analysis", self.target).built_by(self.build_compiler))
1036    }
1037}
1038
1039/// Use the `builder` to make a filtered copy of `base`/X for X in (`src_dirs` - `exclude_dirs`) to
1040/// `dst_dir`.
1041fn copy_src_dirs(
1042    builder: &Builder<'_>,
1043    base: &Path,
1044    src_dirs: &[&str],
1045    exclude_dirs: &[&str],
1046    dst_dir: &Path,
1047) {
1048    // The src directories should be relative to `base`, we depend on them not being absolute
1049    // paths below.
1050    for src_dir in src_dirs {
1051        assert!(Path::new(src_dir).is_relative());
1052    }
1053
1054    // Iterating, filtering and copying a large number of directories can be quite slow.
1055    // Avoid doing it in dry run (and thus also tests).
1056    if builder.config.dry_run() {
1057        return;
1058    }
1059
1060    fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
1061        // The paths are relative, e.g. `llvm-project/...`.
1062        let spath = match path.to_str() {
1063            Some(path) => path,
1064            None => return false,
1065        };
1066        if spath.ends_with('~') || spath.ends_with(".pyc") {
1067            return false;
1068        }
1069        // Normalize slashes
1070        let spath = spath.replace("\\", "/");
1071
1072        static LLVM_PROJECTS: &[&str] = &[
1073            "llvm-project/clang",
1074            "llvm-project/libunwind",
1075            "llvm-project/lld",
1076            "llvm-project/lldb",
1077            "llvm-project/llvm",
1078            "llvm-project/compiler-rt",
1079            "llvm-project/cmake",
1080            "llvm-project/runtimes",
1081            "llvm-project/third-party",
1082        ];
1083        if spath.starts_with("llvm-project") && spath != "llvm-project" {
1084            if !LLVM_PROJECTS.iter().any(|path| spath.starts_with(path)) {
1085                return false;
1086            }
1087
1088            // Keep siphash third-party dependency
1089            if spath.starts_with("llvm-project/third-party")
1090                && spath != "llvm-project/third-party"
1091                && !spath.starts_with("llvm-project/third-party/siphash")
1092            {
1093                return false;
1094            }
1095
1096            if spath.starts_with("llvm-project/llvm/test")
1097                && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
1098            {
1099                return false;
1100            }
1101        }
1102
1103        // Cargo tests use some files like `.gitignore` that we would otherwise exclude.
1104        if spath.starts_with("tools/cargo/tests") {
1105            return true;
1106        }
1107
1108        if !exclude_dirs.is_empty() {
1109            let full_path = Path::new(dir).join(path);
1110            if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
1111                return false;
1112            }
1113        }
1114
1115        static EXCLUDES: &[&str] = &[
1116            "CVS",
1117            "RCS",
1118            "SCCS",
1119            ".git",
1120            ".gitignore",
1121            ".gitmodules",
1122            ".gitattributes",
1123            ".cvsignore",
1124            ".svn",
1125            ".arch-ids",
1126            "{arch}",
1127            "=RELEASE-ID",
1128            "=meta-update",
1129            "=update",
1130            ".bzr",
1131            ".bzrignore",
1132            ".bzrtags",
1133            ".hg",
1134            ".hgignore",
1135            ".hgrags",
1136            "_darcs",
1137        ];
1138
1139        // We want to check if any component of `path` doesn't contain the strings in `EXCLUDES`.
1140        // However, since we traverse directories top-down in `Builder::cp_link_filtered`,
1141        // it is enough to always check only the last component:
1142        // - If the path is a file, we will iterate to it and then check it's filename
1143        // - If the path is a dir, if it's dir name contains an excluded string, we will not even
1144        //   recurse into it.
1145        let last_component = path.iter().next_back().map(|s| s.to_str().unwrap()).unwrap();
1146        !EXCLUDES.contains(&last_component)
1147    }
1148
1149    // Copy the directories using our filter
1150    for item in src_dirs {
1151        let dst = &dst_dir.join(item);
1152        t!(fs::create_dir_all(dst));
1153        builder
1154            .cp_link_filtered(&base.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
1155    }
1156}
1157
1158#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1159pub struct Src;
1160
1161impl Step for Src {
1162    /// The output path of the src installer tarball
1163    type Output = GeneratedTarball;
1164    const IS_HOST: bool = true;
1165
1166    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1167        run.alias("rust-src")
1168    }
1169
1170    fn is_default_step(_builder: &Builder<'_>) -> bool {
1171        true
1172    }
1173
1174    fn make_run(run: RunConfig<'_>) {
1175        run.builder.ensure(Src);
1176    }
1177
1178    /// Creates the `rust-src` installer component
1179    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1180        if !builder.config.dry_run() {
1181            builder.require_submodule("src/llvm-project", None);
1182        }
1183
1184        let tarball = Tarball::new_targetless(builder, "rust-src");
1185
1186        // A lot of tools expect the rust-src component to be entirely in this directory, so if you
1187        // change that (e.g. by adding another directory `lib/rustlib/src/foo` or
1188        // `lib/rustlib/src/rust/foo`), you will need to go around hunting for implicit assumptions
1189        // and fix them...
1190        //
1191        // NOTE: if you update the paths here, you also should update the "virtual" path
1192        // translation code in `imported_source_files` in `src/librustc_metadata/rmeta/decoder.rs`
1193        let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
1194
1195        // This is the reduced set of paths which will become the rust-src component
1196        // (essentially libstd and all of its path dependencies).
1197        copy_src_dirs(
1198            builder,
1199            &builder.src,
1200            &["library", "src/llvm-project/libunwind"],
1201            &[
1202                // not needed and contains symlinks which rustup currently
1203                // chokes on when unpacking.
1204                "library/backtrace/crates",
1205                // these are 30MB combined and aren't necessary for building
1206                // the standard library.
1207                "library/stdarch/Cargo.toml",
1208                "library/stdarch/crates/stdarch-verify",
1209                "library/stdarch/crates/intrinsic-test",
1210            ],
1211            &dst_src,
1212        );
1213
1214        // Vendor all Cargo dependencies
1215        let vendor = builder.ensure(Vendor {
1216            sync_args: vec![],
1217            versioned_dirs: true,
1218            root_dir: dst_src.clone(),
1219            output_dir: None,
1220            only_library_workspace: true,
1221        });
1222
1223        let library_cargo_config_dir = dst_src.join("library").join(".cargo");
1224        builder.create_dir(&library_cargo_config_dir);
1225        builder.create(&library_cargo_config_dir.join("config.toml"), &vendor.config_library);
1226
1227        tarball.generate()
1228    }
1229
1230    fn metadata(&self) -> Option<StepMetadata> {
1231        Some(StepMetadata::dist("src", TargetSelection::default()))
1232    }
1233}
1234
1235/// Tarball for people who want to build rustc and other components from the source.
1236/// Does not contain GPL code, which is separated into `PlainSourceTarballGpl`
1237/// for licensing reasons.
1238#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1239pub struct PlainSourceTarball;
1240
1241impl Step for PlainSourceTarball {
1242    /// Produces the location of the tarball generated
1243    type Output = GeneratedTarball;
1244    const IS_HOST: bool = true;
1245
1246    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1247        run.alias("rustc-src")
1248    }
1249
1250    fn is_default_step(builder: &Builder<'_>) -> bool {
1251        builder.config.rust_dist_src
1252    }
1253
1254    fn make_run(run: RunConfig<'_>) {
1255        run.builder.ensure(PlainSourceTarball);
1256    }
1257
1258    /// Creates the plain source tarball
1259    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1260        let tarball = prepare_source_tarball(
1261            builder,
1262            "src",
1263            &[
1264                // We don't currently use the GCC source code for building any official components,
1265                // it is very big, and has unclear licensing implications due to being GPL licensed.
1266                // We thus exclude it from the source tarball from now.
1267                "src/gcc",
1268            ],
1269        );
1270
1271        let plain_dst_src = tarball.image_dir();
1272        // We keep something in src/gcc because it is a registered submodule,
1273        // and if it misses completely it can cause issues elsewhere
1274        // (see https://github.com/rust-lang/rust/issues/137332).
1275        // We can also let others know why is the source code missing.
1276        if !builder.config.dry_run() {
1277            builder.create_dir(&plain_dst_src.join("src/gcc"));
1278            t!(std::fs::write(
1279                plain_dst_src.join("src/gcc/notice.txt"),
1280                "The GCC source code is not included due to unclear licensing implications\n"
1281            ));
1282        }
1283        tarball.bare()
1284    }
1285}
1286
1287/// Tarball with *all* source code for source builds, including GPL-licensed code.
1288#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1289pub struct PlainSourceTarballGpl;
1290
1291impl Step for PlainSourceTarballGpl {
1292    /// Produces the location of the tarball generated
1293    type Output = GeneratedTarball;
1294    const IS_HOST: bool = true;
1295
1296    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1297        run.alias("rustc-src-gpl")
1298    }
1299
1300    fn is_default_step(builder: &Builder<'_>) -> bool {
1301        builder.config.rust_dist_src
1302    }
1303
1304    fn make_run(run: RunConfig<'_>) {
1305        run.builder.ensure(PlainSourceTarballGpl);
1306    }
1307
1308    /// Creates the plain source tarball
1309    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1310        let tarball = prepare_source_tarball(builder, "src-gpl", &[]);
1311        tarball.bare()
1312    }
1313}
1314
1315fn prepare_source_tarball<'a>(
1316    builder: &'a Builder<'a>,
1317    name: &str,
1318    exclude_dirs: &[&str],
1319) -> Tarball<'a> {
1320    // NOTE: This is a strange component in a lot of ways. It uses `src` as the target, which
1321    // means neither rustup nor rustup-toolchain-install-master know how to download it.
1322    // It also contains symbolic links, unlike other any other dist tarball.
1323    // It's used for distros building rustc from source in a pre-vendored environment.
1324    let mut tarball = Tarball::new(builder, "rustc", name);
1325    tarball.permit_symlinks(true);
1326    let plain_dst_src = tarball.image_dir();
1327
1328    // This is the set of root paths which will become part of the source package
1329    let src_files = [
1330        // tidy-alphabetical-start
1331        ".gitmodules",
1332        "CONTRIBUTING.md",
1333        "COPYRIGHT",
1334        "Cargo.lock",
1335        "Cargo.toml",
1336        "LICENSE-APACHE",
1337        "LICENSE-MIT",
1338        "README.md",
1339        "RELEASES.md",
1340        "REUSE.toml",
1341        "bootstrap.example.toml",
1342        "configure",
1343        "license-metadata.json",
1344        "package.json",
1345        "x",
1346        "x.ps1",
1347        "x.py",
1348        "yarn.lock",
1349        // tidy-alphabetical-end
1350    ];
1351    let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
1352
1353    copy_src_dirs(builder, &builder.src, &src_dirs, exclude_dirs, plain_dst_src);
1354
1355    // Copy the files normally
1356    for item in &src_files {
1357        builder.copy_link(&builder.src.join(item), &plain_dst_src.join(item), FileType::Regular);
1358    }
1359
1360    // Create the version file
1361    builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1362
1363    // Create the files containing git info, to ensure --version outputs the same.
1364    let write_git_info = |info: Option<&Info>, path: &Path| {
1365        if let Some(info) = info {
1366            t!(std::fs::create_dir_all(path));
1367            channel::write_commit_hash_file(path, &info.sha);
1368            channel::write_commit_info_file(path, info);
1369        }
1370    };
1371    write_git_info(builder.rust_info().info(), plain_dst_src);
1372    write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo"));
1373
1374    if builder.config.dist_vendor {
1375        builder.require_and_update_all_submodules();
1376
1377        // Vendor packages that are required by opt-dist to collect PGO profiles.
1378        let pkgs_for_pgo_training =
1379            build_helper::LLVM_PGO_CRATES.iter().chain(build_helper::RUSTC_PGO_CRATES).map(|pkg| {
1380                let mut manifest_path =
1381                    builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks");
1382                manifest_path.push(pkg);
1383                manifest_path.push("Cargo.toml");
1384                manifest_path
1385            });
1386
1387        // Vendor all Cargo dependencies
1388        let vendor = builder.ensure(Vendor {
1389            sync_args: pkgs_for_pgo_training.collect(),
1390            versioned_dirs: true,
1391            root_dir: plain_dst_src.into(),
1392            output_dir: None,
1393            only_library_workspace: false,
1394        });
1395
1396        let cargo_config_dir = plain_dst_src.join(".cargo");
1397        builder.create_dir(&cargo_config_dir);
1398        builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
1399
1400        let library_cargo_config_dir = plain_dst_src.join("library").join(".cargo");
1401        builder.create_dir(&library_cargo_config_dir);
1402        builder.create(&library_cargo_config_dir.join("config.toml"), &vendor.config_library);
1403    }
1404
1405    // Delete extraneous directories
1406    // FIXME: if we're managed by git, we should probably instead ask git if the given path
1407    // is managed by it?
1408    for entry in walkdir::WalkDir::new(tarball.image_dir())
1409        .follow_links(true)
1410        .into_iter()
1411        .filter_map(|e| e.ok())
1412    {
1413        if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__")) {
1414            t!(fs::remove_dir_all(entry.path()));
1415        }
1416    }
1417    tarball
1418}
1419
1420#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1421pub struct Cargo {
1422    pub build_compiler: Compiler,
1423    pub target: TargetSelection,
1424}
1425
1426impl Step for Cargo {
1427    type Output = Option<GeneratedTarball>;
1428    const IS_HOST: bool = true;
1429
1430    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1431        run.alias("cargo")
1432    }
1433
1434    fn is_default_step(builder: &Builder<'_>) -> bool {
1435        should_build_extended_tool(builder, "cargo")
1436    }
1437
1438    fn make_run(run: RunConfig<'_>) {
1439        run.builder.ensure(Cargo {
1440            build_compiler: get_tool_target_compiler(
1441                run.builder,
1442                ToolTargetBuildMode::Build(run.target),
1443            ),
1444            target: run.target,
1445        });
1446    }
1447
1448    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1449        let build_compiler = self.build_compiler;
1450        let target = self.target;
1451
1452        let cargo = builder.ensure(tool::Cargo::from_build_compiler(build_compiler, target));
1453        let src = builder.src.join("src/tools/cargo");
1454        let etc = src.join("src/etc");
1455
1456        // Prepare the image directory
1457        let mut tarball = Tarball::new(builder, "cargo", &target.triple);
1458        tarball.set_overlay(OverlayKind::Cargo);
1459
1460        tarball.add_file(&cargo.tool_path, "bin", FileType::Executable);
1461        tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", FileType::Regular);
1462        tarball.add_renamed_file(
1463            etc.join("cargo.bashcomp.sh"),
1464            "etc/bash_completion.d",
1465            "cargo",
1466            FileType::Regular,
1467        );
1468        tarball.add_dir(etc.join("man"), "share/man/man1");
1469        tarball.add_legal_and_readme_to("share/doc/cargo");
1470
1471        Some(tarball.generate())
1472    }
1473
1474    fn metadata(&self) -> Option<StepMetadata> {
1475        Some(StepMetadata::dist("cargo", self.target).built_by(self.build_compiler))
1476    }
1477}
1478
1479/// Distribute the rust-analyzer component, which is used as a LSP by various IDEs.
1480#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1481pub struct RustAnalyzer {
1482    pub compilers: RustcPrivateCompilers,
1483    pub target: TargetSelection,
1484}
1485
1486impl Step for RustAnalyzer {
1487    type Output = Option<GeneratedTarball>;
1488    const IS_HOST: bool = true;
1489
1490    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1491        run.alias("rust-analyzer")
1492    }
1493
1494    fn is_default_step(builder: &Builder<'_>) -> bool {
1495        should_build_extended_tool(builder, "rust-analyzer")
1496    }
1497
1498    fn make_run(run: RunConfig<'_>) {
1499        run.builder.ensure(RustAnalyzer {
1500            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1501            target: run.target,
1502        });
1503    }
1504
1505    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1506        let target = self.target;
1507        let rust_analyzer = builder.ensure(tool::RustAnalyzer::from_compilers(self.compilers));
1508
1509        let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
1510        tarball.set_overlay(OverlayKind::RustAnalyzer);
1511        tarball.is_preview(true);
1512        tarball.add_file(&rust_analyzer.tool_path, "bin", FileType::Executable);
1513        tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
1514        Some(tarball.generate())
1515    }
1516
1517    fn metadata(&self) -> Option<StepMetadata> {
1518        Some(
1519            StepMetadata::dist("rust-analyzer", self.target)
1520                .built_by(self.compilers.build_compiler()),
1521        )
1522    }
1523}
1524
1525#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1526pub struct Clippy {
1527    pub compilers: RustcPrivateCompilers,
1528    pub target: TargetSelection,
1529}
1530
1531impl Step for Clippy {
1532    type Output = Option<GeneratedTarball>;
1533    const IS_HOST: bool = true;
1534
1535    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1536        run.alias("clippy")
1537    }
1538
1539    fn is_default_step(builder: &Builder<'_>) -> bool {
1540        should_build_extended_tool(builder, "clippy")
1541    }
1542
1543    fn make_run(run: RunConfig<'_>) {
1544        run.builder.ensure(Clippy {
1545            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1546            target: run.target,
1547        });
1548    }
1549
1550    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1551        let target = self.target;
1552
1553        // Prepare the image directory
1554        // We expect clippy to build, because we've exited this step above if tool
1555        // state for clippy isn't testing.
1556        let clippy = builder.ensure(tool::Clippy::from_compilers(self.compilers));
1557        let cargoclippy = builder.ensure(tool::CargoClippy::from_compilers(self.compilers));
1558
1559        let mut tarball = Tarball::new(builder, "clippy", &target.triple);
1560        tarball.set_overlay(OverlayKind::Clippy);
1561        tarball.is_preview(true);
1562        tarball.add_file(&clippy.tool_path, "bin", FileType::Executable);
1563        tarball.add_file(&cargoclippy.tool_path, "bin", FileType::Executable);
1564        tarball.add_legal_and_readme_to("share/doc/clippy");
1565        Some(tarball.generate())
1566    }
1567
1568    fn metadata(&self) -> Option<StepMetadata> {
1569        Some(StepMetadata::dist("clippy", self.target).built_by(self.compilers.build_compiler()))
1570    }
1571}
1572
1573#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1574pub struct Miri {
1575    pub compilers: RustcPrivateCompilers,
1576    pub target: TargetSelection,
1577}
1578
1579impl Step for Miri {
1580    type Output = Option<GeneratedTarball>;
1581    const IS_HOST: bool = true;
1582
1583    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1584        run.alias("miri")
1585    }
1586
1587    fn is_default_step(builder: &Builder<'_>) -> bool {
1588        should_build_extended_tool(builder, "miri")
1589    }
1590
1591    fn make_run(run: RunConfig<'_>) {
1592        run.builder.ensure(Miri {
1593            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1594            target: run.target,
1595        });
1596    }
1597
1598    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1599        // This prevents miri from being built for "dist" or "install"
1600        // on the stable/beta channels. It is a nightly-only tool and should
1601        // not be included.
1602        if !builder.build.unstable_features() {
1603            return None;
1604        }
1605
1606        let miri = builder.ensure(tool::Miri::from_compilers(self.compilers));
1607        let cargomiri = builder.ensure(tool::CargoMiri::from_compilers(self.compilers));
1608
1609        let mut tarball = Tarball::new(builder, "miri", &self.target.triple);
1610        tarball.set_overlay(OverlayKind::Miri);
1611        tarball.is_preview(true);
1612        tarball.add_file(&miri.tool_path, "bin", FileType::Executable);
1613        tarball.add_file(&cargomiri.tool_path, "bin", FileType::Executable);
1614        tarball.add_legal_and_readme_to("share/doc/miri");
1615        Some(tarball.generate())
1616    }
1617
1618    fn metadata(&self) -> Option<StepMetadata> {
1619        Some(StepMetadata::dist("miri", self.target).built_by(self.compilers.build_compiler()))
1620    }
1621}
1622
1623#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1624pub struct CraneliftCodegenBackend {
1625    pub compilers: RustcPrivateCompilers,
1626    pub target: TargetSelection,
1627}
1628
1629impl Step for CraneliftCodegenBackend {
1630    type Output = Option<GeneratedTarball>;
1631    const IS_HOST: bool = true;
1632
1633    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1634        run.alias("rustc_codegen_cranelift")
1635    }
1636
1637    fn is_default_step(builder: &Builder<'_>) -> bool {
1638        // We only want to build the cranelift backend in `x dist` if the backend was enabled
1639        // in rust.codegen-backends.
1640        // Sadly, we don't have access to the actual target for which we're disting clif here..
1641        // So we just use the host target.
1642        builder
1643            .config
1644            .enabled_codegen_backends(builder.host_target)
1645            .contains(&CodegenBackendKind::Cranelift)
1646    }
1647
1648    fn make_run(run: RunConfig<'_>) {
1649        run.builder.ensure(CraneliftCodegenBackend {
1650            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1651            target: run.target,
1652        });
1653    }
1654
1655    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1656        // This prevents rustc_codegen_cranelift from being built for "dist"
1657        // or "install" on the stable/beta channels. It is not yet stable and
1658        // should not be included.
1659        if !builder.build.unstable_features() {
1660            return None;
1661        }
1662
1663        let target = self.target;
1664        if !target_supports_cranelift_backend(target) {
1665            builder.info("target not supported by rustc_codegen_cranelift. skipping");
1666            return None;
1667        }
1668
1669        let mut tarball = Tarball::new(builder, "rustc-codegen-cranelift", &target.triple);
1670        tarball.set_overlay(OverlayKind::RustcCodegenCranelift);
1671        tarball.is_preview(true);
1672        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_cranelift");
1673
1674        let compilers = self.compilers;
1675        let stamp = builder.ensure(compile::CraneliftCodegenBackend { compilers });
1676
1677        if builder.config.dry_run() {
1678            return None;
1679        }
1680
1681        add_codegen_backend_to_tarball(builder, &tarball, compilers.target_compiler(), &stamp);
1682
1683        Some(tarball.generate())
1684    }
1685
1686    fn metadata(&self) -> Option<StepMetadata> {
1687        Some(
1688            StepMetadata::dist("rustc_codegen_cranelift", self.target)
1689                .built_by(self.compilers.build_compiler()),
1690        )
1691    }
1692}
1693
1694/// Builds a dist component containing the GCC codegen backend.
1695/// Note that for this backend to work, it must have a set of libgccjit dylibs available
1696/// at runtime.
1697#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1698pub struct GccCodegenBackend {
1699    pub compilers: RustcPrivateCompilers,
1700    pub target: TargetSelection,
1701}
1702
1703impl Step for GccCodegenBackend {
1704    type Output = Option<GeneratedTarball>;
1705    const IS_HOST: bool = true;
1706
1707    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1708        run.alias("rustc_codegen_gcc")
1709    }
1710
1711    fn is_default_step(builder: &Builder<'_>) -> bool {
1712        // We only want to build the gcc backend in `x dist` if the backend was enabled
1713        // in rust.codegen-backends.
1714        // Sadly, we don't have access to the actual target for which we're disting clif here..
1715        // So we just use the host target.
1716        builder
1717            .config
1718            .enabled_codegen_backends(builder.host_target)
1719            .contains(&CodegenBackendKind::Gcc)
1720    }
1721
1722    fn make_run(run: RunConfig<'_>) {
1723        run.builder.ensure(GccCodegenBackend {
1724            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1725            target: run.target,
1726        });
1727    }
1728
1729    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1730        // This prevents rustc_codegen_gcc from being built for "dist"
1731        // or "install" on the stable/beta channels. It is not yet stable and
1732        // should not be included.
1733        if !builder.build.unstable_features() {
1734            return None;
1735        }
1736
1737        let target = self.target;
1738        if target != "x86_64-unknown-linux-gnu" {
1739            builder
1740                .info(&format!("target `{target}` not supported by rustc_codegen_gcc. skipping"));
1741            return None;
1742        }
1743
1744        let mut tarball = Tarball::new(builder, "rustc-codegen-gcc", &target.triple);
1745        tarball.set_overlay(OverlayKind::RustcCodegenGcc);
1746        tarball.is_preview(true);
1747        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_gcc");
1748
1749        let compilers = self.compilers;
1750        let backend = builder.ensure(compile::GccCodegenBackend::for_target(compilers, target));
1751
1752        if builder.config.dry_run() {
1753            return None;
1754        }
1755
1756        add_codegen_backend_to_tarball(
1757            builder,
1758            &tarball,
1759            compilers.target_compiler(),
1760            backend.stamp(),
1761        );
1762
1763        Some(tarball.generate())
1764    }
1765
1766    fn metadata(&self) -> Option<StepMetadata> {
1767        Some(
1768            StepMetadata::dist("rustc_codegen_gcc", self.target)
1769                .built_by(self.compilers.build_compiler()),
1770        )
1771    }
1772}
1773
1774/// Add a codegen backend built for `compiler`, with its artifacts stored in `stamp`, to the given
1775/// `tarball` at the correct place.
1776fn add_codegen_backend_to_tarball(
1777    builder: &Builder<'_>,
1778    tarball: &Tarball<'_>,
1779    compiler: Compiler,
1780    stamp: &BuildStamp,
1781) {
1782    // Get the relative path of where the codegen backend should be stored.
1783    let backends_dst = builder.sysroot_codegen_backends(compiler);
1784    let backends_rel = backends_dst
1785        .strip_prefix(builder.sysroot(compiler))
1786        .unwrap()
1787        .strip_prefix(builder.sysroot_libdir_relative(compiler))
1788        .unwrap();
1789    // Don't use custom libdir here because ^lib/ will be resolved again with installer
1790    let backends_dst = PathBuf::from("lib").join(backends_rel);
1791
1792    let codegen_backend_dylib = get_codegen_backend_file(stamp);
1793    tarball.add_renamed_file(
1794        &codegen_backend_dylib,
1795        &backends_dst,
1796        &normalize_codegen_backend_name(builder, &codegen_backend_dylib),
1797        FileType::NativeLibrary,
1798    );
1799}
1800
1801#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1802pub struct Rustfmt {
1803    pub compilers: RustcPrivateCompilers,
1804    pub target: TargetSelection,
1805}
1806
1807impl Step for Rustfmt {
1808    type Output = Option<GeneratedTarball>;
1809    const IS_HOST: bool = true;
1810
1811    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1812        run.alias("rustfmt")
1813    }
1814
1815    fn is_default_step(builder: &Builder<'_>) -> bool {
1816        should_build_extended_tool(builder, "rustfmt")
1817    }
1818
1819    fn make_run(run: RunConfig<'_>) {
1820        run.builder.ensure(Rustfmt {
1821            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1822            target: run.target,
1823        });
1824    }
1825
1826    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1827        let rustfmt = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
1828        let cargofmt = builder.ensure(tool::Cargofmt::from_compilers(self.compilers));
1829
1830        let mut tarball = Tarball::new(builder, "rustfmt", &self.target.triple);
1831        tarball.set_overlay(OverlayKind::Rustfmt);
1832        tarball.is_preview(true);
1833        tarball.add_file(&rustfmt.tool_path, "bin", FileType::Executable);
1834        tarball.add_file(&cargofmt.tool_path, "bin", FileType::Executable);
1835        tarball.add_legal_and_readme_to("share/doc/rustfmt");
1836        Some(tarball.generate())
1837    }
1838
1839    fn metadata(&self) -> Option<StepMetadata> {
1840        Some(StepMetadata::dist("rustfmt", self.target).built_by(self.compilers.build_compiler()))
1841    }
1842}
1843
1844/// Extended archive that contains the compiler, standard library and a bunch of tools.
1845#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1846pub struct Extended {
1847    build_compiler: Compiler,
1848    target: TargetSelection,
1849}
1850
1851impl Step for Extended {
1852    type Output = ();
1853    const IS_HOST: bool = true;
1854
1855    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1856        run.alias("extended")
1857    }
1858
1859    fn is_default_step(builder: &Builder<'_>) -> bool {
1860        builder.config.extended
1861    }
1862
1863    fn make_run(run: RunConfig<'_>) {
1864        run.builder.ensure(Extended {
1865            build_compiler: run
1866                .builder
1867                .compiler(run.builder.top_stage - 1, run.builder.host_target),
1868            target: run.target,
1869        });
1870    }
1871
1872    /// Creates a combined installer for the specified target in the provided stage.
1873    fn run(self, builder: &Builder<'_>) {
1874        let target = self.target;
1875        builder.info(&format!("Dist extended stage{} ({target})", builder.top_stage));
1876
1877        let mut tarballs = Vec::new();
1878        let mut built_tools = HashSet::new();
1879        macro_rules! add_component {
1880            ($name:expr => $step:expr) => {
1881                if let Some(Some(tarball)) = builder.ensure_if_default($step, Kind::Dist) {
1882                    tarballs.push(tarball);
1883                    built_tools.insert($name);
1884                }
1885            };
1886        }
1887
1888        let rustc_private_compilers =
1889            RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target);
1890        let build_compiler = rustc_private_compilers.build_compiler();
1891        let target_compiler = rustc_private_compilers.target_compiler();
1892
1893        // When rust-std package split from rustc, we needed to ensure that during
1894        // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1895        // the std files during uninstall. To do this ensure that rustc comes
1896        // before rust-std in the list below.
1897        tarballs.push(builder.ensure(Rustc { target_compiler }));
1898        tarballs.push(builder.ensure(Std { build_compiler, target }).expect("missing std"));
1899
1900        if target.is_windows_gnu() || target.is_windows_gnullvm() {
1901            tarballs.push(builder.ensure(Mingw { target }).expect("missing mingw"));
1902        }
1903
1904        add_component!("rust-docs" => Docs { host: target });
1905        // Std stage N is documented with compiler stage N
1906        add_component!("rust-json-docs" => JsonDocs { build_compiler: target_compiler, target });
1907        add_component!("cargo" => Cargo { build_compiler, target });
1908        add_component!("rustfmt" => Rustfmt { compilers: rustc_private_compilers, target });
1909        add_component!("rust-analyzer" => RustAnalyzer { compilers: rustc_private_compilers, target });
1910        add_component!("llvm-components" => LlvmTools { target });
1911        add_component!("clippy" => Clippy { compilers: rustc_private_compilers, target });
1912        add_component!("miri" => Miri { compilers: rustc_private_compilers, target });
1913        add_component!("analysis" => Analysis { build_compiler, target });
1914        add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend {
1915            compilers: rustc_private_compilers,
1916            target
1917        });
1918        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {
1919            build_compiler,
1920            target
1921        });
1922
1923        let etc = builder.src.join("src/etc/installer");
1924
1925        // Avoid producing tarballs during a dry run.
1926        if builder.config.dry_run() {
1927            return;
1928        }
1929
1930        let tarball = Tarball::new(builder, "rust", &target.triple);
1931        let generated = tarball.combine(&tarballs);
1932
1933        let tmp = tmpdir(builder).join("combined-tarball");
1934        let work = generated.work_dir();
1935
1936        let mut license = String::new();
1937        license += &builder.read(&builder.src.join("COPYRIGHT"));
1938        license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1939        license += &builder.read(&builder.src.join("LICENSE-MIT"));
1940        license.push('\n');
1941        license.push('\n');
1942
1943        let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1944        let mut rtf = rtf.to_string();
1945        rtf.push('\n');
1946        for line in license.lines() {
1947            rtf.push_str(line);
1948            rtf.push_str("\\line ");
1949        }
1950        rtf.push('}');
1951
1952        fn filter(contents: &str, marker: &str) -> String {
1953            let start = format!("tool-{marker}-start");
1954            let end = format!("tool-{marker}-end");
1955            let mut lines = Vec::new();
1956            let mut omitted = false;
1957            for line in contents.lines() {
1958                if line.contains(&start) {
1959                    omitted = true;
1960                } else if line.contains(&end) {
1961                    omitted = false;
1962                } else if !omitted {
1963                    lines.push(line);
1964                }
1965            }
1966
1967            lines.join("\n")
1968        }
1969
1970        let xform = |p: &Path| {
1971            let mut contents = t!(fs::read_to_string(p));
1972            for tool in &["miri", "rust-docs"] {
1973                if !built_tools.contains(tool) {
1974                    contents = filter(&contents, tool);
1975                }
1976            }
1977            let ret = tmp.join(p.file_name().unwrap());
1978            t!(fs::write(&ret, &contents));
1979            ret
1980        };
1981
1982        if target.contains("apple-darwin") {
1983            builder.info("building pkg installer");
1984            let pkg = tmp.join("pkg");
1985            let _ = fs::remove_dir_all(&pkg);
1986
1987            let pkgbuild = |component: &str| {
1988                let mut cmd = command("pkgbuild");
1989                cmd.arg("--identifier")
1990                    .arg(format!("org.rust-lang.{component}"))
1991                    .arg("--scripts")
1992                    .arg(pkg.join(component))
1993                    .arg("--nopayload")
1994                    .arg(pkg.join(component).with_extension("pkg"));
1995                cmd.run(builder);
1996            };
1997
1998            let prepare = |name: &str| {
1999                builder.create_dir(&pkg.join(name));
2000                builder.cp_link_r(
2001                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)),
2002                    &pkg.join(name),
2003                );
2004                builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), FileType::Script);
2005                pkgbuild(name);
2006            };
2007            prepare("rustc");
2008            prepare("cargo");
2009            prepare("rust-std");
2010            prepare("rust-analysis");
2011
2012            for tool in &[
2013                "clippy",
2014                "rustfmt",
2015                "rust-analyzer",
2016                "rust-docs",
2017                "miri",
2018                "rustc-codegen-cranelift",
2019            ] {
2020                if built_tools.contains(tool) {
2021                    prepare(tool);
2022                }
2023            }
2024            // create an 'uninstall' package
2025            builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), FileType::Script);
2026            pkgbuild("uninstall");
2027
2028            builder.create_dir(&pkg.join("res"));
2029            builder.create(&pkg.join("res/LICENSE.txt"), &license);
2030            builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), FileType::Regular);
2031            let mut cmd = command("productbuild");
2032            cmd.arg("--distribution")
2033                .arg(xform(&etc.join("pkg/Distribution.xml")))
2034                .arg("--resources")
2035                .arg(pkg.join("res"))
2036                .arg(distdir(builder).join(format!(
2037                    "{}-{}.pkg",
2038                    pkgname(builder, "rust"),
2039                    target.triple
2040                )))
2041                .arg("--package-path")
2042                .arg(&pkg);
2043            let _time = timeit(builder);
2044            cmd.run(builder);
2045        }
2046
2047        if target.is_windows() {
2048            let exe = tmp.join("exe");
2049            let _ = fs::remove_dir_all(&exe);
2050
2051            let prepare = |name: &str| {
2052                builder.create_dir(&exe.join(name));
2053                let dir = if name == "rust-std" || name == "rust-analysis" {
2054                    format!("{}-{}", name, target.triple)
2055                } else if name == "rust-analyzer" {
2056                    "rust-analyzer-preview".to_string()
2057                } else if name == "clippy" {
2058                    "clippy-preview".to_string()
2059                } else if name == "rustfmt" {
2060                    "rustfmt-preview".to_string()
2061                } else if name == "miri" {
2062                    "miri-preview".to_string()
2063                } else if name == "rustc-codegen-cranelift" {
2064                    // FIXME add installer support for cg_clif once it is ready to be distributed on
2065                    // windows.
2066                    unreachable!("cg_clif shouldn't be built for windows");
2067                } else {
2068                    name.to_string()
2069                };
2070                builder.cp_link_r(
2071                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
2072                    &exe.join(name),
2073                );
2074                builder.remove(&exe.join(name).join("manifest.in"));
2075            };
2076            prepare("rustc");
2077            prepare("cargo");
2078            prepare("rust-analysis");
2079            prepare("rust-std");
2080            for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] {
2081                if built_tools.contains(tool) {
2082                    prepare(tool);
2083                }
2084            }
2085            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2086                prepare("rust-mingw");
2087            }
2088
2089            builder.install(&etc.join("gfx/rust-logo.ico"), &exe, FileType::Regular);
2090
2091            // Generate msi installer
2092            let wix_path = env::var_os("WIX")
2093                .expect("`WIX` environment variable must be set for generating MSI installer(s).");
2094            let wix = PathBuf::from(wix_path);
2095            let heat = wix.join("bin/heat.exe");
2096            let candle = wix.join("bin/candle.exe");
2097            let light = wix.join("bin/light.exe");
2098
2099            let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
2100            command(&heat)
2101                .current_dir(&exe)
2102                .arg("dir")
2103                .arg("rustc")
2104                .args(heat_flags)
2105                .arg("-cg")
2106                .arg("RustcGroup")
2107                .arg("-dr")
2108                .arg("Rustc")
2109                .arg("-var")
2110                .arg("var.RustcDir")
2111                .arg("-out")
2112                .arg(exe.join("RustcGroup.wxs"))
2113                .run(builder);
2114            if built_tools.contains("rust-docs") {
2115                command(&heat)
2116                    .current_dir(&exe)
2117                    .arg("dir")
2118                    .arg("rust-docs")
2119                    .args(heat_flags)
2120                    .arg("-cg")
2121                    .arg("DocsGroup")
2122                    .arg("-dr")
2123                    .arg("Docs")
2124                    .arg("-var")
2125                    .arg("var.DocsDir")
2126                    .arg("-out")
2127                    .arg(exe.join("DocsGroup.wxs"))
2128                    .arg("-t")
2129                    .arg(etc.join("msi/squash-components.xsl"))
2130                    .run(builder);
2131            }
2132            command(&heat)
2133                .current_dir(&exe)
2134                .arg("dir")
2135                .arg("cargo")
2136                .args(heat_flags)
2137                .arg("-cg")
2138                .arg("CargoGroup")
2139                .arg("-dr")
2140                .arg("Cargo")
2141                .arg("-var")
2142                .arg("var.CargoDir")
2143                .arg("-out")
2144                .arg(exe.join("CargoGroup.wxs"))
2145                .arg("-t")
2146                .arg(etc.join("msi/remove-duplicates.xsl"))
2147                .run(builder);
2148            command(&heat)
2149                .current_dir(&exe)
2150                .arg("dir")
2151                .arg("rust-std")
2152                .args(heat_flags)
2153                .arg("-cg")
2154                .arg("StdGroup")
2155                .arg("-dr")
2156                .arg("Std")
2157                .arg("-var")
2158                .arg("var.StdDir")
2159                .arg("-out")
2160                .arg(exe.join("StdGroup.wxs"))
2161                .run(builder);
2162            if built_tools.contains("rust-analyzer") {
2163                command(&heat)
2164                    .current_dir(&exe)
2165                    .arg("dir")
2166                    .arg("rust-analyzer")
2167                    .args(heat_flags)
2168                    .arg("-cg")
2169                    .arg("RustAnalyzerGroup")
2170                    .arg("-dr")
2171                    .arg("RustAnalyzer")
2172                    .arg("-var")
2173                    .arg("var.RustAnalyzerDir")
2174                    .arg("-out")
2175                    .arg(exe.join("RustAnalyzerGroup.wxs"))
2176                    .arg("-t")
2177                    .arg(etc.join("msi/remove-duplicates.xsl"))
2178                    .run(builder);
2179            }
2180            if built_tools.contains("clippy") {
2181                command(&heat)
2182                    .current_dir(&exe)
2183                    .arg("dir")
2184                    .arg("clippy")
2185                    .args(heat_flags)
2186                    .arg("-cg")
2187                    .arg("ClippyGroup")
2188                    .arg("-dr")
2189                    .arg("Clippy")
2190                    .arg("-var")
2191                    .arg("var.ClippyDir")
2192                    .arg("-out")
2193                    .arg(exe.join("ClippyGroup.wxs"))
2194                    .arg("-t")
2195                    .arg(etc.join("msi/remove-duplicates.xsl"))
2196                    .run(builder);
2197            }
2198            if built_tools.contains("rustfmt") {
2199                command(&heat)
2200                    .current_dir(&exe)
2201                    .arg("dir")
2202                    .arg("rustfmt")
2203                    .args(heat_flags)
2204                    .arg("-cg")
2205                    .arg("RustFmtGroup")
2206                    .arg("-dr")
2207                    .arg("RustFmt")
2208                    .arg("-var")
2209                    .arg("var.RustFmtDir")
2210                    .arg("-out")
2211                    .arg(exe.join("RustFmtGroup.wxs"))
2212                    .arg("-t")
2213                    .arg(etc.join("msi/remove-duplicates.xsl"))
2214                    .run(builder);
2215            }
2216            if built_tools.contains("miri") {
2217                command(&heat)
2218                    .current_dir(&exe)
2219                    .arg("dir")
2220                    .arg("miri")
2221                    .args(heat_flags)
2222                    .arg("-cg")
2223                    .arg("MiriGroup")
2224                    .arg("-dr")
2225                    .arg("Miri")
2226                    .arg("-var")
2227                    .arg("var.MiriDir")
2228                    .arg("-out")
2229                    .arg(exe.join("MiriGroup.wxs"))
2230                    .arg("-t")
2231                    .arg(etc.join("msi/remove-duplicates.xsl"))
2232                    .run(builder);
2233            }
2234            command(&heat)
2235                .current_dir(&exe)
2236                .arg("dir")
2237                .arg("rust-analysis")
2238                .args(heat_flags)
2239                .arg("-cg")
2240                .arg("AnalysisGroup")
2241                .arg("-dr")
2242                .arg("Analysis")
2243                .arg("-var")
2244                .arg("var.AnalysisDir")
2245                .arg("-out")
2246                .arg(exe.join("AnalysisGroup.wxs"))
2247                .arg("-t")
2248                .arg(etc.join("msi/remove-duplicates.xsl"))
2249                .run(builder);
2250            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2251                command(&heat)
2252                    .current_dir(&exe)
2253                    .arg("dir")
2254                    .arg("rust-mingw")
2255                    .args(heat_flags)
2256                    .arg("-cg")
2257                    .arg("GccGroup")
2258                    .arg("-dr")
2259                    .arg("Gcc")
2260                    .arg("-var")
2261                    .arg("var.GccDir")
2262                    .arg("-out")
2263                    .arg(exe.join("GccGroup.wxs"))
2264                    .run(builder);
2265            }
2266
2267            let candle = |input: &Path| {
2268                let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
2269                let arch = if target.contains("x86_64") { "x64" } else { "x86" };
2270                let mut cmd = command(&candle);
2271                cmd.current_dir(&exe)
2272                    .arg("-nologo")
2273                    .arg("-dRustcDir=rustc")
2274                    .arg("-dCargoDir=cargo")
2275                    .arg("-dStdDir=rust-std")
2276                    .arg("-dAnalysisDir=rust-analysis")
2277                    .arg("-arch")
2278                    .arg(arch)
2279                    .arg("-out")
2280                    .arg(&output)
2281                    .arg(input);
2282                add_env(builder, &mut cmd, target, &built_tools);
2283
2284                if built_tools.contains("clippy") {
2285                    cmd.arg("-dClippyDir=clippy");
2286                }
2287                if built_tools.contains("rustfmt") {
2288                    cmd.arg("-dRustFmtDir=rustfmt");
2289                }
2290                if built_tools.contains("rust-docs") {
2291                    cmd.arg("-dDocsDir=rust-docs");
2292                }
2293                if built_tools.contains("rust-analyzer") {
2294                    cmd.arg("-dRustAnalyzerDir=rust-analyzer");
2295                }
2296                if built_tools.contains("miri") {
2297                    cmd.arg("-dMiriDir=miri");
2298                }
2299                if target.is_windows_gnu() || target.is_windows_gnullvm() {
2300                    cmd.arg("-dGccDir=rust-mingw");
2301                }
2302                cmd.run(builder);
2303            };
2304            candle(&xform(&etc.join("msi/rust.wxs")));
2305            candle(&etc.join("msi/ui.wxs"));
2306            candle(&etc.join("msi/rustwelcomedlg.wxs"));
2307            candle("RustcGroup.wxs".as_ref());
2308            if built_tools.contains("rust-docs") {
2309                candle("DocsGroup.wxs".as_ref());
2310            }
2311            candle("CargoGroup.wxs".as_ref());
2312            candle("StdGroup.wxs".as_ref());
2313            if built_tools.contains("clippy") {
2314                candle("ClippyGroup.wxs".as_ref());
2315            }
2316            if built_tools.contains("rustfmt") {
2317                candle("RustFmtGroup.wxs".as_ref());
2318            }
2319            if built_tools.contains("miri") {
2320                candle("MiriGroup.wxs".as_ref());
2321            }
2322            if built_tools.contains("rust-analyzer") {
2323                candle("RustAnalyzerGroup.wxs".as_ref());
2324            }
2325            candle("AnalysisGroup.wxs".as_ref());
2326
2327            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2328                candle("GccGroup.wxs".as_ref());
2329            }
2330
2331            builder.create(&exe.join("LICENSE.rtf"), &rtf);
2332            builder.install(&etc.join("gfx/banner.bmp"), &exe, FileType::Regular);
2333            builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, FileType::Regular);
2334
2335            builder.info(&format!("building `msi` installer with {light:?}"));
2336            let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
2337            let mut cmd = command(&light);
2338            cmd.arg("-nologo")
2339                .arg("-ext")
2340                .arg("WixUIExtension")
2341                .arg("-ext")
2342                .arg("WixUtilExtension")
2343                .arg("-out")
2344                .arg(exe.join(&filename))
2345                .arg("rust.wixobj")
2346                .arg("ui.wixobj")
2347                .arg("rustwelcomedlg.wixobj")
2348                .arg("RustcGroup.wixobj")
2349                .arg("CargoGroup.wixobj")
2350                .arg("StdGroup.wixobj")
2351                .arg("AnalysisGroup.wixobj")
2352                .current_dir(&exe);
2353
2354            if built_tools.contains("clippy") {
2355                cmd.arg("ClippyGroup.wixobj");
2356            }
2357            if built_tools.contains("rustfmt") {
2358                cmd.arg("RustFmtGroup.wixobj");
2359            }
2360            if built_tools.contains("miri") {
2361                cmd.arg("MiriGroup.wixobj");
2362            }
2363            if built_tools.contains("rust-analyzer") {
2364                cmd.arg("RustAnalyzerGroup.wixobj");
2365            }
2366            if built_tools.contains("rust-docs") {
2367                cmd.arg("DocsGroup.wixobj");
2368            }
2369
2370            if target.is_windows_gnu() || target.is_windows_gnullvm() {
2371                cmd.arg("GccGroup.wixobj");
2372            }
2373            // ICE57 wrongly complains about the shortcuts
2374            cmd.arg("-sice:ICE57");
2375
2376            let _time = timeit(builder);
2377            cmd.run(builder);
2378
2379            if !builder.config.dry_run() {
2380                t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
2381            }
2382        }
2383    }
2384
2385    fn metadata(&self) -> Option<StepMetadata> {
2386        Some(StepMetadata::dist("extended", self.target).built_by(self.build_compiler))
2387    }
2388}
2389
2390fn add_env(
2391    builder: &Builder<'_>,
2392    cmd: &mut BootstrapCommand,
2393    target: TargetSelection,
2394    built_tools: &HashSet<&'static str>,
2395) {
2396    let mut parts = builder.version.split('.');
2397    cmd.env("CFG_RELEASE_INFO", builder.rust_version())
2398        .env("CFG_RELEASE_NUM", &builder.version)
2399        .env("CFG_RELEASE", builder.rust_release())
2400        .env("CFG_VER_MAJOR", parts.next().unwrap())
2401        .env("CFG_VER_MINOR", parts.next().unwrap())
2402        .env("CFG_VER_PATCH", parts.next().unwrap())
2403        .env("CFG_VER_BUILD", "0") // just needed to build
2404        .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
2405        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
2406        .env("CFG_BUILD", target.triple)
2407        .env("CFG_CHANNEL", &builder.config.channel);
2408
2409    if target.is_windows_gnullvm() {
2410        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
2411    } else if target.is_windows_gnu() {
2412        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
2413    } else {
2414        cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
2415    }
2416
2417    // ensure these variables are defined
2418    let mut define_optional_tool = |tool_name: &str, env_name: &str| {
2419        cmd.env(env_name, if built_tools.contains(tool_name) { "1" } else { "0" });
2420    };
2421    define_optional_tool("rustfmt", "CFG_RUSTFMT");
2422    define_optional_tool("clippy", "CFG_CLIPPY");
2423    define_optional_tool("miri", "CFG_MIRI");
2424    define_optional_tool("rust-analyzer", "CFG_RA");
2425}
2426
2427fn install_llvm_file(
2428    builder: &Builder<'_>,
2429    source: &Path,
2430    destination: &Path,
2431    install_symlink: bool,
2432) {
2433    if builder.config.dry_run() {
2434        return;
2435    }
2436
2437    if source.is_symlink() {
2438        // If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the
2439        // symlink, which is what will actually get loaded at runtime.
2440        builder.install(&t!(fs::canonicalize(source)), destination, FileType::NativeLibrary);
2441
2442        let full_dest = destination.join(source.file_name().unwrap());
2443        if install_symlink {
2444            // For download-ci-llvm, also install the symlink, to match what LLVM does. Using a
2445            // symlink is fine here, as this is not a rustup component.
2446            builder.copy_link(source, &full_dest, FileType::NativeLibrary);
2447        } else {
2448            // Otherwise, replace the symlink with an equivalent linker script. This is used when
2449            // projects like miri link against librustc_driver.so. We don't use a symlink, as
2450            // these are not allowed inside rustup components.
2451            let link = t!(fs::read_link(source));
2452            let mut linker_script = t!(fs::File::create(full_dest));
2453            t!(write!(linker_script, "INPUT({})\n", link.display()));
2454
2455            // We also want the linker script to have the same mtime as the source, otherwise it
2456            // can trigger rebuilds.
2457            let meta = t!(fs::metadata(source));
2458            if let Ok(mtime) = meta.modified() {
2459                t!(linker_script.set_modified(mtime));
2460            }
2461        }
2462    } else {
2463        builder.install(source, destination, FileType::NativeLibrary);
2464    }
2465}
2466
2467/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
2468///
2469/// Returns whether the files were actually copied.
2470#[cfg_attr(
2471    feature = "tracing",
2472    instrument(
2473        level = "trace",
2474        name = "maybe_install_llvm",
2475        skip_all,
2476        fields(target = ?target, dst_libdir = ?dst_libdir, install_symlink = install_symlink),
2477    ),
2478)]
2479fn maybe_install_llvm(
2480    builder: &Builder<'_>,
2481    target: TargetSelection,
2482    dst_libdir: &Path,
2483    install_symlink: bool,
2484) -> bool {
2485    // If the LLVM was externally provided, then we don't currently copy
2486    // artifacts into the sysroot. This is not necessarily the right
2487    // choice (in particular, it will require the LLVM dylib to be in
2488    // the linker's load path at runtime), but the common use case for
2489    // external LLVMs is distribution provided LLVMs, and in that case
2490    // they're usually in the standard search path (e.g., /usr/lib) and
2491    // copying them here is going to cause problems as we may end up
2492    // with the wrong files and isn't what distributions want.
2493    //
2494    // This behavior may be revisited in the future though.
2495    //
2496    // NOTE: this intentionally doesn't use `is_rust_llvm`; whether this is patched or not doesn't matter,
2497    // we only care if the shared object itself is managed by bootstrap.
2498    //
2499    // If the LLVM is coming from ourselves (just from CI) though, we
2500    // still want to install it, as it otherwise won't be available.
2501    if builder.config.is_system_llvm(target) {
2502        trace!("system LLVM requested, no install");
2503        return false;
2504    }
2505
2506    // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
2507    // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely
2508    // clear why this is the case, though. llvm-config will emit the versioned
2509    // paths and we don't want those in the sysroot (as we're expecting
2510    // unversioned paths).
2511    if target.contains("apple-darwin") && builder.llvm_link_shared() {
2512        let src_libdir = builder.llvm_out(target).join("lib");
2513        let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2514        if llvm_dylib_path.exists() {
2515            builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary);
2516        }
2517        !builder.config.dry_run()
2518    } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult {
2519        host_llvm_config, ..
2520    }) = llvm::prebuilt_llvm_config(builder, target, true)
2521    {
2522        trace!("LLVM already built, installing LLVM files");
2523        let mut cmd = command(host_llvm_config);
2524        cmd.cached();
2525        cmd.arg("--libfiles");
2526        builder.do_if_verbose(|| println!("running {cmd:?}"));
2527        let files = cmd.run_capture_stdout(builder).stdout();
2528        let build_llvm_out = &builder.llvm_out(builder.config.host_target);
2529        let target_llvm_out = &builder.llvm_out(target);
2530        for file in files.trim_end().split(' ') {
2531            // If we're not using a custom LLVM, make sure we package for the target.
2532            let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
2533                target_llvm_out.join(relative_path)
2534            } else {
2535                PathBuf::from(file)
2536            };
2537            install_llvm_file(builder, &file, dst_libdir, install_symlink);
2538        }
2539        !builder.config.dry_run()
2540    } else {
2541        false
2542    }
2543}
2544
2545/// Maybe add libLLVM.so to the target lib-dir for linking.
2546#[cfg_attr(
2547    feature = "tracing",
2548    instrument(
2549        level = "trace",
2550        name = "maybe_install_llvm_target",
2551        skip_all,
2552        fields(
2553            llvm_link_shared = ?builder.llvm_link_shared(),
2554            target = ?target,
2555            sysroot = ?sysroot,
2556        ),
2557    ),
2558)]
2559pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2560    let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
2561    // We do not need to copy LLVM files into the sysroot if it is not
2562    // dynamically linked; it is already included into librustc_llvm
2563    // statically.
2564    if builder.llvm_link_shared() {
2565        maybe_install_llvm(builder, target, &dst_libdir, false);
2566    }
2567}
2568
2569/// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
2570#[cfg_attr(
2571    feature = "tracing",
2572    instrument(
2573        level = "trace",
2574        name = "maybe_install_llvm_runtime",
2575        skip_all,
2576        fields(
2577            llvm_link_shared = ?builder.llvm_link_shared(),
2578            target = ?target,
2579            sysroot = ?sysroot,
2580        ),
2581    ),
2582)]
2583pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2584    let dst_libdir = sysroot.join(builder.libdir_relative(Compiler::new(1, target)));
2585    // We do not need to copy LLVM files into the sysroot if it is not
2586    // dynamically linked; it is already included into librustc_llvm
2587    // statically.
2588    if builder.llvm_link_shared() {
2589        maybe_install_llvm(builder, target, &dst_libdir, false);
2590    }
2591}
2592
2593#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2594pub struct LlvmTools {
2595    pub target: TargetSelection,
2596}
2597
2598impl Step for LlvmTools {
2599    type Output = Option<GeneratedTarball>;
2600    const IS_HOST: bool = true;
2601
2602    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2603        let mut run = run.alias("llvm-tools");
2604        for tool in LLVM_TOOLS {
2605            run = run.alias(tool);
2606        }
2607
2608        run
2609    }
2610
2611    fn is_default_step(builder: &Builder<'_>) -> bool {
2612        should_build_extended_tool(builder, "llvm-tools")
2613    }
2614
2615    fn make_run(run: RunConfig<'_>) {
2616        run.builder.ensure(LlvmTools { target: run.target });
2617    }
2618
2619    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2620        fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
2621            let mut tools = vec![];
2622
2623            for path in paths {
2624                let path = path.to_str().unwrap();
2625
2626                // Include all tools if path is 'llvm-tools'.
2627                if path == "llvm-tools" {
2628                    return LLVM_TOOLS.to_owned();
2629                }
2630
2631                for tool in LLVM_TOOLS {
2632                    if path == *tool {
2633                        tools.push(*tool);
2634                    }
2635                }
2636            }
2637
2638            // If no specific tool is requested, include all tools.
2639            if tools.is_empty() {
2640                tools = LLVM_TOOLS.to_owned();
2641            }
2642
2643            tools
2644        }
2645
2646        let target = self.target;
2647
2648        // Run only if a custom llvm-config is not used
2649        if let Some(config) = builder.config.target_config.get(&target)
2650            && !builder.config.llvm_from_ci
2651            && config.llvm_config.is_some()
2652        {
2653            builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
2654            return None;
2655        }
2656
2657        if !builder.config.dry_run() {
2658            builder.require_submodule("src/llvm-project", None);
2659        }
2660
2661        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2662
2663        let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
2664        tarball.set_overlay(OverlayKind::Llvm);
2665        tarball.is_preview(true);
2666
2667        if builder.config.llvm_tools_enabled {
2668            // Prepare the image directory
2669            let src_bindir = builder.llvm_out(target).join("bin");
2670            let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
2671            for tool in tools_to_install(&builder.paths) {
2672                let exe = src_bindir.join(exe(tool, target));
2673                // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
2674                if !exe.exists() && builder.config.llvm_from_ci {
2675                    eprintln!("{} does not exist; skipping copy", exe.display());
2676                    continue;
2677                }
2678
2679                tarball.add_file(&exe, &dst_bindir, FileType::Executable);
2680            }
2681        }
2682
2683        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2684        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2685        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2686        // compiler libraries.
2687        maybe_install_llvm_target(builder, target, tarball.image_dir());
2688
2689        Some(tarball.generate())
2690    }
2691}
2692
2693/// Distributes the `llvm-bitcode-linker` tool so that it can be used by a compiler whose host
2694/// is `target`.
2695#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2696pub struct LlvmBitcodeLinker {
2697    /// The linker will be compiled by this compiler.
2698    pub build_compiler: Compiler,
2699    /// The linker will by usable by rustc on this host.
2700    pub target: TargetSelection,
2701}
2702
2703impl Step for LlvmBitcodeLinker {
2704    type Output = Option<GeneratedTarball>;
2705    const IS_HOST: bool = true;
2706
2707    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2708        run.alias("llvm-bitcode-linker")
2709    }
2710
2711    fn is_default_step(builder: &Builder<'_>) -> bool {
2712        should_build_extended_tool(builder, "llvm-bitcode-linker")
2713    }
2714
2715    fn make_run(run: RunConfig<'_>) {
2716        run.builder.ensure(LlvmBitcodeLinker {
2717            build_compiler: tool::LlvmBitcodeLinker::get_build_compiler_for_target(
2718                run.builder,
2719                run.target,
2720            ),
2721            target: run.target,
2722        });
2723    }
2724
2725    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2726        let target = self.target;
2727
2728        let llbc_linker = builder
2729            .ensure(tool::LlvmBitcodeLinker::from_build_compiler(self.build_compiler, target));
2730
2731        let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
2732
2733        // Prepare the image directory
2734        let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple);
2735        tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
2736        tarball.is_preview(true);
2737
2738        tarball.add_file(&llbc_linker.tool_path, self_contained_bin_dir, FileType::Executable);
2739
2740        Some(tarball.generate())
2741    }
2742}
2743
2744/// Distributes the `enzyme` library so that it can be used by a compiler whose host
2745/// is `target`.
2746#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2747pub struct Enzyme {
2748    /// Enzyme will by usable by rustc on this host.
2749    pub target: TargetSelection,
2750}
2751
2752impl Step for Enzyme {
2753    type Output = Option<GeneratedTarball>;
2754    const IS_HOST: bool = true;
2755
2756    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2757        run.alias("enzyme")
2758    }
2759
2760    fn is_default_step(builder: &Builder<'_>) -> bool {
2761        builder.config.llvm_enzyme
2762    }
2763
2764    fn make_run(run: RunConfig<'_>) {
2765        run.builder.ensure(Enzyme { target: run.target });
2766    }
2767
2768    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2769        // This prevents Enzyme from being built for "dist"
2770        // or "install" on the stable/beta channels. It is not yet stable and
2771        // should not be included.
2772        if !builder.build.unstable_features() {
2773            return None;
2774        }
2775
2776        let target = self.target;
2777
2778        let enzyme = builder.ensure(llvm::Enzyme { target });
2779
2780        let target_libdir = format!("lib/rustlib/{}/lib", target.triple);
2781
2782        // Prepare the image directory
2783        let mut tarball = Tarball::new(builder, "enzyme", &target.triple);
2784        tarball.set_overlay(OverlayKind::Enzyme);
2785        tarball.is_preview(true);
2786
2787        tarball.add_file(enzyme.enzyme_path(), target_libdir, FileType::NativeLibrary);
2788
2789        Some(tarball.generate())
2790    }
2791}
2792
2793/// Tarball intended for internal consumption to ease rustc/std development.
2794///
2795/// Should not be considered stable by end users.
2796///
2797/// In practice, this is the tarball that gets downloaded and used by
2798/// `llvm.download-ci-llvm`.
2799///
2800/// (Don't confuse this with [`RustcDev`], with a `c`!)
2801#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2802pub struct RustDev {
2803    pub target: TargetSelection,
2804}
2805
2806impl Step for RustDev {
2807    type Output = Option<GeneratedTarball>;
2808    const IS_HOST: bool = true;
2809
2810    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2811        run.alias("rust-dev")
2812    }
2813
2814    fn is_default_step(_builder: &Builder<'_>) -> bool {
2815        true
2816    }
2817
2818    fn make_run(run: RunConfig<'_>) {
2819        run.builder.ensure(RustDev { target: run.target });
2820    }
2821
2822    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2823        let target = self.target;
2824
2825        /* run only if llvm-config isn't used */
2826        if let Some(config) = builder.config.target_config.get(&target)
2827            && let Some(ref _s) = config.llvm_config
2828        {
2829            builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
2830            return None;
2831        }
2832
2833        if !builder.config.dry_run() {
2834            builder.require_submodule("src/llvm-project", None);
2835        }
2836
2837        let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
2838        tarball.set_overlay(OverlayKind::Llvm);
2839        // LLVM requires a shared object symlink to exist on some platforms.
2840        tarball.permit_symlinks(true);
2841
2842        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2843
2844        let src_bindir = builder.llvm_out(target).join("bin");
2845        // If updating this, you likely want to change
2846        // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
2847        // will not pick up the extra file until LLVM gets bumped.
2848        // We should include all the build artifacts obtained from a source build,
2849        // so that you can use the downloadable LLVM as if you’ve just run a full source build.
2850        if src_bindir.exists() {
2851            for entry in walkdir::WalkDir::new(&src_bindir) {
2852                let entry = t!(entry);
2853                if entry.file_type().is_file() && !entry.path_is_symlink() {
2854                    let name = entry.file_name().to_str().unwrap();
2855                    tarball.add_file(src_bindir.join(name), "bin", FileType::Executable);
2856                }
2857            }
2858        }
2859
2860        if builder.config.lld_enabled {
2861            // We want to package `lld` to use it with `download-ci-llvm`.
2862            let lld_out = builder.ensure(crate::core::build_steps::llvm::Lld { target });
2863
2864            // We don't build LLD on some platforms, so only add it if it exists
2865            let lld_path = lld_out.join("bin").join(exe("lld", target));
2866            if lld_path.exists() {
2867                tarball.add_file(&lld_path, "bin", FileType::Executable);
2868            }
2869        }
2870
2871        tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable);
2872
2873        // Copy the include directory as well; needed mostly to build
2874        // librustc_llvm properly (e.g., llvm-config.h is in here). But also
2875        // just broadly useful to be able to link against the bundled LLVM.
2876        tarball.add_dir(builder.llvm_out(target).join("include"), "include");
2877
2878        // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2879        // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2880        // of `rustc-dev` to support the inherited `-lLLVM` when using the
2881        // compiler libraries.
2882        let dst_libdir = tarball.image_dir().join("lib");
2883        maybe_install_llvm(builder, target, &dst_libdir, true);
2884        let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
2885        t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
2886
2887        // Copy the `compiler-rt` source, so that `library/profiler_builtins`
2888        // can potentially use it to build the profiler runtime without needing
2889        // to check out the LLVM submodule.
2890        copy_src_dirs(
2891            builder,
2892            &builder.src.join("src").join("llvm-project"),
2893            &["compiler-rt"],
2894            // The test subdirectory is much larger than the rest of the source,
2895            // and we currently don't use these test files anyway.
2896            &["compiler-rt/test"],
2897            tarball.image_dir(),
2898        );
2899
2900        Some(tarball.generate())
2901    }
2902}
2903
2904/// Tarball intended for internal consumption to ease rustc/std development.
2905///
2906/// It only packages the binaries that were already compiled when bootstrap itself was built.
2907///
2908/// Should not be considered stable by end users.
2909#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2910pub struct Bootstrap {
2911    target: TargetSelection,
2912}
2913
2914impl Step for Bootstrap {
2915    type Output = Option<GeneratedTarball>;
2916
2917    const IS_HOST: bool = true;
2918
2919    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2920        run.alias("bootstrap")
2921    }
2922
2923    fn make_run(run: RunConfig<'_>) {
2924        run.builder.ensure(Bootstrap { target: run.target });
2925    }
2926
2927    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2928        let target = self.target;
2929
2930        let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2931
2932        let bootstrap_outdir = &builder.bootstrap_out;
2933        for file in &["bootstrap", "rustc", "rustdoc"] {
2934            tarball.add_file(
2935                bootstrap_outdir.join(exe(file, target)),
2936                "bootstrap/bin",
2937                FileType::Executable,
2938            );
2939        }
2940
2941        Some(tarball.generate())
2942    }
2943
2944    fn metadata(&self) -> Option<StepMetadata> {
2945        Some(StepMetadata::dist("bootstrap", self.target))
2946    }
2947}
2948
2949/// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
2950/// release process to avoid cloning the monorepo and building stuff.
2951///
2952/// Should not be considered stable by end users.
2953#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2954pub struct BuildManifest {
2955    target: TargetSelection,
2956}
2957
2958impl Step for BuildManifest {
2959    type Output = GeneratedTarball;
2960
2961    const IS_HOST: bool = true;
2962
2963    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2964        run.alias("build-manifest")
2965    }
2966
2967    fn make_run(run: RunConfig<'_>) {
2968        run.builder.ensure(BuildManifest { target: run.target });
2969    }
2970
2971    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
2972        // FIXME: Should BuildManifest actually be built for `self.target`?
2973        // Today CI only builds this step where that matches the host_target so it doesn't matter
2974        // today.
2975        let build_manifest =
2976            builder.ensure(tool::BuildManifest::new(builder, builder.config.host_target));
2977
2978        let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
2979        tarball.add_file(&build_manifest.tool_path, "bin", FileType::Executable);
2980        tarball.generate()
2981    }
2982
2983    fn metadata(&self) -> Option<StepMetadata> {
2984        Some(StepMetadata::dist("build-manifest", self.target))
2985    }
2986}
2987
2988/// Tarball containing artifacts necessary to reproduce the build of rustc.
2989///
2990/// Currently this is the PGO (and possibly BOLT) profile data.
2991///
2992/// Should not be considered stable by end users.
2993#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2994pub struct ReproducibleArtifacts {
2995    target: TargetSelection,
2996}
2997
2998impl Step for ReproducibleArtifacts {
2999    type Output = Option<GeneratedTarball>;
3000    const IS_HOST: bool = true;
3001
3002    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3003        run.alias("reproducible-artifacts")
3004    }
3005
3006    fn is_default_step(_builder: &Builder<'_>) -> bool {
3007        true
3008    }
3009
3010    fn make_run(run: RunConfig<'_>) {
3011        run.builder.ensure(ReproducibleArtifacts { target: run.target });
3012    }
3013
3014    fn run(self, builder: &Builder<'_>) -> Self::Output {
3015        let mut added_anything = false;
3016        let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
3017        if let Some(path) = builder.config.rust_profile_use.as_ref() {
3018            tarball.add_file(path, ".", FileType::Regular);
3019            added_anything = true;
3020        }
3021        if let Some(path) = builder.config.llvm_profile_use.as_ref() {
3022            tarball.add_file(path, ".", FileType::Regular);
3023            added_anything = true;
3024        }
3025        for profile in &builder.config.reproducible_artifacts {
3026            tarball.add_file(profile, ".", FileType::Regular);
3027            added_anything = true;
3028        }
3029        if added_anything { Some(tarball.generate()) } else { None }
3030    }
3031
3032    fn metadata(&self) -> Option<StepMetadata> {
3033        Some(StepMetadata::dist("reproducible-artifacts", self.target))
3034    }
3035}
3036
3037/// Tarball containing a prebuilt version of the libgccjit library,
3038/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
3039/// backend needing a prebuilt libLLVM).
3040///
3041/// This component is used for `download-ci-gcc`.
3042#[derive(Clone, Debug, Eq, Hash, PartialEq)]
3043pub struct GccDev {
3044    target: TargetSelection,
3045}
3046
3047impl Step for GccDev {
3048    type Output = GeneratedTarball;
3049
3050    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3051        run.alias("gcc-dev")
3052    }
3053
3054    fn make_run(run: RunConfig<'_>) {
3055        run.builder.ensure(GccDev { target: run.target });
3056    }
3057
3058    fn run(self, builder: &Builder<'_>) -> Self::Output {
3059        let tarball = Tarball::new(builder, "gcc-dev", &self.target.triple);
3060        let output = builder
3061            .ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) });
3062        tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary);
3063        tarball.generate()
3064    }
3065
3066    fn metadata(&self) -> Option<StepMetadata> {
3067        Some(StepMetadata::dist("gcc-dev", self.target))
3068    }
3069}
3070
3071/// Tarball containing a libgccjit dylib,
3072/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
3073/// backend needing a prebuilt libLLVM).
3074///
3075/// This component is used for distribution through rustup.
3076#[derive(Clone, Debug, Eq, Hash, PartialEq)]
3077pub struct Gcc {
3078    host: TargetSelection,
3079    target: TargetSelection,
3080}
3081
3082impl Step for Gcc {
3083    type Output = Option<GeneratedTarball>;
3084
3085    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3086        run.alias("gcc")
3087    }
3088
3089    fn make_run(run: RunConfig<'_>) {
3090        // GCC is always built for a target pair, (host, target).
3091        // We do not yet support cross-compilation here, so the host target is always inferred to
3092        // be the bootstrap host target.
3093        run.builder.ensure(Gcc { host: run.builder.host_target, target: run.target });
3094    }
3095
3096    fn run(self, builder: &Builder<'_>) -> Self::Output {
3097        // This prevents gcc from being built for "dist"
3098        // or "install" on the stable/beta channels. It is not yet stable and
3099        // should not be included.
3100        if !builder.build.unstable_features() {
3101            return None;
3102        }
3103
3104        let host = self.host;
3105        let target = self.target;
3106        if host != "x86_64-unknown-linux-gnu" {
3107            builder.info(&format!("host target `{host}` not supported by gcc. skipping"));
3108            return None;
3109        }
3110
3111        if builder.config.is_running_on_ci() {
3112            assert_eq!(
3113                builder.config.gcc_ci_mode,
3114                GccCiMode::BuildLocally,
3115                "Cannot use gcc.download-ci-gcc when distributing GCC on CI"
3116            );
3117        }
3118
3119        // We need the GCC sources to build GCC and also to add its license and README
3120        // files to the tarball
3121        builder.require_submodule(
3122            "src/gcc",
3123            Some("The src/gcc submodule is required for disting libgccjit"),
3124        );
3125
3126        let target_pair = GccTargetPair::for_target_pair(host, target);
3127        let libgccjit = builder.ensure(super::gcc::Gcc { target_pair });
3128
3129        // We have to include the target name in the component name, so that rustup can somehow
3130        // distinguish that there are multiple gcc components on a given host target.
3131        // So the tarball includes the target name.
3132        let mut tarball = Tarball::new(builder, &format!("gcc-{target}"), &host.triple);
3133        tarball.set_overlay(OverlayKind::Gcc);
3134        tarball.is_preview(true);
3135        tarball.add_legal_and_readme_to("share/doc/gcc");
3136
3137        // The path where to put libgccjit is determined by GccDylibSet.
3138        // However, it requires a Compiler to figure out the path to the codegen backend sysroot.
3139        // We don't really have any compiler here, because we just build libgccjit.
3140        // So we duplicate the logic for determining the CG sysroot here.
3141        let cg_dir = PathBuf::from(format!("lib/rustlib/{host}/codegen-backends"));
3142
3143        // This returns the path to the actual file, but here we need its parent
3144        let rel_libgccjit_path = libgccjit_path_relative_to_cg_dir(&target_pair, &libgccjit);
3145        let path = cg_dir.join(rel_libgccjit_path.parent().unwrap());
3146
3147        tarball.add_file(libgccjit.libgccjit(), path, FileType::NativeLibrary);
3148        Some(tarball.generate())
3149    }
3150
3151    fn metadata(&self) -> Option<StepMetadata> {
3152        Some(StepMetadata::dist(
3153            "gcc",
3154            TargetSelection::from_user(&format!("({}, {})", self.host, self.target)),
3155        ))
3156    }
3157}