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