bootstrap/core/build_steps/
dist.rs

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