about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes3
-rw-r--r--.travis.yml4
-rw-r--r--appveyor.yml12
-rwxr-xr-xconfigure1
-rw-r--r--src/bootstrap/channel.rs3
-rw-r--r--src/bootstrap/config.rs4
-rw-r--r--src/bootstrap/config.toml.example6
-rw-r--r--src/bootstrap/dist.rs392
-rw-r--r--src/bootstrap/lib.rs4
-rw-r--r--src/bootstrap/step.rs14
-rw-r--r--src/ci/docker/dist-arm-linux/Dockerfile2
-rw-r--r--src/ci/docker/dist-armv7-aarch64-linux/Dockerfile2
-rw-r--r--src/ci/docker/dist-freebsd/Dockerfile2
-rw-r--r--src/ci/docker/dist-mips-linux/Dockerfile2
-rw-r--r--src/ci/docker/dist-mips64-linux/Dockerfile2
-rw-r--r--src/ci/docker/dist-powerpc-linux/Dockerfile2
-rw-r--r--src/ci/docker/dist-powerpc64-linux/Dockerfile2
-rw-r--r--src/ci/docker/dist-s390x-linux-netbsd/Dockerfile2
-rw-r--r--src/ci/docker/dist-x86-linux/Dockerfile2
-rw-r--r--src/etc/installer/README.md28
-rw-r--r--src/etc/installer/exe/modpath.iss219
-rw-r--r--src/etc/installer/exe/rust.iss80
-rw-r--r--src/etc/installer/exe/upgrade.iss61
-rw-r--r--src/etc/installer/gfx/banner.bmpbin0 -> 114514 bytes
-rw-r--r--src/etc/installer/gfx/banner.xcfbin0 -> 148261 bytes
-rw-r--r--src/etc/installer/gfx/dialogbg.bmpbin0 -> 615402 bytes
-rw-r--r--src/etc/installer/gfx/dialogbg.xcfbin0 -> 216045 bytes
-rw-r--r--src/etc/installer/gfx/rust-logo.icobin0 -> 370070 bytes
-rw-r--r--src/etc/installer/gfx/rust-logo.pngbin0 -> 5844 bytes
-rw-r--r--src/etc/installer/msi/remove-duplicates.xsl24
-rw-r--r--src/etc/installer/msi/rust.wxs279
-rw-r--r--src/etc/installer/msi/rustwelcomedlg.wxs57
-rw-r--r--src/etc/installer/msi/squash-components.xsl34
-rw-r--r--src/etc/installer/msi/ui.wxs83
-rw-r--r--src/etc/installer/pkg/Distribution.xml71
-rwxr-xr-xsrc/etc/installer/pkg/postinstall26
36 files changed, 1398 insertions, 25 deletions
diff --git a/.gitattributes b/.gitattributes
index 1d4c6252f2c..e2d04142766 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,7 +4,6 @@
 *.cpp rust
 *.h rust
 *.rs rust
