]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
Auto merge of #44251 - kennytm:osx-backtrace, 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::{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("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             "man",
838             "src",
839         ];
840
841         copy_src_dirs(build, &src_dirs[..], &[], &plain_dst_src);
842
843         // Copy the files normally
844         for item in &src_files {
845             copy(&build.src.join(item), &plain_dst_src.join(item));
846         }
847
848         // Create the version file
849         write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
850         if let Some(sha) = build.rust_sha() {
851             write_file(&plain_dst_src.join("git-commit-hash"), sha.as_bytes());
852         }
853
854         // If we're building from git sources, we need to vendor a complete distribution.
855         if build.rust_info.is_git() {
856             // Get cargo-vendor installed, if it isn't already.
857             let mut has_cargo_vendor = false;
858             let mut cmd = Command::new(&build.initial_cargo);
859             for line in output(cmd.arg("install").arg("--list")).lines() {
860                 has_cargo_vendor |= line.starts_with("cargo-vendor ");
861             }
862             if !has_cargo_vendor {
863                 let mut cmd = Command::new(&build.initial_cargo);
864                 cmd.arg("install")
865                    .arg("--force")
866                    .arg("--debug")
867                    .arg("--vers").arg(CARGO_VENDOR_VERSION)
868                    .arg("cargo-vendor")
869                    .env("RUSTC", &build.initial_rustc);
870                 build.run(&mut cmd);
871             }
872
873             // Vendor all Cargo dependencies
874             let mut cmd = Command::new(&build.initial_cargo);
875             cmd.arg("vendor")
876                .current_dir(&plain_dst_src.join("src"));
877             build.run(&mut cmd);
878         }
879
880         // Create plain source tarball
881         let plain_name = format!("rustc-{}-src", build.rust_package_vers());
882         let mut tarball = distdir(build).join(&format!("{}.tar.gz", plain_name));
883         tarball.set_extension(""); // strip .gz
884         tarball.set_extension(""); // strip .tar
885         if let Some(dir) = tarball.parent() {
886             t!(fs::create_dir_all(dir));
887         }
888         println!("running installer");
889         let mut cmd = rust_installer(builder);
890         cmd.arg("tarball")
891            .arg("--input").arg(&plain_name)
892            .arg("--output").arg(&tarball)
893            .arg("--work-dir=.")
894            .current_dir(tmpdir(build));
895         build.run(&mut cmd);
896         distdir(build).join(&format!("{}.tar.gz", plain_name))
897     }
898 }
899
900 fn install(src: &Path, dstdir: &Path, perms: u32) {
901     let dst = dstdir.join(src.file_name().unwrap());
902     t!(fs::create_dir_all(dstdir));
903     t!(fs::copy(src, &dst));
904     chmod(&dst, perms);
905 }
906
907 #[cfg(unix)]
908 fn chmod(path: &Path, perms: u32) {
909     use std::os::unix::fs::*;
910     t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
911 }
912 #[cfg(windows)]
913 fn chmod(_path: &Path, _perms: u32) {}
914
915 // We have to run a few shell scripts, which choke quite a bit on both `\`
916 // characters and on `C:\` paths, so normalize both of them away.
917 pub fn sanitize_sh(path: &Path) -> String {
918     let path = path.to_str().unwrap().replace("\\", "/");
919     return change_drive(&path).unwrap_or(path);
920
921     fn change_drive(s: &str) -> Option<String> {
922         let mut ch = s.chars();
923         let drive = ch.next().unwrap_or('C');
924         if ch.next() != Some(':') {
925             return None
926         }
927         if ch.next() != Some('/') {
928             return None
929         }
930         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
931     }
932 }
933
934 fn write_file(path: &Path, data: &[u8]) {
935     let mut vf = t!(fs::File::create(path));
936     t!(vf.write_all(data));
937 }
938
939 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
940 pub struct Cargo {
941     pub stage: u32,
942     pub target: Interned<String>,
943 }
944
945 impl Step for Cargo {
946     type Output = PathBuf;
947     const ONLY_BUILD_TARGETS: bool = true;
948     const ONLY_HOSTS: bool = true;
949
950     fn should_run(run: ShouldRun) -> ShouldRun {
951         run.path("cargo")
952     }
953
954     fn make_run(run: RunConfig) {
955         run.builder.ensure(Cargo {
956             stage: run.builder.top_stage,
957             target: run.target,
958         });
959     }
960
961     fn run(self, builder: &Builder) -> PathBuf {
962         let build = builder.build;
963         let stage = self.stage;
964         let target = self.target;
965
966         println!("Dist cargo stage{} ({})", stage, target);
967         let src = build.src.join("src/tools/cargo");
968         let etc = src.join("src/etc");
969         let release_num = build.release_num("cargo");
970         let name = pkgname(build, "cargo");
971         let version = builder.cargo_info.version(build, &release_num);
972
973         let tmp = tmpdir(build);
974         let image = tmp.join("cargo-image");
975         drop(fs::remove_dir_all(&image));
976         t!(fs::create_dir_all(&image));
977
978         // Prepare the image directory
979         t!(fs::create_dir_all(image.join("share/zsh/site-functions")));
980         t!(fs::create_dir_all(image.join("etc/bash_completion.d")));
981         let cargo = builder.ensure(tool::Cargo {
982             compiler: builder.compiler(stage, build.build),
983             target
984         });
985         install(&cargo, &image.join("bin"), 0o755);
986         for man in t!(etc.join("man").read_dir()) {
987             let man = t!(man);
988             install(&man.path(), &image.join("share/man/man1"), 0o644);
989         }
990         install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
991         copy(&etc.join("cargo.bashcomp.sh"),
992              &image.join("etc/bash_completion.d/cargo"));
993         let doc = image.join("share/doc/cargo");
994         install(&src.join("README.md"), &doc, 0o644);
995         install(&src.join("LICENSE-MIT"), &doc, 0o644);
996         install(&src.join("LICENSE-APACHE"), &doc, 0o644);
997         install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
998
999         // Prepare the overlay
1000         let overlay = tmp.join("cargo-overlay");
1001         drop(fs::remove_dir_all(&overlay));
1002         t!(fs::create_dir_all(&overlay));
1003         install(&src.join("README.md"), &overlay, 0o644);
1004         install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1005         install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1006         install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
1007         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
1008
1009         // Generate the installer tarball
1010         let mut cmd = rust_installer(builder);
1011         cmd.arg("generate")
1012            .arg("--product-name=Rust")
1013            .arg("--rel-manifest-dir=rustlib")
1014            .arg("--success-message=Rust-is-ready-to-roll.")
1015            .arg("--image-dir").arg(&image)
1016            .arg("--work-dir").arg(&tmpdir(build))
1017            .arg("--output-dir").arg(&distdir(build))
1018            .arg("--non-installed-overlay").arg(&overlay)
1019            .arg(format!("--package-name={}-{}", name, target))
1020            .arg("--component-name=cargo")
1021            .arg("--legacy-manifest-dirs=rustlib,cargo");
1022         build.run(&mut cmd);
1023         distdir(build).join(format!("{}-{}.tar.gz", name, target))
1024     }
1025 }
1026
1027 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1028 pub struct Rls {
1029     pub stage: u32,
1030     pub target: Interned<String>,
1031 }
1032
1033 impl Step for Rls {
1034     type Output = PathBuf;
1035     const ONLY_BUILD_TARGETS: bool = true;
1036     const ONLY_HOSTS: bool = true;
1037
1038     fn should_run(run: ShouldRun) -> ShouldRun {
1039         run.path("rls")
1040     }
1041
1042     fn make_run(run: RunConfig) {
1043         run.builder.ensure(Rls {
1044             stage: run.builder.top_stage,
1045             target: run.target,
1046         });
1047     }
1048
1049     fn run(self, builder: &Builder) -> PathBuf {
1050         let build = builder.build;
1051         let stage = self.stage;
1052         let target = self.target;
1053         assert!(build.config.extended);
1054
1055         println!("Dist RLS stage{} ({})", stage, target);
1056         let src = build.src.join("src/tools/rls");
1057         let release_num = build.release_num("rls");
1058         let name = pkgname(build, "rls");
1059         let version = build.rls_info.version(build, &release_num);
1060
1061         let tmp = tmpdir(build);
1062         let image = tmp.join("rls-image");
1063         drop(fs::remove_dir_all(&image));
1064         t!(fs::create_dir_all(&image));
1065
1066         // Prepare the image directory
1067         let rls = builder.ensure(tool::Rls {
1068             compiler: builder.compiler(stage, build.build),
1069             target
1070         });
1071         install(&rls, &image.join("bin"), 0o755);
1072         let doc = image.join("share/doc/rls");
1073         install(&src.join("README.md"), &doc, 0o644);
1074         install(&src.join("LICENSE-MIT"), &doc, 0o644);
1075         install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1076
1077         // Prepare the overlay
1078         let overlay = tmp.join("rls-overlay");
1079         drop(fs::remove_dir_all(&overlay));
1080         t!(fs::create_dir_all(&overlay));
1081         install(&src.join("README.md"), &overlay, 0o644);
1082         install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1083         install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1084         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
1085
1086         // Generate the installer tarball
1087         let mut cmd = rust_installer(builder);
1088         cmd.arg("generate")
1089            .arg("--product-name=Rust")
1090            .arg("--rel-manifest-dir=rustlib")
1091            .arg("--success-message=RLS-ready-to-serve.")
1092            .arg("--image-dir").arg(&image)
1093            .arg("--work-dir").arg(&tmpdir(build))
1094            .arg("--output-dir").arg(&distdir(build))
1095            .arg("--non-installed-overlay").arg(&overlay)
1096            .arg(format!("--package-name={}-{}", name, target))
1097            .arg("--component-name=rls")
1098            .arg("--legacy-manifest-dirs=rustlib,cargo");
1099         build.run(&mut cmd);
1100         distdir(build).join(format!("{}-{}.tar.gz", name, target))
1101     }
1102 }
1103
1104 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1105 pub struct Extended {
1106     stage: u32,
1107     host: Interned<String>,
1108     target: Interned<String>,
1109 }
1110
1111 impl Step for Extended {
1112     type Output = ();
1113     const DEFAULT: bool = true;
1114     const ONLY_BUILD_TARGETS: bool = true;
1115     const ONLY_HOSTS: bool = true;
1116
1117     fn should_run(run: ShouldRun) -> ShouldRun {
1118         let builder = run.builder;
1119         run.path("extended").default_condition(builder.config.extended)
1120     }
1121
1122     fn make_run(run: RunConfig) {
1123         run.builder.ensure(Extended {
1124             stage: run.builder.top_stage,
1125             host: run.host,
1126             target: run.target,
1127         });
1128     }
1129
1130     /// Creates a combined installer for the specified target in the provided stage.
1131     fn run(self, builder: &Builder) {
1132         let build = builder.build;
1133         let stage = self.stage;
1134         let target = self.target;
1135
1136         println!("Dist extended stage{} ({})", stage, target);
1137
1138         let rustc_installer = builder.ensure(Rustc {
1139             compiler: builder.compiler(stage, target),
1140         });
1141         let cargo_installer = builder.ensure(Cargo { stage, target });
1142         let rls_installer = builder.ensure(Rls { stage, target });
1143         let mingw_installer = builder.ensure(Mingw { host: target });
1144         let analysis_installer = builder.ensure(Analysis {
1145             compiler: builder.compiler(stage, self.host),
1146             target
1147         });
1148
1149         let docs_installer = builder.ensure(Docs { stage, host: target, });
1150         let std_installer = builder.ensure(Std {
1151             compiler: builder.compiler(stage, self.host),
1152             target,
1153         });
1154
1155         let tmp = tmpdir(build);
1156         let overlay = tmp.join("extended-overlay");
1157         let etc = build.src.join("src/etc/installer");
1158         let work = tmp.join("work");
1159
1160         let _ = fs::remove_dir_all(&overlay);
1161         install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
1162         install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
1163         install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
1164         let version = build.rust_version();
1165         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
1166         if let Some(sha) = build.rust_sha() {
1167             t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
1168         }
1169         install(&etc.join("README.md"), &overlay, 0o644);
1170
1171         // When rust-std package split from rustc, we needed to ensure that during
1172         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1173         // the std files during uninstall. To do this ensure that rustc comes
1174         // before rust-std in the list below.
1175         let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer,
1176                                 analysis_installer, std_installer];
1177         if build.config.docs {
1178             tarballs.push(docs_installer);
1179         }
1180         if target.contains("pc-windows-gnu") {
1181             tarballs.push(mingw_installer.unwrap());
1182         }
1183         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1184         for tarball in &tarballs[1..] {
1185             input_tarballs.push(",");
1186             input_tarballs.push(tarball);
1187         }
1188
1189         let mut cmd = rust_installer(builder);
1190         cmd.arg("combine")
1191             .arg("--product-name=Rust")
1192             .arg("--rel-manifest-dir=rustlib")
1193             .arg("--success-message=Rust-is-ready-to-roll.")
1194             .arg("--work-dir").arg(&work)
1195             .arg("--output-dir").arg(&distdir(build))
1196             .arg(format!("--package-name={}-{}", pkgname(build, "rust"), target))
1197             .arg("--legacy-manifest-dirs=rustlib,cargo")
1198             .arg("--input-tarballs").arg(input_tarballs)
1199             .arg("--non-installed-overlay").arg(&overlay);
1200         build.run(&mut cmd);
1201
1202         let mut license = String::new();
1203         t!(t!(File::open(build.src.join("COPYRIGHT"))).read_to_string(&mut license));
1204         license.push_str("\n");
1205         t!(t!(File::open(build.src.join("LICENSE-APACHE"))).read_to_string(&mut license));
1206         license.push_str("\n");
1207         t!(t!(File::open(build.src.join("LICENSE-MIT"))).read_to_string(&mut license));
1208
1209         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1210         let mut rtf = rtf.to_string();
1211         rtf.push_str("\n");
1212         for line in license.lines() {
1213             rtf.push_str(line);
1214             rtf.push_str("\\line ");
1215         }
1216         rtf.push_str("}");
1217
1218         if target.contains("apple-darwin") {
1219             let pkg = tmp.join("pkg");
1220             let _ = fs::remove_dir_all(&pkg);
1221             t!(fs::create_dir_all(pkg.join("rustc")));
1222             t!(fs::create_dir_all(pkg.join("cargo")));
1223             t!(fs::create_dir_all(pkg.join("rust-docs")));
1224             t!(fs::create_dir_all(pkg.join("rust-std")));
1225             t!(fs::create_dir_all(pkg.join("rls")));
1226             t!(fs::create_dir_all(pkg.join("rust-analysis")));
1227
1228             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)),
1229                     &pkg.join("rustc"));
1230             cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)),
1231                     &pkg.join("cargo"));
1232             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)),
1233                     &pkg.join("rust-docs"));
1234             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)),
1235                     &pkg.join("rust-std"));
1236             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)),
1237                     &pkg.join("rls"));
1238             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)),
1239                     &pkg.join("rust-analysis"));
1240
1241             install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755);
1242             install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755);
1243             install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755);
1244             install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755);
1245             install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755);
1246             install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755);
1247
1248             let pkgbuild = |component: &str| {
1249                 let mut cmd = Command::new("pkgbuild");
1250                 cmd.arg("--identifier").arg(format!("org.rust-lang.{}", component))
1251                     .arg("--scripts").arg(pkg.join(component))
1252                     .arg("--nopayload")
1253                     .arg(pkg.join(component).with_extension("pkg"));
1254                 build.run(&mut cmd);
1255             };
1256             pkgbuild("rustc");
1257             pkgbuild("cargo");
1258             pkgbuild("rust-docs");
1259             pkgbuild("rust-std");
1260             pkgbuild("rls");
1261             pkgbuild("rust-analysis");
1262
1263             // create an 'uninstall' package
1264             install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1265             pkgbuild("uninstall");
1266
1267             t!(fs::create_dir_all(pkg.join("res")));
1268             t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
1269             install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1270             let mut cmd = Command::new("productbuild");
1271             cmd.arg("--distribution").arg(etc.join("pkg/Distribution.xml"))
1272                 .arg("--resources").arg(pkg.join("res"))
1273                 .arg(distdir(build).join(format!("{}-{}.pkg",
1274                                                     pkgname(build, "rust"),
1275                                                     target)))
1276                 .arg("--package-path").arg(&pkg);
1277             build.run(&mut cmd);
1278         }
1279
1280         if target.contains("windows") {
1281             let exe = tmp.join("exe");
1282             let _ = fs::remove_dir_all(&exe);
1283             t!(fs::create_dir_all(exe.join("rustc")));
1284             t!(fs::create_dir_all(exe.join("cargo")));
1285             t!(fs::create_dir_all(exe.join("rls")));
1286             t!(fs::create_dir_all(exe.join("rust-analysis")));
1287             t!(fs::create_dir_all(exe.join("rust-docs")));
1288             t!(fs::create_dir_all(exe.join("rust-std")));
1289             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target))
1290                         .join("rustc"),
1291                     &exe.join("rustc"));
1292             cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target))
1293                         .join("cargo"),
1294                     &exe.join("cargo"));
1295             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target))
1296                         .join("rust-docs"),
1297                     &exe.join("rust-docs"));
1298             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
1299                         .join(format!("rust-std-{}", target)),
1300                     &exe.join("rust-std"));
1301             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target))
1302                         .join("rls"),
1303                     &exe.join("rls"));
1304             cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target))
1305                         .join(format!("rust-analysis-{}", target)),
1306                     &exe.join("rust-analysis"));
1307
1308             t!(fs::remove_file(exe.join("rustc/manifest.in")));
1309             t!(fs::remove_file(exe.join("cargo/manifest.in")));
1310             t!(fs::remove_file(exe.join("rust-docs/manifest.in")));
1311             t!(fs::remove_file(exe.join("rust-std/manifest.in")));
1312             t!(fs::remove_file(exe.join("rls/manifest.in")));
1313             t!(fs::remove_file(exe.join("rust-analysis/manifest.in")));
1314
1315             if target.contains("windows-gnu") {
1316                 t!(fs::create_dir_all(exe.join("rust-mingw")));
1317                 cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-mingw"), target))
1318                             .join("rust-mingw"),
1319                         &exe.join("rust-mingw"));
1320                 t!(fs::remove_file(exe.join("rust-mingw/manifest.in")));
1321             }
1322
1323             install(&etc.join("exe/rust.iss"), &exe, 0o644);
1324             install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1325             install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1326             install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1327             t!(t!(File::create(exe.join("LICENSE.txt"))).write_all(license.as_bytes()));
1328
1329             // Generate exe installer
1330             let mut cmd = Command::new("iscc");
1331             cmd.arg("rust.iss")
1332                 .current_dir(&exe);
1333             if target.contains("windows-gnu") {
1334                 cmd.arg("/dMINGW");
1335             }
1336             add_env(build, &mut cmd, target);
1337             build.run(&mut cmd);
1338             install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
1339                     &distdir(build),
1340                     0o755);
1341
1342             // Generate msi installer
1343             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1344             let heat = wix.join("bin/heat.exe");
1345             let candle = wix.join("bin/candle.exe");
1346             let light = wix.join("bin/light.exe");
1347
1348             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1349             build.run(Command::new(&heat)
1350                             .current_dir(&exe)
1351                             .arg("dir")
1352                             .arg("rustc")
1353                             .args(&heat_flags)
1354                             .arg("-cg").arg("RustcGroup")
1355                             .arg("-dr").arg("Rustc")
1356                             .arg("-var").arg("var.RustcDir")
1357                             .arg("-out").arg(exe.join("RustcGroup.wxs")));
1358             build.run(Command::new(&heat)
1359                             .current_dir(&exe)
1360                             .arg("dir")
1361                             .arg("rust-docs")
1362                             .args(&heat_flags)
1363                             .arg("-cg").arg("DocsGroup")
1364                             .arg("-dr").arg("Docs")
1365                             .arg("-var").arg("var.DocsDir")
1366                             .arg("-out").arg(exe.join("DocsGroup.wxs"))
1367                             .arg("-t").arg(etc.join("msi/squash-components.xsl")));
1368             build.run(Command::new(&heat)
1369                             .current_dir(&exe)
1370                             .arg("dir")
1371                             .arg("cargo")
1372                             .args(&heat_flags)
1373                             .arg("-cg").arg("CargoGroup")
1374                             .arg("-dr").arg("Cargo")
1375                             .arg("-var").arg("var.CargoDir")
1376                             .arg("-out").arg(exe.join("CargoGroup.wxs"))
1377                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1378             build.run(Command::new(&heat)
1379                             .current_dir(&exe)
1380                             .arg("dir")
1381                             .arg("rust-std")
1382                             .args(&heat_flags)
1383                             .arg("-cg").arg("StdGroup")
1384                             .arg("-dr").arg("Std")
1385                             .arg("-var").arg("var.StdDir")
1386                             .arg("-out").arg(exe.join("StdGroup.wxs")));
1387             build.run(Command::new(&heat)
1388                             .current_dir(&exe)
1389                             .arg("dir")
1390                             .arg("rls")
1391                             .args(&heat_flags)
1392                             .arg("-cg").arg("RlsGroup")
1393                             .arg("-dr").arg("Rls")
1394                             .arg("-var").arg("var.RlsDir")
1395                             .arg("-out").arg(exe.join("RlsGroup.wxs"))
1396                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1397             build.run(Command::new(&heat)
1398                             .current_dir(&exe)
1399                             .arg("dir")
1400                             .arg("rust-analysis")
1401                             .args(&heat_flags)
1402                             .arg("-cg").arg("AnalysisGroup")
1403                             .arg("-dr").arg("Analysis")
1404                             .arg("-var").arg("var.AnalysisDir")
1405                             .arg("-out").arg(exe.join("AnalysisGroup.wxs"))
1406                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1407             if target.contains("windows-gnu") {
1408                 build.run(Command::new(&heat)
1409                                 .current_dir(&exe)
1410                                 .arg("dir")
1411                                 .arg("rust-mingw")
1412                                 .args(&heat_flags)
1413                                 .arg("-cg").arg("GccGroup")
1414                                 .arg("-dr").arg("Gcc")
1415                                 .arg("-var").arg("var.GccDir")
1416                                 .arg("-out").arg(exe.join("GccGroup.wxs")));
1417             }
1418
1419             let candle = |input: &Path| {
1420                 let output = exe.join(input.file_stem().unwrap())
1421                                 .with_extension("wixobj");
1422                 let arch = if target.contains("x86_64") {"x64"} else {"x86"};
1423                 let mut cmd = Command::new(&candle);
1424                 cmd.current_dir(&exe)
1425                     .arg("-nologo")
1426                     .arg("-dRustcDir=rustc")
1427                     .arg("-dDocsDir=rust-docs")
1428                     .arg("-dCargoDir=cargo")
1429                     .arg("-dStdDir=rust-std")
1430                     .arg("-dRlsDir=rls")
1431                     .arg("-dAnalysisDir=rust-analysis")
1432                     .arg("-arch").arg(&arch)
1433                     .arg("-out").arg(&output)
1434                     .arg(&input);
1435                 add_env(build, &mut cmd, target);
1436
1437                 if target.contains("windows-gnu") {
1438                     cmd.arg("-dGccDir=rust-mingw");
1439                 }
1440                 build.run(&mut cmd);
1441             };
1442             candle(&etc.join("msi/rust.wxs"));
1443             candle(&etc.join("msi/ui.wxs"));
1444             candle(&etc.join("msi/rustwelcomedlg.wxs"));
1445             candle("RustcGroup.wxs".as_ref());
1446             candle("DocsGroup.wxs".as_ref());
1447             candle("CargoGroup.wxs".as_ref());
1448             candle("StdGroup.wxs".as_ref());
1449             candle("RlsGroup.wxs".as_ref());
1450             candle("AnalysisGroup.wxs".as_ref());
1451
1452             if target.contains("windows-gnu") {
1453                 candle("GccGroup.wxs".as_ref());
1454             }
1455
1456             t!(t!(File::create(exe.join("LICENSE.rtf"))).write_all(rtf.as_bytes()));
1457             install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1458             install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1459
1460             let filename = format!("{}-{}.msi", pkgname(build, "rust"), target);
1461             let mut cmd = Command::new(&light);
1462             cmd.arg("-nologo")
1463                 .arg("-ext").arg("WixUIExtension")
1464                 .arg("-ext").arg("WixUtilExtension")
1465                 .arg("-out").arg(exe.join(&filename))
1466                 .arg("rust.wixobj")
1467                 .arg("ui.wixobj")
1468                 .arg("rustwelcomedlg.wixobj")
1469                 .arg("RustcGroup.wixobj")
1470                 .arg("DocsGroup.wixobj")
1471                 .arg("CargoGroup.wixobj")
1472                 .arg("StdGroup.wixobj")
1473                 .arg("RlsGroup.wixobj")
1474                 .arg("AnalysisGroup.wixobj")
1475                 .current_dir(&exe);
1476
1477             if target.contains("windows-gnu") {
1478                 cmd.arg("GccGroup.wixobj");
1479             }
1480             // ICE57 wrongly complains about the shortcuts
1481             cmd.arg("-sice:ICE57");
1482
1483             build.run(&mut cmd);
1484
1485             t!(fs::rename(exe.join(&filename), distdir(build).join(&filename)));
1486         }
1487     }
1488 }
1489
1490 fn add_env(build: &Build, cmd: &mut Command, target: Interned<String>) {
1491     let mut parts = channel::CFG_RELEASE_NUM.split('.');
1492     cmd.env("CFG_RELEASE_INFO", build.rust_version())
1493        .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
1494        .env("CFG_RELEASE", build.rust_release())
1495        .env("CFG_PRERELEASE_VERSION", channel::CFG_PRERELEASE_VERSION)
1496        .env("CFG_VER_MAJOR", parts.next().unwrap())
1497        .env("CFG_VER_MINOR", parts.next().unwrap())
1498        .env("CFG_VER_PATCH", parts.next().unwrap())
1499        .env("CFG_VER_BUILD", "0") // just needed to build
1500        .env("CFG_PACKAGE_VERS", build.rust_package_vers())
1501        .env("CFG_PACKAGE_NAME", pkgname(build, "rust"))
1502        .env("CFG_BUILD", target)
1503        .env("CFG_CHANNEL", &build.config.channel);
1504
1505     if target.contains("windows-gnu") {
1506        cmd.env("CFG_MINGW", "1")
1507           .env("CFG_ABI", "GNU");
1508     } else {
1509        cmd.env("CFG_MINGW", "0")
1510           .env("CFG_ABI", "MSVC");
1511     }
1512
1513     if target.contains("x86_64") {
1514        cmd.env("CFG_PLATFORM", "x64");
1515     } else {
1516        cmd.env("CFG_PLATFORM", "x86");
1517     }
1518 }
1519
1520 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
1521 pub struct HashSign;
1522
1523 impl Step for HashSign {
1524     type Output = ();
1525     const ONLY_BUILD_TARGETS: bool = true;
1526     const ONLY_HOSTS: bool = true;
1527     const ONLY_BUILD: bool = true;
1528
1529     fn should_run(run: ShouldRun) -> ShouldRun {
1530         run.path("hash-and-sign")
1531     }
1532
1533     fn make_run(run: RunConfig) {
1534         run.builder.ensure(HashSign);
1535     }
1536
1537     fn run(self, builder: &Builder) {
1538         let build = builder.build;
1539         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
1540         let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
1541             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
1542         });
1543         let addr = build.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
1544             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
1545         });
1546         let file = build.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
1547             panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
1548         });
1549         let mut pass = String::new();
1550         t!(t!(File::open(&file)).read_to_string(&mut pass));
1551
1552         let today = output(Command::new("date").arg("+%Y-%m-%d"));
1553
1554         cmd.arg(sign);
1555         cmd.arg(distdir(build));
1556         cmd.arg(today.trim());
1557         cmd.arg(build.rust_package_vers());
1558         cmd.arg(build.package_vers(&build.release_num("cargo")));
1559         cmd.arg(build.package_vers(&build.release_num("rls")));
1560         cmd.arg(addr);
1561
1562         t!(fs::create_dir_all(distdir(build)));
1563
1564         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
1565         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
1566         let status = t!(child.wait());
1567         assert!(status.success());
1568     }
1569 }