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