]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
4fd6c81e5978682ec19ea71b65387362bfe3cabd
[rust.git] / src / bootstrap / dist.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Implementation of the various distribution aspects of the compiler.
12 //!
13 //! This module is responsible for creating tarballs of the standard library,
14 //! compiler, and documentation. This ends up being what we distribute to
15 //! everyone as well.
16 //!
17 //! No tarball is actually created literally in this file, but rather we shell
18 //! out to `rust-installer` still. This may one day be replaced with bits and
19 //! pieces of `rustup.rs`!
20
21 use std::env;
22 use std::fs::{self, File};
23 use std::io::{Read, Write};
24 use std::path::{PathBuf, Path};
25 use std::process::{Command, Stdio};
26
27 use build_helper::output;
28
29 use {Compiler, Mode, LLVM_TOOLS};
30 use channel;
31 use util::{libdir, is_dylib, exe};
32 use builder::{Builder, RunConfig, ShouldRun, Step};
33 use compile;
34 use native;
35 use tool::{self, Tool};
36 use cache::{INTERNER, Interned};
37 use time;
38
39 pub fn pkgname(builder: &Builder, component: &str) -> String {
40     if component == "cargo" {
41         format!("{}-{}", component, builder.cargo_package_vers())
42     } else if component == "rls" {
43         format!("{}-{}", component, builder.rls_package_vers())
44     } else if component == "rustfmt" {
45         format!("{}-{}", component, builder.rustfmt_package_vers())
46     } else if component == "llvm-tools" {
47         format!("{}-{}", component, builder.llvm_tools_package_vers())
48     } else {
49         assert!(component.starts_with("rust"));
50         format!("{}-{}", component, builder.rust_package_vers())
51     }
52 }
53
54 fn distdir(builder: &Builder) -> PathBuf {
55     builder.out.join("dist")
56 }
57
58 pub fn tmpdir(builder: &Builder) -> PathBuf {
59     builder.out.join("tmp/dist")
60 }
61
62 fn rust_installer(builder: &Builder) -> Command {
63     builder.tool_cmd(Tool::RustInstaller)
64 }
65
66 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
67 pub struct Docs {
68     pub stage: u32,
69     pub host: Interned<String>,
70 }
71
72 impl Step for Docs {
73     type Output = PathBuf;
74     const DEFAULT: bool = true;
75
76     fn should_run(run: ShouldRun) -> ShouldRun {
77         run.path("src/doc")
78     }
79
80     fn make_run(run: RunConfig) {
81         run.builder.ensure(Docs {
82             stage: run.builder.top_stage,
83             host: run.target,
84         });
85     }
86
87     /// Builds the `rust-docs` installer component.
88     fn run(self, builder: &Builder) -> PathBuf {
89         let host = self.host;
90
91         let name = pkgname(builder, "rust-docs");
92
93         builder.info(&format!("Dist docs ({})", host));
94         if !builder.config.docs {
95             builder.info(&format!("\tskipping - docs disabled"));
96             return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
97         }
98
99         builder.default_doc(None);
100
101         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
102         let _ = fs::remove_dir_all(&image);
103
104         let dst = image.join("share/doc/rust/html");
105         t!(fs::create_dir_all(&dst));
106         let src = builder.doc_out(host);
107         builder.cp_r(&src, &dst);
108
109         let mut cmd = rust_installer(builder);
110         cmd.arg("generate")
111            .arg("--product-name=Rust-Documentation")
112            .arg("--rel-manifest-dir=rustlib")
113            .arg("--success-message=Rust-documentation-is-installed.")
114            .arg("--image-dir").arg(&image)
115            .arg("--work-dir").arg(&tmpdir(builder))
116            .arg("--output-dir").arg(&distdir(builder))
117            .arg(format!("--package-name={}-{}", name, host))
118            .arg("--component-name=rust-docs")
119            .arg("--legacy-manifest-dirs=rustlib,cargo")
120            .arg("--bulk-dirs=share/doc/rust/html");
121         builder.run(&mut cmd);
122         builder.remove_dir(&image);
123
124         distdir(builder).join(format!("{}-{}.tar.gz", name, host))
125     }
126 }
127
128 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
129 pub struct RustcDocs {
130     pub stage: u32,
131     pub host: Interned<String>,
132 }
133
134 impl Step for RustcDocs {
135     type Output = PathBuf;
136     const DEFAULT: bool = true;
137
138     fn should_run(run: ShouldRun) -> ShouldRun {
139         run.path("src/librustc")
140     }
141
142     fn make_run(run: RunConfig) {
143         run.builder.ensure(RustcDocs {
144             stage: run.builder.top_stage,
145             host: run.target,
146         });
147     }
148
149     /// Builds the `rustc-docs` installer component.
150     fn run(self, builder: &Builder) -> PathBuf {
151         let host = self.host;
152
153         let name = pkgname(builder, "rustc-docs");
154
155         builder.info(&format!("Dist compiler docs ({})", host));
156         if !builder.config.compiler_docs {
157             builder.info(&format!("\tskipping - compiler docs disabled"));
158             return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
159         }
160
161         builder.default_doc(None);
162
163         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
164         let _ = fs::remove_dir_all(&image);
165
166         let dst = image.join("share/doc/rust/html");
167         t!(fs::create_dir_all(&dst));
168         let src = builder.compiler_doc_out(host);
169         builder.cp_r(&src, &dst);
170
171         let mut cmd = rust_installer(builder);
172         cmd.arg("generate")
173            .arg("--product-name=Rustc-Documentation")
174            .arg("--rel-manifest-dir=rustlib")
175            .arg("--success-message=Rustc-documentation-is-installed.")
176            .arg("--image-dir").arg(&image)
177            .arg("--work-dir").arg(&tmpdir(builder))
178            .arg("--output-dir").arg(&distdir(builder))
179            .arg(format!("--package-name={}-{}", name, host))
180            .arg("--component-name=rustc-docs")
181            .arg("--legacy-manifest-dirs=rustlib,cargo")
182            .arg("--bulk-dirs=share/doc/rust/html");
183         builder.run(&mut cmd);
184         builder.remove_dir(&image);
185
186         distdir(builder).join(format!("{}-{}.tar.gz", name, host))
187     }
188 }
189
190 fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
191     let mut found = Vec::with_capacity(files.len());
192
193     for file in files {
194         let file_path =
195             path.iter()
196                 .map(|dir| dir.join(file))
197                 .find(|p| p.exists());
198
199         if let Some(file_path) = file_path {
200             found.push(file_path);
201         } else {
202             panic!("Could not find '{}' in {:?}", file, path);
203         }
204     }
205
206     found
207 }
208
209 fn make_win_dist(
210     rust_root: &Path, plat_root: &Path, target_triple: Interned<String>, builder: &Builder
211 ) {
212     //Ask gcc where it keeps its stuff
213     let mut cmd = Command::new(builder.cc(target_triple));
214     cmd.arg("-print-search-dirs");
215     let gcc_out = output(&mut cmd);
216
217     let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
218     let mut lib_path = Vec::new();
219
220     for line in gcc_out.lines() {
221         let idx = line.find(':').unwrap();
222         let key = &line[..idx];
223         let trim_chars: &[_] = &[' ', '='];
224         let value =
225             line[(idx + 1)..]
226                 .trim_left_matches(trim_chars)
227                 .split(';')
228                 .map(PathBuf::from);
229
230         if key == "programs" {
231             bin_path.extend(value);
232         } else if key == "libraries" {
233             lib_path.extend(value);
234         }
235     }
236
237     let target_tools = ["gcc.exe", "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
238     let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"];
239     if target_triple.starts_with("i686-") {
240         rustc_dlls.push("libgcc_s_dw2-1.dll");
241     } else {
242         rustc_dlls.push("libgcc_s_seh-1.dll");
243     }
244
245     let target_libs = [ //MinGW libs
246         "libgcc.a",
247         "libgcc_eh.a",
248         "libgcc_s.a",
249         "libm.a",
250         "libmingw32.a",
251         "libmingwex.a",
252         "libstdc++.a",
253         "libiconv.a",
254         "libmoldname.a",
255         "libpthread.a",
256         //Windows import libs
257         "libadvapi32.a",
258         "libbcrypt.a",
259         "libcomctl32.a",
260         "libcomdlg32.a",
261         "libcredui.a",
262         "libcrypt32.a",
263         "libdbghelp.a",
264         "libgdi32.a",
265         "libimagehlp.a",
266         "libiphlpapi.a",
267         "libkernel32.a",
268         "libmsimg32.a",
269         "libmsvcrt.a",
270         "libodbc32.a",
271         "libole32.a",
272         "liboleaut32.a",
273         "libopengl32.a",
274         "libpsapi.a",
275         "librpcrt4.a",
276         "libsecur32.a",
277         "libsetupapi.a",
278         "libshell32.a",
279         "libsynchronization.a",
280         "libuser32.a",
281         "libuserenv.a",
282         "libuuid.a",
283         "libwinhttp.a",
284         "libwinmm.a",
285         "libwinspool.a",
286         "libws2_32.a",
287         "libwsock32.a",
288     ];
289
290     //Find mingw artifacts we want to bundle
291     let target_tools = find_files(&target_tools, &bin_path);
292     let rustc_dlls = find_files(&rustc_dlls, &bin_path);
293     let target_libs = find_files(&target_libs, &lib_path);
294
295     // Copy runtime dlls next to rustc.exe
296     let dist_bin_dir = rust_root.join("bin/");
297     fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
298     for src in rustc_dlls {
299         builder.copy_to_folder(&src, &dist_bin_dir);
300     }
301
302     //Copy platform tools to platform-specific bin directory
303     let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
304     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
305     for src in target_tools {
306         builder.copy_to_folder(&src, &target_bin_dir);
307     }
308
309     //Copy platform libs to platform-specific lib directory
310     let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
311     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
312     for src in target_libs {
313         builder.copy_to_folder(&src, &target_lib_dir);
314     }
315 }
316
317 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
318 pub struct Mingw {
319     pub host: Interned<String>,
320 }
321
322 impl Step for Mingw {
323     type Output = Option<PathBuf>;
324     const DEFAULT: bool = true;
325
326     fn should_run(run: ShouldRun) -> ShouldRun {
327         run.never()
328     }
329
330     fn make_run(run: RunConfig) {
331         run.builder.ensure(Mingw { host: run.target });
332     }
333
334     /// Build the `rust-mingw` installer component.
335     ///
336     /// This contains all the bits and pieces to run the MinGW Windows targets
337     /// without any extra installed software (e.g. we bundle gcc, libraries, etc).
338     fn run(self, builder: &Builder) -> Option<PathBuf> {
339         let host = self.host;
340
341         if !host.contains("pc-windows-gnu") {
342             return None;
343         }
344
345         builder.info(&format!("Dist mingw ({})", host));
346         let name = pkgname(builder, "rust-mingw");
347         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
348         let _ = fs::remove_dir_all(&image);
349         t!(fs::create_dir_all(&image));
350
351         // The first argument is a "temporary directory" which is just
352         // thrown away (this contains the runtime DLLs included in the rustc package
353         // above) and the second argument is where to place all the MinGW components
354         // (which is what we want).
355         make_win_dist(&tmpdir(builder), &image, host, &builder);
356
357         let mut cmd = rust_installer(builder);
358         cmd.arg("generate")
359            .arg("--product-name=Rust-MinGW")
360            .arg("--rel-manifest-dir=rustlib")
361            .arg("--success-message=Rust-MinGW-is-installed.")
362            .arg("--image-dir").arg(&image)
363            .arg("--work-dir").arg(&tmpdir(builder))
364            .arg("--output-dir").arg(&distdir(builder))
365            .arg(format!("--package-name={}-{}", name, host))
366            .arg("--component-name=rust-mingw")
367            .arg("--legacy-manifest-dirs=rustlib,cargo");
368         builder.run(&mut cmd);
369         t!(fs::remove_dir_all(&image));
370         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host)))
371     }
372 }
373
374 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
375 pub struct Rustc {
376     pub compiler: Compiler,
377 }
378
379 impl Step for Rustc {
380     type Output = PathBuf;
381     const DEFAULT: bool = true;
382     const ONLY_HOSTS: bool = true;
383
384     fn should_run(run: ShouldRun) -> ShouldRun {
385         run.path("src/librustc")
386     }
387
388     fn make_run(run: RunConfig) {
389         run.builder.ensure(Rustc {
390             compiler: run.builder.compiler(run.builder.top_stage, run.target),
391         });
392     }
393
394     /// Creates the `rustc` installer component.
395     fn run(self, builder: &Builder) -> PathBuf {
396         let compiler = self.compiler;
397         let host = self.compiler.host;
398
399         builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host));
400         let name = pkgname(builder, "rustc");
401         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
402         let _ = fs::remove_dir_all(&image);
403         let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host));
404         let _ = fs::remove_dir_all(&overlay);
405
406         // Prepare the rustc "image", what will actually end up getting installed
407         prepare_image(builder, compiler, &image);
408
409         // Prepare the overlay which is part of the tarball but won't actually be
410         // installed
411         let cp = |file: &str| {
412             builder.install(&builder.src.join(file), &overlay, 0o644);
413         };
414         cp("COPYRIGHT");
415         cp("LICENSE-APACHE");
416         cp("LICENSE-MIT");
417         cp("README.md");
418         // tiny morsel of metadata is used by rust-packaging
419         let version = builder.rust_version();
420         builder.create(&overlay.join("version"), &version);
421         if let Some(sha) = builder.rust_sha() {
422             builder.create(&overlay.join("git-commit-hash"), &sha);
423         }
424
425         // On MinGW we've got a few runtime DLL dependencies that we need to
426         // include. The first argument to this script is where to put these DLLs
427         // (the image we're creating), and the second argument is a junk directory
428         // to ignore all other MinGW stuff the script creates.
429         //
430         // On 32-bit MinGW we're always including a DLL which needs some extra
431         // licenses to distribute. On 64-bit MinGW we don't actually distribute
432         // anything requiring us to distribute a license, but it's likely the
433         // install will *also* include the rust-mingw package, which also needs
434         // licenses, so to be safe we just include it here in all MinGW packages.
435         if host.contains("pc-windows-gnu") {
436             make_win_dist(&image, &tmpdir(builder), host, builder);
437
438             let dst = image.join("share/doc");
439             t!(fs::create_dir_all(&dst));
440             builder.cp_r(&builder.src.join("src/etc/third-party"), &dst);
441         }
442
443         // Finally, wrap everything up in a nice tarball!
444         let mut cmd = rust_installer(builder);
445         cmd.arg("generate")
446            .arg("--product-name=Rust")
447            .arg("--rel-manifest-dir=rustlib")
448            .arg("--success-message=Rust-is-ready-to-roll.")
449            .arg("--image-dir").arg(&image)
450            .arg("--work-dir").arg(&tmpdir(builder))
451            .arg("--output-dir").arg(&distdir(builder))
452            .arg("--non-installed-overlay").arg(&overlay)
453            .arg(format!("--package-name={}-{}", name, host))
454            .arg("--component-name=rustc")
455            .arg("--legacy-manifest-dirs=rustlib,cargo");
456         builder.run(&mut cmd);
457         builder.remove_dir(&image);
458         builder.remove_dir(&overlay);
459
460         return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
461
462         fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) {
463             let host = compiler.host;
464             let src = builder.sysroot(compiler);
465             let libdir = libdir(&host);
466
467             // Copy rustc/rustdoc binaries
468             t!(fs::create_dir_all(image.join("bin")));
469             builder.cp_r(&src.join("bin"), &image.join("bin"));
470
471             builder.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
472
473             // Copy runtime DLLs needed by the compiler
474             if libdir != "bin" {
475                 for entry in builder.read_dir(&src.join(libdir)) {
476                     let name = entry.file_name();
477                     if let Some(s) = name.to_str() {
478                         if is_dylib(s) {
479                             builder.install(&entry.path(), &image.join(libdir), 0o644);
480                         }
481                     }
482                 }
483             }
484
485             // Copy over the codegen backends
486             let backends_src = builder.sysroot_codegen_backends(compiler);
487             let backends_rel = backends_src.strip_prefix(&src).unwrap();
488             let backends_dst = image.join(&backends_rel);
489             t!(fs::create_dir_all(&backends_dst));
490             builder.cp_r(&backends_src, &backends_dst);
491
492             // Copy over lld if it's there
493             if builder.config.lld_enabled {
494                 let exe = exe("lld", &compiler.host);
495                 let src = builder.sysroot_libdir(compiler, host)
496                     .parent()
497                     .unwrap()
498                     .join("bin")
499                     .join(&exe);
500                 let dst = image.join("lib/rustlib")
501                     .join(&*host)
502                     .join("bin")
503                     .join(&exe);
504                 t!(fs::create_dir_all(&dst.parent().unwrap()));
505                 builder.copy(&src, &dst);
506             }
507
508             // Man pages
509             t!(fs::create_dir_all(image.join("share/man/man1")));
510             let man_src = builder.src.join("src/doc/man");
511             let man_dst = image.join("share/man/man1");
512             let month_year = t!(time::strftime("%B %Y", &time::now()));
513             // don't use our `bootstrap::util::{copy, cp_r}`, because those try
514             // to hardlink, and we don't want to edit the source templates
515             for file_entry in builder.read_dir(&man_src) {
516                 let page_src = file_entry.path();
517                 let page_dst = man_dst.join(file_entry.file_name());
518                 t!(fs::copy(&page_src, &page_dst));
519                 // template in month/year and version number
520                 builder.replace_in_file(&page_dst,
521                                 &[("<INSERT DATE HERE>", &month_year),
522                                   ("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]);
523             }
524
525             // Debugger scripts
526             builder.ensure(DebuggerScripts {
527                 sysroot: INTERNER.intern_path(image.to_owned()),
528                 host,
529             });
530
531             // Misc license info
532             let cp = |file: &str| {
533                 builder.install(&builder.src.join(file), &image.join("share/doc/rust"), 0o644);
534             };
535             cp("COPYRIGHT");
536             cp("LICENSE-APACHE");
537             cp("LICENSE-MIT");
538             cp("README.md");
539         }
540     }
541 }
542
543 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
544 pub struct DebuggerScripts {
545     pub sysroot: Interned<PathBuf>,
546     pub host: Interned<String>,
547 }
548
549 impl Step for DebuggerScripts {
550     type Output = ();
551
552     fn should_run(run: ShouldRun) -> ShouldRun {
553         run.path("src/lldb_batchmode.py")
554     }
555
556     fn make_run(run: RunConfig) {
557         run.builder.ensure(DebuggerScripts {
558             sysroot: run.builder.sysroot(run.builder.compiler(run.builder.top_stage, run.host)),
559             host: run.target,
560         });
561     }
562
563     /// Copies debugger scripts for `target` into the `sysroot` specified.
564     fn run(self, builder: &Builder) {
565         let host = self.host;
566         let sysroot = self.sysroot;
567         let dst = sysroot.join("lib/rustlib/etc");
568         t!(fs::create_dir_all(&dst));
569         let cp_debugger_script = |file: &str| {
570             builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644);
571         };
572         if host.contains("windows-msvc") {
573             // windbg debugger scripts
574             builder.install(&builder.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
575                 0o755);
576
577             cp_debugger_script("natvis/intrinsic.natvis");
578             cp_debugger_script("natvis/liballoc.natvis");
579             cp_debugger_script("natvis/libcore.natvis");
580         } else {
581             cp_debugger_script("debugger_pretty_printers_common.py");
582
583             // gdb debugger scripts
584             builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
585                     0o755);
586
587             cp_debugger_script("gdb_load_rust_pretty_printers.py");
588             cp_debugger_script("gdb_rust_pretty_printing.py");
589
590             // lldb debugger scripts
591             builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
592                     0o755);
593
594             cp_debugger_script("lldb_rust_formatters.py");
595         }
596     }
597 }
598
599 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
600 pub struct Std {
601     pub compiler: Compiler,
602     pub target: Interned<String>,
603 }
604
605 impl Step for Std {
606     type Output = PathBuf;
607     const DEFAULT: bool = true;
608
609     fn should_run(run: ShouldRun) -> ShouldRun {
610         run.path("src/libstd")
611     }
612
613     fn make_run(run: RunConfig) {
614         run.builder.ensure(Std {
615             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
616             target: run.target,
617         });
618     }
619
620     fn run(self, builder: &Builder) -> PathBuf {
621         let compiler = self.compiler;
622         let target = self.target;
623
624         let name = pkgname(builder, "rust-std");
625         builder.info(&format!("Dist std stage{} ({} -> {})",
626             compiler.stage, &compiler.host, target));
627
628         // The only true set of target libraries came from the build triple, so
629         // let's reduce redundant work by only producing archives from that host.
630         if compiler.host != builder.config.build {
631             builder.info(&format!("\tskipping, not a build host"));
632             return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
633         }
634
635         // We want to package up as many target libraries as possible
636         // for the `rust-std` package, so if this is a host target we
637         // depend on librustc and otherwise we just depend on libtest.
638         if builder.hosts.iter().any(|t| t == target) {
639             builder.ensure(compile::Rustc { compiler, target });
640         } else {
641             if builder.no_std(target) == Some(true) {
642                 // the `test` doesn't compile for no-std targets
643                 builder.ensure(compile::Std { compiler, target });
644             } else {
645                 builder.ensure(compile::Test { compiler, target });
646             }
647         }
648
649         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
650         let _ = fs::remove_dir_all(&image);
651
652         let dst = image.join("lib/rustlib").join(target);
653         t!(fs::create_dir_all(&dst));
654         let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
655         src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
656         builder.cp_filtered(&src, &dst, &|path| {
657             let name = path.file_name().and_then(|s| s.to_str());
658             name != Some(builder.config.rust_codegen_backends_dir.as_str()) &&
659                 name != Some("bin")
660
661         });
662
663         let mut cmd = rust_installer(builder);
664         cmd.arg("generate")
665            .arg("--product-name=Rust")
666            .arg("--rel-manifest-dir=rustlib")
667            .arg("--success-message=std-is-standing-at-the-ready.")
668            .arg("--image-dir").arg(&image)
669            .arg("--work-dir").arg(&tmpdir(builder))
670            .arg("--output-dir").arg(&distdir(builder))
671            .arg(format!("--package-name={}-{}", name, target))
672            .arg(format!("--component-name=rust-std-{}", target))
673            .arg("--legacy-manifest-dirs=rustlib,cargo");
674         builder.run(&mut cmd);
675         builder.remove_dir(&image);
676         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
677     }
678 }
679
680 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
681 pub struct Analysis {
682     pub compiler: Compiler,
683     pub target: Interned<String>,
684 }
685
686 impl Step for Analysis {
687     type Output = PathBuf;
688     const DEFAULT: bool = true;
689
690     fn should_run(run: ShouldRun) -> ShouldRun {
691         let builder = run.builder;
692         run.path("analysis").default_condition(builder.config.extended)
693     }
694
695     fn make_run(run: RunConfig) {
696         run.builder.ensure(Analysis {
697             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
698             target: run.target,
699         });
700     }
701
702     /// Creates a tarball of save-analysis metadata, if available.
703     fn run(self, builder: &Builder) -> PathBuf {
704         let compiler = self.compiler;
705         let target = self.target;
706         assert!(builder.config.extended);
707         builder.info(&format!("Dist analysis"));
708         let name = pkgname(builder, "rust-analysis");
709
710         if &compiler.host != builder.config.build {
711             builder.info(&format!("\tskipping, not a build host"));
712             return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
713         }
714
715         builder.ensure(Std { compiler, target });
716
717         // Package save-analysis from stage1 if not doing a full bootstrap, as the
718         // stage2 artifacts is simply copied from stage1 in that case.
719         let compiler = if builder.force_use_stage1(compiler, target) {
720             builder.compiler(1, compiler.host)
721         } else {
722             compiler.clone()
723         };
724
725         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
726
727         let src = builder.stage_out(compiler, Mode::Std)
728             .join(target).join(builder.cargo_dir()).join("deps");
729
730         let image_src = src.join("save-analysis");
731         let dst = image.join("lib/rustlib").join(target).join("analysis");
732         t!(fs::create_dir_all(&dst));
733         builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
734         builder.cp_r(&image_src, &dst);
735
736         let mut cmd = rust_installer(builder);
737         cmd.arg("generate")
738            .arg("--product-name=Rust")
739            .arg("--rel-manifest-dir=rustlib")
740            .arg("--success-message=save-analysis-saved.")
741            .arg("--image-dir").arg(&image)
742            .arg("--work-dir").arg(&tmpdir(builder))
743            .arg("--output-dir").arg(&distdir(builder))
744            .arg(format!("--package-name={}-{}", name, target))
745            .arg(format!("--component-name=rust-analysis-{}", target))
746            .arg("--legacy-manifest-dirs=rustlib,cargo");
747         builder.run(&mut cmd);
748         builder.remove_dir(&image);
749         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
750     }
751 }
752
753 fn copy_src_dirs(builder: &Builder, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) {
754     fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
755         let spath = match path.to_str() {
756             Some(path) => path,
757             None => return false,
758         };
759         if spath.ends_with("~") || spath.ends_with(".pyc") {
760             return false
761         }
762         if (spath.contains("llvm/test") || spath.contains("llvm\\test")) &&
763             (spath.ends_with(".ll") ||
764              spath.ends_with(".td") ||
765              spath.ends_with(".s")) {
766             return false
767         }
768         if spath.contains("test/emscripten") || spath.contains("test\\emscripten") {
769             return false
770         }
771
772         let full_path = Path::new(dir).join(path);
773         if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
774             return false;
775         }
776
777         let excludes = [
778             "CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules",
779             ".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}",
780             "=RELEASE-ID", "=meta-update", "=update", ".bzr", ".bzrignore",
781             ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
782         ];
783         !path.iter()
784              .map(|s| s.to_str().unwrap())
785              .any(|s| excludes.contains(&s))
786     }
787
788     // Copy the directories using our filter
789     for item in src_dirs {
790         let dst = &dst_dir.join(item);
791         t!(fs::create_dir_all(dst));
792         builder.cp_filtered(
793             &builder.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
794     }
795 }
796
797 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
798 pub struct Src;
799
800 impl Step for Src {
801     /// The output path of the src installer tarball
802     type Output = PathBuf;
803     const DEFAULT: bool = true;
804     const ONLY_HOSTS: bool = true;
805
806     fn should_run(run: ShouldRun) -> ShouldRun {
807         run.path("src")
808     }
809
810     fn make_run(run: RunConfig) {
811         run.builder.ensure(Src);
812     }
813
814     /// Creates the `rust-src` installer component
815     fn run(self, builder: &Builder) -> PathBuf {
816         builder.info(&format!("Dist src"));
817
818         let name = pkgname(builder, "rust-src");
819         let image = tmpdir(builder).join(format!("{}-image", name));
820         let _ = fs::remove_dir_all(&image);
821
822         let dst = image.join("lib/rustlib/src");
823         let dst_src = dst.join("rust");
824         t!(fs::create_dir_all(&dst_src));
825
826         let src_files = [
827             "src/Cargo.lock",
828         ];
829         // This is the reduced set of paths which will become the rust-src component
830         // (essentially libstd and all of its path dependencies)
831         let std_src_dirs = [
832             "src/build_helper",
833             "src/dlmalloc",
834             "src/liballoc",
835             "src/liballoc_jemalloc",
836             "src/liballoc_system",
837             "src/libbacktrace",
838             "src/libcompiler_builtins",
839             "src/libcore",
840             "src/liblibc",
841             "src/libpanic_abort",
842             "src/libpanic_unwind",
843             "src/librustc_asan",
844             "src/librustc_lsan",
845             "src/librustc_msan",
846             "src/librustc_tsan",
847             "src/libstd",
848             "src/libstd_unicode",
849             "src/libunwind",
850             "src/rustc/compiler_builtins_shim",
851             "src/rustc/libc_shim",
852             "src/rustc/dlmalloc_shim",
853             "src/libtest",
854             "src/libterm",
855             "src/jemalloc",
856             "src/libprofiler_builtins",
857             "src/stdsimd",
858         ];
859         let std_src_dirs_exclude = [
860             "src/libcompiler_builtins/compiler-rt/test",
861             "src/jemalloc/test/unit",
862         ];
863
864         copy_src_dirs(builder, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
865         for file in src_files.iter() {
866             builder.copy(&builder.src.join(file), &dst_src.join(file));
867         }
868
869         // Create source tarball in rust-installer format
870         let mut cmd = rust_installer(builder);
871         cmd.arg("generate")
872            .arg("--product-name=Rust")
873            .arg("--rel-manifest-dir=rustlib")
874            .arg("--success-message=Awesome-Source.")
875            .arg("--image-dir").arg(&image)
876            .arg("--work-dir").arg(&tmpdir(builder))
877            .arg("--output-dir").arg(&distdir(builder))
878            .arg(format!("--package-name={}", name))
879            .arg("--component-name=rust-src")
880            .arg("--legacy-manifest-dirs=rustlib,cargo");
881         builder.run(&mut cmd);
882
883         builder.remove_dir(&image);
884         distdir(builder).join(&format!("{}.tar.gz", name))
885     }
886 }
887
888 const CARGO_VENDOR_VERSION: &str = "0.1.4";
889
890 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
891 pub struct PlainSourceTarball;
892
893 impl Step for PlainSourceTarball {
894     /// Produces the location of the tarball generated
895     type Output = PathBuf;
896     const DEFAULT: bool = true;
897     const ONLY_HOSTS: bool = true;
898
899     fn should_run(run: ShouldRun) -> ShouldRun {
900         let builder = run.builder;
901         run.path("src").default_condition(builder.config.rust_dist_src)
902     }
903
904     fn make_run(run: RunConfig) {
905         run.builder.ensure(PlainSourceTarball);
906     }
907
908     /// Creates the plain source tarball
909     fn run(self, builder: &Builder) -> PathBuf {
910         builder.info(&format!("Create plain source tarball"));
911
912         // Make sure that the root folder of tarball has the correct name
913         let plain_name = format!("{}-src", pkgname(builder, "rustc"));
914         let plain_dst_src = tmpdir(builder).join(&plain_name);
915         let _ = fs::remove_dir_all(&plain_dst_src);
916         t!(fs::create_dir_all(&plain_dst_src));
917
918         // This is the set of root paths which will become part of the source package
919         let src_files = [
920             "COPYRIGHT",
921             "LICENSE-APACHE",
922             "LICENSE-MIT",
923             "CONTRIBUTING.md",
924             "README.md",
925             "RELEASES.md",
926             "configure",
927             "x.py",
928             "config.toml.example",
929         ];
930         let src_dirs = [
931             "src",
932         ];
933
934         copy_src_dirs(builder, &src_dirs[..], &[], &plain_dst_src);
935
936         // Copy the files normally
937         for item in &src_files {
938             builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
939         }
940
941         // Create the version file
942         builder.create(&plain_dst_src.join("version"), &builder.rust_version());
943         if let Some(sha) = builder.rust_sha() {
944             builder.create(&plain_dst_src.join("git-commit-hash"), &sha);
945         }
946
947         // If we're building from git sources, we need to vendor a complete distribution.
948         if builder.rust_info.is_git() {
949             // Get cargo-vendor installed, if it isn't already.
950             let mut has_cargo_vendor = false;
951             let mut cmd = Command::new(&builder.initial_cargo);
952             for line in output(cmd.arg("install").arg("--list")).lines() {
953                 has_cargo_vendor |= line.starts_with("cargo-vendor ");
954             }
955             if !has_cargo_vendor {
956                 let mut cmd = builder.cargo(
957                     builder.compiler(0, builder.config.build),
958                     Mode::ToolRustc,
959                     builder.config.build,
960                     "install"
961                 );
962                 cmd.arg("--force")
963                    .arg("--debug")
964                    .arg("--vers").arg(CARGO_VENDOR_VERSION)
965                    .arg("cargo-vendor");
966                 if let Some(dir) = builder.openssl_install_dir(builder.config.build) {
967                     builder.ensure(native::Openssl {
968                         target: builder.config.build,
969                     });
970                     cmd.env("OPENSSL_DIR", dir);
971                 }
972                 builder.run(&mut cmd);
973             }
974
975             // Vendor all Cargo dependencies
976             let mut cmd = Command::new(&builder.initial_cargo);
977             cmd.arg("vendor")
978                .current_dir(&plain_dst_src.join("src"));
979             builder.run(&mut cmd);
980         }
981
982         // Create plain source tarball
983         let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
984         let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
985         tarball.set_extension(""); // strip .gz
986         tarball.set_extension(""); // strip .tar
987         if let Some(dir) = tarball.parent() {
988             builder.create_dir(&dir);
989         }
990         builder.info(&format!("running installer"));
991         let mut cmd = rust_installer(builder);
992         cmd.arg("tarball")
993            .arg("--input").arg(&plain_name)
994            .arg("--output").arg(&tarball)
995            .arg("--work-dir=.")
996            .current_dir(tmpdir(builder));
997         builder.run(&mut cmd);
998         distdir(builder).join(&format!("{}.tar.gz", plain_name))
999     }
1000 }
1001
1002 // We have to run a few shell scripts, which choke quite a bit on both `\`
1003 // characters and on `C:\` paths, so normalize both of them away.
1004 pub fn sanitize_sh(path: &Path) -> String {
1005     let path = path.to_str().unwrap().replace("\\", "/");
1006     return change_drive(&path).unwrap_or(path);
1007
1008     fn change_drive(s: &str) -> Option<String> {
1009         let mut ch = s.chars();
1010         let drive = ch.next().unwrap_or('C');
1011         if ch.next() != Some(':') {
1012             return None
1013         }
1014         if ch.next() != Some('/') {
1015             return None
1016         }
1017         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
1018     }
1019 }
1020
1021 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1022 pub struct Cargo {
1023     pub stage: u32,
1024     pub target: Interned<String>,
1025 }
1026
1027 impl Step for Cargo {
1028     type Output = PathBuf;
1029     const ONLY_HOSTS: bool = true;
1030
1031     fn should_run(run: ShouldRun) -> ShouldRun {
1032         run.path("cargo")
1033     }
1034
1035     fn make_run(run: RunConfig) {
1036         run.builder.ensure(Cargo {
1037             stage: run.builder.top_stage,
1038             target: run.target,
1039         });
1040     }
1041
1042     fn run(self, builder: &Builder) -> PathBuf {
1043         let stage = self.stage;
1044         let target = self.target;
1045
1046         builder.info(&format!("Dist cargo stage{} ({})", stage, target));
1047         let src = builder.src.join("src/tools/cargo");
1048         let etc = src.join("src/etc");
1049         let release_num = builder.release_num("cargo");
1050         let name = pkgname(builder, "cargo");
1051         let version = builder.cargo_info.version(builder, &release_num);
1052
1053         let tmp = tmpdir(builder);
1054         let image = tmp.join("cargo-image");
1055         drop(fs::remove_dir_all(&image));
1056         builder.create_dir(&image);
1057
1058         // Prepare the image directory
1059         builder.create_dir(&image.join("share/zsh/site-functions"));
1060         builder.create_dir(&image.join("etc/bash_completion.d"));
1061         let cargo = builder.ensure(tool::Cargo {
1062             compiler: builder.compiler(stage, builder.config.build),
1063             target
1064         });
1065         builder.install(&cargo, &image.join("bin"), 0o755);
1066         for man in t!(etc.join("man").read_dir()) {
1067             let man = t!(man);
1068             builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
1069         }
1070         builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
1071         builder.copy(&etc.join("cargo.bashcomp.sh"),
1072              &image.join("etc/bash_completion.d/cargo"));
1073         let doc = image.join("share/doc/cargo");
1074         builder.install(&src.join("README.md"), &doc, 0o644);
1075         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1076         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1077         builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
1078
1079         // Prepare the overlay
1080         let overlay = tmp.join("cargo-overlay");
1081         drop(fs::remove_dir_all(&overlay));
1082         builder.create_dir(&overlay);
1083         builder.install(&src.join("README.md"), &overlay, 0o644);
1084         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1085         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1086         builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
1087         builder.create(&overlay.join("version"), &version);
1088
1089         // Generate the installer tarball
1090         let mut cmd = rust_installer(builder);
1091         cmd.arg("generate")
1092            .arg("--product-name=Rust")
1093            .arg("--rel-manifest-dir=rustlib")
1094            .arg("--success-message=Rust-is-ready-to-roll.")
1095            .arg("--image-dir").arg(&image)
1096            .arg("--work-dir").arg(&tmpdir(builder))
1097            .arg("--output-dir").arg(&distdir(builder))
1098            .arg("--non-installed-overlay").arg(&overlay)
1099            .arg(format!("--package-name={}-{}", name, target))
1100            .arg("--component-name=cargo")
1101            .arg("--legacy-manifest-dirs=rustlib,cargo");
1102         builder.run(&mut cmd);
1103         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
1104     }
1105 }
1106
1107 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1108 pub struct Rls {
1109     pub stage: u32,
1110     pub target: Interned<String>,
1111 }
1112
1113 impl Step for Rls {
1114     type Output = Option<PathBuf>;
1115     const ONLY_HOSTS: bool = true;
1116
1117     fn should_run(run: ShouldRun) -> ShouldRun {
1118         run.path("rls")
1119     }
1120
1121     fn make_run(run: RunConfig) {
1122         run.builder.ensure(Rls {
1123             stage: run.builder.top_stage,
1124             target: run.target,
1125         });
1126     }
1127
1128     fn run(self, builder: &Builder) -> Option<PathBuf> {
1129         let stage = self.stage;
1130         let target = self.target;
1131         assert!(builder.config.extended);
1132
1133         builder.info(&format!("Dist RLS stage{} ({})", stage, target));
1134         let src = builder.src.join("src/tools/rls");
1135         let release_num = builder.release_num("rls");
1136         let name = pkgname(builder, "rls");
1137         let version = builder.rls_info.version(builder, &release_num);
1138
1139         let tmp = tmpdir(builder);
1140         let image = tmp.join("rls-image");
1141         drop(fs::remove_dir_all(&image));
1142         t!(fs::create_dir_all(&image));
1143
1144         // Prepare the image directory
1145         // We expect RLS to build, because we've exited this step above if tool
1146         // state for RLS isn't testing.
1147         let rls = builder.ensure(tool::Rls {
1148             compiler: builder.compiler(stage, builder.config.build),
1149             target, extra_features: Vec::new()
1150         }).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?;
1151
1152         builder.install(&rls, &image.join("bin"), 0o755);
1153         let doc = image.join("share/doc/rls");
1154         builder.install(&src.join("README.md"), &doc, 0o644);
1155         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1156         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1157
1158         // Prepare the overlay
1159         let overlay = tmp.join("rls-overlay");
1160         drop(fs::remove_dir_all(&overlay));
1161         t!(fs::create_dir_all(&overlay));
1162         builder.install(&src.join("README.md"), &overlay, 0o644);
1163         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1164         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1165         builder.create(&overlay.join("version"), &version);
1166
1167         // Generate the installer tarball
1168         let mut cmd = rust_installer(builder);
1169         cmd.arg("generate")
1170            .arg("--product-name=Rust")
1171            .arg("--rel-manifest-dir=rustlib")
1172            .arg("--success-message=RLS-ready-to-serve.")
1173            .arg("--image-dir").arg(&image)
1174            .arg("--work-dir").arg(&tmpdir(builder))
1175            .arg("--output-dir").arg(&distdir(builder))
1176            .arg("--non-installed-overlay").arg(&overlay)
1177            .arg(format!("--package-name={}-{}", name, target))
1178            .arg("--legacy-manifest-dirs=rustlib,cargo")
1179            .arg("--component-name=rls-preview");
1180
1181         builder.run(&mut cmd);
1182         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1183     }
1184 }
1185
1186
1187 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1188 pub struct Rustfmt {
1189     pub stage: u32,
1190     pub target: Interned<String>,
1191 }
1192
1193 impl Step for Rustfmt {
1194     type Output = Option<PathBuf>;
1195     const ONLY_HOSTS: bool = true;
1196
1197     fn should_run(run: ShouldRun) -> ShouldRun {
1198         run.path("rustfmt")
1199     }
1200
1201     fn make_run(run: RunConfig) {
1202         run.builder.ensure(Rustfmt {
1203             stage: run.builder.top_stage,
1204             target: run.target,
1205         });
1206     }
1207
1208     fn run(self, builder: &Builder) -> Option<PathBuf> {
1209         let stage = self.stage;
1210         let target = self.target;
1211
1212         builder.info(&format!("Dist Rustfmt stage{} ({})", stage, target));
1213         let src = builder.src.join("src/tools/rustfmt");
1214         let release_num = builder.release_num("rustfmt");
1215         let name = pkgname(builder, "rustfmt");
1216         let version = builder.rustfmt_info.version(builder, &release_num);
1217
1218         let tmp = tmpdir(builder);
1219         let image = tmp.join("rustfmt-image");
1220         drop(fs::remove_dir_all(&image));
1221         builder.create_dir(&image);
1222
1223         // Prepare the image directory
1224         let rustfmt = builder.ensure(tool::Rustfmt {
1225             compiler: builder.compiler(stage, builder.config.build),
1226             target, extra_features: Vec::new()
1227         }).or_else(|| { println!("Unable to build Rustfmt, skipping dist"); None })?;
1228         let cargofmt = builder.ensure(tool::Cargofmt {
1229             compiler: builder.compiler(stage, builder.config.build),
1230             target, extra_features: Vec::new()
1231         }).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?;
1232
1233         builder.install(&rustfmt, &image.join("bin"), 0o755);
1234         builder.install(&cargofmt, &image.join("bin"), 0o755);
1235         let doc = image.join("share/doc/rustfmt");
1236         builder.install(&src.join("README.md"), &doc, 0o644);
1237         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1238         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1239
1240         // Prepare the overlay
1241         let overlay = tmp.join("rustfmt-overlay");
1242         drop(fs::remove_dir_all(&overlay));
1243         builder.create_dir(&overlay);
1244         builder.install(&src.join("README.md"), &overlay, 0o644);
1245         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1246         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1247         builder.create(&overlay.join("version"), &version);
1248
1249         // Generate the installer tarball
1250         let mut cmd = rust_installer(builder);
1251         cmd.arg("generate")
1252            .arg("--product-name=Rust")
1253            .arg("--rel-manifest-dir=rustlib")
1254            .arg("--success-message=rustfmt-ready-to-fmt.")
1255            .arg("--image-dir").arg(&image)
1256            .arg("--work-dir").arg(&tmpdir(builder))
1257            .arg("--output-dir").arg(&distdir(builder))
1258            .arg("--non-installed-overlay").arg(&overlay)
1259            .arg(format!("--package-name={}-{}", name, target))
1260            .arg("--legacy-manifest-dirs=rustlib,cargo")
1261            .arg("--component-name=rustfmt-preview");
1262
1263         builder.run(&mut cmd);
1264         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1265     }
1266 }
1267
1268 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1269 pub struct Extended {
1270     stage: u32,
1271     host: Interned<String>,
1272     target: Interned<String>,
1273 }
1274
1275 impl Step for Extended {
1276     type Output = ();
1277     const DEFAULT: bool = true;
1278     const ONLY_HOSTS: bool = true;
1279
1280     fn should_run(run: ShouldRun) -> ShouldRun {
1281         let builder = run.builder;
1282         run.path("extended").default_condition(builder.config.extended)
1283     }
1284
1285     fn make_run(run: RunConfig) {
1286         run.builder.ensure(Extended {
1287             stage: run.builder.top_stage,
1288             host: run.builder.config.build,
1289             target: run.target,
1290         });
1291     }
1292
1293     /// Creates a combined installer for the specified target in the provided stage.
1294     fn run(self, builder: &Builder) {
1295         let stage = self.stage;
1296         let target = self.target;
1297
1298         builder.info(&format!("Dist extended stage{} ({})", stage, target));
1299
1300         let rustc_installer = builder.ensure(Rustc {
1301             compiler: builder.compiler(stage, target),
1302         });
1303         let cargo_installer = builder.ensure(Cargo { stage, target });
1304         let rustfmt_installer = builder.ensure(Rustfmt { stage, target });
1305         let rls_installer = builder.ensure(Rls { stage, target });
1306         let llvm_tools_installer = builder.ensure(LlvmTools { stage, target });
1307         let mingw_installer = builder.ensure(Mingw { host: target });
1308         let analysis_installer = builder.ensure(Analysis {
1309             compiler: builder.compiler(stage, self.host),
1310             target
1311         });
1312
1313         let docs_installer = builder.ensure(Docs { stage, host: target, });
1314         let std_installer = builder.ensure(Std {
1315             compiler: builder.compiler(stage, self.host),
1316             target,
1317         });
1318
1319         let tmp = tmpdir(builder);
1320         let overlay = tmp.join("extended-overlay");
1321         let etc = builder.src.join("src/etc/installer");
1322         let work = tmp.join("work");
1323
1324         let _ = fs::remove_dir_all(&overlay);
1325         builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
1326         builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
1327         builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
1328         let version = builder.rust_version();
1329         builder.create(&overlay.join("version"), &version);
1330         if let Some(sha) = builder.rust_sha() {
1331             builder.create(&overlay.join("git-commit-hash"), &sha);
1332         }
1333         builder.install(&etc.join("README.md"), &overlay, 0o644);
1334
1335         // When rust-std package split from rustc, we needed to ensure that during
1336         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1337         // the std files during uninstall. To do this ensure that rustc comes
1338         // before rust-std in the list below.
1339         let mut tarballs = Vec::new();
1340         tarballs.push(rustc_installer);
1341         tarballs.push(cargo_installer);
1342         tarballs.extend(rls_installer.clone());
1343         tarballs.extend(rustfmt_installer.clone());
1344         tarballs.extend(llvm_tools_installer.clone());
1345         tarballs.push(analysis_installer);
1346         tarballs.push(std_installer);
1347         if builder.config.docs {
1348             tarballs.push(docs_installer);
1349         }
1350         if target.contains("pc-windows-gnu") {
1351             tarballs.push(mingw_installer.unwrap());
1352         }
1353         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1354         for tarball in &tarballs[1..] {
1355             input_tarballs.push(",");
1356             input_tarballs.push(tarball);
1357         }
1358
1359         let mut cmd = rust_installer(builder);
1360         cmd.arg("combine")
1361             .arg("--product-name=Rust")
1362             .arg("--rel-manifest-dir=rustlib")
1363             .arg("--success-message=Rust-is-ready-to-roll.")
1364             .arg("--work-dir").arg(&work)
1365             .arg("--output-dir").arg(&distdir(builder))
1366             .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
1367             .arg("--legacy-manifest-dirs=rustlib,cargo")
1368             .arg("--input-tarballs").arg(input_tarballs)
1369             .arg("--non-installed-overlay").arg(&overlay);
1370         builder.run(&mut cmd);
1371
1372         let mut license = String::new();
1373         license += &builder.read(&builder.src.join("COPYRIGHT"));
1374         license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1375         license += &builder.read(&builder.src.join("LICENSE-MIT"));
1376         license.push_str("\n");
1377         license.push_str("\n");
1378
1379         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1380         let mut rtf = rtf.to_string();
1381         rtf.push_str("\n");
1382         for line in license.lines() {
1383             rtf.push_str(line);
1384             rtf.push_str("\\line ");
1385         }
1386         rtf.push_str("}");
1387
1388         fn filter(contents: &str, marker: &str) -> String {
1389             let start = format!("tool-{}-start", marker);
1390             let end = format!("tool-{}-end", marker);
1391             let mut lines = Vec::new();
1392             let mut omitted = false;
1393             for line in contents.lines() {
1394                 if line.contains(&start) {
1395                     omitted = true;
1396                 } else if line.contains(&end) {
1397                     omitted = false;
1398                 } else if !omitted {
1399                     lines.push(line);
1400                 }
1401             }
1402
1403             lines.join("\n")
1404         }
1405
1406         let xform = |p: &Path| {
1407             let mut contents = String::new();
1408             t!(t!(File::open(p)).read_to_string(&mut contents));
1409             if rls_installer.is_none() {
1410                 contents = filter(&contents, "rls");
1411             }
1412             if rustfmt_installer.is_none() {
1413                 contents = filter(&contents, "rustfmt");
1414             }
1415             let ret = tmp.join(p.file_name().unwrap());
1416             t!(t!(File::create(&ret)).write_all(contents.as_bytes()));
1417             return ret
1418         };
1419
1420         if target.contains("apple-darwin") {
1421             let pkg = tmp.join("pkg");
1422             let _ = fs::remove_dir_all(&pkg);
1423
1424             let pkgbuild = |component: &str| {
1425                 let mut cmd = Command::new("pkgbuild");
1426                 cmd.arg("--identifier").arg(format!("org.rust-lang.{}", component))
1427                     .arg("--scripts").arg(pkg.join(component))
1428                     .arg("--nopayload")
1429                     .arg(pkg.join(component).with_extension("pkg"));
1430                 builder.run(&mut cmd);
1431             };
1432
1433             let prepare = |name: &str| {
1434                 builder.create_dir(&pkg.join(name));
1435                 builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target)),
1436                         &pkg.join(name));
1437                 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
1438                 pkgbuild(name);
1439             };
1440             prepare("rustc");
1441             prepare("cargo");
1442             prepare("rust-docs");
1443             prepare("rust-std");
1444             prepare("rust-analysis");
1445
1446             if rls_installer.is_some() {
1447                 prepare("rls");
1448             }
1449
1450             // create an 'uninstall' package
1451             builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1452             pkgbuild("uninstall");
1453
1454             builder.create_dir(&pkg.join("res"));
1455             builder.create(&pkg.join("res/LICENSE.txt"), &license);
1456             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1457             let mut cmd = Command::new("productbuild");
1458             cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
1459                 .arg("--resources").arg(pkg.join("res"))
1460                 .arg(distdir(builder).join(format!("{}-{}.pkg",
1461                                                     pkgname(builder, "rust"),
1462                                                     target)))
1463                 .arg("--package-path").arg(&pkg);
1464             builder.run(&mut cmd);
1465         }
1466
1467         if target.contains("windows") {
1468             let exe = tmp.join("exe");
1469             let _ = fs::remove_dir_all(&exe);
1470
1471             let prepare = |name: &str| {
1472                 builder.create_dir(&exe.join(name));
1473                 let dir = if name == "rust-std" || name == "rust-analysis" {
1474                     format!("{}-{}", name, target)
1475                 } else if name == "rls" {
1476                     "rls-preview".to_string()
1477                 } else {
1478                     name.to_string()
1479                 };
1480                 builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target))
1481                             .join(dir),
1482                         &exe.join(name));
1483                 builder.remove(&exe.join(name).join("manifest.in"));
1484             };
1485             prepare("rustc");
1486             prepare("cargo");
1487             prepare("rust-analysis");
1488             prepare("rust-docs");
1489             prepare("rust-std");
1490             if rls_installer.is_some() {
1491                 prepare("rls");
1492             }
1493             if target.contains("windows-gnu") {
1494                 prepare("rust-mingw");
1495             }
1496
1497             builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
1498             builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1499             builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1500             builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1501             builder.create(&exe.join("LICENSE.txt"), &license);
1502
1503             // Generate exe installer
1504             let mut cmd = Command::new("iscc");
1505             cmd.arg("rust.iss")
1506                 .current_dir(&exe);
1507             if target.contains("windows-gnu") {
1508                 cmd.arg("/dMINGW");
1509             }
1510             add_env(builder, &mut cmd, target);
1511             builder.run(&mut cmd);
1512             builder.install(&exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)),
1513                     &distdir(builder),
1514                     0o755);
1515
1516             // Generate msi installer
1517             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1518             let heat = wix.join("bin/heat.exe");
1519             let candle = wix.join("bin/candle.exe");
1520             let light = wix.join("bin/light.exe");
1521
1522             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1523             builder.run(Command::new(&heat)
1524                             .current_dir(&exe)
1525                             .arg("dir")
1526                             .arg("rustc")
1527                             .args(&heat_flags)
1528                             .arg("-cg").arg("RustcGroup")
1529                             .arg("-dr").arg("Rustc")
1530                             .arg("-var").arg("var.RustcDir")
1531                             .arg("-out").arg(exe.join("RustcGroup.wxs")));
1532             builder.run(Command::new(&heat)
1533                             .current_dir(&exe)
1534                             .arg("dir")
1535                             .arg("rust-docs")
1536                             .args(&heat_flags)
1537                             .arg("-cg").arg("DocsGroup")
1538                             .arg("-dr").arg("Docs")
1539                             .arg("-var").arg("var.DocsDir")
1540                             .arg("-out").arg(exe.join("DocsGroup.wxs"))
1541                             .arg("-t").arg(etc.join("msi/squash-components.xsl")));
1542             builder.run(Command::new(&heat)
1543                             .current_dir(&exe)
1544                             .arg("dir")
1545                             .arg("cargo")
1546                             .args(&heat_flags)
1547                             .arg("-cg").arg("CargoGroup")
1548                             .arg("-dr").arg("Cargo")
1549                             .arg("-var").arg("var.CargoDir")
1550                             .arg("-out").arg(exe.join("CargoGroup.wxs"))
1551                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1552             builder.run(Command::new(&heat)
1553                             .current_dir(&exe)
1554                             .arg("dir")
1555                             .arg("rust-std")
1556                             .args(&heat_flags)
1557                             .arg("-cg").arg("StdGroup")
1558                             .arg("-dr").arg("Std")
1559                             .arg("-var").arg("var.StdDir")
1560                             .arg("-out").arg(exe.join("StdGroup.wxs")));
1561             if rls_installer.is_some() {
1562                 builder.run(Command::new(&heat)
1563                                 .current_dir(&exe)
1564                                 .arg("dir")
1565                                 .arg("rls")
1566                                 .args(&heat_flags)
1567                                 .arg("-cg").arg("RlsGroup")
1568                                 .arg("-dr").arg("Rls")
1569                                 .arg("-var").arg("var.RlsDir")
1570                                 .arg("-out").arg(exe.join("RlsGroup.wxs"))
1571                                 .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1572             }
1573             builder.run(Command::new(&heat)
1574                             .current_dir(&exe)
1575                             .arg("dir")
1576                             .arg("rust-analysis")
1577                             .args(&heat_flags)
1578                             .arg("-cg").arg("AnalysisGroup")
1579                             .arg("-dr").arg("Analysis")
1580                             .arg("-var").arg("var.AnalysisDir")
1581                             .arg("-out").arg(exe.join("AnalysisGroup.wxs"))
1582                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1583             if target.contains("windows-gnu") {
1584                 builder.run(Command::new(&heat)
1585                                 .current_dir(&exe)
1586                                 .arg("dir")
1587                                 .arg("rust-mingw")
1588                                 .args(&heat_flags)
1589                                 .arg("-cg").arg("GccGroup")
1590                                 .arg("-dr").arg("Gcc")
1591                                 .arg("-var").arg("var.GccDir")
1592                                 .arg("-out").arg(exe.join("GccGroup.wxs")));
1593             }
1594
1595             let candle = |input: &Path| {
1596                 let output = exe.join(input.file_stem().unwrap())
1597                                 .with_extension("wixobj");
1598                 let arch = if target.contains("x86_64") {"x64"} else {"x86"};
1599                 let mut cmd = Command::new(&candle);
1600                 cmd.current_dir(&exe)
1601                     .arg("-nologo")
1602                     .arg("-dRustcDir=rustc")
1603                     .arg("-dDocsDir=rust-docs")
1604                     .arg("-dCargoDir=cargo")
1605                     .arg("-dStdDir=rust-std")
1606                     .arg("-dAnalysisDir=rust-analysis")
1607                     .arg("-arch").arg(&arch)
1608                     .arg("-out").arg(&output)
1609                     .arg(&input);
1610                 add_env(builder, &mut cmd, target);
1611
1612                 if rls_installer.is_some() {
1613                     cmd.arg("-dRlsDir=rls");
1614                 }
1615                 if target.contains("windows-gnu") {
1616                     cmd.arg("-dGccDir=rust-mingw");
1617                 }
1618                 builder.run(&mut cmd);
1619             };
1620             candle(&xform(&etc.join("msi/rust.wxs")));
1621             candle(&etc.join("msi/ui.wxs"));
1622             candle(&etc.join("msi/rustwelcomedlg.wxs"));
1623             candle("RustcGroup.wxs".as_ref());
1624             candle("DocsGroup.wxs".as_ref());
1625             candle("CargoGroup.wxs".as_ref());
1626             candle("StdGroup.wxs".as_ref());
1627             if rls_installer.is_some() {
1628                 candle("RlsGroup.wxs".as_ref());
1629             }
1630             candle("AnalysisGroup.wxs".as_ref());
1631
1632             if target.contains("windows-gnu") {
1633                 candle("GccGroup.wxs".as_ref());
1634             }
1635
1636             builder.create(&exe.join("LICENSE.rtf"), &rtf);
1637             builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1638             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1639
1640             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
1641             let mut cmd = Command::new(&light);
1642             cmd.arg("-nologo")
1643                 .arg("-ext").arg("WixUIExtension")
1644                 .arg("-ext").arg("WixUtilExtension")
1645                 .arg("-out").arg(exe.join(&filename))
1646                 .arg("rust.wixobj")
1647                 .arg("ui.wixobj")
1648                 .arg("rustwelcomedlg.wixobj")
1649                 .arg("RustcGroup.wixobj")
1650                 .arg("DocsGroup.wixobj")
1651                 .arg("CargoGroup.wixobj")
1652                 .arg("StdGroup.wixobj")
1653                 .arg("AnalysisGroup.wixobj")
1654                 .current_dir(&exe);
1655
1656             if rls_installer.is_some() {
1657                 cmd.arg("RlsGroup.wixobj");
1658             }
1659
1660             if target.contains("windows-gnu") {
1661                 cmd.arg("GccGroup.wixobj");
1662             }
1663             // ICE57 wrongly complains about the shortcuts
1664             cmd.arg("-sice:ICE57");
1665
1666             builder.run(&mut cmd);
1667
1668             if !builder.config.dry_run {
1669                 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
1670             }
1671         }
1672     }
1673 }
1674
1675 fn add_env(builder: &Builder, cmd: &mut Command, target: Interned<String>) {
1676     let mut parts = channel::CFG_RELEASE_NUM.split('.');
1677     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
1678        .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
1679        .env("CFG_RELEASE", builder.rust_release())
1680        .env("CFG_VER_MAJOR", parts.next().unwrap())
1681        .env("CFG_VER_MINOR", parts.next().unwrap())
1682        .env("CFG_VER_PATCH", parts.next().unwrap())
1683        .env("CFG_VER_BUILD", "0") // just needed to build
1684        .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
1685        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
1686        .env("CFG_BUILD", target)
1687        .env("CFG_CHANNEL", &builder.config.channel);
1688
1689     if target.contains("windows-gnu") {
1690        cmd.env("CFG_MINGW", "1")
1691           .env("CFG_ABI", "GNU");
1692     } else {
1693        cmd.env("CFG_MINGW", "0")
1694           .env("CFG_ABI", "MSVC");
1695     }
1696
1697     if target.contains("x86_64") {
1698        cmd.env("CFG_PLATFORM", "x64");
1699     } else {
1700        cmd.env("CFG_PLATFORM", "x86");
1701     }
1702 }
1703
1704 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1705 pub struct HashSign;
1706
1707 impl Step for HashSign {
1708     type Output = ();
1709     const ONLY_HOSTS: bool = true;
1710
1711     fn should_run(run: ShouldRun) -> ShouldRun {
1712         run.path("hash-and-sign")
1713     }
1714
1715     fn make_run(run: RunConfig) {
1716         run.builder.ensure(HashSign);
1717     }
1718
1719     fn run(self, builder: &Builder) {
1720         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
1721         if builder.config.dry_run {
1722             return;
1723         }
1724         let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
1725             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
1726         });
1727         let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
1728             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
1729         });
1730         let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
1731             panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
1732         });
1733         let mut pass = String::new();
1734         t!(t!(File::open(&file)).read_to_string(&mut pass));
1735
1736         let today = output(Command::new("date").arg("+%Y-%m-%d"));
1737
1738         cmd.arg(sign);
1739         cmd.arg(distdir(builder));
1740         cmd.arg(today.trim());
1741         cmd.arg(builder.rust_package_vers());
1742         cmd.arg(builder.package_vers(&builder.release_num("cargo")));
1743         cmd.arg(builder.package_vers(&builder.release_num("rls")));
1744         cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
1745         cmd.arg(builder.llvm_tools_package_vers());
1746         cmd.arg(addr);
1747
1748         builder.create_dir(&distdir(builder));
1749
1750         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
1751         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
1752         let status = t!(child.wait());
1753         assert!(status.success());
1754     }
1755 }
1756
1757 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1758 pub struct LlvmTools {
1759     pub stage: u32,
1760     pub target: Interned<String>,
1761 }
1762
1763 impl Step for LlvmTools {
1764     type Output = Option<PathBuf>;
1765     const ONLY_HOSTS: bool = true;
1766
1767     fn should_run(run: ShouldRun) -> ShouldRun {
1768         run.path("llvm-tools")
1769     }
1770
1771     fn make_run(run: RunConfig) {
1772         run.builder.ensure(LlvmTools {
1773             stage: run.builder.top_stage,
1774             target: run.target,
1775         });
1776     }
1777
1778     fn run(self, builder: &Builder) -> Option<PathBuf> {
1779         let stage = self.stage;
1780         let target = self.target;
1781         assert!(builder.config.extended);
1782
1783         builder.info(&format!("Dist LlvmTools stage{} ({})", stage, target));
1784         let src = builder.src.join("src/llvm");
1785         let name = pkgname(builder, "llvm-tools");
1786
1787         let tmp = tmpdir(builder);
1788         let image = tmp.join("llvm-tools-image");
1789         drop(fs::remove_dir_all(&image));
1790         t!(fs::create_dir_all(&image.join("bin")));
1791
1792         // Prepare the image directory
1793         for tool in LLVM_TOOLS {
1794             let exe = builder
1795                 .llvm_out(target)
1796                 .join("bin")
1797                 .join(exe(tool, &target));
1798             builder.install(&exe, &image.join("bin"), 0o755);
1799         }
1800
1801         // Prepare the overlay
1802         let overlay = tmp.join("llvm-tools-overlay");
1803         drop(fs::remove_dir_all(&overlay));
1804         builder.create_dir(&overlay);
1805         builder.install(&src.join("README.txt"), &overlay, 0o644);
1806         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
1807         builder.create(&overlay.join("version"), &builder.llvm_tools_vers());
1808
1809         // Generate the installer tarball
1810         let mut cmd = rust_installer(builder);
1811         cmd.arg("generate")
1812             .arg("--product-name=Rust")
1813             .arg("--rel-manifest-dir=rustlib")
1814             .arg("--success-message=llvm-tools-installed.")
1815             .arg("--image-dir").arg(&image)
1816             .arg("--work-dir").arg(&tmpdir(builder))
1817             .arg("--output-dir").arg(&distdir(builder))
1818             .arg("--non-installed-overlay").arg(&overlay)
1819             .arg(format!("--package-name={}-{}", name, target))
1820             .arg("--legacy-manifest-dirs=rustlib,cargo")
1821             .arg("--component-name=llvm-tools");
1822
1823
1824         builder.run(&mut cmd);
1825         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1826     }
1827 }