提交 477cae3b 编写于 作者: J Joshua Nelson 提交者: Mark Rousskov

copy over `std::path::absolute` instead of adding `canonicalize` hacks

this also fixes a bug where bootstrap would try to use the fake `rustc` binary built by bootstrap -
cargo puts it in a different directory when using `cargo run` instead of x.py
上级 984527f7
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
fn main() { fn main() {
let args = env::args().skip(1).collect::<Vec<_>>(); let args = env::args().skip(1).collect::<Vec<_>>();
let config = Config::parse(&args, false); let config = Config::parse(&args);
// check_version warnings are not printed during setup // check_version warnings are not printed during setup
let changelog_suggestion = let changelog_suggestion =
......
...@@ -883,7 +883,7 @@ pub fn rustdoc(&self, compiler: Compiler) -> PathBuf { ...@@ -883,7 +883,7 @@ pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
} }
pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command { pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); let mut cmd = Command::new(&self.bootstrap_out.join("rustdoc"));
cmd.env("RUSTC_STAGE", compiler.stage.to_string()) cmd.env("RUSTC_STAGE", compiler.stage.to_string())
.env("RUSTC_SYSROOT", self.sysroot(compiler)) .env("RUSTC_SYSROOT", self.sysroot(compiler))
// Note that this is *not* the sysroot_libdir because rustdoc must be linked // Note that this is *not* the sysroot_libdir because rustdoc must be linked
...@@ -1249,7 +1249,7 @@ pub fn cargo( ...@@ -1249,7 +1249,7 @@ pub fn cargo(
.env("RUSTC_STAGE", stage.to_string()) .env("RUSTC_STAGE", stage.to_string())
.env("RUSTC_SYSROOT", &sysroot) .env("RUSTC_SYSROOT", &sysroot)
.env("RUSTC_LIBDIR", &libdir) .env("RUSTC_LIBDIR", &libdir)
.env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
.env( .env(
"RUSTDOC_REAL", "RUSTDOC_REAL",
if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) { if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
...@@ -1263,7 +1263,7 @@ pub fn cargo( ...@@ -1263,7 +1263,7 @@ pub fn cargo(
// Clippy support is a hack and uses the default `cargo-clippy` in path. // Clippy support is a hack and uses the default `cargo-clippy` in path.
// Don't override RUSTC so that the `cargo-clippy` in path will be run. // Don't override RUSTC so that the `cargo-clippy` in path will be run.
if cmd != "clippy" { if cmd != "clippy" {
cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc")); cargo.env("RUSTC", self.bootstrap_out.join("rustc"));
} }
// Dealing with rpath here is a little special, so let's go into some // Dealing with rpath here is a little special, so let's go into some
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
use std::thread; use std::thread;
fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
let mut config = Config::parse(&[cmd.to_owned()], true); let mut config = Config::parse(&[cmd.to_owned()]);
// don't save toolstates // don't save toolstates
config.save_toolstates = None; config.save_toolstates = None;
config.dry_run = true; config.dry_run = true;
......
...@@ -619,7 +619,7 @@ pub fn default_opts() -> Config { ...@@ -619,7 +619,7 @@ pub fn default_opts() -> Config {
config config
} }
pub fn parse(args: &[String], unit_test: bool) -> Config { pub fn parse(args: &[String]) -> Config {
let flags = Flags::parse(&args); let flags = Flags::parse(&args);
let mut config = Config::default_opts(); let mut config = Config::default_opts();
...@@ -681,26 +681,13 @@ pub fn parse(args: &[String], unit_test: bool) -> Config { ...@@ -681,26 +681,13 @@ pub fn parse(args: &[String], unit_test: bool) -> Config {
let build = toml.build.unwrap_or_default(); let build = toml.build.unwrap_or_default();
set(&mut config.out, build.build_dir.map(String::into)); set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
set(&mut config.out, build.build_dir.map(PathBuf::from));
// NOTE: Bootstrap spawns various commands with different working directories. // NOTE: Bootstrap spawns various commands with different working directories.
// To avoid writing to random places on the file system, `config.out` needs to be an absolute path. // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
if !config.out.is_absolute() {
// FIXME: using `canonicalize()` makes this a lot more complicated than it needs to be - // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead.
// if/when `std::path::absolute` lands, we should use that instead. config.out = crate::util::absolute(&config.out);
// HACK: in tests, we override the build directory manually.
// Avoid creating a directory we won't actually need.
// (The original motivation for this is that CI uses read-only directories.)
if !config.out.is_absolute() && !unit_test {
// canonicalize() gives a hard error if the directory doesn't exist
t!(
fs::create_dir_all(&config.out),
format!("failed to create build dir: {}", config.out.display())
);
config.out = t!(
config.out.canonicalize(),
format!("failed to canonicalize {}", config.out.display())
);
} }
if config.dry_run { if config.dry_run {
......
...@@ -343,7 +343,7 @@ pub fn parse(args: &[String]) -> Flags { ...@@ -343,7 +343,7 @@ pub fn parse(args: &[String]) -> Flags {
// All subcommands except `clean` can have an optional "Available paths" section // All subcommands except `clean` can have an optional "Available paths" section
if verbose { if verbose {
let config = Config::parse(&["build".to_string()], false); let config = Config::parse(&["build".to_string()]);
let build = Build::new(config); let build = Build::new(config);
let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
......
...@@ -261,6 +261,7 @@ pub struct Build { ...@@ -261,6 +261,7 @@ pub struct Build {
// Properties derived from the above configuration // Properties derived from the above configuration
src: PathBuf, src: PathBuf,
out: PathBuf, out: PathBuf,
bootstrap_out: PathBuf,
rust_info: channel::GitInfo, rust_info: channel::GitInfo,
cargo_info: channel::GitInfo, cargo_info: channel::GitInfo,
rls_info: channel::GitInfo, rls_info: channel::GitInfo,
...@@ -435,6 +436,20 @@ pub fn new(config: Config) -> Build { ...@@ -435,6 +436,20 @@ pub fn new(config: Config) -> Build {
.expect("failed to read src/version"); .expect("failed to read src/version");
let version = version.trim(); let version = version.trim();
let bootstrap_out = if std::env::var("BOOTSTRAP_PYTHON").is_ok() {
out.join("bootstrap").join("debug")
} else {
let workspace_target_dir = std::env::var("CARGO_TARGET_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| src.join("target"));
let bootstrap_out = workspace_target_dir.join("debug");
if !bootstrap_out.join("rustc").exists() {
// this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
panic!("run `cargo build --bins` before `cargo run`")
}
bootstrap_out
};
let mut build = Build { let mut build = Build {
initial_rustc: config.initial_rustc.clone(), initial_rustc: config.initial_rustc.clone(),
initial_cargo: config.initial_cargo.clone(), initial_cargo: config.initial_cargo.clone(),
...@@ -453,6 +468,7 @@ pub fn new(config: Config) -> Build { ...@@ -453,6 +468,7 @@ pub fn new(config: Config) -> Build {
version: version.to_string(), version: version.to_string(),
src, src,
out, out,
bootstrap_out,
rust_info, rust_info,
cargo_info, cargo_info,
......
...@@ -730,7 +730,7 @@ fn make_run(run: RunConfig<'_>) { ...@@ -730,7 +730,7 @@ fn make_run(run: RunConfig<'_>) {
} }
fn run(self, builder: &Builder<'_>) { fn run(self, builder: &Builder<'_>) {
let rustdoc = builder.out.join("bootstrap/debug/rustdoc"); let rustdoc = builder.bootstrap_out.join("rustdoc");
let mut cmd = builder.tool_cmd(Tool::RustdocTheme); let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
cmd.arg(rustdoc.to_str().unwrap()) cmd.arg(rustdoc.to_str().unwrap())
.arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap()) .arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
......
...@@ -440,3 +440,112 @@ fn fail(s: &str) -> ! { ...@@ -440,3 +440,112 @@ fn fail(s: &str) -> ! {
println!("\n\n{}\n\n", s); println!("\n\n{}\n\n", s);
std::process::exit(1); std::process::exit(1);
} }
/// Copied from `std::path::absolute` until it stabilizes.
///
/// FIXME: this shouldn't exist.
pub(crate) fn absolute(path: &Path) -> PathBuf {
if path.as_os_str().is_empty() {
panic!("can't make empty path absolute");
}
#[cfg(unix)]
{
t!(absolute_unix(path), format!("could not make path absolute: {}", path.display()))
}
#[cfg(windows)]
{
t!(absolute_windows(path), format!("could not make path absolute: {}", path.display()))
}
#[cfg(not(any(unix, windows)))]
{
println!("warning: bootstrap is not supported on non-unix platforms");
t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path)
}
}
#[cfg(unix)]
/// Make a POSIX path absolute without changing its semantics.
fn absolute_unix(path: &Path) -> io::Result<PathBuf> {
// This is mostly a wrapper around collecting `Path::components`, with
// exceptions made where this conflicts with the POSIX specification.
// See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
use std::os::unix::prelude::OsStrExt;
let mut components = path.components();
let path_os = path.as_os_str().as_bytes();
let mut normalized = if path.is_absolute() {
// "If a pathname begins with two successive <slash> characters, the
// first component following the leading <slash> characters may be
// interpreted in an implementation-defined manner, although more than
// two leading <slash> characters shall be treated as a single <slash>
// character."
if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
components.next();
PathBuf::from("//")
} else {
PathBuf::new()
}
} else {
env::current_dir()?
};
normalized.extend(components);
// "Interfaces using pathname resolution may specify additional constraints
// when a pathname that does not name an existing directory contains at
// least one non- <slash> character and contains one or more trailing
// <slash> characters".
// A trailing <slash> is also meaningful if "a symbolic link is
// encountered during pathname resolution".
if path_os.ends_with(b"/") {
normalized.push("");
}
Ok(normalized)
}
#[cfg(windows)]
fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBuf> {
use std::ffi::OsString;
use std::io::Error;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::ptr::null_mut;
#[link(name = "kernel32")]
extern "system" {
fn GetFullPathNameW(
lpFileName: *const u16,
nBufferLength: u32,
lpBuffer: *mut u16,
lpFilePart: *mut *const u16,
) -> u32;
}
unsafe {
// encode the path as UTF-16
let path: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
let mut buffer = Vec::new();
// Loop until either success or failure.
loop {
// Try to get the absolute path
let len = GetFullPathNameW(
path.as_ptr(),
buffer.len().try_into().unwrap(),
buffer.as_mut_ptr(),
null_mut(),
);
match len as usize {
// Failure
0 => return Err(Error::last_os_error()),
// Buffer is too small, resize.
len if len > buffer.len() => buffer.resize(len, 0),
// Success!
len => {
buffer.truncate(len);
return Ok(OsString::from_wide(&buffer).into());
}
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册