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