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