1use 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::{get_codegen_backend_file, normalize_codegen_backend_name};
23use crate::core::build_steps::doc::DocumentationFormat;
24use crate::core::build_steps::tool::{
25    self, RustcPrivateCompilers, Tool, ToolTargetBuildMode, get_tool_target_compiler,
26};
27use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor};
28use crate::core::build_steps::{compile, llvm};
29use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata};
30use crate::core::config::TargetSelection;
31use crate::utils::build_stamp::{self, BuildStamp};
32use crate::utils::channel::{self, Info};
33use crate::utils::exec::{BootstrapCommand, command};
34use crate::utils::helpers::{
35    exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit,
36};
37use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
38use crate::{CodegenBackendKind, Compiler, DependencyType, FileType, LLVM_TOOLS, Mode, trace};
39
40pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
41    format!("{}-{}", component, builder.rust_package_vers())
42}
43
44pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf {
45    builder.out.join("dist")
46}
47
48pub fn tmpdir(builder: &Builder<'_>) -> PathBuf {
49    builder.out.join("tmp/dist")
50}
51
52fn should_build_extended_tool(builder: &Builder<'_>, tool: &str) -> bool {
53    if !builder.config.extended {
54        return false;
55    }
56    builder.config.tools.as_ref().is_none_or(|tools| tools.contains(tool))
57}
58
59#[derive(Debug, Clone, Hash, PartialEq, Eq)]
60pub struct Docs {
61    pub host: TargetSelection,
62}
63
64impl Step for Docs {
65    type Output = Option<GeneratedTarball>;
66    const DEFAULT: bool = true;
67
68    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
69        let default = run.builder.config.docs;
70        run.alias("rust-docs").default_condition(default)
71    }
72
73    fn make_run(run: RunConfig<'_>) {
74        run.builder.ensure(Docs { host: run.target });
75    }
76
77    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
79        let host = self.host;
80        builder.run_default_doc_steps();
84
85        let dest = "share/doc/rust/html";
86
87        let mut tarball = Tarball::new(builder, "rust-docs", &host.triple);
88        tarball.set_product_name("Rust Documentation");
89        tarball.add_bulk_dir(builder.doc_out(host), dest);
90        tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, FileType::Regular);
91        tarball.add_file(builder.src.join("src/doc/sitemap.txt"), dest, FileType::Regular);
92        Some(tarball.generate())
93    }
94
95    fn metadata(&self) -> Option<StepMetadata> {
96        Some(StepMetadata::dist("docs", self.host))
97    }
98}
99
100#[derive(Debug, Clone, Hash, PartialEq, Eq)]
103pub struct JsonDocs {
104    build_compiler: Compiler,
105    target: TargetSelection,
106}
107
108impl Step for JsonDocs {
109    type Output = Option<GeneratedTarball>;
110    const DEFAULT: bool = true;
111
112    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
113        let default = run.builder.config.docs;
114        run.alias("rust-docs-json").default_condition(default)
115    }
116
117    fn make_run(run: RunConfig<'_>) {
118        run.builder.ensure(JsonDocs {
119            build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
120            target: run.target,
121        });
122    }
123
124    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
125        let target = self.target;
126        let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
127            self.build_compiler,
128            target,
129            DocumentationFormat::Json,
130        ));
131
132        let dest = "share/doc/rust/json";
133
134        let mut tarball = Tarball::new(builder, "rust-docs-json", &target.triple);
135        tarball.set_product_name("Rust Documentation In JSON Format");
136        tarball.is_preview(true);
137        tarball.add_bulk_dir(directory, dest);
138        Some(tarball.generate())
139    }
140
141    fn metadata(&self) -> Option<StepMetadata> {
142        Some(StepMetadata::dist("json-docs", self.target).built_by(self.build_compiler))
143    }
144}
145
146#[derive(Debug, Clone, Hash, PartialEq, Eq)]
153pub struct RustcDocs {
154    target: TargetSelection,
155}
156
157impl Step for RustcDocs {
158    type Output = GeneratedTarball;
159
160    const DEFAULT: bool = true;
161    const IS_HOST: bool = true;
162
163    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
164        let builder = run.builder;
165        run.alias("rustc-docs").default_condition(builder.config.compiler_docs)
166    }
167
168    fn make_run(run: RunConfig<'_>) {
169        run.builder.ensure(RustcDocs { target: run.target });
170    }
171
172    fn run(self, builder: &Builder<'_>) -> Self::Output {
173        let target = self.target;
174        builder.run_default_doc_steps();
175
176        let mut tarball = Tarball::new(builder, "rustc-docs", &target.triple);
177        tarball.set_product_name("Rustc Documentation");
178        tarball.add_bulk_dir(builder.compiler_doc_out(target), "share/doc/rust/html/rustc");
179        tarball.generate()
180    }
181}
182
183fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
184    let mut found = Vec::with_capacity(files.len());
185
186    for file in files {
187        let file_path = path.iter().map(|dir| dir.join(file)).find(|p| p.exists());
188
189        if let Some(file_path) = file_path {
190            found.push(file_path);
191        } else {
192            panic!("Could not find '{file}' in {path:?}");
193        }
194    }
195
196    found
197}
198
199fn make_win_dist(plat_root: &Path, target: TargetSelection, builder: &Builder<'_>) {
200    if builder.config.dry_run() {
201        return;
202    }
203
204    let (bin_path, lib_path) = get_cc_search_dirs(target, builder);
205
206    let compiler = if target == "i686-pc-windows-gnu" {
207        "i686-w64-mingw32-gcc.exe"
208    } else if target == "x86_64-pc-windows-gnu" {
209        "x86_64-w64-mingw32-gcc.exe"
210    } else {
211        "gcc.exe"
212    };
213    let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
214
215    let target_libs = [
218        "libgcc.a",
220        "libgcc_eh.a",
221        "libgcc_s.a",
222        "libm.a",
223        "libmingw32.a",
224        "libmingwex.a",
225        "libstdc++.a",
226        "libiconv.a",
227        "libmoldname.a",
228        "libpthread.a",
229        "libadvapi32.a",
234        "libbcrypt.a",
235        "libcomctl32.a",
236        "libcomdlg32.a",
237        "libcredui.a",
238        "libcrypt32.a",
239        "libdbghelp.a",
240        "libgdi32.a",
241        "libimagehlp.a",
242        "libiphlpapi.a",
243        "libkernel32.a",
244        "libmsimg32.a",
245        "libmsvcrt.a",
246        "libntdll.a",
247        "libodbc32.a",
248        "libole32.a",
249        "liboleaut32.a",
250        "libopengl32.a",
251        "libpsapi.a",
252        "librpcrt4.a",
253        "libsecur32.a",
254        "libsetupapi.a",
255        "libshell32.a",
256        "libsynchronization.a",
257        "libuser32.a",
258        "libuserenv.a",
259        "libuuid.a",
260        "libwinhttp.a",
261        "libwinmm.a",
262        "libwinspool.a",
263        "libws2_32.a",
264        "libwsock32.a",
265    ];
266
267    let target_tools = find_files(&target_tools, &bin_path);
269    let target_libs = find_files(&target_libs, &lib_path);
270
271    let plat_target_bin_self_contained_dir =
273        plat_root.join("lib/rustlib").join(target).join("bin/self-contained");
274    fs::create_dir_all(&plat_target_bin_self_contained_dir)
275        .expect("creating plat_target_bin_self_contained_dir failed");
276    for src in target_tools {
277        builder.copy_link_to_folder(&src, &plat_target_bin_self_contained_dir);
278    }
279
280    builder.create(
282        &plat_target_bin_self_contained_dir.join("GCC-WARNING.txt"),
283        "gcc.exe contained in this folder cannot be used for compiling C files - it is only \
284         used as a linker. In order to be able to compile projects containing C code use \
285         the GCC provided by MinGW or Cygwin.",
286    );
287
288    let plat_target_lib_self_contained_dir =
290        plat_root.join("lib/rustlib").join(target).join("lib/self-contained");
291    fs::create_dir_all(&plat_target_lib_self_contained_dir)
292        .expect("creating plat_target_lib_self_contained_dir failed");
293    for src in target_libs {
294        builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir);
295    }
296}
297
298fn runtime_dll_dist(rust_root: &Path, target: TargetSelection, builder: &Builder<'_>) {
299    if builder.config.dry_run() {
300        return;
301    }
302
303    let (bin_path, libs_path) = get_cc_search_dirs(target, builder);
304
305    let mut rustc_dlls = vec![];
306    if target.ends_with("windows-gnu") {
308        rustc_dlls.push("libwinpthread-1.dll");
309        if target.starts_with("i686-") {
310            rustc_dlls.push("libgcc_s_dw2-1.dll");
311        } else {
312            rustc_dlls.push("libgcc_s_seh-1.dll");
313        }
314    } else if target.ends_with("windows-gnullvm") {
315        rustc_dlls.push("libunwind.dll");
316    } else {
317        panic!("Vendoring of runtime DLLs for `{target}` is not supported`");
318    }
319    let bin_path = if target.ends_with("windows-gnullvm") && builder.host_target != target {
321        bin_path
322            .into_iter()
323            .chain(libs_path.iter().map(|path| path.with_file_name("bin")))
324            .collect()
325    } else {
326        bin_path
327    };
328    let rustc_dlls = find_files(&rustc_dlls, &bin_path);
329
330    let rust_bin_dir = rust_root.join("bin/");
332    fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed");
333    for src in &rustc_dlls {
334        builder.copy_link_to_folder(src, &rust_bin_dir);
335    }
336
337    if builder.config.lld_enabled {
338        let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin");
340        fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed");
341        for src in &rustc_dlls {
342            builder.copy_link_to_folder(src, &rust_target_bin_dir);
343        }
344    }
345}
346
347fn get_cc_search_dirs(
348    target: TargetSelection,
349    builder: &Builder<'_>,
350) -> (Vec<PathBuf>, Vec<PathBuf>) {
351    let mut cmd = command(builder.cc(target));
353    cmd.arg("-print-search-dirs");
354    let gcc_out = cmd.run_capture_stdout(builder).stdout();
355
356    let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
357    let mut lib_path = Vec::new();
358
359    for line in gcc_out.lines() {
360        let idx = line.find(':').unwrap();
361        let key = &line[..idx];
362        let trim_chars: &[_] = &[' ', '='];
363        let value = env::split_paths(line[(idx + 1)..].trim_start_matches(trim_chars));
364
365        if key == "programs" {
366            bin_path.extend(value);
367        } else if key == "libraries" {
368            lib_path.extend(value);
369        }
370    }
371    (bin_path, lib_path)
372}
373
374#[derive(Debug, Clone, Hash, PartialEq, Eq)]
379pub struct Mingw {
380    target: TargetSelection,
381}
382
383impl Step for Mingw {
384    type Output = Option<GeneratedTarball>;
385    const DEFAULT: bool = true;
386
387    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
388        run.alias("rust-mingw")
389    }
390
391    fn make_run(run: RunConfig<'_>) {
392        run.builder.ensure(Mingw { target: run.target });
393    }
394
395    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
396        let target = self.target;
397        if !target.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker {
398            return None;
399        }
400
401        let mut tarball = Tarball::new(builder, "rust-mingw", &target.triple);
402        tarball.set_product_name("Rust MinGW");
403
404        make_win_dist(tarball.image_dir(), target, builder);
405
406        Some(tarball.generate())
407    }
408
409    fn metadata(&self) -> Option<StepMetadata> {
410        Some(StepMetadata::dist("mingw", self.target))
411    }
412}
413
414#[derive(Debug, Clone, Hash, PartialEq, Eq)]
424pub struct Rustc {
425    pub target_compiler: Compiler,
427}
428
429impl Step for Rustc {
430    type Output = GeneratedTarball;
431
432    const DEFAULT: bool = true;
433    const IS_HOST: bool = true;
434
435    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
436        run.alias("rustc")
437    }
438
439    fn make_run(run: RunConfig<'_>) {
440        run.builder.ensure(Rustc {
441            target_compiler: run.builder.compiler(run.builder.top_stage, run.target),
442        });
443    }
444
445    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
446        let target_compiler = self.target_compiler;
447        let target = self.target_compiler.host;
448
449        let tarball = Tarball::new(builder, "rustc", &target.triple);
450
451        prepare_image(builder, target_compiler, tarball.image_dir());
453
454        if target.contains("pc-windows-gnu") && builder.config.dist_include_mingw_linker {
462            runtime_dll_dist(tarball.image_dir(), target, builder);
463            tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
464        }
465
466        return tarball.generate();
467
468        fn prepare_image(builder: &Builder<'_>, target_compiler: Compiler, image: &Path) {
469            let target = target_compiler.host;
470            let src = builder.sysroot(target_compiler);
471
472            t!(fs::create_dir_all(image.join("bin")));
474            builder.cp_link_r(&src.join("bin"), &image.join("bin"));
475
476            if builder
478                .config
479                .tools
480                .as_ref()
481                .is_none_or(|tools| tools.iter().any(|tool| tool == "rustdoc"))
482            {
483                let rustdoc = builder.rustdoc_for_compiler(target_compiler);
484                builder.install(&rustdoc, &image.join("bin"), FileType::Executable);
485            }
486
487            let compilers = RustcPrivateCompilers::from_target_compiler(builder, target_compiler);
488
489            if let Some(ra_proc_macro_srv) = builder.ensure_if_default(
490                tool::RustAnalyzerProcMacroSrv::from_compilers(compilers),
491                builder.kind,
492            ) {
493                let dst = image.join("libexec");
494                builder.install(&ra_proc_macro_srv.tool_path, &dst, FileType::Executable);
495            }
496
497            let libdir_relative = builder.libdir_relative(target_compiler);
498
499            if libdir_relative.to_str() != Some("bin") {
501                let libdir = builder.rustc_libdir(target_compiler);
502                for entry in builder.read_dir(&libdir) {
503                    if is_dylib(&entry.path())
509                        && !entry
510                            .path()
511                            .file_name()
512                            .and_then(|n| n.to_str())
513                            .map(|n| n.contains("libgccjit"))
514                            .unwrap_or(false)
515                    {
516                        builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary);
519                    }
520                }
521            }
522
523            maybe_install_llvm_runtime(builder, target, image);
529
530            let dst_dir = image.join("lib/rustlib").join(target).join("bin");
531            t!(fs::create_dir_all(&dst_dir));
532
533            if builder.config.lld_enabled {
535                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
536                let rust_lld = exe("rust-lld", target_compiler.host);
537                builder.copy_link(
538                    &src_dir.join(&rust_lld),
539                    &dst_dir.join(&rust_lld),
540                    FileType::Executable,
541                );
542                let self_contained_lld_src_dir = src_dir.join("gcc-ld");
543                let self_contained_lld_dst_dir = dst_dir.join("gcc-ld");
544                t!(fs::create_dir(&self_contained_lld_dst_dir));
545                for name in crate::LLD_FILE_NAMES {
546                    let exe_name = exe(name, target_compiler.host);
547                    builder.copy_link(
548                        &self_contained_lld_src_dir.join(&exe_name),
549                        &self_contained_lld_dst_dir.join(&exe_name),
550                        FileType::Executable,
551                    );
552                }
553            }
554
555            if builder.config.llvm_enabled(target_compiler.host)
556                && builder.config.llvm_tools_enabled
557            {
558                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
559                let llvm_objcopy = exe("llvm-objcopy", target_compiler.host);
560                let rust_objcopy = exe("rust-objcopy", target_compiler.host);
561                builder.copy_link(
562                    &src_dir.join(&llvm_objcopy),
563                    &dst_dir.join(&rust_objcopy),
564                    FileType::Executable,
565                );
566            }
567
568            if builder.tool_enabled("wasm-component-ld") {
569                let src_dir = builder.sysroot_target_bindir(target_compiler, target);
570                let ld = exe("wasm-component-ld", target_compiler.host);
571                builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld), FileType::Executable);
572            }
573
574            t!(fs::create_dir_all(image.join("share/man/man1")));
576            let man_src = builder.src.join("src/doc/man");
577            let man_dst = image.join("share/man/man1");
578
579            for file_entry in builder.read_dir(&man_src) {
582                let page_src = file_entry.path();
583                let page_dst = man_dst.join(file_entry.file_name());
584                let src_text = t!(std::fs::read_to_string(&page_src));
585                let new_text = src_text.replace("<INSERT VERSION HERE>", &builder.version);
586                t!(std::fs::write(&page_dst, &new_text));
587                t!(fs::copy(&page_src, &page_dst));
588            }
589
590            builder.ensure(DebuggerScripts { sysroot: image.to_owned(), target });
592
593            generate_target_spec_json_schema(builder, image);
594
595            let file_list = builder.ensure(super::run::GenerateCopyright);
597            for file in file_list {
598                builder.install(&file, &image.join("share/doc/rust"), FileType::Regular);
599            }
600
601            builder.install(
603                &builder.src.join("README.md"),
604                &image.join("share/doc/rust"),
605                FileType::Regular,
606            );
607
608            let license = |path: &Path| {
610                builder.install(path, &image.join("share/doc/rust/licenses"), FileType::Regular);
611            };
612            for entry in t!(std::fs::read_dir(builder.src.join("LICENSES"))).flatten() {
613                license(&entry.path());
614            }
615        }
616    }
617
618    fn metadata(&self) -> Option<StepMetadata> {
619        Some(StepMetadata::dist("rustc", self.target_compiler.host))
620    }
621}
622
623fn generate_target_spec_json_schema(builder: &Builder<'_>, sysroot: &Path) {
624    let stage1_host = builder.compiler(1, builder.host_target);
628    let mut rustc = builder.rustc_cmd(stage1_host).fail_fast();
629    rustc
630        .env("RUSTC_BOOTSTRAP", "1")
631        .args(["--print=target-spec-json-schema", "-Zunstable-options"]);
632    let schema = rustc.run_capture(builder).stdout();
633
634    let schema_dir = tmpdir(builder);
635    t!(fs::create_dir_all(&schema_dir));
636    let schema_file = schema_dir.join("target-spec-json-schema.json");
637    t!(std::fs::write(&schema_file, schema));
638
639    let dst = sysroot.join("etc");
640    t!(fs::create_dir_all(&dst));
641
642    builder.install(&schema_file, &dst, FileType::Regular);
643}
644
645#[derive(Debug, Clone, Hash, PartialEq, Eq)]
647pub struct DebuggerScripts {
648    pub sysroot: PathBuf,
650    pub target: TargetSelection,
651}
652
653impl Step for DebuggerScripts {
654    type Output = ();
655
656    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
657        run.never()
658    }
659
660    fn run(self, builder: &Builder<'_>) {
661        let target = self.target;
662        let sysroot = self.sysroot;
663        let dst = sysroot.join("lib/rustlib/etc");
664        t!(fs::create_dir_all(&dst));
665        let cp_debugger_script = |file: &str| {
666            builder.install(&builder.src.join("src/etc/").join(file), &dst, FileType::Regular);
667        };
668        if target.contains("windows-msvc") {
669            builder.install(
671                &builder.src.join("src/etc/rust-windbg.cmd"),
672                &sysroot.join("bin"),
673                FileType::Script,
674            );
675
676            cp_debugger_script("natvis/intrinsic.natvis");
677            cp_debugger_script("natvis/liballoc.natvis");
678            cp_debugger_script("natvis/libcore.natvis");
679            cp_debugger_script("natvis/libstd.natvis");
680        }
681
682        cp_debugger_script("rust_types.py");
683
684        builder.install(
686            &builder.src.join("src/etc/rust-gdb"),
687            &sysroot.join("bin"),
688            FileType::Script,
689        );
690        builder.install(
691            &builder.src.join("src/etc/rust-gdbgui"),
692            &sysroot.join("bin"),
693            FileType::Script,
694        );
695
696        cp_debugger_script("gdb_load_rust_pretty_printers.py");
697        cp_debugger_script("gdb_lookup.py");
698        cp_debugger_script("gdb_providers.py");
699
700        builder.install(
702            &builder.src.join("src/etc/rust-lldb"),
703            &sysroot.join("bin"),
704            FileType::Script,
705        );
706
707        cp_debugger_script("lldb_lookup.py");
708        cp_debugger_script("lldb_providers.py");
709        cp_debugger_script("lldb_commands")
710    }
711}
712
713fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
714    if !builder.config.is_host_target(compiler.host) {
717        builder.info("\tskipping, not a build host");
718        true
719    } else {
720        false
721    }
722}
723
724fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &BuildStamp) {
728    if !target.ends_with("-uefi") {
729        return;
730    }
731
732    for (path, _) in builder.read_stamp_file(stamp) {
733        if path.extension() != Some(OsStr::new("rlib")) {
734            continue;
735        }
736
737        let data = t!(fs::read(&path));
738        let data = data.as_slice();
739        let archive = t!(ArchiveFile::parse(data));
740        for member in archive.members() {
741            let member = t!(member);
742            let member_data = t!(member.data(data));
743
744            let is_coff = match object::File::parse(member_data) {
745                Ok(member_file) => member_file.format() == BinaryFormat::Coff,
746                Err(_) => false,
747            };
748
749            if !is_coff {
750                let member_name = String::from_utf8_lossy(member.name());
751                panic!("member {} in {} is not COFF", member_name, path.display());
752            }
753        }
754    }
755}
756
757fn copy_target_libs(
759    builder: &Builder<'_>,
760    target: TargetSelection,
761    image: &Path,
762    stamp: &BuildStamp,
763) {
764    let dst = image.join("lib/rustlib").join(target).join("lib");
765    let self_contained_dst = dst.join("self-contained");
766    t!(fs::create_dir_all(&dst));
767    t!(fs::create_dir_all(&self_contained_dst));
768    for (path, dependency_type) in builder.read_stamp_file(stamp) {
769        if dependency_type == DependencyType::TargetSelfContained {
770            builder.copy_link(
771                &path,
772                &self_contained_dst.join(path.file_name().unwrap()),
773                FileType::NativeLibrary,
774            );
775        } else if dependency_type == DependencyType::Target || builder.config.is_host_target(target)
776        {
777            builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary);
778        }
779    }
780}
781
782#[derive(Debug, Clone, Hash, PartialEq, Eq)]
789pub struct Std {
790    pub build_compiler: Compiler,
792    pub target: TargetSelection,
793}
794
795impl Std {
796    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
797        Std { build_compiler: builder.compiler_for_std(builder.top_stage), target }
798    }
799}
800
801impl Step for Std {
802    type Output = Option<GeneratedTarball>;
803    const DEFAULT: bool = true;
804
805    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
806        run.alias("rust-std")
807    }
808
809    fn make_run(run: RunConfig<'_>) {
810        run.builder.ensure(Std::new(run.builder, run.target));
811    }
812
813    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
814        let build_compiler = self.build_compiler;
815        let target = self.target;
816
817        if skip_host_target_lib(builder, build_compiler) {
818            return None;
819        }
820
821        let stamp =
824            builder.std(build_compiler, target).expect("Standard library has to be built for dist");
825
826        let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
827        tarball.include_target_in_component_name(true);
828
829        verify_uefi_rlib_format(builder, target, &stamp);
830        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
831
832        Some(tarball.generate())
833    }
834
835    fn metadata(&self) -> Option<StepMetadata> {
836        Some(StepMetadata::dist("std", self.target).built_by(self.build_compiler))
837    }
838}
839
840#[derive(Debug, Clone, Hash, PartialEq, Eq)]
845pub struct RustcDev {
846    build_compiler: Compiler,
848    target: TargetSelection,
849}
850
851impl RustcDev {
852    pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
853        Self {
854            build_compiler: builder.compiler(1, builder.config.host_target),
858            target,
859        }
860    }
861}
862
863impl Step for RustcDev {
864    type Output = Option<GeneratedTarball>;
865    const DEFAULT: bool = true;
866    const IS_HOST: bool = true;
867
868    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
869        run.alias("rustc-dev")
870    }
871
872    fn make_run(run: RunConfig<'_>) {
873        run.builder.ensure(RustcDev::new(run.builder, run.target));
874    }
875
876    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
877        let build_compiler = self.build_compiler;
878        let target = self.target;
879        if skip_host_target_lib(builder, build_compiler) {
880            return None;
881        }
882
883        builder.ensure(compile::Rustc::new(build_compiler, target));
885
886        let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
887
888        let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);
889        copy_target_libs(builder, target, tarball.image_dir(), &stamp);
890
891        let src_files = &["Cargo.lock"];
892        copy_src_dirs(
895            builder,
896            &builder.src,
897            &["compiler", "library/proc_macro"],
899            &[],
900            &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
901        );
902        for file in src_files {
903            tarball.add_file(
904                builder.src.join(file),
905                "lib/rustlib/rustc-src/rust",
906                FileType::Regular,
907            );
908        }
909
910        Some(tarball.generate())
911    }
912
913    fn metadata(&self) -> Option<StepMetadata> {
914        Some(StepMetadata::dist("rustc-dev", self.target).built_by(self.build_compiler))
915    }
916}
917
918#[derive(Debug, Clone, Hash, PartialEq, Eq)]
923pub struct Analysis {
924    build_compiler: Compiler,
925    target: TargetSelection,
926}
927
928impl Step for Analysis {
929    type Output = Option<GeneratedTarball>;
930
931    const DEFAULT: bool = true;
932
933    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
934        let default = should_build_extended_tool(run.builder, "analysis");
935        run.alias("rust-analysis").default_condition(default)
936    }
937
938    fn make_run(run: RunConfig<'_>) {
939        run.builder.ensure(Analysis {
941            build_compiler: run.builder.compiler(1, run.builder.config.host_target),
942            target: run.target,
943        });
944    }
945
946    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
947        let compiler = self.build_compiler;
948        let target = self.target;
949        if skip_host_target_lib(builder, compiler) {
950            return None;
951        }
952
953        let src = builder
954            .stage_out(compiler, Mode::Std)
955            .join(target)
956            .join(builder.cargo_dir())
957            .join("deps")
958            .join("save-analysis");
959
960        t!(std::fs::create_dir_all(&src));
962        let mut removed = src.clone();
963        removed.push("removed.json");
964        let mut f = t!(std::fs::File::create(removed));
965        t!(write!(f, r#"{{ "warning": "The `rust-analysis` component has been removed." }}"#));
966
967        let mut tarball = Tarball::new(builder, "rust-analysis", &target.triple);
968        tarball.include_target_in_component_name(true);
969        tarball.add_dir(src, format!("lib/rustlib/{}/analysis", target.triple));
970        Some(tarball.generate())
971    }
972
973    fn metadata(&self) -> Option<StepMetadata> {
974        Some(StepMetadata::dist("analysis", self.target).built_by(self.build_compiler))
975    }
976}
977
978fn copy_src_dirs(
981    builder: &Builder<'_>,
982    base: &Path,
983    src_dirs: &[&str],
984    exclude_dirs: &[&str],
985    dst_dir: &Path,
986) {
987    for src_dir in src_dirs {
990        assert!(Path::new(src_dir).is_relative());
991    }
992
993    if builder.config.dry_run() {
996        return;
997    }
998
999    fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
1000        let spath = match path.to_str() {
1002            Some(path) => path,
1003            None => return false,
1004        };
1005        if spath.ends_with('~') || spath.ends_with(".pyc") {
1006            return false;
1007        }
1008        let spath = spath.replace("\\", "/");
1010
1011        static LLVM_PROJECTS: &[&str] = &[
1012            "llvm-project/clang",
1013            "llvm-project/libunwind",
1014            "llvm-project/lld",
1015            "llvm-project/lldb",
1016            "llvm-project/llvm",
1017            "llvm-project/compiler-rt",
1018            "llvm-project/cmake",
1019            "llvm-project/runtimes",
1020            "llvm-project/third-party",
1021        ];
1022        if spath.starts_with("llvm-project") && spath != "llvm-project" {
1023            if !LLVM_PROJECTS.iter().any(|path| spath.starts_with(path)) {
1024                return false;
1025            }
1026
1027            if spath.starts_with("llvm-project/third-party")
1029                && spath != "llvm-project/third-party"
1030                && !spath.starts_with("llvm-project/third-party/siphash")
1031            {
1032                return false;
1033            }
1034
1035            if spath.starts_with("llvm-project/llvm/test")
1036                && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
1037            {
1038                return false;
1039            }
1040        }
1041
1042        if spath.starts_with("tools/cargo/tests") {
1044            return true;
1045        }
1046
1047        if !exclude_dirs.is_empty() {
1048            let full_path = Path::new(dir).join(path);
1049            if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
1050                return false;
1051            }
1052        }
1053
1054        static EXCLUDES: &[&str] = &[
1055            "CVS",
1056            "RCS",
1057            "SCCS",
1058            ".git",
1059            ".gitignore",
1060            ".gitmodules",
1061            ".gitattributes",
1062            ".cvsignore",
1063            ".svn",
1064            ".arch-ids",
1065            "{arch}",
1066            "=RELEASE-ID",
1067            "=meta-update",
1068            "=update",
1069            ".bzr",
1070            ".bzrignore",
1071            ".bzrtags",
1072            ".hg",
1073            ".hgignore",
1074            ".hgrags",
1075            "_darcs",
1076        ];
1077
1078        let last_component = path.iter().next_back().map(|s| s.to_str().unwrap()).unwrap();
1085        !EXCLUDES.contains(&last_component)
1086    }
1087
1088    for item in src_dirs {
1090        let dst = &dst_dir.join(item);
1091        t!(fs::create_dir_all(dst));
1092        builder
1093            .cp_link_filtered(&base.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
1094    }
1095}
1096
1097#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1098pub struct Src;
1099
1100impl Step for Src {
1101    type Output = GeneratedTarball;
1103    const DEFAULT: bool = true;
1104    const IS_HOST: bool = true;
1105
1106    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1107        run.alias("rust-src")
1108    }
1109
1110    fn make_run(run: RunConfig<'_>) {
1111        run.builder.ensure(Src);
1112    }
1113
1114    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1116        if !builder.config.dry_run() {
1117            builder.require_submodule("src/llvm-project", None);
1118        }
1119
1120        let tarball = Tarball::new_targetless(builder, "rust-src");
1121
1122        let dst_src = tarball.image_dir().join("lib/rustlib/src/rust");
1130
1131        copy_src_dirs(
1134            builder,
1135            &builder.src,
1136            &["library", "src/llvm-project/libunwind"],
1137            &[
1138                "library/backtrace/crates",
1141                "library/stdarch/Cargo.toml",
1144                "library/stdarch/crates/stdarch-verify",
1145                "library/stdarch/crates/intrinsic-test",
1146            ],
1147            &dst_src,
1148        );
1149
1150        tarball.generate()
1151    }
1152
1153    fn metadata(&self) -> Option<StepMetadata> {
1154        Some(StepMetadata::dist("src", TargetSelection::default()))
1155    }
1156}
1157
1158#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1159pub struct PlainSourceTarball;
1160
1161impl Step for PlainSourceTarball {
1162    type Output = GeneratedTarball;
1164    const DEFAULT: bool = true;
1165    const IS_HOST: bool = true;
1166
1167    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1168        let builder = run.builder;
1169        run.alias("rustc-src").default_condition(builder.config.rust_dist_src)
1170    }
1171
1172    fn make_run(run: RunConfig<'_>) {
1173        run.builder.ensure(PlainSourceTarball);
1174    }
1175
1176    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
1178        let mut tarball = Tarball::new(builder, "rustc", "src");
1183        tarball.permit_symlinks(true);
1184        let plain_dst_src = tarball.image_dir();
1185
1186        let src_files = [
1188            ".gitmodules",
1190            "CONTRIBUTING.md",
1191            "COPYRIGHT",
1192            "Cargo.lock",
1193            "Cargo.toml",
1194            "LICENSE-APACHE",
1195            "LICENSE-MIT",
1196            "README.md",
1197            "RELEASES.md",
1198            "REUSE.toml",
1199            "bootstrap.example.toml",
1200            "configure",
1201            "license-metadata.json",
1202            "package-lock.json",
1203            "package.json",
1204            "x",
1205            "x.ps1",
1206            "x.py",
1207            ];
1209        let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"];
1210
1211        copy_src_dirs(
1212            builder,
1213            &builder.src,
1214            &src_dirs,
1215            &[
1216                "src/gcc",
1220            ],
1221            plain_dst_src,
1222        );
1223        if !builder.config.dry_run() {
1228            builder.create_dir(&plain_dst_src.join("src/gcc"));
1229            t!(std::fs::write(
1230                plain_dst_src.join("src/gcc/notice.txt"),
1231                "The GCC source code is not included due to unclear licensing implications\n"
1232            ));
1233        }
1234
1235        for item in &src_files {
1237            builder.copy_link(
1238                &builder.src.join(item),
1239                &plain_dst_src.join(item),
1240                FileType::Regular,
1241            );
1242        }
1243
1244        builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1246
1247        let write_git_info = |info: Option<&Info>, path: &Path| {
1249            if let Some(info) = info {
1250                t!(std::fs::create_dir_all(path));
1251                channel::write_commit_hash_file(path, &info.sha);
1252                channel::write_commit_info_file(path, info);
1253            }
1254        };
1255        write_git_info(builder.rust_info().info(), plain_dst_src);
1256        write_git_info(builder.cargo_info.info(), &plain_dst_src.join("./src/tools/cargo"));
1257
1258        if builder.config.dist_vendor {
1259            builder.require_and_update_all_submodules();
1260
1261            let pkgs_for_pgo_training = build_helper::LLVM_PGO_CRATES
1263                .iter()
1264                .chain(build_helper::RUSTC_PGO_CRATES)
1265                .map(|pkg| {
1266                    let mut manifest_path =
1267                        builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks");
1268                    manifest_path.push(pkg);
1269                    manifest_path.push("Cargo.toml");
1270                    manifest_path
1271                });
1272
1273            let vendor = builder.ensure(Vendor {
1275                sync_args: pkgs_for_pgo_training.collect(),
1276                versioned_dirs: true,
1277                root_dir: plain_dst_src.into(),
1278                output_dir: VENDOR_DIR.into(),
1279            });
1280
1281            let cargo_config_dir = plain_dst_src.join(".cargo");
1282            builder.create_dir(&cargo_config_dir);
1283            builder.create(&cargo_config_dir.join("config.toml"), &vendor.config);
1284        }
1285
1286        for entry in walkdir::WalkDir::new(tarball.image_dir())
1290            .follow_links(true)
1291            .into_iter()
1292            .filter_map(|e| e.ok())
1293        {
1294            if entry.path().is_dir() && entry.path().file_name() == Some(OsStr::new("__pycache__"))
1295            {
1296                t!(fs::remove_dir_all(entry.path()));
1297            }
1298        }
1299
1300        tarball.bare()
1301    }
1302}
1303
1304#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1305pub struct Cargo {
1306    pub build_compiler: Compiler,
1307    pub target: TargetSelection,
1308}
1309
1310impl Step for Cargo {
1311    type Output = Option<GeneratedTarball>;
1312    const DEFAULT: bool = true;
1313    const IS_HOST: bool = true;
1314
1315    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1316        let default = should_build_extended_tool(run.builder, "cargo");
1317        run.alias("cargo").default_condition(default)
1318    }
1319
1320    fn make_run(run: RunConfig<'_>) {
1321        run.builder.ensure(Cargo {
1322            build_compiler: get_tool_target_compiler(
1323                run.builder,
1324                ToolTargetBuildMode::Build(run.target),
1325            ),
1326            target: run.target,
1327        });
1328    }
1329
1330    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1331        let build_compiler = self.build_compiler;
1332        let target = self.target;
1333
1334        let cargo = builder.ensure(tool::Cargo::from_build_compiler(build_compiler, target));
1335        let src = builder.src.join("src/tools/cargo");
1336        let etc = src.join("src/etc");
1337
1338        let mut tarball = Tarball::new(builder, "cargo", &target.triple);
1340        tarball.set_overlay(OverlayKind::Cargo);
1341
1342        tarball.add_file(&cargo.tool_path, "bin", FileType::Executable);
1343        tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", FileType::Regular);
1344        tarball.add_renamed_file(
1345            etc.join("cargo.bashcomp.sh"),
1346            "etc/bash_completion.d",
1347            "cargo",
1348            FileType::Regular,
1349        );
1350        tarball.add_dir(etc.join("man"), "share/man/man1");
1351        tarball.add_legal_and_readme_to("share/doc/cargo");
1352
1353        Some(tarball.generate())
1354    }
1355
1356    fn metadata(&self) -> Option<StepMetadata> {
1357        Some(StepMetadata::dist("cargo", self.target).built_by(self.build_compiler))
1358    }
1359}
1360
1361#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1363pub struct RustAnalyzer {
1364    pub compilers: RustcPrivateCompilers,
1365    pub target: TargetSelection,
1366}
1367
1368impl Step for RustAnalyzer {
1369    type Output = Option<GeneratedTarball>;
1370    const DEFAULT: bool = true;
1371    const IS_HOST: bool = true;
1372
1373    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1374        let default = should_build_extended_tool(run.builder, "rust-analyzer");
1375        run.alias("rust-analyzer").default_condition(default)
1376    }
1377
1378    fn make_run(run: RunConfig<'_>) {
1379        run.builder.ensure(RustAnalyzer {
1380            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1381            target: run.target,
1382        });
1383    }
1384
1385    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1386        let target = self.target;
1387        let rust_analyzer = builder.ensure(tool::RustAnalyzer::from_compilers(self.compilers));
1388
1389        let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
1390        tarball.set_overlay(OverlayKind::RustAnalyzer);
1391        tarball.is_preview(true);
1392        tarball.add_file(&rust_analyzer.tool_path, "bin", FileType::Executable);
1393        tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
1394        Some(tarball.generate())
1395    }
1396
1397    fn metadata(&self) -> Option<StepMetadata> {
1398        Some(
1399            StepMetadata::dist("rust-analyzer", self.target)
1400                .built_by(self.compilers.build_compiler()),
1401        )
1402    }
1403}
1404
1405#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1406pub struct Clippy {
1407    pub compilers: RustcPrivateCompilers,
1408    pub target: TargetSelection,
1409}
1410
1411impl Step for Clippy {
1412    type Output = Option<GeneratedTarball>;
1413    const DEFAULT: bool = true;
1414    const IS_HOST: bool = true;
1415
1416    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1417        let default = should_build_extended_tool(run.builder, "clippy");
1418        run.alias("clippy").default_condition(default)
1419    }
1420
1421    fn make_run(run: RunConfig<'_>) {
1422        run.builder.ensure(Clippy {
1423            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1424            target: run.target,
1425        });
1426    }
1427
1428    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1429        let target = self.target;
1430
1431        let clippy = builder.ensure(tool::Clippy::from_compilers(self.compilers));
1435        let cargoclippy = builder.ensure(tool::CargoClippy::from_compilers(self.compilers));
1436
1437        let mut tarball = Tarball::new(builder, "clippy", &target.triple);
1438        tarball.set_overlay(OverlayKind::Clippy);
1439        tarball.is_preview(true);
1440        tarball.add_file(&clippy.tool_path, "bin", FileType::Executable);
1441        tarball.add_file(&cargoclippy.tool_path, "bin", FileType::Executable);
1442        tarball.add_legal_and_readme_to("share/doc/clippy");
1443        Some(tarball.generate())
1444    }
1445
1446    fn metadata(&self) -> Option<StepMetadata> {
1447        Some(StepMetadata::dist("clippy", self.target).built_by(self.compilers.build_compiler()))
1448    }
1449}
1450
1451#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1452pub struct Miri {
1453    pub compilers: RustcPrivateCompilers,
1454    pub target: TargetSelection,
1455}
1456
1457impl Step for Miri {
1458    type Output = Option<GeneratedTarball>;
1459    const DEFAULT: bool = true;
1460    const IS_HOST: bool = true;
1461
1462    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1463        let default = should_build_extended_tool(run.builder, "miri");
1464        run.alias("miri").default_condition(default)
1465    }
1466
1467    fn make_run(run: RunConfig<'_>) {
1468        run.builder.ensure(Miri {
1469            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1470            target: run.target,
1471        });
1472    }
1473
1474    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1475        if !builder.build.unstable_features() {
1479            return None;
1480        }
1481
1482        let miri = builder.ensure(tool::Miri::from_compilers(self.compilers));
1483        let cargomiri = builder.ensure(tool::CargoMiri::from_compilers(self.compilers));
1484
1485        let mut tarball = Tarball::new(builder, "miri", &self.target.triple);
1486        tarball.set_overlay(OverlayKind::Miri);
1487        tarball.is_preview(true);
1488        tarball.add_file(&miri.tool_path, "bin", FileType::Executable);
1489        tarball.add_file(&cargomiri.tool_path, "bin", FileType::Executable);
1490        tarball.add_legal_and_readme_to("share/doc/miri");
1491        Some(tarball.generate())
1492    }
1493
1494    fn metadata(&self) -> Option<StepMetadata> {
1495        Some(StepMetadata::dist("miri", self.target).built_by(self.compilers.build_compiler()))
1496    }
1497}
1498
1499#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1500pub struct CraneliftCodegenBackend {
1501    pub compilers: RustcPrivateCompilers,
1502    pub target: TargetSelection,
1503}
1504
1505impl Step for CraneliftCodegenBackend {
1506    type Output = Option<GeneratedTarball>;
1507    const DEFAULT: bool = true;
1508    const IS_HOST: bool = true;
1509
1510    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1511        let clif_enabled_by_default = run
1516            .builder
1517            .config
1518            .enabled_codegen_backends(run.builder.host_target)
1519            .contains(&CodegenBackendKind::Cranelift);
1520        run.alias("rustc_codegen_cranelift").default_condition(clif_enabled_by_default)
1521    }
1522
1523    fn make_run(run: RunConfig<'_>) {
1524        run.builder.ensure(CraneliftCodegenBackend {
1525            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1526            target: run.target,
1527        });
1528    }
1529
1530    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1531        if !builder.build.unstable_features() {
1535            return None;
1536        }
1537
1538        let target = self.target;
1539        if !target_supports_cranelift_backend(target) {
1540            builder.info("target not supported by rustc_codegen_cranelift. skipping");
1541            return None;
1542        }
1543
1544        let mut tarball = Tarball::new(builder, "rustc-codegen-cranelift", &target.triple);
1545        tarball.set_overlay(OverlayKind::RustcCodegenCranelift);
1546        tarball.is_preview(true);
1547        tarball.add_legal_and_readme_to("share/doc/rustc_codegen_cranelift");
1548
1549        let compilers = self.compilers;
1550        let stamp = builder.ensure(compile::CraneliftCodegenBackend { compilers });
1551
1552        if builder.config.dry_run() {
1553            return None;
1554        }
1555
1556        let backends_dst = builder.sysroot_codegen_backends(compilers.target_compiler());
1558        let backends_rel = backends_dst
1559            .strip_prefix(builder.sysroot(compilers.target_compiler()))
1560            .unwrap()
1561            .strip_prefix(builder.sysroot_libdir_relative(compilers.target_compiler()))
1562            .unwrap();
1563        let backends_dst = PathBuf::from("lib").join(backends_rel);
1565
1566        let codegen_backend_dylib = get_codegen_backend_file(&stamp);
1567        tarball.add_renamed_file(
1568            &codegen_backend_dylib,
1569            &backends_dst,
1570            &normalize_codegen_backend_name(builder, &codegen_backend_dylib),
1571            FileType::NativeLibrary,
1572        );
1573
1574        Some(tarball.generate())
1575    }
1576
1577    fn metadata(&self) -> Option<StepMetadata> {
1578        Some(
1579            StepMetadata::dist("rustc_codegen_cranelift", self.target)
1580                .built_by(self.compilers.build_compiler()),
1581        )
1582    }
1583}
1584
1585#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1586pub struct Rustfmt {
1587    pub compilers: RustcPrivateCompilers,
1588    pub target: TargetSelection,
1589}
1590
1591impl Step for Rustfmt {
1592    type Output = Option<GeneratedTarball>;
1593    const DEFAULT: bool = true;
1594    const IS_HOST: bool = true;
1595
1596    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1597        let default = should_build_extended_tool(run.builder, "rustfmt");
1598        run.alias("rustfmt").default_condition(default)
1599    }
1600
1601    fn make_run(run: RunConfig<'_>) {
1602        run.builder.ensure(Rustfmt {
1603            compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1604            target: run.target,
1605        });
1606    }
1607
1608    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1609        let rustfmt = builder.ensure(tool::Rustfmt::from_compilers(self.compilers));
1610        let cargofmt = builder.ensure(tool::Cargofmt::from_compilers(self.compilers));
1611
1612        let mut tarball = Tarball::new(builder, "rustfmt", &self.target.triple);
1613        tarball.set_overlay(OverlayKind::Rustfmt);
1614        tarball.is_preview(true);
1615        tarball.add_file(&rustfmt.tool_path, "bin", FileType::Executable);
1616        tarball.add_file(&cargofmt.tool_path, "bin", FileType::Executable);
1617        tarball.add_legal_and_readme_to("share/doc/rustfmt");
1618        Some(tarball.generate())
1619    }
1620
1621    fn metadata(&self) -> Option<StepMetadata> {
1622        Some(StepMetadata::dist("rustfmt", self.target).built_by(self.compilers.build_compiler()))
1623    }
1624}
1625
1626#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1628pub struct Extended {
1629    build_compiler: Compiler,
1630    target: TargetSelection,
1631}
1632
1633impl Step for Extended {
1634    type Output = ();
1635    const DEFAULT: bool = true;
1636    const IS_HOST: bool = true;
1637
1638    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1639        let builder = run.builder;
1640        run.alias("extended").default_condition(builder.config.extended)
1641    }
1642
1643    fn make_run(run: RunConfig<'_>) {
1644        run.builder.ensure(Extended {
1645            build_compiler: run
1646                .builder
1647                .compiler(run.builder.top_stage - 1, run.builder.host_target),
1648            target: run.target,
1649        });
1650    }
1651
1652    fn run(self, builder: &Builder<'_>) {
1654        let target = self.target;
1655        builder.info(&format!("Dist extended stage{} ({target})", builder.top_stage));
1656
1657        let mut tarballs = Vec::new();
1658        let mut built_tools = HashSet::new();
1659        macro_rules! add_component {
1660            ($name:expr => $step:expr) => {
1661                if let Some(Some(tarball)) = builder.ensure_if_default($step, Kind::Dist) {
1662                    tarballs.push(tarball);
1663                    built_tools.insert($name);
1664                }
1665            };
1666        }
1667
1668        let rustc_private_compilers =
1669            RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target);
1670        let build_compiler = rustc_private_compilers.build_compiler();
1671        let target_compiler = rustc_private_compilers.target_compiler();
1672
1673        tarballs.push(builder.ensure(Rustc { target_compiler }));
1678        tarballs.push(builder.ensure(Std { build_compiler, target }).expect("missing std"));
1679
1680        if target.is_windows_gnu() {
1681            tarballs.push(builder.ensure(Mingw { target }).expect("missing mingw"));
1682        }
1683
1684        add_component!("rust-docs" => Docs { host: target });
1685        add_component!("rust-json-docs" => JsonDocs { build_compiler: target_compiler, target });
1687        add_component!("cargo" => Cargo { build_compiler, target });
1688        add_component!("rustfmt" => Rustfmt { compilers: rustc_private_compilers, target });
1689        add_component!("rust-analyzer" => RustAnalyzer { compilers: rustc_private_compilers, target });
1690        add_component!("llvm-components" => LlvmTools { target });
1691        add_component!("clippy" => Clippy { compilers: rustc_private_compilers, target });
1692        add_component!("miri" => Miri { compilers: rustc_private_compilers, target });
1693        add_component!("analysis" => Analysis { build_compiler, target });
1694        add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend {
1695            compilers: rustc_private_compilers,
1696            target
1697        });
1698        add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {
1699            build_compiler,
1700            target
1701        });
1702
1703        let etc = builder.src.join("src/etc/installer");
1704
1705        if builder.config.dry_run() {
1707            return;
1708        }
1709
1710        let tarball = Tarball::new(builder, "rust", &target.triple);
1711        let generated = tarball.combine(&tarballs);
1712
1713        let tmp = tmpdir(builder).join("combined-tarball");
1714        let work = generated.work_dir();
1715
1716        let mut license = String::new();
1717        license += &builder.read(&builder.src.join("COPYRIGHT"));
1718        license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1719        license += &builder.read(&builder.src.join("LICENSE-MIT"));
1720        license.push('\n');
1721        license.push('\n');
1722
1723        let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1724        let mut rtf = rtf.to_string();
1725        rtf.push('\n');
1726        for line in license.lines() {
1727            rtf.push_str(line);
1728            rtf.push_str("\\line ");
1729        }
1730        rtf.push('}');
1731
1732        fn filter(contents: &str, marker: &str) -> String {
1733            let start = format!("tool-{marker}-start");
1734            let end = format!("tool-{marker}-end");
1735            let mut lines = Vec::new();
1736            let mut omitted = false;
1737            for line in contents.lines() {
1738                if line.contains(&start) {
1739                    omitted = true;
1740                } else if line.contains(&end) {
1741                    omitted = false;
1742                } else if !omitted {
1743                    lines.push(line);
1744                }
1745            }
1746
1747            lines.join("\n")
1748        }
1749
1750        let xform = |p: &Path| {
1751            let mut contents = t!(fs::read_to_string(p));
1752            for tool in &["miri", "rust-docs"] {
1753                if !built_tools.contains(tool) {
1754                    contents = filter(&contents, tool);
1755                }
1756            }
1757            let ret = tmp.join(p.file_name().unwrap());
1758            t!(fs::write(&ret, &contents));
1759            ret
1760        };
1761
1762        if target.contains("apple-darwin") {
1763            builder.info("building pkg installer");
1764            let pkg = tmp.join("pkg");
1765            let _ = fs::remove_dir_all(&pkg);
1766
1767            let pkgbuild = |component: &str| {
1768                let mut cmd = command("pkgbuild");
1769                cmd.arg("--identifier")
1770                    .arg(format!("org.rust-lang.{component}"))
1771                    .arg("--scripts")
1772                    .arg(pkg.join(component))
1773                    .arg("--nopayload")
1774                    .arg(pkg.join(component).with_extension("pkg"));
1775                cmd.run(builder);
1776            };
1777
1778            let prepare = |name: &str| {
1779                builder.create_dir(&pkg.join(name));
1780                builder.cp_link_r(
1781                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)),
1782                    &pkg.join(name),
1783                );
1784                builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), FileType::Script);
1785                pkgbuild(name);
1786            };
1787            prepare("rustc");
1788            prepare("cargo");
1789            prepare("rust-std");
1790            prepare("rust-analysis");
1791
1792            for tool in &[
1793                "clippy",
1794                "rustfmt",
1795                "rust-analyzer",
1796                "rust-docs",
1797                "miri",
1798                "rustc-codegen-cranelift",
1799            ] {
1800                if built_tools.contains(tool) {
1801                    prepare(tool);
1802                }
1803            }
1804            builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), FileType::Script);
1806            pkgbuild("uninstall");
1807
1808            builder.create_dir(&pkg.join("res"));
1809            builder.create(&pkg.join("res/LICENSE.txt"), &license);
1810            builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), FileType::Regular);
1811            let mut cmd = command("productbuild");
1812            cmd.arg("--distribution")
1813                .arg(xform(&etc.join("pkg/Distribution.xml")))
1814                .arg("--resources")
1815                .arg(pkg.join("res"))
1816                .arg(distdir(builder).join(format!(
1817                    "{}-{}.pkg",
1818                    pkgname(builder, "rust"),
1819                    target.triple
1820                )))
1821                .arg("--package-path")
1822                .arg(&pkg);
1823            let _time = timeit(builder);
1824            cmd.run(builder);
1825        }
1826
1827        if target.is_windows() && !target.contains("gnullvm") {
1829            let exe = tmp.join("exe");
1830            let _ = fs::remove_dir_all(&exe);
1831
1832            let prepare = |name: &str| {
1833                builder.create_dir(&exe.join(name));
1834                let dir = if name == "rust-std" || name == "rust-analysis" {
1835                    format!("{}-{}", name, target.triple)
1836                } else if name == "rust-analyzer" {
1837                    "rust-analyzer-preview".to_string()
1838                } else if name == "clippy" {
1839                    "clippy-preview".to_string()
1840                } else if name == "rustfmt" {
1841                    "rustfmt-preview".to_string()
1842                } else if name == "miri" {
1843                    "miri-preview".to_string()
1844                } else if name == "rustc-codegen-cranelift" {
1845                    unreachable!("cg_clif shouldn't be built for windows");
1848                } else {
1849                    name.to_string()
1850                };
1851                builder.cp_link_r(
1852                    &work.join(format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
1853                    &exe.join(name),
1854                );
1855                builder.remove(&exe.join(name).join("manifest.in"));
1856            };
1857            prepare("rustc");
1858            prepare("cargo");
1859            prepare("rust-analysis");
1860            prepare("rust-std");
1861            for tool in &["clippy", "rustfmt", "rust-analyzer", "rust-docs", "miri"] {
1862                if built_tools.contains(tool) {
1863                    prepare(tool);
1864                }
1865            }
1866            if target.is_windows_gnu() {
1867                prepare("rust-mingw");
1868            }
1869
1870            builder.install(&etc.join("gfx/rust-logo.ico"), &exe, FileType::Regular);
1871
1872            let wix_path = env::var_os("WIX")
1874                .expect("`WIX` environment variable must be set for generating MSI installer(s).");
1875            let wix = PathBuf::from(wix_path);
1876            let heat = wix.join("bin/heat.exe");
1877            let candle = wix.join("bin/candle.exe");
1878            let light = wix.join("bin/light.exe");
1879
1880            let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1881            command(&heat)
1882                .current_dir(&exe)
1883                .arg("dir")
1884                .arg("rustc")
1885                .args(heat_flags)
1886                .arg("-cg")
1887                .arg("RustcGroup")
1888                .arg("-dr")
1889                .arg("Rustc")
1890                .arg("-var")
1891                .arg("var.RustcDir")
1892                .arg("-out")
1893                .arg(exe.join("RustcGroup.wxs"))
1894                .run(builder);
1895            if built_tools.contains("rust-docs") {
1896                command(&heat)
1897                    .current_dir(&exe)
1898                    .arg("dir")
1899                    .arg("rust-docs")
1900                    .args(heat_flags)
1901                    .arg("-cg")
1902                    .arg("DocsGroup")
1903                    .arg("-dr")
1904                    .arg("Docs")
1905                    .arg("-var")
1906                    .arg("var.DocsDir")
1907                    .arg("-out")
1908                    .arg(exe.join("DocsGroup.wxs"))
1909                    .arg("-t")
1910                    .arg(etc.join("msi/squash-components.xsl"))
1911                    .run(builder);
1912            }
1913            command(&heat)
1914                .current_dir(&exe)
1915                .arg("dir")
1916                .arg("cargo")
1917                .args(heat_flags)
1918                .arg("-cg")
1919                .arg("CargoGroup")
1920                .arg("-dr")
1921                .arg("Cargo")
1922                .arg("-var")
1923                .arg("var.CargoDir")
1924                .arg("-out")
1925                .arg(exe.join("CargoGroup.wxs"))
1926                .arg("-t")
1927                .arg(etc.join("msi/remove-duplicates.xsl"))
1928                .run(builder);
1929            command(&heat)
1930                .current_dir(&exe)
1931                .arg("dir")
1932                .arg("rust-std")
1933                .args(heat_flags)
1934                .arg("-cg")
1935                .arg("StdGroup")
1936                .arg("-dr")
1937                .arg("Std")
1938                .arg("-var")
1939                .arg("var.StdDir")
1940                .arg("-out")
1941                .arg(exe.join("StdGroup.wxs"))
1942                .run(builder);
1943            if built_tools.contains("rust-analyzer") {
1944                command(&heat)
1945                    .current_dir(&exe)
1946                    .arg("dir")
1947                    .arg("rust-analyzer")
1948                    .args(heat_flags)
1949                    .arg("-cg")
1950                    .arg("RustAnalyzerGroup")
1951                    .arg("-dr")
1952                    .arg("RustAnalyzer")
1953                    .arg("-var")
1954                    .arg("var.RustAnalyzerDir")
1955                    .arg("-out")
1956                    .arg(exe.join("RustAnalyzerGroup.wxs"))
1957                    .arg("-t")
1958                    .arg(etc.join("msi/remove-duplicates.xsl"))
1959                    .run(builder);
1960            }
1961            if built_tools.contains("clippy") {
1962                command(&heat)
1963                    .current_dir(&exe)
1964                    .arg("dir")
1965                    .arg("clippy")
1966                    .args(heat_flags)
1967                    .arg("-cg")
1968                    .arg("ClippyGroup")
1969                    .arg("-dr")
1970                    .arg("Clippy")
1971                    .arg("-var")
1972                    .arg("var.ClippyDir")
1973                    .arg("-out")
1974                    .arg(exe.join("ClippyGroup.wxs"))
1975                    .arg("-t")
1976                    .arg(etc.join("msi/remove-duplicates.xsl"))
1977                    .run(builder);
1978            }
1979            if built_tools.contains("rustfmt") {
1980                command(&heat)
1981                    .current_dir(&exe)
1982                    .arg("dir")
1983                    .arg("rustfmt")
1984                    .args(heat_flags)
1985                    .arg("-cg")
1986                    .arg("RustFmtGroup")
1987                    .arg("-dr")
1988                    .arg("RustFmt")
1989                    .arg("-var")
1990                    .arg("var.RustFmtDir")
1991                    .arg("-out")
1992                    .arg(exe.join("RustFmtGroup.wxs"))
1993                    .arg("-t")
1994                    .arg(etc.join("msi/remove-duplicates.xsl"))
1995                    .run(builder);
1996            }
1997            if built_tools.contains("miri") {
1998                command(&heat)
1999                    .current_dir(&exe)
2000                    .arg("dir")
2001                    .arg("miri")
2002                    .args(heat_flags)
2003                    .arg("-cg")
2004                    .arg("MiriGroup")
2005                    .arg("-dr")
2006                    .arg("Miri")
2007                    .arg("-var")
2008                    .arg("var.MiriDir")
2009                    .arg("-out")
2010                    .arg(exe.join("MiriGroup.wxs"))
2011                    .arg("-t")
2012                    .arg(etc.join("msi/remove-duplicates.xsl"))
2013                    .run(builder);
2014            }
2015            command(&heat)
2016                .current_dir(&exe)
2017                .arg("dir")
2018                .arg("rust-analysis")
2019                .args(heat_flags)
2020                .arg("-cg")
2021                .arg("AnalysisGroup")
2022                .arg("-dr")
2023                .arg("Analysis")
2024                .arg("-var")
2025                .arg("var.AnalysisDir")
2026                .arg("-out")
2027                .arg(exe.join("AnalysisGroup.wxs"))
2028                .arg("-t")
2029                .arg(etc.join("msi/remove-duplicates.xsl"))
2030                .run(builder);
2031            if target.is_windows_gnu() {
2032                command(&heat)
2033                    .current_dir(&exe)
2034                    .arg("dir")
2035                    .arg("rust-mingw")
2036                    .args(heat_flags)
2037                    .arg("-cg")
2038                    .arg("GccGroup")
2039                    .arg("-dr")
2040                    .arg("Gcc")
2041                    .arg("-var")
2042                    .arg("var.GccDir")
2043                    .arg("-out")
2044                    .arg(exe.join("GccGroup.wxs"))
2045                    .run(builder);
2046            }
2047
2048            let candle = |input: &Path| {
2049                let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
2050                let arch = if target.contains("x86_64") { "x64" } else { "x86" };
2051                let mut cmd = command(&candle);
2052                cmd.current_dir(&exe)
2053                    .arg("-nologo")
2054                    .arg("-dRustcDir=rustc")
2055                    .arg("-dCargoDir=cargo")
2056                    .arg("-dStdDir=rust-std")
2057                    .arg("-dAnalysisDir=rust-analysis")
2058                    .arg("-arch")
2059                    .arg(arch)
2060                    .arg("-out")
2061                    .arg(&output)
2062                    .arg(input);
2063                add_env(builder, &mut cmd, target, &built_tools);
2064
2065                if built_tools.contains("clippy") {
2066                    cmd.arg("-dClippyDir=clippy");
2067                }
2068                if built_tools.contains("rustfmt") {
2069                    cmd.arg("-dRustFmtDir=rustfmt");
2070                }
2071                if built_tools.contains("rust-docs") {
2072                    cmd.arg("-dDocsDir=rust-docs");
2073                }
2074                if built_tools.contains("rust-analyzer") {
2075                    cmd.arg("-dRustAnalyzerDir=rust-analyzer");
2076                }
2077                if built_tools.contains("miri") {
2078                    cmd.arg("-dMiriDir=miri");
2079                }
2080                if target.is_windows_gnu() {
2081                    cmd.arg("-dGccDir=rust-mingw");
2082                }
2083                cmd.run(builder);
2084            };
2085            candle(&xform(&etc.join("msi/rust.wxs")));
2086            candle(&etc.join("msi/ui.wxs"));
2087            candle(&etc.join("msi/rustwelcomedlg.wxs"));
2088            candle("RustcGroup.wxs".as_ref());
2089            if built_tools.contains("rust-docs") {
2090                candle("DocsGroup.wxs".as_ref());
2091            }
2092            candle("CargoGroup.wxs".as_ref());
2093            candle("StdGroup.wxs".as_ref());
2094            if built_tools.contains("clippy") {
2095                candle("ClippyGroup.wxs".as_ref());
2096            }
2097            if built_tools.contains("rustfmt") {
2098                candle("RustFmtGroup.wxs".as_ref());
2099            }
2100            if built_tools.contains("miri") {
2101                candle("MiriGroup.wxs".as_ref());
2102            }
2103            if built_tools.contains("rust-analyzer") {
2104                candle("RustAnalyzerGroup.wxs".as_ref());
2105            }
2106            candle("AnalysisGroup.wxs".as_ref());
2107
2108            if target.is_windows_gnu() {
2109                candle("GccGroup.wxs".as_ref());
2110            }
2111
2112            builder.create(&exe.join("LICENSE.rtf"), &rtf);
2113            builder.install(&etc.join("gfx/banner.bmp"), &exe, FileType::Regular);
2114            builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, FileType::Regular);
2115
2116            builder.info(&format!("building `msi` installer with {light:?}"));
2117            let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
2118            let mut cmd = command(&light);
2119            cmd.arg("-nologo")
2120                .arg("-ext")
2121                .arg("WixUIExtension")
2122                .arg("-ext")
2123                .arg("WixUtilExtension")
2124                .arg("-out")
2125                .arg(exe.join(&filename))
2126                .arg("rust.wixobj")
2127                .arg("ui.wixobj")
2128                .arg("rustwelcomedlg.wixobj")
2129                .arg("RustcGroup.wixobj")
2130                .arg("CargoGroup.wixobj")
2131                .arg("StdGroup.wixobj")
2132                .arg("AnalysisGroup.wixobj")
2133                .current_dir(&exe);
2134
2135            if built_tools.contains("clippy") {
2136                cmd.arg("ClippyGroup.wixobj");
2137            }
2138            if built_tools.contains("rustfmt") {
2139                cmd.arg("RustFmtGroup.wixobj");
2140            }
2141            if built_tools.contains("miri") {
2142                cmd.arg("MiriGroup.wixobj");
2143            }
2144            if built_tools.contains("rust-analyzer") {
2145                cmd.arg("RustAnalyzerGroup.wixobj");
2146            }
2147            if built_tools.contains("rust-docs") {
2148                cmd.arg("DocsGroup.wixobj");
2149            }
2150
2151            if target.is_windows_gnu() {
2152                cmd.arg("GccGroup.wixobj");
2153            }
2154            cmd.arg("-sice:ICE57");
2156
2157            let _time = timeit(builder);
2158            cmd.run(builder);
2159
2160            if !builder.config.dry_run() {
2161                t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
2162            }
2163        }
2164    }
2165
2166    fn metadata(&self) -> Option<StepMetadata> {
2167        Some(StepMetadata::dist("extended", self.target).built_by(self.build_compiler))
2168    }
2169}
2170
2171fn add_env(
2172    builder: &Builder<'_>,
2173    cmd: &mut BootstrapCommand,
2174    target: TargetSelection,
2175    built_tools: &HashSet<&'static str>,
2176) {
2177    let mut parts = builder.version.split('.');
2178    cmd.env("CFG_RELEASE_INFO", builder.rust_version())
2179        .env("CFG_RELEASE_NUM", &builder.version)
2180        .env("CFG_RELEASE", builder.rust_release())
2181        .env("CFG_VER_MAJOR", parts.next().unwrap())
2182        .env("CFG_VER_MINOR", parts.next().unwrap())
2183        .env("CFG_VER_PATCH", parts.next().unwrap())
2184        .env("CFG_VER_BUILD", "0") .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
2186        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
2187        .env("CFG_BUILD", target.triple)
2188        .env("CFG_CHANNEL", &builder.config.channel);
2189
2190    if target.contains("windows-gnullvm") {
2191        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
2192    } else if target.is_windows_gnu() {
2193        cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
2194    } else {
2195        cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
2196    }
2197
2198    let mut define_optional_tool = |tool_name: &str, env_name: &str| {
2200        cmd.env(env_name, if built_tools.contains(tool_name) { "1" } else { "0" });
2201    };
2202    define_optional_tool("rustfmt", "CFG_RUSTFMT");
2203    define_optional_tool("clippy", "CFG_CLIPPY");
2204    define_optional_tool("miri", "CFG_MIRI");
2205    define_optional_tool("rust-analyzer", "CFG_RA");
2206}
2207
2208fn install_llvm_file(
2209    builder: &Builder<'_>,
2210    source: &Path,
2211    destination: &Path,
2212    install_symlink: bool,
2213) {
2214    if builder.config.dry_run() {
2215        return;
2216    }
2217
2218    if source.is_symlink() {
2219        builder.install(&t!(fs::canonicalize(source)), destination, FileType::NativeLibrary);
2222
2223        let full_dest = destination.join(source.file_name().unwrap());
2224        if install_symlink {
2225            builder.copy_link(source, &full_dest, FileType::NativeLibrary);
2228        } else {
2229            let link = t!(fs::read_link(source));
2233            let mut linker_script = t!(fs::File::create(full_dest));
2234            t!(write!(linker_script, "INPUT({})\n", link.display()));
2235
2236            let meta = t!(fs::metadata(source));
2239            if let Ok(mtime) = meta.modified() {
2240                t!(linker_script.set_modified(mtime));
2241            }
2242        }
2243    } else {
2244        builder.install(source, destination, FileType::NativeLibrary);
2245    }
2246}
2247
2248#[cfg_attr(
2252    feature = "tracing",
2253    instrument(
2254        level = "trace",
2255        name = "maybe_install_llvm",
2256        skip_all,
2257        fields(target = ?target, dst_libdir = ?dst_libdir, install_symlink = install_symlink),
2258    ),
2259)]
2260fn maybe_install_llvm(
2261    builder: &Builder<'_>,
2262    target: TargetSelection,
2263    dst_libdir: &Path,
2264    install_symlink: bool,
2265) -> bool {
2266    if builder.config.is_system_llvm(target) {
2283        trace!("system LLVM requested, no install");
2284        return false;
2285    }
2286
2287    if target.contains("apple-darwin") && builder.llvm_link_shared() {
2293        let src_libdir = builder.llvm_out(target).join("lib");
2294        let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2295        if llvm_dylib_path.exists() {
2296            builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary);
2297        }
2298        !builder.config.dry_run()
2299    } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult {
2300        host_llvm_config, ..
2301    }) = llvm::prebuilt_llvm_config(builder, target, true)
2302    {
2303        trace!("LLVM already built, installing LLVM files");
2304        let mut cmd = command(host_llvm_config);
2305        cmd.cached();
2306        cmd.arg("--libfiles");
2307        builder.verbose(|| println!("running {cmd:?}"));
2308        let files = cmd.run_capture_stdout(builder).stdout();
2309        let build_llvm_out = &builder.llvm_out(builder.config.host_target);
2310        let target_llvm_out = &builder.llvm_out(target);
2311        for file in files.trim_end().split(' ') {
2312            let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
2314                target_llvm_out.join(relative_path)
2315            } else {
2316                PathBuf::from(file)
2317            };
2318            install_llvm_file(builder, &file, dst_libdir, install_symlink);
2319        }
2320        !builder.config.dry_run()
2321    } else {
2322        false
2323    }
2324}
2325
2326#[cfg_attr(
2328    feature = "tracing",
2329    instrument(
2330        level = "trace",
2331        name = "maybe_install_llvm_target",
2332        skip_all,
2333        fields(
2334            llvm_link_shared = ?builder.llvm_link_shared(),
2335            target = ?target,
2336            sysroot = ?sysroot,
2337        ),
2338    ),
2339)]
2340pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2341    let dst_libdir = sysroot.join("lib/rustlib").join(target).join("lib");
2342    if builder.llvm_link_shared() {
2346        maybe_install_llvm(builder, target, &dst_libdir, false);
2347    }
2348}
2349
2350#[cfg_attr(
2352    feature = "tracing",
2353    instrument(
2354        level = "trace",
2355        name = "maybe_install_llvm_runtime",
2356        skip_all,
2357        fields(
2358            llvm_link_shared = ?builder.llvm_link_shared(),
2359            target = ?target,
2360            sysroot = ?sysroot,
2361        ),
2362    ),
2363)]
2364pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
2365    let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler::new(1, target)));
2366    if builder.llvm_link_shared() {
2370        maybe_install_llvm(builder, target, &dst_libdir, false);
2371    }
2372}
2373
2374#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2375pub struct LlvmTools {
2376    pub target: TargetSelection,
2377}
2378
2379impl Step for LlvmTools {
2380    type Output = Option<GeneratedTarball>;
2381    const IS_HOST: bool = true;
2382    const DEFAULT: bool = true;
2383
2384    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2385        let default = should_build_extended_tool(run.builder, "llvm-tools");
2386
2387        let mut run = run.alias("llvm-tools");
2388        for tool in LLVM_TOOLS {
2389            run = run.alias(tool);
2390        }
2391
2392        run.default_condition(default)
2393    }
2394
2395    fn make_run(run: RunConfig<'_>) {
2396        run.builder.ensure(LlvmTools { target: run.target });
2397    }
2398
2399    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2400        fn tools_to_install(paths: &[PathBuf]) -> Vec<&'static str> {
2401            let mut tools = vec![];
2402
2403            for path in paths {
2404                let path = path.to_str().unwrap();
2405
2406                if path == "llvm-tools" {
2408                    return LLVM_TOOLS.to_owned();
2409                }
2410
2411                for tool in LLVM_TOOLS {
2412                    if path == *tool {
2413                        tools.push(*tool);
2414                    }
2415                }
2416            }
2417
2418            if tools.is_empty() {
2420                tools = LLVM_TOOLS.to_owned();
2421            }
2422
2423            tools
2424        }
2425
2426        let target = self.target;
2427
2428        if let Some(config) = builder.config.target_config.get(&target)
2430            && !builder.config.llvm_from_ci
2431            && config.llvm_config.is_some()
2432        {
2433            builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
2434            return None;
2435        }
2436
2437        if !builder.config.dry_run() {
2438            builder.require_submodule("src/llvm-project", None);
2439        }
2440
2441        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2442
2443        let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
2444        tarball.set_overlay(OverlayKind::Llvm);
2445        tarball.is_preview(true);
2446
2447        if builder.config.llvm_tools_enabled {
2448            let src_bindir = builder.llvm_out(target).join("bin");
2450            let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
2451            for tool in tools_to_install(&builder.paths) {
2452                let exe = src_bindir.join(exe(tool, target));
2453                if !exe.exists() && builder.config.llvm_from_ci {
2455                    eprintln!("{} does not exist; skipping copy", exe.display());
2456                    continue;
2457                }
2458
2459                tarball.add_file(&exe, &dst_bindir, FileType::Executable);
2460            }
2461        }
2462
2463        maybe_install_llvm_target(builder, target, tarball.image_dir());
2468
2469        Some(tarball.generate())
2470    }
2471}
2472
2473#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2476pub struct LlvmBitcodeLinker {
2477    pub build_compiler: Compiler,
2479    pub target: TargetSelection,
2481}
2482
2483impl Step for LlvmBitcodeLinker {
2484    type Output = Option<GeneratedTarball>;
2485    const DEFAULT: bool = true;
2486    const IS_HOST: bool = true;
2487
2488    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2489        let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker");
2490        run.alias("llvm-bitcode-linker").default_condition(default)
2491    }
2492
2493    fn make_run(run: RunConfig<'_>) {
2494        run.builder.ensure(LlvmBitcodeLinker {
2495            build_compiler: tool::LlvmBitcodeLinker::get_build_compiler_for_target(
2496                run.builder,
2497                run.target,
2498            ),
2499            target: run.target,
2500        });
2501    }
2502
2503    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2504        let target = self.target;
2505
2506        let llbc_linker = builder
2507            .ensure(tool::LlvmBitcodeLinker::from_build_compiler(self.build_compiler, target));
2508
2509        let self_contained_bin_dir = format!("lib/rustlib/{}/bin/self-contained", target.triple);
2510
2511        let mut tarball = Tarball::new(builder, "llvm-bitcode-linker", &target.triple);
2513        tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
2514        tarball.is_preview(true);
2515
2516        tarball.add_file(&llbc_linker.tool_path, self_contained_bin_dir, FileType::Executable);
2517
2518        Some(tarball.generate())
2519    }
2520}
2521
2522#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2531pub struct RustDev {
2532    pub target: TargetSelection,
2533}
2534
2535impl Step for RustDev {
2536    type Output = Option<GeneratedTarball>;
2537    const DEFAULT: bool = true;
2538    const IS_HOST: bool = true;
2539
2540    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2541        run.alias("rust-dev")
2542    }
2543
2544    fn make_run(run: RunConfig<'_>) {
2545        run.builder.ensure(RustDev { target: run.target });
2546    }
2547
2548    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2549        let target = self.target;
2550
2551        if let Some(config) = builder.config.target_config.get(&target)
2553            && let Some(ref _s) = config.llvm_config
2554        {
2555            builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
2556            return None;
2557        }
2558
2559        if !builder.config.dry_run() {
2560            builder.require_submodule("src/llvm-project", None);
2561        }
2562
2563        let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
2564        tarball.set_overlay(OverlayKind::Llvm);
2565        tarball.permit_symlinks(true);
2567
2568        builder.ensure(crate::core::build_steps::llvm::Llvm { target });
2569
2570        let src_bindir = builder.llvm_out(target).join("bin");
2571        if src_bindir.exists() {
2577            for entry in walkdir::WalkDir::new(&src_bindir) {
2578                let entry = t!(entry);
2579                if entry.file_type().is_file() && !entry.path_is_symlink() {
2580                    let name = entry.file_name().to_str().unwrap();
2581                    tarball.add_file(src_bindir.join(name), "bin", FileType::Executable);
2582                }
2583            }
2584        }
2585
2586        if builder.config.lld_enabled {
2587            let lld_out = builder.ensure(crate::core::build_steps::llvm::Lld { target });
2589
2590            let lld_path = lld_out.join("bin").join(exe("lld", target));
2592            if lld_path.exists() {
2593                tarball.add_file(&lld_path, "bin", FileType::Executable);
2594            }
2595        }
2596
2597        tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable);
2598
2599        tarball.add_dir(builder.llvm_out(target).join("include"), "include");
2603
2604        let dst_libdir = tarball.image_dir().join("lib");
2609        maybe_install_llvm(builder, target, &dst_libdir, true);
2610        let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
2611        t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
2612
2613        copy_src_dirs(
2617            builder,
2618            &builder.src.join("src").join("llvm-project"),
2619            &["compiler-rt"],
2620            &["compiler-rt/test"],
2623            tarball.image_dir(),
2624        );
2625
2626        Some(tarball.generate())
2627    }
2628}
2629
2630#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2636pub struct Bootstrap {
2637    target: TargetSelection,
2638}
2639
2640impl Step for Bootstrap {
2641    type Output = Option<GeneratedTarball>;
2642
2643    const IS_HOST: bool = true;
2644
2645    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2646        run.alias("bootstrap")
2647    }
2648
2649    fn make_run(run: RunConfig<'_>) {
2650        run.builder.ensure(Bootstrap { target: run.target });
2651    }
2652
2653    fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2654        let target = self.target;
2655
2656        let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2657
2658        let bootstrap_outdir = &builder.bootstrap_out;
2659        for file in &["bootstrap", "rustc", "rustdoc"] {
2660            tarball.add_file(
2661                bootstrap_outdir.join(exe(file, target)),
2662                "bootstrap/bin",
2663                FileType::Executable,
2664            );
2665        }
2666
2667        Some(tarball.generate())
2668    }
2669
2670    fn metadata(&self) -> Option<StepMetadata> {
2671        Some(StepMetadata::dist("bootstrap", self.target))
2672    }
2673}
2674
2675#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2680pub struct BuildManifest {
2681    target: TargetSelection,
2682}
2683
2684impl Step for BuildManifest {
2685    type Output = GeneratedTarball;
2686
2687    const IS_HOST: bool = true;
2688
2689    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2690        run.alias("build-manifest")
2691    }
2692
2693    fn make_run(run: RunConfig<'_>) {
2694        run.builder.ensure(BuildManifest { target: run.target });
2695    }
2696
2697    fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
2698        let build_manifest = builder.tool_exe(Tool::BuildManifest);
2699
2700        let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
2701        tarball.add_file(&build_manifest, "bin", FileType::Executable);
2702        tarball.generate()
2703    }
2704
2705    fn metadata(&self) -> Option<StepMetadata> {
2706        Some(StepMetadata::dist("build-manifest", self.target))
2707    }
2708}
2709
2710#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2716pub struct ReproducibleArtifacts {
2717    target: TargetSelection,
2718}
2719
2720impl Step for ReproducibleArtifacts {
2721    type Output = Option<GeneratedTarball>;
2722    const DEFAULT: bool = true;
2723    const IS_HOST: bool = true;
2724
2725    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2726        run.alias("reproducible-artifacts")
2727    }
2728
2729    fn make_run(run: RunConfig<'_>) {
2730        run.builder.ensure(ReproducibleArtifacts { target: run.target });
2731    }
2732
2733    fn run(self, builder: &Builder<'_>) -> Self::Output {
2734        let mut added_anything = false;
2735        let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
2736        if let Some(path) = builder.config.rust_profile_use.as_ref() {
2737            tarball.add_file(path, ".", FileType::Regular);
2738            added_anything = true;
2739        }
2740        if let Some(path) = builder.config.llvm_profile_use.as_ref() {
2741            tarball.add_file(path, ".", FileType::Regular);
2742            added_anything = true;
2743        }
2744        for profile in &builder.config.reproducible_artifacts {
2745            tarball.add_file(profile, ".", FileType::Regular);
2746            added_anything = true;
2747        }
2748        if added_anything { Some(tarball.generate()) } else { None }
2749    }
2750
2751    fn metadata(&self) -> Option<StepMetadata> {
2752        Some(StepMetadata::dist("reproducible-artifacts", self.target))
2753    }
2754}
2755
2756#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2760pub struct Gcc {
2761    target: TargetSelection,
2762}
2763
2764impl Step for Gcc {
2765    type Output = GeneratedTarball;
2766
2767    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2768        run.alias("gcc")
2769    }
2770
2771    fn make_run(run: RunConfig<'_>) {
2772        run.builder.ensure(Gcc { target: run.target });
2773    }
2774
2775    fn run(self, builder: &Builder<'_>) -> Self::Output {
2776        let tarball = Tarball::new(builder, "gcc", &self.target.triple);
2777        let output = builder.ensure(super::gcc::Gcc { target: self.target });
2778        tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary);
2779        tarball.generate()
2780    }
2781
2782    fn metadata(&self) -> Option<StepMetadata> {
2783        Some(StepMetadata::dist("gcc", self.target))
2784    }
2785}