## [Non-breaking changes since the last major version]
+ - Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631)
- Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626)
- Optionally, download LLVM from CI on Linux and NixOS
+ [#76439](https://github.com/rust-lang/rust/pull/76349)
- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625)
- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588)
- Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628)
+- Add `--keep-stage-std`, which behaves like `keep-stage` but allows the stage
+ 0 compiler artifacts (i.e., stage1/bin/rustc) to be rebuilt if changed
+ [#77120](https://github.com/rust-lang/rust/pull/77120).
+
## [Version 0] - 2020-09-11
use std::env;
- use bootstrap::{Build, Config};
+ use bootstrap::{Build, Config, Subcommand};
fn main() {
let args = env::args().skip(1).collect::<Vec<_>>();
let config = Config::parse(&args);
let changelog_suggestion = check_version(&config);
- if let Some(suggestion) = &changelog_suggestion {
+
+ // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
+ // changelog warning, not the `x.py setup` message.
+ let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. });
+ if suggest_setup {
+ println!("warning: you have not made a `config.toml`");
+ println!("help: consider running `x.py setup` or copying `config.toml.example`");
+ } else if let Some(suggestion) = &changelog_suggestion {
println!("{}", suggestion);
}
Build::new(config).build();
- if let Some(suggestion) = changelog_suggestion {
+ if suggest_setup {
+ println!("warning: you have not made a `config.toml`");
+ println!("help: consider running `x.py setup` or copying `config.toml.example`");
+ } else if let Some(suggestion) = &changelog_suggestion {
println!("{}", suggestion);
+ }
+
+ if suggest_setup || changelog_suggestion.is_some() {
println!("note: this message was printed twice to make it more likely to be seen");
}
}
}
} else {
msg.push_str("warning: x.py has made several changes recently you may want to look at\n");
- format!("add `changelog-seen = {}` to `config.toml`", VERSION)
+ format!("add `changelog-seen = {}` at the top of `config.toml`", VERSION)
};
msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n");
pub on_fail: Option<String>,
pub stage: u32,
pub keep_stage: Vec<u32>,
+ pub keep_stage_std: Vec<u32>,
pub src: PathBuf,
+ // defaults to `config.toml`
+ pub config: PathBuf,
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
config.deny_warnings = true;
config.missing_tools = false;
+ config.config = PathBuf::from("config.toml");
// set by bootstrap.py
config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
config.incremental = flags.incremental;
config.dry_run = flags.dry_run;
config.keep_stage = flags.keep_stage;
+ config.keep_stage_std = flags.keep_stage_std;
config.bindir = "bin".into(); // default
if let Some(value) = flags.deny_warnings {
config.deny_warnings = value;
let get_toml = |file: PathBuf| {
use std::process;
- let contents = t!(fs::read_to_string(&file), "configuration file did not exist");
+ let contents = t!(fs::read_to_string(&file), "`include` config not found");
match toml::from_str(&contents) {
Ok(table) => table,
Err(err) => {
| Subcommand::Clippy { .. }
| Subcommand::Fix { .. }
| Subcommand::Run { .. }
+ | Subcommand::Setup { .. }
| Subcommand::Format { .. } => flags.stage.unwrap_or(0),
};
| Subcommand::Clippy { .. }
| Subcommand::Fix { .. }
| Subcommand::Run { .. }
+ | Subcommand::Setup { .. }
| Subcommand::Format { .. } => {}
}
}
use std::path::PathBuf;
use std::process;
+ use build_helper::t;
use getopts::Options;
use crate::builder::Builder;
pub on_fail: Option<String>,
pub stage: Option<u32>,
pub keep_stage: Vec<u32>,
+ pub keep_stage_std: Vec<u32>,
pub host: Option<Vec<TargetSelection>>,
pub target: Option<Vec<TargetSelection>>,
Run {
paths: Vec<PathBuf>,
},
+ Setup {
+ path: String,
+ },
}
impl Default for Subcommand {
(pass multiple times to keep e.g., both stages 0 and 1)",
"N",
);
+ opts.optmulti(
+ "",
+ "keep-stage-std",
+ "stage(s) of the standard library to keep without recompiling \
+ (pass multiple times to keep e.g., both stages 0 and 1)",
+ "N",
+ );
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
let j_msg = format!(
"number of jobs to run in parallel; \
|| (s == "install")
|| (s == "run")
|| (s == "r")
+ || (s == "setup")
});
let subcommand = match subcommand {
Some(s) => s,
At least a tool needs to be called.",
);
}
+ "setup" => {
+ subcommand_help.push_str(
+ "\n
+ Arguments:
+ This subcommand accepts a 'profile' to use for builds. For example:
+
+ ./x.py setup library
+
+ The profile is optional and you will be prompted interactively if it is not given.",
+ );
+ }
_ => {}
};
// Get any optional paths which occur after the subcommand
- let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
+ let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
let verbose = matches.opt_present("verbose");
}
Subcommand::Run { paths }
}
+ "setup" => {
+ let path = if paths.len() > 1 {
+ println!("\nat most one profile can be passed to setup\n");
+ usage(1, &opts, verbose, &subcommand_help)
+ } else if let Some(path) = paths.pop() {
+ t!(path.into_os_string().into_string().map_err(|path| format!(
+ "{} is not a valid UTF8 string",
+ path.to_string_lossy()
+ )))
+ } else {
+ t!(crate::setup::interactive_path())
+ };
+ Subcommand::Setup { path }
+ }
_ => {
usage(1, &opts, verbose, &subcommand_help);
}
println!("--stage not supported for x.py check, always treated as stage 0");
process::exit(1);
}
- if matches.opt_str("keep-stage").is_some() {
+ if matches.opt_str("keep-stage").is_some()
+ || matches.opt_str("keep-stage-std").is_some()
+ {
println!("--keep-stage not supported for x.py check, only one stage available");
process::exit(1);
}
.into_iter()
.map(|j| j.parse().expect("`keep-stage` should be a number"))
.collect(),
+ keep_stage_std: matches
+ .opt_strs("keep-stage-std")
+ .into_iter()
+ .map(|j| j.parse().expect("`keep-stage-std` should be a number"))
+ .collect(),
host: if matches.opt_present("host") {
Some(
split(&matches.opt_strs("host"))