rustbuild: split Install out of Dist subcommand

only create source tarball for the Dist subcommand
mark install rule as default for Kind::Install
split install-docs
split install-std
factor out empty_dir handling
split install-cargo
split install-analysis
split install-src
rework install-rustc
properly handle cross-compilation setups for install
use pkgname in install
split plain source tarball generation from rust-src dist
document src-tarball in config.toml.exmaple

Signed-off-by: Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
This commit is contained in:
Marc-Antoine Perennou 2017-05-18 22:48:14 +02:00
parent 81734e0e06
commit 150d644c21
7 changed files with 212 additions and 143 deletions

View file

@ -35,7 +35,7 @@ Read ["Installing Rust"] from [The Book].
3. Build and install: 3. Build and install:
```sh ```sh
$ ./x.py build && sudo ./x.py dist --install $ ./x.py build && sudo ./x.py install
``` ```
> ***Note:*** Install locations can be adjusted by copying the config file > ***Note:*** Install locations can be adjusted by copying the config file
@ -43,7 +43,7 @@ Read ["Installing Rust"] from [The Book].
> adjusting the `prefix` option under `[install]`. Various other options are > adjusting the `prefix` option under `[install]`. Various other options are
> also supported, and are documented in the config file. > also supported, and are documented in the config file.
When complete, `sudo ./x.py dist --install` will place several programs into When complete, `sudo ./x.py install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
API-documentation tool. This install does not include [Cargo], API-documentation tool. This install does not include [Cargo],
Rust's package manager, which you may also want to build. Rust's package manager, which you may also want to build.
@ -96,7 +96,7 @@ build.
4. Navigate to Rust's source code (or clone it), then build it: 4. Navigate to Rust's source code (or clone it), then build it:
```sh ```sh
$ ./x.py build && ./x.py dist --install $ ./x.py build && ./x.py install
``` ```
#### MSVC #### MSVC

View file

@ -314,3 +314,9 @@
# Note that this address should not contain a trailing slash as file names will # Note that this address should not contain a trailing slash as file names will
# be appended to it. # be appended to it.
#upload-addr = "https://example.com/folder" #upload-addr = "https://example.com/folder"
# Whether to build a plain source tarball to upload
# We disable that on Windows not to override the one already uploaded on S3
# as the one built on Windows will contain backslashes in paths causing problems
# on linux
#src-tarball = true

View file

@ -30,11 +30,11 @@ use {Build, Compiler, Mode};
use channel; use channel;
use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe}; use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe};
fn pkgname(build: &Build, component: &str) -> String { pub fn pkgname(build: &Build, component: &str) -> String {
if component == "cargo" { if component == "cargo" {
format!("{}-{}", component, build.cargo_package_vers()) format!("{}-{}", component, build.cargo_package_vers())
} else if component == "rls" { } else if component == "rls" {
format!("{}-{}", component, build.package_vers(&build.release_num("rls"))) format!("{}-{}", component, build.rls_package_vers())
} else { } else {
assert!(component.starts_with("rust")); assert!(component.starts_with("rust"));
format!("{}-{}", component, build.rust_package_vers()) format!("{}-{}", component, build.rust_package_vers())
@ -369,38 +369,7 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
t!(fs::remove_dir_all(&image)); t!(fs::remove_dir_all(&image));
} }
const CARGO_VENDOR_VERSION: &'static str = "0.1.4"; fn copy_src_dirs(build: &Build, src_dirs: &[&str], dst_dir: &Path) {
/// Creates the `rust-src` installer component and the plain source tarball
pub fn rust_src(build: &Build) {
if !build.config.rust_dist_src {
return
}
println!("Dist src");
// Make sure that the root folder of tarball has the correct name
let plain_name = format!("rustc-{}-src", build.rust_package_vers());
let plain_dst_src = tmpdir(build).join(&plain_name);
let _ = fs::remove_dir_all(&plain_dst_src);
t!(fs::create_dir_all(&plain_dst_src));
// This is the set of root paths which will become part of the source package
let src_files = [
"COPYRIGHT",
"LICENSE-APACHE",
"LICENSE-MIT",
"CONTRIBUTING.md",
"README.md",
"RELEASES.md",
"configure",
"x.py",
];
let src_dirs = [
"man",
"src",
];
let filter_fn = move |path: &Path| { let filter_fn = move |path: &Path| {
let spath = match path.to_str() { let spath = match path.to_str() {
Some(path) => path, Some(path) => path,
@ -429,60 +398,16 @@ pub fn rust_src(build: &Build) {
}; };
// Copy the directories using our filter // Copy the directories using our filter
for item in &src_dirs { for item in src_dirs {
let dst = &plain_dst_src.join(item); let dst = &dst_dir.join(item);
t!(fs::create_dir(dst)); t!(fs::create_dir_all(dst));
cp_filtered(&build.src.join(item), dst, &filter_fn); cp_filtered(&build.src.join(item), dst, &filter_fn);
} }
// Copy the files normally }
for item in &src_files {
copy(&build.src.join(item), &plain_dst_src.join(item));
}
// If we're building from git sources, we need to vendor a complete distribution.
if build.src_is_git {
// Get cargo-vendor installed, if it isn't already.
let mut has_cargo_vendor = false;
let mut cmd = Command::new(&build.cargo);
for line in output(cmd.arg("install").arg("--list")).lines() {
has_cargo_vendor |= line.starts_with("cargo-vendor ");
}
if !has_cargo_vendor {
let mut cmd = Command::new(&build.cargo);
cmd.arg("install")
.arg("--force")
.arg("--debug")
.arg("--vers").arg(CARGO_VENDOR_VERSION)
.arg("cargo-vendor")
.env("RUSTC", &build.rustc);
build.run(&mut cmd);
}
// Vendor all Cargo dependencies
let mut cmd = Command::new(&build.cargo);
cmd.arg("vendor")
.current_dir(&plain_dst_src.join("src"));
build.run(&mut cmd);
}
// Create the version file
write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
// Create plain source tarball
let mut tarball = rust_src_location(build);
tarball.set_extension(""); // strip .gz
tarball.set_extension(""); // strip .tar
if let Some(dir) = tarball.parent() {
t!(fs::create_dir_all(dir));
}
let mut cmd = rust_installer(build);
cmd.arg("tarball")
.arg("--input").arg(&plain_name)
.arg("--output").arg(&tarball)
.arg("--work-dir=.")
.current_dir(tmpdir(build));
build.run(&mut cmd);
/// Creates the `rust-src` installer component
pub fn rust_src(build: &Build) {
println!("Dist src");
let name = pkgname(build, "rust-src"); let name = pkgname(build, "rust-src");
let image = tmpdir(build).join(format!("{}-image", name)); let image = tmpdir(build).join(format!("{}-image", name));
@ -516,11 +441,7 @@ pub fn rust_src(build: &Build) {
"src/rustc/libc_shim", "src/rustc/libc_shim",
]; ];
for item in &std_src_dirs { copy_src_dirs(build, &std_src_dirs[..], &dst_src);
let dst = &dst_src.join(item);
t!(fs::create_dir_all(dst));
cp_r(&plain_dst_src.join(item), dst);
}
// Create source tarball in rust-installer format // Create source tarball in rust-installer format
let mut cmd = rust_installer(build); let mut cmd = rust_installer(build);
@ -537,7 +458,86 @@ pub fn rust_src(build: &Build) {
build.run(&mut cmd); build.run(&mut cmd);
t!(fs::remove_dir_all(&image)); t!(fs::remove_dir_all(&image));
t!(fs::remove_dir_all(&plain_dst_src)); }
const CARGO_VENDOR_VERSION: &'static str = "0.1.4";
/// Creates the plain source tarball
pub fn plain_source_tarball(build: &Build) {
println!("Create plain source tarball");
// Make sure that the root folder of tarball has the correct name
let plain_name = format!("{}-src", pkgname(build, "rustc"));
let plain_dst_src = tmpdir(build).join(&plain_name);
let _ = fs::remove_dir_all(&plain_dst_src);
t!(fs::create_dir_all(&plain_dst_src));
// This is the set of root paths which will become part of the source package
let src_files = [
"COPYRIGHT",
"LICENSE-APACHE",
"LICENSE-MIT",
"CONTRIBUTING.md",
"README.md",
"RELEASES.md",
"configure",
"x.py",
];
let src_dirs = [
"man",
"src",
];
copy_src_dirs(build, &src_dirs[..], &plain_dst_src);
// Copy the files normally
for item in &src_files {
copy(&build.src.join(item), &plain_dst_src.join(item));
}
// Create the version file
write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
// If we're building from git sources, we need to vendor a complete distribution.
if build.src_is_git {
// Get cargo-vendor installed, if it isn't already.
let mut has_cargo_vendor = false;
let mut cmd = Command::new(&build.cargo);
for line in output(cmd.arg("install").arg("--list")).lines() {
has_cargo_vendor |= line.starts_with("cargo-vendor ");
}
if !has_cargo_vendor {
let mut cmd = Command::new(&build.cargo);
cmd.arg("install")
.arg("--force")
.arg("--debug")
.arg("--vers").arg(CARGO_VENDOR_VERSION)
.arg("cargo-vendor")
.env("RUSTC", &build.rustc);
build.run(&mut cmd);
}
// Vendor all Cargo dependencies
let mut cmd = Command::new(&build.cargo);
cmd.arg("vendor")
.current_dir(&plain_dst_src.join("src"));
build.run(&mut cmd);
}
// Create plain source tarball
let mut tarball = rust_src_location(build);
tarball.set_extension(""); // strip .gz
tarball.set_extension(""); // strip .tar
if let Some(dir) = tarball.parent() {
t!(fs::create_dir_all(dir));
}
let mut cmd = rust_installer(build);
cmd.arg("tarball")
.arg("--input").arg(&plain_name)
.arg("--output").arg(&tarball)
.arg("--work-dir=.")
.current_dir(tmpdir(build));
build.run(&mut cmd);
} }
fn install(src: &Path, dstdir: &Path, perms: u32) { fn install(src: &Path, dstdir: &Path, perms: u32) {

View file

@ -69,7 +69,9 @@ pub enum Subcommand {
Clean, Clean,
Dist { Dist {
paths: Vec<PathBuf>, paths: Vec<PathBuf>,
install: bool, },
Install {
paths: Vec<PathBuf>,
}, },
} }
@ -85,7 +87,8 @@ Subcommands:
bench Build and run some benchmarks bench Build and run some benchmarks
doc Build documentation doc Build documentation
clean Clean out build directories clean Clean out build directories
dist Build and/or install distribution artifacts dist Build distribution artifacts
install Install distribution artifacts
To learn more about a subcommand, run `./x.py <subcommand> -h`"); To learn more about a subcommand, run `./x.py <subcommand> -h`");
@ -125,7 +128,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
|| (s == "bench") || (s == "bench")
|| (s == "doc") || (s == "doc")
|| (s == "clean") || (s == "clean")
|| (s == "dist")); || (s == "dist")
|| (s == "install"));
let subcommand = match possible_subcommands.first() { let subcommand = match possible_subcommands.first() {
Some(s) => s, Some(s) => s,
None => { None => {
@ -139,7 +143,6 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
match subcommand.as_str() { match subcommand.as_str() {
"test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"dist" => { opts.optflag("", "install", "run installer as well"); },
_ => { }, _ => { },
}; };
@ -281,7 +284,11 @@ Arguments:
"dist" => { "dist" => {
Subcommand::Dist { Subcommand::Dist {
paths: paths, paths: paths,
install: matches.opt_present("install"), }
}
"install" => {
Subcommand::Install {
paths: paths,
} }
} }
_ => { _ => {

View file

@ -19,7 +19,7 @@ use std::path::{Path, PathBuf, Component};
use std::process::Command; use std::process::Command;
use Build; use Build;
use dist::{sanitize_sh, tmpdir}; use dist::{pkgname, sanitize_sh, tmpdir};
pub struct Installer<'a> { pub struct Installer<'a> {
build: &'a Build, build: &'a Build,
@ -29,6 +29,13 @@ pub struct Installer<'a> {
bindir: PathBuf, bindir: PathBuf,
libdir: PathBuf, libdir: PathBuf,
mandir: PathBuf, mandir: PathBuf,
empty_dir: PathBuf,
}
impl<'a> Drop for Installer<'a> {
fn drop(&mut self) {
t!(fs::remove_dir_all(&self.empty_dir));
}
} }
impl<'a> Installer<'a> { impl<'a> Installer<'a> {
@ -61,6 +68,10 @@ impl<'a> Installer<'a> {
let libdir = add_destdir(&libdir, &destdir); let libdir = add_destdir(&libdir, &destdir);
let mandir = add_destdir(&mandir, &destdir); let mandir = add_destdir(&mandir, &destdir);
let empty_dir = build.out.join("tmp/empty_dir");
t!(fs::create_dir_all(&empty_dir));
Installer { Installer {
build, build,
prefix, prefix,
@ -69,52 +80,49 @@ impl<'a> Installer<'a> {
bindir, bindir,
libdir, libdir,
mandir, mandir,
empty_dir,
} }
} }
/// Installs everything. pub fn install_docs(&self, stage: u32, host: &str) {
pub fn install(&self, stage: u32, host: &str) { self.install_sh("docs", "rust-docs", stage, Some(host));
let empty_dir = self.build.out.join("tmp/empty_dir"); }
t!(fs::create_dir_all(&empty_dir));
if self.build.config.docs {
self.install_sh("docs", "rust-docs", &self.build.rust_package_vers(),
stage, Some(host), &empty_dir);
}
pub fn install_std(&self, stage: u32) {
for target in self.build.config.target.iter() { for target in self.build.config.target.iter() {
self.install_sh("std", "rust-std", &self.build.rust_package_vers(), self.install_sh("std", "rust-std", stage, Some(target));
stage, Some(target), &empty_dir);
} }
if self.build.config.extended {
self.install_sh("cargo", "cargo", &self.build.cargo_package_vers(),
stage, Some(host), &empty_dir);
self.install_sh("rls", "rls", &self.build.rls_package_vers(),
stage, Some(host), &empty_dir);
self.install_sh("analysis", "rust-analysis", &self.build.rust_package_vers(),
stage, Some(host), &empty_dir);
self.install_sh("src", "rust-src", &self.build.rust_package_vers(),
stage, None, &empty_dir);
}
self.install_sh("rustc", "rustc", &self.build.rust_package_vers(),
stage, Some(host), &empty_dir);
t!(fs::remove_dir_all(&empty_dir));
} }
fn install_sh(&self, package: &str, name: &str, version: &str, pub fn install_cargo(&self, stage: u32, host: &str) {
stage: u32, host: Option<&str>, empty_dir: &Path) { self.install_sh("cargo", "cargo", stage, Some(host));
}
pub fn install_rls(&self, stage: u32, host: &str) {
self.install_sh("rls", "rls", stage, Some(host));
}
pub fn install_analysis(&self, stage: u32, host: &str) {
self.install_sh("analysis", "rust-analysis", stage, Some(host));
}
pub fn install_src(&self, stage: u32) {
self.install_sh("src", "rust-src", stage, None);
}
pub fn install_rustc(&self, stage: u32, host: &str) {
self.install_sh("rustc", "rustc", stage, Some(host));
}
fn install_sh(&self, package: &str, name: &str, stage: u32, host: Option<&str>) {
println!("Install {} stage{} ({:?})", package, stage, host); println!("Install {} stage{} ({:?})", package, stage, host);
let package_name = if let Some(host) = host { let package_name = if let Some(host) = host {
format!("{}-{}-{}", name, version, host) format!("{}-{}", pkgname(self.build, name), host)
} else { } else {
format!("{}-{}", name, version) pkgname(self.build, name)
}; };
let mut cmd = Command::new("sh"); let mut cmd = Command::new("sh");
cmd.current_dir(empty_dir) cmd.current_dir(&self.empty_dir)
.arg(sanitize_sh(&tmpdir(self.build).join(&package_name).join("install.sh"))) .arg(sanitize_sh(&tmpdir(self.build).join(&package_name).join("install.sh")))
.arg(format!("--prefix={}", sanitize_sh(&self.prefix))) .arg(format!("--prefix={}", sanitize_sh(&self.prefix)))
.arg(format!("--sysconfdir={}", sanitize_sh(&self.sysconfdir))) .arg(format!("--sysconfdir={}", sanitize_sh(&self.sysconfdir)))

View file

@ -69,7 +69,7 @@ distcheck:
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
$(Q)$(BOOTSTRAP) test distcheck $(BOOTSTRAP_ARGS) $(Q)$(BOOTSTRAP) test distcheck $(BOOTSTRAP_ARGS)
install: install:
$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) $(Q)$(BOOTSTRAP) install $(BOOTSTRAP_ARGS)
tidy: tidy:
$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
prepare: prepare:

View file

@ -734,6 +734,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
dist::mingw(build, s.target) dist::mingw(build, s.target)
} }
}); });
rules.dist("dist-plain-source-tarball", "src")
.default(build.config.rust_dist_src)
.host(true)
.only_build(true)
.only_host_build(true)
.dep(move |s| tool_rust_installer(build, s))
.run(move |_| dist::plain_source_tarball(build));
rules.dist("dist-src", "src") rules.dist("dist-src", "src")
.default(true) .default(true)
.host(true) .host(true)
@ -759,9 +766,6 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
.dep(|s| s.name("tool-rls")) .dep(|s| s.name("tool-rls"))
.dep(move |s| tool_rust_installer(build, s)) .dep(move |s| tool_rust_installer(build, s))
.run(move |s| dist::rls(build, s.stage, s.target)); .run(move |s| dist::rls(build, s.stage, s.target));
rules.dist("install", "path/to/nowhere")
.dep(|s| s.name("default:dist"))
.run(move |s| install::Installer::new(build).install(s.stage, s.target));
rules.dist("dist-cargo", "cargo") rules.dist("dist-cargo", "cargo")
.host(true) .host(true)
.only_host_build(true) .only_host_build(true)
@ -789,6 +793,47 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
.dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0)) .dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0))
.run(move |_| dist::hash_and_sign(build)); .run(move |_| dist::hash_and_sign(build));
rules.install("install-docs", "src/doc")
.default(build.config.docs)
.only_host_build(true)
.dep(|s| s.name("dist-docs"))
.run(move |s| install::Installer::new(build).install_docs(s.stage, s.target));
rules.install("install-std", "src/libstd")
.default(true)
.only_host_build(true)
.dep(|s| s.name("dist-std"))
.run(move |s| install::Installer::new(build).install_std(s.stage));
rules.install("install-cargo", "cargo")
.default(build.config.extended)
.host(true)
.only_host_build(true)
.dep(|s| s.name("dist-cargo"))
.run(move |s| install::Installer::new(build).install_cargo(s.stage, s.target));
rules.install("install-rls", "rls")
.default(build.config.extended)
.host(true)
.only_host_build(true)
.dep(|s| s.name("dist-rls"))
.run(move |s| install::Installer::new(build).install_rls(s.stage, s.target));
rules.install("install-analysis", "analysis")
.default(build.config.extended)
.only_host_build(true)
.dep(|s| s.name("dist-analysis"))
.run(move |s| install::Installer::new(build).install_analysis(s.stage, s.target));
rules.install("install-src", "src")
.default(build.config.extended)
.host(true)
.only_build(true)
.only_host_build(true)
.dep(|s| s.name("dist-src"))
.run(move |s| install::Installer::new(build).install_src(s.stage));
rules.install("install-rustc", "src/librustc")
.default(true)
.host(true)
.only_host_build(true)
.dep(|s| s.name("dist-rustc"))
.run(move |s| install::Installer::new(build).install_rustc(s.stage, s.target));
rules.verify(); rules.verify();
return rules; return rules;
@ -902,6 +947,7 @@ enum Kind {
Bench, Bench,
Dist, Dist,
Doc, Doc,
Install,
} }
impl<'a> Rule<'a> { impl<'a> Rule<'a> {
@ -1033,6 +1079,12 @@ impl<'a> Rules<'a> {
self.rule(name, path, Kind::Dist) self.rule(name, path, Kind::Dist)
} }
/// Same as `build`, but for `Kind::Install`.
fn install<'b>(&'b mut self, name: &'a str, path: &'a str)
-> RuleBuilder<'a, 'b> {
self.rule(name, path, Kind::Install)
}
fn rule<'b>(&'b mut self, fn rule<'b>(&'b mut self,
name: &'a str, name: &'a str,
path: &'a str, path: &'a str,
@ -1073,6 +1125,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
"test" => Kind::Test, "test" => Kind::Test,
"bench" => Kind::Bench, "bench" => Kind::Bench,
"dist" => Kind::Dist, "dist" => Kind::Dist,
"install" => Kind::Install,
_ => return None, _ => return None,
}; };
let rules = self.rules.values().filter(|r| r.kind == kind); let rules = self.rules.values().filter(|r| r.kind == kind);
@ -1122,13 +1175,8 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]), Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]), Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]),
Subcommand::Dist { ref paths, install } => { Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
if install { Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
return vec![self.sbuild.name("install")]
} else {
(Kind::Dist, &paths[..])
}
}
Subcommand::Clean => panic!(), Subcommand::Clean => panic!(),
}; };