-src/etc/pkg/rust-logo.ico binary
-src/etc/pkg/rust-logo.png binary
+src/etc/installer/gfx/* binary
 *.woff binary
 src/vendor/* binary
diff --git a/.travis.yml b/.travis.yml
index 0546f6827a6..bbe0cdfb6f8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -57,7 +57,7 @@ matrix:
 
     - env: >
         SCRIPT="./x.py test && ./x.py dist"
-        RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
+        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended"
         SRC=.
         DEPLOY=1
       os: osx
@@ -76,7 +76,7 @@ matrix:
       after_failure: *osx_after_failure
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS=--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios
+        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended"
         SRC=.
         DEPLOY=1
       os: osx
diff --git a/appveyor.yml b/appveyor.yml
index cd61f95875f..f158d788d16 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,11 +7,11 @@ environment:
   matrix:
   # 32/64 bit MSVC
   - MSYS_BITS: 64
-    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
+    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended
     SCRIPT: python x.py test && python x.py dist
     DEPLOY: 1
   - MSYS_BITS: 32
-    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc
+    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-extended
     SCRIPT: python x.py test --host i686-pc-windows-msvc --target i686-pc-windows-msvc && python x.py dist
     DEPLOY: 1
 
@@ -51,7 +51,7 @@ environment:
   # *not* use debug assertions and llvm assertions. This is because they take
   # too long on appveyor and this is tested by rustbuild below.
   - MSYS_BITS: 32
-    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+    RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended
     SCRIPT: python x.py test && python x.py dist
     MINGW_URL: https://s3.amazonaws.com/rust-lang-ci
     MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z
@@ -67,7 +67,7 @@ environment:
 
   - MSYS_BITS: 64
     SCRIPT: python x.py test && python x.py dist
-    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
+    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended
     MINGW_URL: https://s3.amazonaws.com/rust-lang-ci
     MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z
     MINGW_DIR: mingw64
@@ -103,6 +103,10 @@ install:
   - 7z x -y sccache.tar > nul
   - set PATH=%PATH%;%CD%\sccache2
 
+  # Install InnoSetup to get `iscc` used to produce installers
+  - choco install -y InnoSetup
+  - set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
+
   # Help debug some handle issues on AppVeyor
   - ps: Invoke-WebRequest -Uri https://download.sysinternals.com/files/Handle.zip -OutFile handle.zip
   - mkdir handle
diff --git a/configure b/configure
index 208fb7e6836..505767cede5 100755
--- a/configure
+++ b/configure
@@ -707,6 +707,7 @@ opt_nosave clang 0 "prefer clang to gcc for building the runtime"
 opt_nosave jemalloc 1 "build liballoc with jemalloc"
 opt elf-tls 1 "elf thread local storage on platforms where supported"
 opt full-bootstrap 0 "build three compilers instead of two"
+opt extended 0 "build an extended rust tool set"
 
 valopt_nosave prefix "/usr/local" "set installation prefix"
 valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index c38bb33aa02..585d9f51b92 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -40,6 +40,9 @@ pub fn collect(build: &mut Build) {
         }
     }
 
+    build.release_num = release_num.to_string();
+    build.prerelease_version = release_num.to_string();
+
     // Depending on the channel, passed in `./configure --release-channel`,
     // determine various properties of the build.
     match &build.config.channel[..] {
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 152164342cd..7d1abcfa6f6 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -47,6 +47,7 @@ pub struct Config {
     pub vendor: bool,
     pub target_config: HashMap<String, Target>,
     pub full_bootstrap: bool,
+    pub extended: bool,
 
     // llvm codegen options
     pub llvm_assertions: bool,
@@ -140,6 +141,7 @@ struct Build {
     nodejs: Option<String>,
     python: Option<String>,
     full_bootstrap: Option<bool>,
+    extended: Option<bool>,
 }
 
 /// TOML representation of various global install decisions.
@@ -276,6 +278,7 @@ impl Config {
         set(&mut config.submodules, build.submodules);
         set(&mut config.vendor, build.vendor);
         set(&mut config.full_bootstrap, build.full_bootstrap);
+        set(&mut config.extended, build.extended);
 
         if let Some(ref install) = toml.install {
             config.prefix = install.prefix.clone().map(PathBuf::from);
@@ -412,6 +415,7 @@ impl Config {
                 ("CODEGEN_TESTS", self.codegen_tests),
                 ("VENDOR", self.vendor),
                 ("FULL_BOOTSTRAP", self.full_bootstrap),
+                ("EXTENDED", self.extended),
             }
 
             match key {
diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example
index 47e50cb79b4..4b859482562 100644
--- a/src/bootstrap/config.toml.example
+++ b/src/bootstrap/config.toml.example
@@ -118,6 +118,12 @@
 # option to true.
 #full-bootstrap = false
 
+# Enable a build of the and extended rust tool set which is not only the
+# compiler but also tools such as Cargo. This will also produce "combined
+# installers" which are used to install Rust and Cargo together. This is
+# disabled by default.
+#extended = false
+
 # =============================================================================
 # General install configuration options
 # =============================================================================
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index dc45d3817fe..e5f05059523 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -18,11 +18,14 @@
 //! out to `rust-installer` still. This may one day be replaced with bits and
 //! pieces of `rustup.rs`!
 
+use std::env;
 use std::fs::{self, File};
-use std::io::Write;
+use std::io::{Read, Write};
 use std::path::{PathBuf, Path};
 use std::process::Command;
 
+use build_helper::output;
+
 use {Build, Compiler, Mode};
 use util::{cp_r, libdir, is_dylib, cp_filtered, copy};
 
@@ -35,6 +38,10 @@ pub fn package_vers(build: &Build) -> &str {
     }
 }
 
+fn pkgname(build: &Build, component: &str) -> String {
+    format!("{}-{}", component, package_vers(build))
+}
+
 fn distdir(build: &Build) -> PathBuf {
     build.out.join("dist")
 }
@@ -53,8 +60,8 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
         return
     }
 
-    let name = format!("rust-docs-{}", package_vers(build));
-    let image = tmpdir(build).join(format!("{}-{}-image", name, name));
+    let name = pkgname(build, "rust-docs");
+    let image = tmpdir(build).join(format!("{}-{}-image", name, host));
     let _ = fs::remove_dir_all(&image);
 
     let dst = image.join("share/doc/rust/html");
@@ -94,7 +101,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
 /// in Rust.
 pub fn mingw(build: &Build, host: &str) {
     println!("Dist mingw ({})", host);
-    let name = format!("rust-mingw-{}", package_vers(build));
+    let name = pkgname(build, "rust-mingw");
     let image = tmpdir(build).join(format!("{}-{}-image", name, host));
     let _ = fs::remove_dir_all(&image);
     t!(fs::create_dir_all(&image));
@@ -130,7 +137,7 @@ pub fn mingw(build: &Build, host: &str) {
 /// Creates the `rustc` installer component.
 pub fn rustc(build: &Build, stage: u32, host: &str) {
     println!("Dist rustc stage{} ({})", stage, host);
-    let name = format!("rustc-{}", package_vers(build));
+    let name = pkgname(build, "rustc");
     let image = tmpdir(build).join(format!("{}-{}-image", name, host));
     let _ = fs::remove_dir_all(&image);
     let overlay = tmpdir(build).join(format!("{}-{}-overlay", name, host));
@@ -274,7 +281,7 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) {
         return
     }
 
-    let name = format!("rust-std-{}", package_vers(build));
+    let name = pkgname(build, "rust-std");
     let image = tmpdir(build).join(format!("{}-{}-image", name, target));
     let _ = fs::remove_dir_all(&image);
 
@@ -328,7 +335,7 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
         compiler.clone()
     };
 
-    let name = format!("rust-analysis-{}", package_vers(build));
+    let name = pkgname(build, "rust-analysis");
     let image = tmpdir(build).join(format!("{}-{}-image", name, target));
 
     let src = build.stage_out(&compiler, Mode::Libstd).join(target).join("release").join("deps");
@@ -357,7 +364,7 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
 pub fn rust_src(build: &Build) {
     println!("Dist src");
 
-    let name = format!("rust-src-{}", package_vers(build));
+    let name = pkgname(build, "rust-src");
     let image = tmpdir(build).join(format!("{}-image", name));
     let _ = fs::remove_dir_all(&image);
 
@@ -500,3 +507,372 @@ fn write_file(path: &Path, data: &[u8]) {
     let mut vf = t!(fs::File::create(path));
     t!(vf.write_all(data));
 }
+
+// FIXME(#38531) eventually this should package up a Cargo that we just compiled
+//               and tested locally, but for now we're downloading cargo
+//               artifacts from their compiled location.
+pub fn cargo(build: &Build, stage: u32, target: &str) {
+    println!("Dist cargo stage{} ({})", stage, target);
+
+    let branch = match &build.config.channel[..] {
+        "stable" |
+        "beta" => {
+            build.release.split(".").take(2).collect::<Vec<_>>().join(".")
+        }
+        _ => "master".to_string(),
+    };
+
+    let dst = tmpdir(build).join("cargo");
+    let _ = fs::remove_dir_all(&dst);
+    build.run(Command::new("git")
+                .arg("clone")
+                .arg("--depth").arg("1")
+                .arg("--branch").arg(&branch)
+                .arg("https://github.com/rust-lang/cargo")
+                .current_dir(dst.parent().unwrap()));
+    let sha = output(Command::new("git")
+                .arg("rev-parse")
+                .arg("HEAD")
+                .current_dir(&dst));
+    let sha = sha.trim();
+    println!("\tgot cargo sha: {}", sha);
+
+    let input = format!("https://s3.amazonaws.com/rust-lang-ci/cargo-builds\
+                         /{}/cargo-nightly-{}.tar.gz", sha, target);
+    let output = distdir(build).join(format!("cargo-nightly-{}.tar.gz", target));
+    println!("\tdownloading {}", input);
+    let mut curl = Command::new("curl");
+    curl.arg("-f")
+        .arg("-o").arg(&output)
+        .arg(&input)
+        .arg("--retry").arg("3");
+    build.run(&mut curl);
+}
+
+/// Creates a combined installer for the specified target in the provided stage.
+pub fn extended(build: &Build, stage: u32, target: &str) {
+    println!("Dist extended stage{} ({})", stage, target);
+
+    let dist = distdir(build);
+    let rustc_installer = dist.join(format!("{}-{}.tar.gz",
+                                            pkgname(build, "rustc"),
+                                            target));
+    let cargo_installer = dist.join(format!("cargo-nightly-{}.tar.gz", target));
+    let docs_installer = dist.join(format!("{}-{}.tar.gz",
+                                           pkgname(build, "rust-docs"),
+                                           target));
+    let mingw_installer = dist.join(format!("{}-{}.tar.gz",
+                                            pkgname(build, "rust-mingw"),
+                                            target));
+    let std_installer = dist.join(format!("{}-{}.tar.gz",
+                                          pkgname(build, "rust-std"),
+                                          target));
+
+    let tmp = tmpdir(build);
+    let overlay = tmp.join("extended-overlay");
+    let etc = build.src.join("src/etc/installer");
+    let work = tmp.join("work");
+
+    let _ = fs::remove_dir_all(&overlay);
+    install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
+    install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
+    install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
+    let version = &build.version;
+    t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
+    install(&etc.join("README.md"), &overlay, 0o644);
+
+    // When rust-std package split from rustc, we needed to ensure that during
+    // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
+    // the std files during uninstall. To do this ensure that rustc comes
+    // before rust-std in the list below.
+    let mut input_tarballs = format!("{},{},{},{}",
+                                     sanitize_sh(&rustc_installer),
+                                     sanitize_sh(&cargo_installer),
+                                     sanitize_sh(&docs_installer),
+                                     sanitize_sh(&std_installer));
+    if target.contains("pc-windows-gnu") {
+        input_tarballs.push_str(",");
+        input_tarballs.push_str(&sanitize_sh(&mingw_installer));
+    }
+
+    let mut cmd = Command::new("sh");
+    cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/combine-installers.sh")))
+       .arg("--product-name=Rust")
+       .arg("--rel-manifest-dir=rustlib")
+       .arg("--success-message=Rust-is-ready-to-roll.")
+       .arg(format!("--work-dir={}", sanitize_sh(&work)))
+       .arg(format!("--output-dir={}", sanitize_sh(&distdir(build))))
+       .arg(format!("--package-name={}-{}", pkgname(build, "rust"), target))
+       .arg("--legacy-manifest-dirs=rustlib,cargo")
+       .arg(format!("--input-tarballs={}", input_tarballs))
+       .arg(format!("--non-installed-overlay={}", sanitize_sh(&overlay)));
+    build.run(&mut cmd);
+
+    let mut license = String::new();
+    t!(t!(File::open(build.src.join("COPYRIGHT"))).read_to_string(&mut license));
+    license.push_str("\n");
+    t!(t!(File::open(build.src.join("LICENSE-APACHE"))).read_to_string(&mut license));
+    license.push_str("\n");
+    t!(t!(File::open(build.src.join("LICENSE-MIT"))).read_to_string(&mut license));
+
+    let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
+    let mut rtf = rtf.to_string();
+    rtf.push_str("\n");
+    for line in license.lines() {
+        rtf.push_str(line);
+        rtf.push_str("\\line ");
+    }
+    rtf.push_str("}");
+
+    if target.contains("apple-darwin") {
+        let pkg = tmp.join("pkg");
+        let _ = fs::remove_dir_all(&pkg);
+        t!(fs::create_dir_all(pkg.join("rustc")));
+        t!(fs::create_dir_all(pkg.join("cargo")));
+        t!(fs::create_dir_all(pkg.join("rust-docs")));
+        t!(fs::create_dir_all(pkg.join("rust-std")));
+
+        cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)),
+             &pkg.join("rustc"));
+        cp_r(&work.join(&format!("cargo-nightly-{}", target)),
+             &pkg.join("cargo"));
+        cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)),
+             &pkg.join("rust-docs"));
+        cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)),
+             &pkg.join("rust-std"));
+
+        install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755);
+        install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755);
+        install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755);
+        install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755);
+
+        let pkgbuild = |component: &str| {
+            let mut cmd = Command::new("pkgbuild");
+            cmd.arg("--identifier").arg(format!("org.rust-lang.{}", component))
+               .arg("--scripts").arg(pkg.join(component))
+               .arg("--nopayload")
+               .arg(pkg.join(component).with_extension("pkg"));
+            build.run(&mut cmd);
+        };
+        pkgbuild("rustc");
+        pkgbuild("cargo");
+        pkgbuild("rust-docs");
+        pkgbuild("rust-std");
+
+        // create an 'uninstall' package
+        install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
+        pkgbuild("uninstall");
+
+        t!(fs::create_dir_all(pkg.join("res")));
+        t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
+        install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
+        let mut cmd = Command::new("productbuild");
+        cmd.arg("--distribution").arg(etc.join("pkg/Distribution.xml"))
+           .arg("--resources").arg(pkg.join("res"))
+           .arg(distdir(build).join(format!("{}-{}.pkg",
+                                             pkgname(build, "rust"),
+                                             target)))
+           .arg("--package-path").arg(&pkg);
+        build.run(&mut cmd);
+    }
+
+    if target.contains("windows") {
+        let exe = tmp.join("exe");
+        let _ = fs::remove_dir_all(&exe);
+        t!(fs::create_dir_all(exe.join("rustc")));
+        t!(fs::create_dir_all(exe.join("cargo")));
+        t!(fs::create_dir_all(exe.join("rust-docs")));
+        t!(fs::create_dir_all(exe.join("rust-std")));
+        cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target))
+                  .join("rustc"),
+             &exe.join("rustc"));
+        cp_r(&work.join(&format!("cargo-nightly-{}", target))
+                  .join("cargo"),
+             &exe.join("cargo"));
+        cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target))
+                  .join("rust-docs"),
+             &exe.join("rust-docs"));
+        cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
+                  .join(format!("rust-std-{}", target)),
+             &exe.join("rust-std"));
+
+        t!(fs::remove_file(exe.join("rustc/manifest.in")));
+        t!(fs::remove_file(exe.join("cargo/manifest.in")));
+        t!(fs::remove_file(exe.join("rust-docs/manifest.in")));
+        t!(fs::remove_file(exe.join("rust-std/manifest.in")));
+
+        if target.contains("windows-gnu") {
+            t!(fs::create_dir_all(exe.join("rust-mingw")));
+            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-mingw"), target))
+                      .join("rust-mingw"),
+                 &exe.join("rust-mingw"));
+            t!(fs::remove_file(exe.join("rust-mingw/manifest.in")));
+        }
+
+        install(&etc.join("exe/rust.iss"), &exe, 0o644);
+        install(&etc.join("exe/modpath.iss"), &exe, 0o644);
+        install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
+        install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
+        t!(t!(File::create(exe.join("LICENSE.txt"))).write_all(license.as_bytes()));
+
+        // Generate exe installer
+        let mut cmd = Command::new("iscc");
+        cmd.arg("rust.iss")
+           .current_dir(&exe);
+        if target.contains("windows-gnu") {
+            cmd.arg("/dMINGW");
+        }
+        add_env(build, &mut cmd, target);
+        build.run(&mut cmd);
+        install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
+                &distdir(build),
+                0o755);
+
+        // Generate msi installer
+        let wix = PathBuf::from(env::var_os("WIX").unwrap());
+        let heat = wix.join("bin/heat.exe");
+        let candle = wix.join("bin/candle.exe");
+        let light = wix.join("bin/light.exe");
+
+        let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
+        build.run(Command::new(&heat)
+                        .current_dir(&exe)
+                        .arg("dir")
+                        .arg("rustc")
+                        .args(&heat_flags)
+                        .arg("-cg").arg("RustcGroup")
+                        .arg("-dr").arg("Rustc")
+                        .arg("-var").arg("var.RustcDir")
+                        .arg("-out").arg(exe.join("RustcGroup.wxs")));
+        build.run(Command::new(&heat)
+                        .current_dir(&exe)
+                        .arg("dir")
+                        .arg("rust-docs")
+                        .args(&heat_flags)
+                        .arg("-cg").arg("DocsGroup")
+                        .arg("-dr").arg("Docs")
+                        .arg("-var").arg("var.DocsDir")
+                        .arg("-out").arg(exe.join("DocsGroup.wxs"))
+                        .arg("-t").arg(etc.join("msi/squash-components.xsl")));
+        build.run(Command::new(&heat)
+                        .current_dir(&exe)
+                        .arg("dir")
+                        .arg("cargo")
+                        .args(&heat_flags)
+                        .arg("-cg").arg("CargoGroup")
+                        .arg("-dr").arg("Cargo")
+                        .arg("-var").arg("var.CargoDir")
+                        .arg("-out").arg(exe.join("CargoGroup.wxs"))
+                        .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
+        build.run(Command::new(&heat)
+                        .current_dir(&exe)
+                        .arg("dir")
+                        .arg("rust-std")
+                        .args(&heat_flags)
+                        .arg("-cg").arg("StdGroup")
+                        .arg("-dr").arg("Std")
+                        .arg("-var").arg("var.StdDir")
+                        .arg("-out").arg(exe.join("StdGroup.wxs")));
+        if target.contains("windows-gnu") {
+            build.run(Command::new(&heat)
+                            .current_dir(&exe)
+                            .arg("dir")
+                            .arg("rust-mingw")
+                            .args(&heat_flags)
+                            .arg("-cg").arg("GccGroup")
+                            .arg("-dr").arg("Gcc")
+                            .arg("-var").arg("var.GccDir")
+                            .arg("-out").arg(exe.join("GccGroup.wxs")));
+        }
+
+        let candle = |input: &Path| {
+            let output = exe.join(input.file_stem().unwrap())
+                            .with_extension("wixobj");
+            let arch = if target.contains("x86_64") {"x64"} else {"x86"};
+            let mut cmd = Command::new(&candle);
+            cmd.current_dir(&exe)
+               .arg("-nologo")
+               .arg("-dRustcDir=rustc")
+               .arg("-dDocsDir=rust-docs")
+               .arg("-dCargoDir=cargo")
+               .arg("-dStdDir=rust-std")
+               .arg("-arch").arg(&arch)
+               .arg("-out").arg(&output)
+               .arg(&input);
+            add_env(build, &mut cmd, target);
+
+            if target.contains("windows-gnu") {
+               cmd.arg("-dGccDir=rust-mingw");
+            }
+            build.run(&mut cmd);
+        };
+        candle(&etc.join("msi/rust.wxs"));
+        candle(&etc.join("msi/ui.wxs"));
+        candle(&etc.join("msi/rustwelcomedlg.wxs"));
+        candle("RustcGroup.wxs".as_ref());
+        candle("DocsGroup.wxs".as_ref());
+        candle("CargoGroup.wxs".as_ref());
+        candle("StdGroup.wxs".as_ref());
+
+        if target.contains("windows-gnu") {
+            candle("GccGroup.wxs".as_ref());
+        }
+
+        t!(t!(File::create(exe.join("LICENSE.rtf"))).write_all(rtf.as_bytes()));
+        install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
+        install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
+
+        let filename = format!("{}-{}.msi", pkgname(build, "rust"), target);
+        let mut cmd = Command::new(&light);
+        cmd.arg("-nologo")
+           .arg("-ext").arg("WixUIExtension")
+           .arg("-ext").arg("WixUtilExtension")
+           .arg("-out").arg(distdir(build).join(filename))
+           .arg("rust.wixobj")
+           .arg("ui.wixobj")
+           .arg("rustwelcomedlg.wixobj")
+           .arg("RustcGroup.wixobj")
+           .arg("DocsGroup.wixobj")
+           .arg("CargoGroup.wixobj")
+           .arg("StdGroup.wixobj")
+           .current_dir(&exe);
+
+        if target.contains("windows-gnu") {
+           cmd.arg("GccGroup.wixobj");
+        }
+        // ICE57 wrongly complains about the shortcuts
+        cmd.arg("-sice:ICE57");
+
+        build.run(&mut cmd);
+    }
+}
+
+fn add_env(build: &Build, cmd: &mut Command, target: &str) {
+    let mut parts = build.release_num.split('.');
+    cmd.env("CFG_RELEASE_INFO", &build.version)
+       .env("CFG_RELEASE_NUM", &build.release_num)
+       .env("CFG_RELEASE", &build.release)
+       .env("CFG_PRERELEASE_VERSION", &build.prerelease_version)
+       .env("CFG_VER_MAJOR", parts.next().unwrap())
+       .env("CFG_VER_MINOR", parts.next().unwrap())
+       .env("CFG_VER_PATCH", parts.next().unwrap())
+       .env("CFG_VER_BUILD", "0") // just needed to build
+       .env("CFG_PACKAGE_VERS", package_vers(build))
+       .env("CFG_PACKAGE_NAME", pkgname(build, "rust"))
+       .env("CFG_BUILD", target)
+       .env("CFG_CHANNEL", &build.config.channel);
+
+    if target.contains("windows-gnu") {
+       cmd.env("CFG_MINGW", "1")
+          .env("CFG_ABI", "GNU");
+    } else {
+       cmd.env("CFG_MINGW", "0")
+          .env("CFG_ABI", "MSVC");
+    }
+
+    if target.contains("x86_64") {
+       cmd.env("CFG_PLATFORM", "x64");
+    } else {
+       cmd.env("CFG_PLATFORM", "x86");
+    }
+}
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 6b2b6ad5c02..db2fe2db813 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -170,6 +170,8 @@ pub struct Build {
     version: String,
     package_vers: String,
     local_rebuild: bool,
+    release_num: String,
+    prerelease_version: String,
 
     // Probed tools at runtime
     lldb_version: Option<String>,
@@ -271,6 +273,8 @@ impl Build {
             lldb_version: None,
             lldb_python_dir: None,
             is_sudo: is_sudo,
+            release_num: String::new(),
+            prerelease_version: String::new(),
         }
     }
 
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index 289621184f0..697b14c6050 100644
--- a/src/bootstrap/step.rs
+++ b/src/bootstrap/step.rs
@@ -618,6 +618,20 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
     rules.dist("install", "path/to/nowhere")
          .dep(|s| s.name("default:dist"))
          .run(move |s| install::install(build, s.stage, s.target));
+    rules.dist("dist-cargo", "cargo")
+         .host(true)
+         .only_host_build(true)
+         .run(move |s| dist::cargo(build, s.stage, s.target));
+    rules.dist("dist-extended", "extended")
+         .default(build.config.extended)
+         .host(true)
+         .only_host_build(true)
+         .dep(|d| d.name("dist-std"))
+         .dep(|d| d.name("dist-rustc"))
+         .dep(|d| d.name("dist-mingw"))
+         .dep(|d| d.name("dist-docs"))
+         .dep(|d| d.name("dist-cargo"))
+         .run(move |s| dist::extended(build, s.stage, s.target));
 
     rules.verify();
     return rules;
diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile
index 03ca4c28078..217a724fb9a 100644
--- a/src/ci/docker/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/dist-arm-linux/Dockerfile
@@ -76,5 +76,5 @@ ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
 ENV HOSTS=arm-unknown-linux-gnueabi
 ENV HOSTS=$HOSTS,arm-unknown-linux-gnueabihf
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
index 93d9e004c8c..f26885bbb53 100644
--- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
+++ b/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
@@ -77,5 +77,5 @@ ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \
 ENV HOSTS=armv7-unknown-linux-gnueabihf
 ENV HOSTS=$HOSTS,aarch64-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-freebsd/Dockerfile
index 4b6db62d389..d824c4041ce 100644
--- a/src/ci/docker/dist-freebsd/Dockerfile
+++ b/src/ci/docker/dist-freebsd/Dockerfile
@@ -38,5 +38,5 @@ ENV \
 ENV HOSTS=x86_64-unknown-freebsd
 ENV HOSTS=$HOSTS,i686-unknown-freebsd
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile
index df189c25809..38ee95038f6 100644
--- a/src/ci/docker/dist-mips-linux/Dockerfile
+++ b/src/ci/docker/dist-mips-linux/Dockerfile
@@ -27,5 +27,5 @@ ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 ENV HOSTS=mips-unknown-linux-gnu
 ENV HOSTS=$HOSTS,mipsel-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile
index 9152965caee..c9d89d62874 100644
--- a/src/ci/docker/dist-mips64-linux/Dockerfile
+++ b/src/ci/docker/dist-mips64-linux/Dockerfile
@@ -27,5 +27,5 @@ ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 ENV HOSTS=mips64-unknown-linux-gnuabi64
 ENV HOSTS=$HOSTS,mips64el-unknown-linux-gnuabi64
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile
index d5f9e5269f1..ed4e9a35960 100644
--- a/src/ci/docker/dist-powerpc-linux/Dockerfile
+++ b/src/ci/docker/dist-powerpc-linux/Dockerfile
@@ -25,7 +25,7 @@ ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 ENV HOSTS=powerpc-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
 
 # FIXME(#36150) this will fail the bootstrap. Probably means something bad is
diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile
index 3b222581bd4..6c04048f4dd 100644
--- a/src/ci/docker/dist-powerpc64-linux/Dockerfile
+++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile
@@ -32,5 +32,5 @@ ENV \
 ENV HOSTS=powerpc64-unknown-linux-gnu
 ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
index 7350b11a69f..ec38855fe3a 100644
--- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
+++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
@@ -36,5 +36,5 @@ ENV \
 ENV HOSTS=x86_64-unknown-netbsd
 ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile
index 283a4aaab56..4e4f5dd6f1e 100644
--- a/src/ci/docker/dist-x86-linux/Dockerfile
+++ b/src/ci/docker/dist-x86-linux/Dockerfile
@@ -76,5 +76,5 @@ RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST |
 ENV HOSTS=i686-unknown-linux-gnu
 ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --host=$HOSTS
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/etc/installer/README.md b/src/etc/installer/README.md
new file mode 100644
index 00000000000..dbefe753bee
--- /dev/null
+++ b/src/etc/installer/README.md
@@ -0,0 +1,28 @@
+# The Rust Programming Language
+
+This is a compiler for Rust, including standard libraries, tools and
+documentation. Rust is a systems programming language that is fast,
+memory safe and multithreaded, but does not employ a garbage collector
+or otherwise impose significant runtime overhead.
+
+To install to /usr/local (the default), run the included `install.sh` script:
+
+    $ sudo ./install.sh
+
+To uninstall:
+
+    $ sudo /usr/local/lib/rustlib/uninstall.sh
+
+`install.sh` has a few options, including the possibility to set an installation
+prefix. You can display these options by running:
+
+    $ sudo ./install.sh --help
+
+Read [The Book](http://doc.rust-lang.org/book/index.html) to learn how
+to use Rust.
+
+Rust is primarily distributed under the terms of both the MIT license
+and the Apache License (Version 2.0), with portions covered by various
+BSD-like licenses.
+
+See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.
diff --git a/src/etc/installer/exe/modpath.iss b/src/etc/installer/exe/modpath.iss
new file mode 100644
index 00000000000..35cc0097035
--- /dev/null
+++ b/src/etc/installer/exe/modpath.iss
@@ -0,0 +1,219 @@
+// ----------------------------------------------------------------------------
+//
+// Inno Setup Ver:	5.4.2
+// Script Version:	1.4.1
+// Author:			Jared Breland <jbreland@legroom.net>
+// Homepage:		http://www.legroom.net/software
+// License:			GNU Lesser General Public License (LGPL), version 3
+//						http://www.gnu.org/licenses/lgpl.html
+//
+// Script Function:
+//	Allow modification of environmental path directly from Inno Setup installers
+//
+// Instructions:
+//	Copy modpath.iss to the same directory as your setup script
+//
+//	Add this statement to your [Setup] section
+//		ChangesEnvironment=true
+//
+//	Add this statement to your [Tasks] section
+//	You can change the Description or Flags
+//	You can change the Name, but it must match the ModPathName setting below
+//		Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
+//
+//	Add the following to the end of your [Code] section
+//	ModPathName defines the name of the task defined above
+//	ModPathType defines whether the 'user' or 'system' path will be modified;
+//		this will default to user if anything other than system is set
+//	setArrayLength must specify the total number of dirs to be added
+//	Result[0] contains first directory, Result[1] contains second, etc.
+//		const
+//			ModPathName = 'modifypath';
+//			ModPathType = 'user';
+//
+//		function ModPathDir(): TArrayOfString;
+//		begin
+//			setArrayLength(Result, 1);
+//			Result[0] := ExpandConstant('{app}');
+//		end;
+//		#include "modpath.iss"
+// ----------------------------------------------------------------------------
+
+procedure ModPath();
+var
+	oldpath:	String;
+	newpath:	String;
+	updatepath:	Boolean;
+	pathArr:	TArrayOfString;
+	aExecFile:	String;
+	aExecArr:	TArrayOfString;
+	i, d:		Integer;
+	pathdir:	TArrayOfString;
+	regroot:	Integer;
+	regpath:	String;
+
+begin
+	// Get constants from main script and adjust behavior accordingly
+	// ModPathType MUST be 'system' or 'user'; force 'user' if invalid
+	if ModPathType = 'system' then begin
+		regroot := HKEY_LOCAL_MACHINE;
+		regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
+	end else begin
+		regroot := HKEY_CURRENT_USER;
+		regpath := 'Environment';
+	end;
+
+	// Get array of new directories and act on each individually
+	pathdir := ModPathDir();
+	for d := 0 to GetArrayLength(pathdir)-1 do begin
+		updatepath := true;
+
+		// Modify WinNT path
+		if UsingWinNT() = true then begin
+
+			// Get current path, split into an array
+			RegQueryStringValue(regroot, regpath, 'Path', oldpath);
+			oldpath := oldpath + ';';
+			i := 0;
+
+			while (Pos(';', oldpath) > 0) do begin
+				SetArrayLength(pathArr, i+1);
+				pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
+				oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
+				i := i + 1;
+
+				// Check if current directory matches app dir
+				if pathdir[d] = pathArr[i-1] then begin
+					// if uninstalling, remove dir from path
+					if IsUninstaller() = true then begin
+						continue;
+					// if installing, flag that dir already exists in path
+					end else begin
+						updatepath := false;
+					end;
+				end;
+
+				// Add current directory to new path
+				if i = 1 then begin
+					newpath := pathArr[i-1];
+				end else begin
+					newpath := newpath + ';' + pathArr[i-1];
+				end;
+			end;
+
+			// Append app dir to path if not already included
+			if (IsUninstaller() = false) AND (updatepath = true) then
+				newpath := newpath + ';' + pathdir[d];
+
+			// Write new path
+			RegWriteStringValue(regroot, regpath, 'Path', newpath);
+
+		// Modify Win9x path
+		end else begin
+
+			// Convert to shortened dirname
+			pathdir[d] := GetShortName(pathdir[d]);
+
+			// If autoexec.bat exists, check if app dir already exists in path
+			aExecFile := 'C:\AUTOEXEC.BAT';
+			if FileExists(aExecFile) then begin
+				LoadStringsFromFile(aExecFile, aExecArr);
+				for i := 0 to GetArrayLength(aExecArr)-1 do begin
+					if IsUninstaller() = false then begin
+						// If app dir already exists while installing, skip add
+						if (Pos(pathdir[d], aExecArr[i]) > 0) then
+							updatepath := false;
+							break;
+					end else begin
+						// If app dir exists and = what we originally set, then delete at uninstall
+						if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
+							aExecArr[i] := '';
+					end;
+				end;
+			end;
+
+			// If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path
+			if (IsUninstaller() = false) AND (updatepath = true) then begin
+				SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True);
+
+			// If uninstalling, write the full autoexec out
+			end else begin
+				SaveStringsToFile(aExecFile, aExecArr, False);
+			end;
+		end;
+	end;
+end;
+
+// Split a string into an array using passed delimeter
+procedure Explode(var Dest: TArrayOfString; Text: String; Separator: String);
+var
+	i: Integer;
+begin
+	i := 0;
+	repeat
+		SetArrayLength(Dest, i+1);
+		if Pos(Separator,Text) > 0 then	begin
+			Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1);
+			Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text));
+			i := i + 1;
+		end else begin
+			 Dest[i] := Text;
+			 Text := '';
+		end;
+	until Length(Text)=0;
+end;
+
+
+procedure ModPathCurStepChanged(CurStep: TSetupStep);
+var
+	taskname:	String;
+begin
+	taskname := ModPathName;
+	if CurStep = ssPostInstall then
+		if IsTaskSelected(taskname) then
+			ModPath();
+end;
+
+procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
+var
+	aSelectedTasks:	TArrayOfString;
+	i:				Integer;
+	taskname:		String;
+	regpath:		String;
+	regstring:		String;
+	appid:			String;
+begin
+	// only run during actual uninstall
+	if CurUninstallStep = usUninstall then begin
+		// get list of selected tasks saved in registry at install time
+		appid := '{#emit SetupSetting("AppId")}';
+		if appid = '' then appid := '{#emit SetupSetting("AppName")}';
+		regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1');
+		RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring);
+		if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring);
+
+		// check each task; if matches modpath taskname, trigger patch removal
+		if regstring <> '' then begin
+			taskname := ModPathName;
+			Explode(aSelectedTasks, regstring, ',');
+			if GetArrayLength(aSelectedTasks) > 0 then begin
+				for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin
+					if comparetext(aSelectedTasks[i], taskname) = 0 then
+						ModPath();
+				end;
+			end;
+		end;
+	end;
+end;
+
+function NeedRestart(): Boolean;
+var
+	taskname:	String;
+begin
+	taskname := ModPathName;
+	if IsTaskSelected(taskname) and not UsingWinNT() then begin
+		Result := True;
+	end else begin
+		Result := False;
+	end;
+end;
diff --git a/src/etc/installer/exe/rust.iss b/src/etc/installer/exe/rust.iss
new file mode 100644
index 00000000000..a61a19f909a
--- /dev/null
+++ b/src/etc/installer/exe/rust.iss
@@ -0,0 +1,80 @@
+#define CFG_RELEASE_NUM GetEnv("CFG_RELEASE_NUM")
+#define CFG_RELEASE GetEnv("CFG_RELEASE")
+#define CFG_PACKAGE_NAME GetEnv("CFG_PACKAGE_NAME")
+#define CFG_BUILD GetEnv("CFG_BUILD")
+
+[Setup]
+
+SetupIconFile=rust-logo.ico
+AppName=Rust
+AppVersion={#CFG_RELEASE}
+AppCopyright=Copyright (C) 2006-2014 Mozilla Foundation, MIT license
+AppPublisher=Mozilla Foundation
+AppPublisherURL=http://www.rust-lang.org
+VersionInfoVersion={#CFG_RELEASE_NUM}
+LicenseFile=LICENSE.txt
+
+PrivilegesRequired=lowest
+DisableWelcomePage=true
+DisableProgramGroupPage=true
+DisableReadyPage=true
+DisableStartupPrompt=true
+
+OutputDir=.\
+SourceDir=.\
+OutputBaseFilename={#CFG_PACKAGE_NAME}-{#CFG_BUILD}
+DefaultDirName={sd}\Rust
+
+Compression=lzma2/ultra
+InternalCompressLevel=ultra
+SolidCompression=true
+
+ChangesEnvironment=true
+ChangesAssociations=no
+AllowUNCPath=false
+AllowNoIcons=true
+Uninstallable=yes
+
+[Tasks]
+Name: modifypath; Description: &Add {app}\bin to your PATH (recommended)
+
+[Components]
+Name: rust; Description: "Rust compiler and standard crates"; Types: full compact custom; Flags: fixed
+#ifdef MINGW
+Name: gcc; Description: "Linker and platform libraries"; Types: full
+#endif
+Name: docs; Description: "HTML documentation"; Types: full
+Name: cargo; Description: "Cargo, the Rust package manager"; Types: full
+Name: std; Description: "The Rust Standard Library"; Types: full
+
+[Files]
+Source: "rustc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust
+#ifdef MINGW
+Source: "rust-mingw/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: gcc
+#endif
+Source: "rust-docs/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: docs
+Source: "cargo/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: cargo
+Source: "rust-std/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: std
+
+[Code]
+const
+	ModPathName = 'modifypath';
+	ModPathType = 'user';
+
+function ModPathDir(): TArrayOfString;
+begin
+	setArrayLength(Result, 1)
+	Result[0] := ExpandConstant('{app}\bin');
+end;
+
+#include "modpath.iss"
+#include "upgrade.iss"
+
+// Both modpath.iss and upgrade.iss want to overload CurStepChanged.
+// This version does the overload then delegates to each.
+
+procedure CurStepChanged(CurStep: TSetupStep);
+begin
+  UpgradeCurStepChanged(CurStep);
+  ModPathCurStepChanged(CurStep);
+end;
diff --git a/src/etc/installer/exe/upgrade.iss b/src/etc/installer/exe/upgrade.iss
new file mode 100644
index 00000000000..29da7c333bb
--- /dev/null
+++ b/src/etc/installer/exe/upgrade.iss
@@ -0,0 +1,61 @@
+// The following code taken from https://stackoverflow.com/questions/2000296/innosetup-how-to-automatically-uninstall-previous-installed-version
+// It performs upgrades by running the uninstaller before the install
+
+/////////////////////////////////////////////////////////////////////
+function GetUninstallString(): String;
+var
+  sUnInstPath: String;
+  sUnInstallString: String;
+begin
+  sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust_is1');
+  sUnInstallString := '';
+  if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
+    RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
+  Result := sUnInstallString;
+end;
+
+
+/////////////////////////////////////////////////////////////////////
+function IsUpgrade(): Boolean;
+begin
+  Result := (GetUninstallString() <> '');
+end;
+
+
+/////////////////////////////////////////////////////////////////////
+function UnInstallOldVersion(): Integer;
+var
+  sUnInstallString: String;
+  iResultCode: Integer;
+begin
+// Return Values:
+// 1 - uninstall string is empty
+// 2 - error executing the UnInstallString
+// 3 - successfully executed the UnInstallString
+
+  // default return value
+  Result := 0;
+
+  // get the uninstall string of the old app
+  sUnInstallString := GetUninstallString();
+  if sUnInstallString <> '' then begin
+    sUnInstallString := RemoveQuotes(sUnInstallString);
+    if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
+      Result := 3
+    else
+      Result := 2;
+  end else
+    Result := 1;
+end;
+
+/////////////////////////////////////////////////////////////////////
+procedure UpgradeCurStepChanged(CurStep: TSetupStep);
+begin
+  if (CurStep=ssInstall) then
+  begin
+    if (IsUpgrade()) then
+    begin
+      UnInstallOldVersion();
+    end;
+  end;
+end;
diff --git a/src/etc/installer/gfx/banner.bmp b/src/etc/installer/gfx/banner.bmp
new file mode 100644
index 00000000000..b5459a797d2
--- /dev/null
+++ b/src/etc/installer/gfx/banner.bmp
Binary files differdiff --git a/src/etc/installer/gfx/banner.xcf b/src/etc/installer/gfx/banner.xcf
new file mode 100644
index 00000000000..53296518ee2
--- /dev/null
+++ b/src/etc/installer/gfx/banner.xcf
Binary files differdiff --git a/src/etc/installer/gfx/dialogbg.bmp b/src/etc/installer/gfx/dialogbg.bmp
new file mode 100644
index 00000000000..7e4674a4fea
--- /dev/null
+++ b/src/etc/installer/gfx/dialogbg.bmp
Binary files differdiff --git a/src/etc/installer/gfx/dialogbg.xcf b/src/etc/installer/gfx/dialogbg.xcf
new file mode 100644
index 00000000000..49ca4e0c33e
--- /dev/null
+++ b/src/etc/installer/gfx/dialogbg.xcf
Binary files differdiff --git a/src/etc/installer/gfx/rust-logo.ico b/src/etc/installer/gfx/rust-logo.ico
new file mode 100644
index 00000000000..a58225d5acb
--- /dev/null
+++ b/src/etc/installer/gfx/rust-logo.ico
Binary files differdiff --git a/src/etc/installer/gfx/rust-logo.png b/src/etc/installer/gfx/rust-logo.png
new file mode 100644
index 00000000000..2c3de300087
--- /dev/null
+++ b/src/etc/installer/gfx/rust-logo.png
Binary files differdiff --git a/src/etc/installer/msi/remove-duplicates.xsl b/src/etc/installer/msi/remove-duplicates.xsl
new file mode 100644
index 00000000000..05b4c9bcc93
--- /dev/null
+++ b/src/etc/installer/msi/remove-duplicates.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0"
+        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+        xmlns:wix="http://schemas.microsoft.com/wix/2006/wi">
+    <!-- Copy all attributes and elements to the output. -->
+    <xsl:template match="@*|*">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|*"/>
+        </xsl:copy>
+    </xsl:template>
+    <xsl:output method="xml" indent="yes" />
+
+    <!-- LICENSE* files are installed from rustc dir. -->
+    <xsl:key name="duplicates-cmp-ids" match="wix:Component[./wix:File[contains(@Source, 'LICENSE')]|./wix:File[contains(@Source, 'rust-installer-version')]]" use="@Id" />
+    <xsl:template match="wix:Component[key('duplicates-cmp-ids', @Id)]" />
+    <xsl:template match="wix:ComponentRef[key('duplicates-cmp-ids', @Id)]" />
+
+    <xsl:template match="wix:File[contains(@Source, 'README.md')]">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|*"/>
+            <xsl:attribute name="Name">README-CARGO.md</xsl:attribute>
+        </xsl:copy>
+    </xsl:template>
+</xsl:stylesheet>
diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs
new file mode 100644
index 00000000000..fb076ccb091
--- /dev/null
+++ b/src/etc/installer/msi/rust.wxs
@@ -0,0 +1,279 @@
+<?xml version="1.0"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+
+    <?if $(sys.BUILDARCH)="x64" ?>
+        <?define ArchSuffix=" 64-bit" ?>
+    <?else?>
+        <?define ArchSuffix="" ?>
+    <?endif?>
+
+    <?if $(env.CFG_CHANNEL)="stable" ?>
+        <?define ProductName="Rust $(env.CFG_VER_MAJOR).$(env.CFG_VER_MINOR) ($(env.CFG_ABI)$(var.ArchSuffix))" ?>
+    <?else?>
+        <?define ProductName="Rust $(env.CFG_CHANNEL) $(env.CFG_VER_MAJOR).$(env.CFG_VER_MINOR) ($(env.CFG_ABI)$(var.ArchSuffix))" ?>
+    <?endif?>
+
+    <?define BaseRegKey="Software\[Manufacturer]\Rust $(env.CFG_CHANNEL) ($(env.CFG_ABI)$(var.ArchSuffix))\$(env.CFG_VER_MAJOR).$(env.CFG_VER_MINOR)" ?>
+
+    <!-- Upgrade code should be different for each platform -->
+    <?if $(sys.BUILDARCH)="x64" ?>
+        <?if $(env.CFG_ABI)="GNU" ?>
+            <!-- UpgradeCode shoud stay the same for all MSI versions in channel -->
+            <?if $(env.CFG_CHANNEL)="stable" ?>
+                <?define UpgradeCode="B440B077-F8D1-4730-8E1D-D6D37702B4CE" ?>
+            <?elseif $(env.CFG_CHANNEL)="beta" ?>
+                <?define UpgradeCode="7205CEDC-CDA6-4B62-8E4E-4D19EC5D88FC" ?>
+            <?elseif $(env.CFG_CHANNEL)="nightly" ?>
+                <?define UpgradeCode="622497D9-E0B1-448E-838A-4A33D0C5F82C" ?>
+            <?elseif $(env.CFG_CHANNEL)="dev" ?>
+                <?define UpgradeCode="7D32FD99-BB26-45CF-935D-1B0593BBDDBE" ?>
+            <?endif ?>
+        <?elseif $(env.CFG_ABI)="MSVC" ?>
+            <?if $(env.CFG_CHANNEL)="stable" ?>
+                <?define UpgradeCode="123039F9-68E3-44F1-AC9F-C78ADD4D0723" ?>
+            <?elseif $(env.CFG_CHANNEL)="beta" ?>
+                <?define UpgradeCode="ABC640B9-2AB5-4270-9A0D-E54E502A1CCA" ?>
+            <?elseif $(env.CFG_CHANNEL)="nightly" ?>
+                <?define UpgradeCode="56263F12-4AA1-4FE1-AFAE-572915C4FA3E" ?>
+            <?elseif $(env.CFG_CHANNEL)="dev" ?>
+                <?define UpgradeCode="231A9544-7E39-4A60-A069-0EB3CA4BAB2E" ?>
+            <?endif ?>
+        <?endif ?>
+        <?define PlatformProgramFilesFolder="ProgramFiles64Folder" ?>
+    <?elseif $(sys.BUILDARCH)="x86" ?>
+        <?if $(env.CFG_ABI)="GNU" ?>
+            <?if $(env.CFG_CHANNEL)="stable" ?>
+                <?define UpgradeCode="1C7CADA5-D117-43F8-A356-DF15F9FBEFF6" ?>
+            <?elseif $(env.CFG_CHANNEL)="beta" ?>
+                <?define UpgradeCode="5229EAC1-AB7C-4A62-9881-6FAD2DE7D0F9" ?>
+            <?elseif $(env.CFG_CHANNEL)="nightly" ?>
+                <?define UpgradeCode="B94FF1C2-2C7B-4859-A08B-546815516FDA" ?>
+            <?elseif $(env.CFG_CHANNEL)="dev" ?>
+                <?define UpgradeCode="7E6D1349-2773-4792-B8CD-EA2685D86A99" ?>
+            <?endif ?>
+        <?elseif $(env.CFG_ABI)="MSVC" ?>
+            <?if $(env.CFG_CHANNEL)="stable" ?>
+                <?define UpgradeCode="5805719C-45E9-4CF6-9CE7-1E8B57F3C243" ?>
+            <?elseif $(env.CFG_CHANNEL)="beta" ?>
+                <?define UpgradeCode="BC0731C1-BED1-424C-BE99-3589C35C84DE" ?>
+            <?elseif $(env.CFG_CHANNEL)="nightly" ?>
+                <?define UpgradeCode="FF193BBC-E73B-4FBD-ADE0-12F3CFC84145" ?>
+            <?elseif $(env.CFG_CHANNEL)="dev" ?>
+                <?define UpgradeCode="87DFC303-6492-4E9B-911E-56EAD56C5E58" ?>
+            <?endif ?>
+        <?endif ?>
+        <?define PlatformProgramFilesFolder="ProgramFilesFolder" ?>
+    <?else ?>
+        <?error Unsupported value of sys.BUILDARCH=$(sys.BUILDARCH)?>
+    <?endif ?>
+
+    <Product Id="*"
+        Name="$(var.ProductName)"
+        Language="1033"
+        Version="$(env.CFG_VER_MAJOR).$(env.CFG_VER_MINOR).$(env.CFG_VER_PATCH).$(env.CFG_VER_BUILD)"
+        UpgradeCode="$(var.UpgradeCode)"
+        Manufacturer="The Rust Project Developers">
+        <Package
+            Comments="Rust is a systems programming language that runs blazingly fast, prevents almost all crashes, and eliminates data races."
+            InstallerVersion="200"
+            InstallPrivileges="elevated"
+            Compressed="yes" />
+
+        <Icon Id="rust.ico" SourceFile="rust-logo.ico" />
+        <Property Id="ApplicationFolderName" Value="Rust $(env.CFG_CHANNEL) $(env.CFG_ABI) $(env.CFG_VER_MAJOR).$(env.CFG_VER_MINOR)" />
+        <Property Id="WixAppFolder" Value="WixPerMachineFolder" />
+        <Property Id="ARPPRODUCTICON" Value="rust.ico" />
+        <Property Id="ARPURLINFOABOUT" Value="https://www.rust-lang.org/" />
+        <Property Id="ARPCOMMENTS" Value="$(env.CFG_RELEASE_INFO)" />
+        <!-- This is a dual-mode package. http://msdn.microsoft.com/en-us/library/windows/desktop/dd408068.aspx -->
+        <Property Id="ALLUSERS" Value="2" Secure="yes" />
+        <Property Id="MSIINSTALLPERUSER" Secure="yes" />
+        <!-- The actual install location (initialized below) -->
+        <Property Id="INSTALLDIR" Secure="yes" />
+
+        <!-- Detect path(s) of a previous installation. -->
+        <Property Id="INSTALLDIR_USER">
+            <RegistrySearch Id="InstallDir_User" Type="raw" Root="HKCU" Key="$(var.BaseRegKey)" Name="InstallDir" />
+        </Property>
+        <Property Id="INSTALLDIR_MACHINE">
+            <RegistrySearch Id="InstallDir_Mach" Type="raw" Root="HKLM" Key="$(var.BaseRegKey)" Name="InstallDir" />
+        </Property>
+
+        <!-- Set ALLUSERS to match the previous installation mode, otherwise FindRelatedProducts will ignore
+             the previous installation. If both INSTALLDIR_USER and INSTALLDIR_MACHINE are set, prefer the former. -->
+        <SetProperty Sequence="first" Before="FindRelatedProducts"
+            Id="ALLUSERS" Value="{}">INSTALLDIR_USER</SetProperty>
+
+        <!-- Set default values if RegSearch found nothing, or if we not upgrading -->
+        <SetProperty Sequence="both" Before="SetINSTALLDIR1"
+            Id="INSTALLDIR_USER" Value="[LocalAppDataFolder]Programs\[ApplicationFolderName]">NOT INSTALLDIR_USER</SetProperty>
+        <SetProperty Sequence="both" Before="SetINSTALLDIR1"
+            Id="INSTALLDIR_MACHINE" Value="[$(var.PlatformProgramFilesFolder)][ApplicationFolderName]">NOT INSTALLDIR_MACHINE</SetProperty>
+
+        <!-- Choose the default install location according to ALLUSERS (unless set from the command line) -->
+        <SetProperty Sequence="both" Action="SetINSTALLDIR1" Before="SetINSTALLDIR2"
+            Id="INSTALLDIR" Value="[INSTALLDIR_USER]">NOT INSTALLDIR AND NOT ALLUSERS</SetProperty>
+        <SetProperty Sequence="both" Action="SetINSTALLDIR2" Before="CostFinalize"
+            Id="INSTALLDIR" Value="[INSTALLDIR_MACHINE]">NOT INSTALLDIR AND ALLUSERS</SetProperty>
+
+        <SetProperty Sequence="ui" Before="CostFinalize"
+            Id="WixAppFolder" Value="WixPerUserFolder">NOT ALLUSERS</SetProperty>
+
+        <!-- UI sets ALLUSERS per user selection; progagate this choice to MSIINSTALLPERUSER before executing installation actions -->
+        <SetProperty Sequence="ui" Before="ExecuteAction"
+            Id="MSIINSTALLPERUSER" Value="1">NOT ALLUSERS</SetProperty>
+
+        <!-- Update ARPINSTALLLOCATION to match INSTALLDIR -->
+        <SetProperty Sequence="execute" Before="CostFinalize"
+            Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
+
+        <!-- Path of cmd.exe for the shortcut -->
+        <Property Id="SHORTCUTTARGET" Value="%windir%\System32\cmd.exe" />
+        <!-- Microsoft Installer will resolve any Enviroment Variables in the working directory at install time -->
+        <Property Id="SHORTCUTWKDIR" Value="%SystemDrive%\" />
+
+        <InstallUISequence>
+            <FindRelatedProducts After="AppSearch" />
+        </InstallUISequence>
+        <InstallExecuteSequence>
+            <FindRelatedProducts After="AppSearch" />
+            <RemoveExistingProducts Before="InstallInitialize" />
+        </InstallExecuteSequence>
+
+        <Upgrade Id="$(var.UpgradeCode)">
+            <UpgradeVersion
+                Minimum="$(env.CFG_VER_MAJOR).$(env.CFG_VER_MINOR).0"
+                Maximum="$(env.CFG_VER_MAJOR).$(env.CFG_VER_MINOR).65535"
+                IncludeMinimum="yes"
+                IncludeMaximum="yes"
+                MigrateFeatures="yes"
+                Property="UPGRADE_DETECTED"
+                />
+        </Upgrade>
+
+        <!-- Specifies a single cab file to be embedded in the installer's .msi. -->
+        <MediaTemplate EmbedCab="yes" CompressionLevel="high" />
+
+        <!-- Send a WM_SETTINGCHANGE message to tell processes like explorer to update their
+             environments so any new command prompts get the updated %PATH% -->
+        <CustomActionRef Id="WixBroadcastEnvironmentChange" />
+
+        <!-- Installation directory and files are defined in Files.wxs -->
+        <Directory Id="TARGETDIR" Name="SourceDir">
+            <Directory Id="$(var.PlatformProgramFilesFolder)">
+                <Directory Id="INSTALLDIR" Name="Rust">
+                    <!-- Root directories for every feature should have different IDs for correct work of heat.exe -->
+                    <Directory Id="Rustc" Name="." />
+                    <?if $(env.CFG_MINGW)="1" ?>
+                        <Directory Id="Gcc" Name="." />
+                    <?endif?>
+                    <Directory Id="Docs" Name="." />
+                    <Directory Id="Cargo" Name="." />
+                    <Directory Id="Std" Name="." />
+                </Directory>
+            </Directory>
+
+            <!-- Record our install location -->
+            <Component Id="InstallDir" Guid="*">
+                <RegistryValue Root="HKMU" Key="$(var.BaseRegKey)"
+                               Type="string"
+                               Name="InstallDir"
+                               Value="[INSTALLDIR]" />
+            </Component>
+
+            <!-- Add $/bin to PATH -->
+            <Component Id="PathEnvPerMachine" Guid="*">
+                <Condition>ALLUSERS=1 OR (ALLUSERS=2 AND Privileged)</Condition>
+                <RegistryValue Root="HKMU" Key="$(var.BaseRegKey)" Name="PathEnvPerMachine" Type="string" Value="1" KeyPath="yes" />
+                <!-- [INSTALLDIR] contains trailing backslash -->
+                <Environment Id="PathPerMachine" Name="PATH" Value="[INSTALLDIR]bin" Permanent="no" Part="last" Action="set" System="yes" />
+            </Component>
+            <Component Id="PathEnvPerUser" Guid="*">
+                <Condition>ALLUSERS="" OR (ALLUSERS=2 AND (NOT Privileged))</Condition>
+                <RegistryValue Root="HKMU" Key="$(var.BaseRegKey)" Name="PathEnvPerUser" Type="string" Value="1" KeyPath="yes" />
+                <Environment Id="PathPerUser" Name="PATH" Value="[INSTALLDIR]bin" Permanent="no" Part="last" Action="set" System="no" />
+            </Component>
+
+            <!-- Start Menu shortcuts -->
+            <Directory Id="ProgramMenuFolder">
+                <Directory Id="ApplicationProgramsFolder" Name="Rust">
+                    <Component Id="RustShellShortcut" Guid="*">
+                        <Shortcut Id="RustShell"
+                                  Name="$(var.ProductName) Shell"
+                                  Description="Opens Command Prompt with Rust tools directory added to the PATH"
+                                  Target="[SHORTCUTTARGET]"
+                                  Arguments="/K path [INSTALLDIR]bin;%PATH%"
+                                  WorkingDirectory="SHORTCUTWKDIR">
+                            <Icon Id="rust2.ico" SourceFile="rust-logo.ico" />
+                        </Shortcut>
+                        <RegistryValue Root="HKMU" Key="$(var.BaseRegKey)" Name="RustShell" Type="integer" Value="1" KeyPath="yes" />
+                        <RemoveFolder Id="ApplicationProgramsFolder1" On="uninstall" />
+                    </Component>
+                    <Component Id="DocIndexShortcut" Guid="*">
+                        <Shortcut Id="RustDocs"
+                                  Name="$(var.ProductName) Documentation"
+                                  Description="Opens Rust HTML documentation in the default browser"
+                                  Target="[INSTALLDIR]share\doc\rust\html\index.html" />
+                        <RegistryValue Root="HKMU" Key="$(var.BaseRegKey)" Name="RustDocs" Type="integer" Value="1" KeyPath="yes" />
+                        <RemoveFolder Id="ApplicationProgramsFolder2" On="uninstall" />
+                    </Component>
+                </Directory>
+            </Directory>
+
+        </Directory>
+
+        <Feature Id="Rustc"
+                 Title="Rust compiler and standard crates"
+                 Display="1"
+                 Level="1"
+                 Absent="disallow"
+                 AllowAdvertise="no">
+                 <ComponentGroupRef Id="RustcGroup" />
+                 <ComponentRef Id="RustShellShortcut" />
+                 <ComponentRef Id="InstallDir" />
+        </Feature>
+        <Feature Id="Std"
+                 Title="The Rust standard library"
+                 Display="2"
+                 Level="1"
+                 AllowAdvertise="no">
+                 <ComponentGroupRef Id="StdGroup" />
+        </Feature>
+        <Feature Id="Cargo"
+                 Title="Cargo, the Rust package manager"
+                 Display="3"
+                 Level="1"
+                 AllowAdvertise="no">
+                 <ComponentGroupRef Id="CargoGroup" />
+        </Feature>
+        <?if $(env.CFG_MINGW)="1" ?>
+            <Feature Id="Gcc"
+                     Title="Linker and platform libraries"
+                     Description="If you choose to not install this component, you will require an external MinGW installation in order to create executables and libraries."
+                     Display="4"
+                     Level="1"
+                     AllowAdvertise="no">
+                     <ComponentGroupRef Id="GccGroup" />
+            </Feature>
+        <?endif?>
+        <Feature Id="Docs"
+                 Title="HTML documentation"
+                 Display="5"
+                 Level="1"
+                 AllowAdvertise="no">
+                 <ComponentGroupRef Id="DocsGroup" />
+                 <ComponentRef Id="DocIndexShortcut" />
+        </Feature>
+        <Feature Id="Path"
+                 Title="Add to PATH"
+                 Description="Add Rust to PATH environment variable"
+                 Display="6"
+                 Level="1"
+                 AllowAdvertise="no">
+                 <ComponentRef Id="PathEnvPerMachine" />
+                 <ComponentRef Id="PathEnvPerUser" />
+        </Feature>
+
+        <UIRef Id="RustUI" />
+    </Product>
+</Wix>
diff --git a/src/etc/installer/msi/rustwelcomedlg.wxs b/src/etc/installer/msi/rustwelcomedlg.wxs
new file mode 100644
index 00000000000..0ee5415ffba
--- /dev/null
+++ b/src/etc/installer/msi/rustwelcomedlg.wxs
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+    <Fragment>
+        <UI>
+            <Dialog Id="RustWelcomeDlg" Width="370" Height="270" Title="!(loc.AdvancedWelcomeEulaDlg_Title)">
+                <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.AdvancedWelcomeEulaDlgBannerBitmap)" />
+                <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
+                <Control Id="Title" Type="Text" X="20" Y="10" Width="300" Height="24" Transparent="yes" NoPrefix="yes" Text="!(loc.AdvancedWelcomeEulaDlgTitle)" />
+                <Control Id="DescriptionPerMachine" Type="Text" X="20" Y="182" Width="330" Height="31" Transparent="yes" NoPrefix="yes" Hidden="yes" Text="!(loc.AdvancedWelcomeEulaDlgDescriptionPerMachine)">
+                    <Condition Action="show">NOT UPGRADE_DETECTED AND ALLUSERS</Condition>
+                </Control>
+                <Control Id="DescriptionPerUser" Type="Text" X="20" Y="182" Width="330" Height="31" Transparent="yes" NoPrefix="yes" Hidden="yes" Text="!(loc.AdvancedWelcomeEulaDlgDescriptionPerUser)">
+                    <Condition Action="show">NOT UPGRADE_DETECTED AND NOT ALLUSERS</Condition>
+                </Control>
+                <Control Id="DescriptionUpgrade" Type="Text" X="20" Y="182" Width="330" Height="31" Transparent="yes" NoPrefix="yes" Hidden="yes"
+                    Text="Click Install to upgrade the existing version of [ProductName].  Click Advanced to change installation options.">
+                    <Condition Action="show">UPGRADE_DETECTED</Condition>
+                </Control>
+                <Control Id="TargetPath" Type="Text" X="20" Y="212" Width="330" Height="31" Transparent="yes" NoPrefix="yes" Hidden="no"
+                    Text="Install Directory: [INSTALLDIR]">
+                </Control>
+                <Control Id="Print" Type="PushButton" X="88" Y="243" Width="56" Height="17" Text="!(loc.WixUIPrint)">
+                    <Publish Event="DoAction" Value="WixUIPrintEula">1</Publish>
+                </Control>
+                <Control Id="Advanced" Type="PushButton" X="156" Y="243" Width="56" Height="17" Text="!(loc.AdvancedWelcomeEulaDlgAdvanced)" />
+                <Control Id="Install" Type="PushButton" ElevationShield="yes" X="212" Y="243" Width="80" Height="17" Default="yes" Text="!(loc.AdvancedWelcomeEulaDlgInstall)" Hidden="yes">
+                    <Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">!(wix.WixUICostingPopupOptOut) OR CostingComplete = 1</Publish>
+                    <Publish Event="EndDialog" Value="Return"><![CDATA[OutOfDiskSpace <> 1]]></Publish>
+                    <Publish Event="SpawnDialog" Value="OutOfRbDiskDlg">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)</Publish>
+                    <Publish Event="EndDialog" Value="Return">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish>
+                    <Publish Event="EnableRollback" Value="False">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish>
+                    <Publish Event="SpawnDialog" Value="OutOfDiskDlg">(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")</Publish>
+                    <Condition Action="show">ALLUSERS</Condition>
+                </Control>
+                <Control Id="InstallNoShield" Type="PushButton" ElevationShield="no" X="212" Y="243" Width="80" Height="17" Default="yes" Text="!(loc.AdvancedWelcomeEulaDlgInstall)" Hidden="yes">
+                    <Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">!(wix.WixUICostingPopupOptOut) OR CostingComplete = 1</Publish>
+                    <Publish Event="EndDialog" Value="Return"><![CDATA[OutOfDiskSpace <> 1]]></Publish>
+                    <Publish Event="SpawnDialog" Value="OutOfRbDiskDlg">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)</Publish>
+                    <Publish Event="EndDialog" Value="Return">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish>
+                    <Publish Event="EnableRollback" Value="False">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish>
+                    <Publish Event="SpawnDialog" Value="OutOfDiskDlg">(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")</Publish>
+                    <Condition Action="show">NOT ALLUSERS</Condition>
+                </Control>
+                <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
+                    <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
+                </Control>
+                <Control Id="LicenseText" Type="ScrollableText" X="20" Y="55" Width="330" Height="121" Sunken="yes" TabSkip="no">
+                    <Text SourceFile="!(wix.WixUILicenseRtf)" />
+                </Control>
+            </Dialog>
+        </UI>
+
+        <InstallUISequence>
+            <Show Dialog="RustWelcomeDlg" Before="ProgressDlg">NOT Installed</Show>
+        </InstallUISequence>
+    </Fragment>
+</Wix>
diff --git a/src/etc/installer/msi/squash-components.xsl b/src/etc/installer/msi/squash-components.xsl
new file mode 100644
index 00000000000..17b4e0388f9
--- /dev/null
+++ b/src/etc/installer/msi/squash-components.xsl
@@ -0,0 +1,34 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0"
+        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+        xmlns:wix="http://schemas.microsoft.com/wix/2006/wi">
+    <!-- Copy all attributes and elements to the output. -->
+    <xsl:template match="@*|*">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|*"/>
+        </xsl:copy>
+    </xsl:template>
+    <xsl:output method="xml" indent="yes" />
+
+    <!-- Move all files in directory into first component in that directory. -->
+    <xsl:template match="wix:Component[1]">
+        <xsl:copy>
+            <xsl:apply-templates select="@*|*"/>
+            <xsl:for-each select="../wix:Component[preceding-sibling::*]/wix:File">
+                <xsl:copy>
+                    <!-- Component can only have one KeyPath -->
+                    <xsl:apply-templates select="@*[not(name()='KeyPath')]|*"/>
+                </xsl:copy>
+            </xsl:for-each>
+        </xsl:copy>
+    </xsl:template>
+
+    <!-- Now the rest of components are empty, find them. -->
+    <xsl:key name="empty-cmp-ids" match="wix:Component[preceding-sibling::*]" use="@Id" />
+
+    <!-- And remove. -->
+    <xsl:template match="wix:Component[preceding-sibling::*]" />
+
+    <!-- Also remove componentsrefs referencing empty components. -->
+    <xsl:template match="wix:ComponentRef[key('empty-cmp-ids', @Id)]" />
+</xsl:stylesheet>
diff --git a/src/etc/installer/msi/ui.wxs b/src/etc/installer/msi/ui.wxs
new file mode 100644
index 00000000000..3e2db6051bc
--- /dev/null
+++ b/src/etc/installer/msi/ui.wxs
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Based on WixUI_Advanced
+-->
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+    <Fragment>
+        <WixVariable Id="WixUISupportPerUser" Value="1" Overridable="yes" />
+        <WixVariable Id="WixUISupportPerMachine" Value="1" Overridable="yes" />
+        <WixVariable Id="WixUILicenseRtf" Value="LICENSE.rtf" />
+        <WixVariable Id="WixUIDialogBmp" Value="dialogbg.bmp" />
+        <WixVariable Id="WixUIBannerBmp" Value="banner.bmp" />
+
+        <UI Id="RustUI">
+            <TextStyle Id="WixUI_Font_Normal" FaceName="!(loc.Advanced_Font_FaceName)" Size="!(loc.Advanced_Font_Normal_Size)" />
+            <TextStyle Id="WixUI_Font_Bigger" FaceName="!(loc.Advanced_Font_FaceName)" Size="!(loc.Advanced_Font_Bigger_Size)" />
+            <TextStyle Id="WixUI_Font_Title" FaceName="!(loc.Advanced_Font_FaceName)" Size="!(loc.Advanced_Font_Title_Size)" Bold="yes" />
+            <TextStyle Id="WixUI_Font_Emphasized" FaceName="!(loc.Advanced_Font_FaceName)" Size="!(loc.Advanced_Font_Emphasized_Size)" Bold="yes" />
+
+            <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
+            <Property Id="WixUI_Mode" Value="Advanced" />
+
+            <DialogRef Id="BrowseDlg" />
+            <DialogRef Id="DiskCostDlg" />
+            <DialogRef Id="ErrorDlg" />
+            <DialogRef Id="FatalError" />
+            <DialogRef Id="FilesInUse" />
+            <DialogRef Id="MsiRMFilesInUse" />
+            <DialogRef Id="PrepareDlg" />
+            <DialogRef Id="ProgressDlg" />
+            <DialogRef Id="ResumeDlg" />
+            <DialogRef Id="UserExit" />
+            <DialogRef Id="WelcomeDlg"/>
+
+            <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
+
+            <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="1">1</Publish>
+            <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="2"><![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+
+            <Publish Dialog="RustWelcomeDlg" Control="Advanced" Event="NewDialog" Value="InstallScopeDlg" Order="1" />
+
+            <Publish Dialog="InstallScopeDlg" Control="Back" Event="NewDialog" Value="RustWelcomeDlg">1</Publish>
+            <!-- override default WixAppFolder of WixPerMachineFolder as standard user won't be shown the radio group to set WixAppFolder -->
+            <Publish Dialog="InstallScopeDlg" Control="Next" Property="WixAppFolder" Value="WixPerUserFolder" Order="1">!(wix.WixUISupportPerUser) AND NOT Privileged</Publish>
+            <Publish Dialog="InstallScopeDlg" Control="Next" Property="ALLUSERS" Value="{}" Order="2">WixAppFolder = "WixPerUserFolder"</Publish>
+            <Publish Dialog="InstallScopeDlg" Control="Next" Property="ALLUSERS" Value="1" Order="3">WixAppFolder = "WixPerMachineFolder"</Publish>
+            <Publish Dialog="InstallScopeDlg" Control="Next" Property="INSTALLDIR" Value="[INSTALLDIR_USER]" Order="4">WixAppFolder = "WixPerUserFolder"</Publish>
+            <Publish Dialog="InstallScopeDlg" Control="Next" Property="INSTALLDIR" Value="[INSTALLDIR_MACHINE]" Order="5">WixAppFolder = "WixPerMachineFolder"</Publish>
+            <Publish Dialog="InstallScopeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Order="6">1</Publish>
+
+            <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="InstallScopeDlg" />
+            <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+            <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
+            <Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+            <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="FeaturesDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
+            <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+            <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
+
+            <Publish Dialog="FeaturesDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">NOT Installed AND WixAppFolder = "WixPerUserFolder"</Publish>
+            <Publish Dialog="FeaturesDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">NOT Installed AND WixAppFolder = "WixPerMachineFolder"</Publish>
+            <Publish Dialog="FeaturesDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg">Installed</Publish>
+
+            <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+            <Publish Dialog="MaintenanceTypeDlg" Control="ChangeButton" Event="NewDialog" Value="FeaturesDlg">1</Publish>
+            <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+            <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+            <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
+
+            <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
+            <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="3">Installed AND PATCH</Publish>
+
+            <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
+        </UI>
+
+        <InstallUISequence>
+            <Show Dialog="WelcomeDlg" Before="RustWelcomeDlg" >Installed AND PATCH</Show>
+        </InstallUISequence>
+
+        <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
+        <UIRef Id="WixUI_Common" />
+    </Fragment>
+</Wix>
diff --git a/src/etc/installer/pkg/Distribution.xml b/src/etc/installer/pkg/Distribution.xml
new file mode 100644
index 00000000000..79f99818ba3
--- /dev/null
+++ b/src/etc/installer/pkg/Distribution.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<installer-gui-script minSpecVersion="2">
+    <title>The Rust Compiler</title>
+    <license file="LICENSE.txt" mime-type="text/plain"/>
+    <pkg-ref id="org.rust-lang.rust"/>
+    <options customize="always" require-scripts="false" hostArchitectures="i386,x86_64"/>
+    <domains enable_anywhere="false" enable_currentUserHome="false" enable_localSystem="true" />
+    <volume-check>
+        <allowed-os-versions>
+            <os-version min="10.7"/>
+        </allowed-os-versions>
+    </volume-check>
+    <choices-outline>
+      <line choice="install">
+	<line choice="rustc"/>
+    <line choice="rust-std"/>
+	<line choice="cargo"/>
+	<line choice="rust-docs"/>
+      </line>
+      <line choice="uninstall" />
+    </choices-outline>
+    <!--
+	These 'selected' scripts ensure that install and uninstall can never be selected at
+	the same time. Exectly how they work is pretty mysterious, tied to the unspecified algorithm
+	the installer uses to traverse the options after one is toggled.
+      -->
+    <choice id="install" visible="true"
+	    title="Install Rust" description="Install the Rust compiler, package manager and documentation."
+	    customLocation="/usr/local"
+	    selected="!choices.uninstall.selected"
+	    />
+    <choice id="uninstall" visible="true"
+	    title="Uninstall Rust" description="Select this option to uninstall an existing Rust installation."
+	    customLocation="/usr/local"
+	    selected="!(choices.install.selected || choices.rustc.selected || choices.cargo.selected || choices['rust-docs'].selected)"
+	    start_selected="false"
+	    >
+        <pkg-ref id="org.rust-lang.uninstall" />
+    </choice>
+    <choice id="rustc" visible="true"
+	    title="Compiler" description="rustc, the Rust compiler, and rustdoc, the API documentation tool."
+	    selected="(!choices.uninstall.selected &amp;&amp; choices.rustc.selected) || (choices.uninstall.selected &amp;&amp; choices.install.selected)"
+	    >
+        <pkg-ref id="org.rust-lang.rustc"/>
+    </choice>
+    <choice id="cargo" visible="true"
+	    title="Cargo" description="cargo, the Rust package manager."
+	    selected="(!choices.uninstall.selected &amp;&amp; choices.cargo.selected) || (choices.uninstall.selected &amp;&amp; choices.install.selected)"
+	    >
+        <pkg-ref id="org.rust-lang.cargo"/>
+    </choice>
+    <choice id="rust-std" visible="true"
+	    title="Standard Library" description="The Rust standard library."
+	    selected="(!choices.uninstall.selected &amp;&amp; choices['rust-std'].selected) || (choices.uninstall.selected &amp;&amp; choices.install.selected)"
+	    >
+        <pkg-ref id="org.rust-lang.rust-std"/>
+    </choice>
+    <choice id="rust-docs" visible="true"
+	    title="Documentation" description="HTML documentation."
+	    selected="(!choices.uninstall.selected &amp;&amp; choices['rust-docs'].selected) || (choices.uninstall.selected &amp;&amp; choices.install.selected)"
+	    >
+        <pkg-ref id="org.rust-lang.rust-docs"/>
+    </choice>
+    <pkg-ref id="org.rust-lang.rustc" version="0" onConclusion="none">rustc.pkg</pkg-ref>
+    <pkg-ref id="org.rust-lang.cargo" version="0" onConclusion="none">cargo.pkg</pkg-ref>
+    <pkg-ref id="org.rust-lang.rust-docs" version="0" onConclusion="none">rust-docs.pkg</pkg-ref>
+    <pkg-ref id="org.rust-lang.rust-std" version="0" onConclusion="none">rust-std.pkg</pkg-ref>
+    <pkg-ref id="org.rust-lang.uninstall" version="0" onConclusion="none">uninstall.pkg</pkg-ref>
+    <background file="rust-logo.png" mime-type="image/png"
+                alignment="bottomleft"/>
+</installer-gui-script>
diff --git a/src/etc/installer/pkg/postinstall b/src/etc/installer/pkg/postinstall
new file mode 100755
index 00000000000..fb035a48690
--- /dev/null
+++ b/src/etc/installer/pkg/postinstall
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+source_dir="$(dirname "$0")"
+dest_dir="$2"
+package_id="$INSTALL_PKG_SESSION_ID"
+
+if [ -z "$source_dir" ]; then
+    exit 1
+fi
+if [ -z "$dest_dir" ]; then
+    exit 1
+fi
+if [ -z "$package_id" ]; then
+    exit 1
+fi
+
+if [ "$package_id" = "org.rust-lang.uninstall" ]; then
+    if [ ! -e "$dest_dir/lib/rustlib/uninstall.sh" ]; then
+	exit 1
+    fi
+    sh "$dest_dir/lib/rustlib/uninstall.sh"
+else
+    sh "$source_dir/install.sh" --prefix="$dest_dir"
+fi
+
+exit 0