]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
Rollup merge of #44073 - murarth:rc-into-raw-unsized, r=alexcrichton
[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", "ar.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
1103         if build.config.channel == "nightly" {
1104             cmd.arg("--component-name=rls");
1105         } else {
1106             cmd.arg("--component-name=rls-preview");
1107         }
1108
1109         build.run(&mut cmd);
1110         distdir(build).join(format!("{}-{}.tar.gz", name, target))
1111     }
1112 }
1113
1114 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1115 pub struct Extended {
1116     stage: u32,
1117     host: Interned<String>,
1118     target: Interned<String>,
1119 }
1120
1121 impl Step for Extended {
1122     type Output = ();
1123     const DEFAULT: bool = true;
1124     const ONLY_BUILD_TARGETS: bool = true;
1125     const ONLY_HOSTS: bool = true;
1126
1127     fn should_run(run: ShouldRun) -> ShouldRun {
1128         let builder = run.builder;
1129         run.path("extended").default_condition(builder.config.extended)
1130     }
1131
1132     fn make_run(run: RunConfig) {
1133         run.builder.ensure(Extended {
1134             stage: run.builder.top_stage,
1135             host: run.host,
1136             target: run.target,
1137         });
1138     }
1139
1140     /// Creates a combined installer for the specified target in the provided stage.
1141     fn run(self, builder: &Builder) {
1142         let build = builder.build;
1143         let stage = self.stage;
1144         let target = self.target;
1145
1146         println!("Dist extended stage{} ({})", stage, target);
1147
1148         let rustc_installer = builder.ensure(Rustc {
1149             compiler: builder.compiler(stage, target),
1150         });
1151         let cargo_installer = builder.ensure(Cargo { stage, target });
1152         let rls_installer = builder.ensure(Rls { stage, target });
1153         let mingw_installer = builder.ensure(Mingw { host: target });
1154         let analysis_installer = builder.ensure(Analysis {
1155             compiler: builder.compiler(stage, self.host),
1156             target
1157         });
1158
1159         let docs_installer = builder.ensure(Docs { stage, host: target, });
1160         let std_installer = builder.ensure(Std {
1161             compiler: builder.compiler(stage, self.host),
1162             target,
1163         });
1164
1165         let tmp = tmpdir(build);
1166         let overlay = tmp.join("extended-overlay");
1167         let etc = build.src.join("src/etc/installer");
1168         let work = tmp.join("work");
1169
1170         let _ = fs::remove_dir_all(&overlay);
1171         install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
1172         install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
1173         install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
1174         let version = build.rust_version();
1175         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
1176         if let Some(sha) = build.rust_sha() {
1177             t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
1178         }
1179         install(&etc.join("README.md"), &overlay, 0o644);
1180
1181         // When rust-std package split from rustc, we needed to ensure that during
1182         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1183         // the std files during uninstall. To do this ensure that rustc comes
1184         // before rust-std in the list below.
1185         let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer,
1186                                 analysis_installer, std_installer];
1187         if build.config.docs {
1188             tarballs.push(docs_installer);
1189         }
1190         if target.contains("pc-windows-gnu") {
1191             tarballs.push(mingw_installer.unwrap());
1192         }
1193         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1194         for tarball in &tarballs[1..] {
1195             input_tarballs.push(",");
1196             input_tarballs.push(tarball);
1197         }
1198
1199         let mut cmd = rust_installer(builder);
1200         cmd.arg("combine")
1201             .arg("--product-name=Rust")
1202             .arg("--rel-manifest-dir=rustlib")
1203             .arg("--success-message=Rust-is-ready-to-roll.")
1204             .arg("--work-dir").arg(&work)
1205             .arg("--output-dir").arg(&distdir(build))
1206             .arg(format!("--package-name={}-{}", pkgname(build, "rust"), target))
1207             .arg("--legacy-manifest-dirs=rustlib,cargo")
1208             .arg("--input-tarballs").arg(input_tarballs)
1209             .arg("--non-installed-overlay").arg(&overlay);
1210         build.run(&mut cmd);
1211
1212         let mut license = String::new();
1213         t!(t!(File::open(build.src.join("COPYRIGHT"))).read_to_string(&mut license));
1214         license.push_str("\n");
1215         t!(t!(File::open(build.src.join("LICENSE-APACHE"))).read_to_string(&mut license));
1216         license.push_str("\n");
1217         t!(t!(File::open(build.src.join("LICENSE-MIT"))).read_to_string(&mut license));
1218
1219         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1220         let mut rtf = rtf.to_string();
1221         rtf.push_str("\n");
1222         for line in license.lines() {
1223             rtf.push_str(line);
1224             rtf.push_str("\\line ");
1225         }
1226         rtf.push_str("}");
1227
1228         if target.contains("apple-darwin") {
1229             let pkg = tmp.join("pkg");
1230             let _ = fs::remove_dir_all(&pkg);
1231             t!(fs::create_dir_all(pkg.join("rustc")));
1232             t!(fs::create_dir_all(pkg.join("cargo")));
1233             t!(fs::create_dir_all(pkg.join("rust-docs")));
1234             t!(fs::create_dir_all(pkg.join("rust-std")));
1235             t!(fs::create_dir_all(pkg.join("rls")));
1236             t!(fs::create_dir_all(pkg.join("rust-analysis")));
1237
1238             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)),
1239                     &pkg.join("rustc"));
1240             cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)),
1241                     &pkg.join("cargo"));
1242             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)),
1243                     &pkg.join("rust-docs"));
1244             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)),
1245                     &pkg.join("rust-std"));
1246             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)),
1247                     &pkg.join("rls"));
1248             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)),
1249                     &pkg.join("rust-analysis"));
1250
1251             install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755);
1252             install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755);
1253             install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755);
1254             install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755);
1255             install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755);
1256             install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755);
1257
1258             let pkgbuild = |component: &str| {
1259                 let mut cmd = Command::new("pkgbuild");
1260                 cmd.arg("--identifier").arg(format!("org.rust-lang.{}", component))
1261                     .arg("--scripts").arg(pkg.join(component))
1262                     .arg("--nopayload")
1263                     .arg(pkg.join(component).with_extension("pkg"));
1264                 build.run(&mut cmd);
1265             };
1266             pkgbuild("rustc");
1267             pkgbuild("cargo");
1268             pkgbuild("rust-docs");
1269             pkgbuild("rust-std");
1270             pkgbuild("rls");
1271             pkgbuild("rust-analysis");
1272
1273             // create an 'uninstall' package
1274             install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1275             pkgbuild("uninstall");
1276
1277             t!(fs::create_dir_all(pkg.join("res")));
1278             t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
1279             install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1280             let mut cmd = Command::new("productbuild");
1281             cmd.arg("--distribution").arg(etc.join("pkg/Distribution.xml"))
1282                 .arg("--resources").arg(pkg.join("res"))
1283                 .arg(distdir(build).join(format!("{}-{}.pkg",
1284                                                     pkgname(build, "rust"),
1285                                                     target)))
1286                 .arg("--package-path").arg(&pkg);
1287             build.run(&mut cmd);
1288         }
1289
1290         if target.contains("windows") {
1291             let exe = tmp.join("exe");
1292             let _ = fs::remove_dir_all(&exe);
1293             t!(fs::create_dir_all(exe.join("rustc")));
1294             t!(fs::create_dir_all(exe.join("cargo")));
1295             t!(fs::create_dir_all(exe.join("rls")));
1296             t!(fs::create_dir_all(exe.join("rust-analysis")));
1297             t!(fs::create_dir_all(exe.join("rust-docs")));
1298             t!(fs::create_dir_all(exe.join("rust-std")));
1299             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target))
1300                         .join("rustc"),
1301                     &exe.join("rustc"));
1302             cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target))
1303                         .join("cargo"),
1304                     &exe.join("cargo"));
1305             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target))
1306                         .join("rust-docs"),
1307                     &exe.join("rust-docs"));
1308             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
1309                         .join(format!("rust-std-{}", target)),
1310                     &exe.join("rust-std"));
1311             let rls_path = if build.config.channel == "nightly" {
1312                 work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls")
1313             } else {
1314                 work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls-preview")
1315             };
1316             cp_r(&rls_path, &exe.join("rls"));
1317             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target))
1318                         .join(format!("rust-analysis-{}", target)),
1319                     &exe.join("rust-analysis"));
1320
1321             t!(fs::remove_file(exe.join("rustc/manifest.in")));
1322             t!(fs::remove_file(exe.join("cargo/manifest.in")));
1323             t!(fs::remove_file(exe.join("rust-docs/manifest.in")));
1324             t!(fs::remove_file(exe.join("rust-std/manifest.in")));
1325             t!(fs::remove_file(exe.join("rls/manifest.in")));
1326             t!(fs::remove_file(exe.join("rust-analysis/manifest.in")));
1327
1328             if target.contains("windows-gnu") {
1329                 t!(fs::create_dir_all(exe.join("rust-mingw")));
1330                 cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-mingw"), target))
1331                             .join("rust-mingw"),
1332                         &exe.join("rust-mingw"));
1333                 t!(fs::remove_file(exe.join("rust-mingw/manifest.in")));
1334             }
1335
1336             install(&etc.join("exe/rust.iss"), &exe, 0o644);
1337             install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1338             install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1339             install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1340             t!(t!(File::create(exe.join("LICENSE.txt"))).write_all(license.as_bytes()));
1341
1342             // Generate exe installer
1343             let mut cmd = Command::new("iscc");
1344             cmd.arg("rust.iss")
1345                 .current_dir(&exe);
1346             if target.contains("windows-gnu") {
1347                 cmd.arg("/dMINGW");
1348             }
1349             add_env(build, &mut cmd, target);
1350             build.run(&mut cmd);
1351             install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
1352                     &distdir(build),
1353                     0o755);
1354
1355             // Generate msi installer
1356             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1357             let heat = wix.join("bin/heat.exe");
1358             let candle = wix.join("bin/candle.exe");
1359             let light = wix.join("bin/light.exe");
1360
1361             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1362             build.run(Command::new(&heat)
1363                             .current_dir(&exe)
1364                             .arg("dir")
1365                             .arg("rustc")
1366                             .args(&heat_flags)
1367                             .arg("-cg").arg("RustcGroup")
1368                             .arg("-dr").arg("Rustc")
1369                             .arg("-var").arg("var.RustcDir")
1370                             .arg("-out").arg(exe.join("RustcGroup.wxs")));
1371             build.run(Command::new(&heat)
1372                             .current_dir(&exe)
1373                             .arg("dir")
1374                             .arg("rust-docs")
1375                             .args(&heat_flags)
1376                             .arg("-cg").arg("DocsGroup")
1377                             .arg("-dr").arg("Docs")
1378                             .arg("-var").arg("var.DocsDir")
1379                             .arg("-out").arg(exe.join("DocsGroup.wxs"))
1380                             .arg("-t").arg(etc.join("msi/squash-components.xsl")));
1381             build.run(Command::new(&heat)
1382                             .current_dir(&exe)
1383                             .arg("dir")
1384                             .arg("cargo")
1385                             .args(&heat_flags)
1386                             .arg("-cg").arg("CargoGroup")
1387                             .arg("-dr").arg("Cargo")
1388                             .arg("-var").arg("var.CargoDir")
1389                             .arg("-out").arg(exe.join("CargoGroup.wxs"))
1390                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1391             build.run(Command::new(&heat)
1392                             .current_dir(&exe)
1393                             .arg("dir")
1394                             .arg("rust-std")
1395                             .args(&heat_flags)
1396                             .arg("-cg").arg("StdGroup")
1397                             .arg("-dr").arg("Std")
1398                             .arg("-var").arg("var.StdDir")
1399                             .arg("-out").arg(exe.join("StdGroup.wxs")));
1400             build.run(Command::new(&heat)
1401                             .current_dir(&exe)
1402                             .arg("dir")
1403                             .arg("rls")
1404                             .args(&heat_flags)
1405                             .arg("-cg").arg("RlsGroup")
1406                             .arg("-dr").arg("Rls")
1407                             .arg("-var").arg("var.RlsDir")
1408                             .arg("-out").arg(exe.join("RlsGroup.wxs"))
1409                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1410             build.run(Command::new(&heat)
1411                             .current_dir(&exe)
1412                             .arg("dir")
1413                             .arg("rust-analysis")
1414                             .args(&heat_flags)
1415                             .arg("-cg").arg("AnalysisGroup")
1416                             .arg("-dr").arg("Analysis")
1417                             .arg("-var").arg("var.AnalysisDir")
1418                             .arg("-out").arg(exe.join("AnalysisGroup.wxs"))
1419                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1420             if target.contains("windows-gnu") {
1421                 build.run(Command::new(&heat)
1422                                 .current_dir(&exe)
1423                                 .arg("dir")
1424                                 .arg("rust-mingw")
1425                                 .args(&heat_flags)
1426                                 .arg("-cg").arg("GccGroup")
1427                                 .arg("-dr").arg("Gcc")
1428                                 .arg("-var").arg("var.GccDir")
1429                                 .arg("-out").arg(exe.join("GccGroup.wxs")));
1430             }
1431
1432             let candle = |input: &Path| {
1433                 let output = exe.join(input.file_stem().unwrap())
1434                                 .with_extension("wixobj");
1435                 let arch = if target.contains("x86_64") {"x64"} else {"x86"};
1436                 let mut cmd = Command::new(&candle);
1437                 cmd.current_dir(&exe)
1438                     .arg("-nologo")
1439                     .arg("-dRustcDir=rustc")
1440                     .arg("-dDocsDir=rust-docs")
1441                     .arg("-dCargoDir=cargo")
1442                     .arg("-dStdDir=rust-std")
1443                     .arg("-dRlsDir=rls")
1444                     .arg("-dAnalysisDir=rust-analysis")
1445                     .arg("-arch").arg(&arch)
1446                     .arg("-out").arg(&output)
1447                     .arg(&input);
1448                 add_env(build, &mut cmd, target);
1449
1450                 if target.contains("windows-gnu") {
1451                     cmd.arg("-dGccDir=rust-mingw");
1452                 }
1453                 build.run(&mut cmd);
1454             };
1455             candle(&etc.join("msi/rust.wxs"));
1456             candle(&etc.join("msi/ui.wxs"));
1457             candle(&etc.join("msi/rustwelcomedlg.wxs"));
1458             candle("RustcGroup.wxs".as_ref());
1459             candle("DocsGroup.wxs".as_ref());
1460             candle("CargoGroup.wxs".as_ref());
1461             candle("StdGroup.wxs".as_ref());
1462             candle("RlsGroup.wxs".as_ref());
1463             candle("AnalysisGroup.wxs".as_ref());
1464
1465             if target.contains("windows-gnu") {
1466                 candle("GccGroup.wxs".as_ref());
1467             }
1468
1469             t!(t!(File::create(exe.join("LICENSE.rtf"))).write_all(rtf.as_bytes()));
1470             install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1471             install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1472
1473             let filename = format!("{}-{}.msi", pkgname(build, "rust"), target);
1474             let mut cmd = Command::new(&light);
1475             cmd.arg("-nologo")
1476                 .arg("-ext").arg("WixUIExtension")
1477                 .arg("-ext").arg("WixUtilExtension")
1478                 .arg("-out").arg(exe.join(&filename))
1479                 .arg("rust.wixobj")
1480                 .arg("ui.wixobj")
1481                 .arg("rustwelcomedlg.wixobj")
1482                 .arg("RustcGroup.wixobj")
1483                 .arg("DocsGroup.wixobj")
1484                 .arg("CargoGroup.wixobj")
1485                 .arg("StdGroup.wixobj")
1486                 .arg("RlsGroup.wixobj")
1487                 .arg("AnalysisGroup.wixobj")
1488                 .current_dir(&exe);
1489
1490             if target.contains("windows-gnu") {
1491                 cmd.arg("GccGroup.wixobj");
1492             }
1493             // ICE57 wrongly complains about the shortcuts
1494             cmd.arg("-sice:ICE57");
1495
1496             build.run(&mut cmd);
1497
1498             t!(fs::rename(exe.join(&filename), distdir(build).join(&filename)));
1499         }
1500     }
1501 }
1502
1503 fn add_env(build: &Build, cmd: &mut Command, target: Interned<String>) {
1504     let mut parts = channel::CFG_RELEASE_NUM.split('.');
1505     cmd.env("CFG_RELEASE_INFO", build.rust_version())
1506        .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
1507        .env("CFG_RELEASE", build.rust_release())
1508        .env("CFG_PRERELEASE_VERSION", channel::CFG_PRERELEASE_VERSION)
1509        .env("CFG_VER_MAJOR", parts.next().unwrap())
1510        .env("CFG_VER_MINOR", parts.next().unwrap())
1511        .env("CFG_VER_PATCH", parts.next().unwrap())
1512        .env("CFG_VER_BUILD", "0") // just needed to build
1513        .env("CFG_PACKAGE_VERS", build.rust_package_vers())
1514        .env("CFG_PACKAGE_NAME", pkgname(build, "rust"))
1515        .env("CFG_BUILD", target)
1516        .env("CFG_CHANNEL", &build.config.channel);
1517
1518     if target.contains("windows-gnu") {
1519        cmd.env("CFG_MINGW", "1")
1520           .env("CFG_ABI", "GNU");
1521     } else {
1522        cmd.env("CFG_MINGW", "0")
1523           .env("CFG_ABI", "MSVC");
1524     }
1525
1526     if target.contains("x86_64") {
1527        cmd.env("CFG_PLATFORM", "x64");
1528     } else {
1529        cmd.env("CFG_PLATFORM", "x86");
1530     }
1531 }
1532
1533 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1534 pub struct HashSign;
1535
1536 impl Step for HashSign {
1537     type Output = ();
1538     const ONLY_BUILD_TARGETS: bool = true;
1539     const ONLY_HOSTS: bool = true;
1540     const ONLY_BUILD: bool = true;
1541
1542     fn should_run(run: ShouldRun) -> ShouldRun {
1543         run.path("hash-and-sign")
1544     }
1545
1546     fn make_run(run: RunConfig) {
1547         run.builder.ensure(HashSign);
1548     }
1549
1550     fn run(self, builder: &Builder) {
1551         let build = builder.build;
1552         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
1553         let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
1554             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
1555         });
1556         let addr = build.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
1557             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
1558         });
1559         let file = build.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
1560             panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
1561         });
1562         let mut pass = String::new();
1563         t!(t!(File::open(&file)).read_to_string(&mut pass));
1564
1565         let today = output(Command::new("date").arg("+%Y-%m-%d"));
1566
1567         cmd.arg(sign);
1568         cmd.arg(distdir(build));
1569         cmd.arg(today.trim());
1570         cmd.arg(build.rust_package_vers());
1571         cmd.arg(build.package_vers(&build.release_num("cargo")));
1572         cmd.arg(build.package_vers(&build.release_num("rls")));
1573         cmd.arg(addr);
1574
1575         t!(fs::create_dir_all(distdir(build)));
1576
1577         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
1578         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
1579         let status = t!(child.wait());
1580         assert!(status.success());
1581     }
1582 }