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