mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 10:13:54 +00:00
Auto merge of #109133 - weihanglo:make-cargo-a-workspace, r=ehuss
Make cargo a workspace 8 commits in 7bf43f028ba5eb1f4d70d271c2546c38512c9875..39116ccc9b420a883a98a960f0597f9cf87414b8 2023-04-10 16:01:41 +0000 to 2023-04-15 20:24:15 +0000 - Make cargo a workspace (rust-lang/cargo#11851) - Fix flaky not_found_permutations test. (rust-lang/cargo#11976) - Use restricted Damerau-Levenshtein algorithm (rust-lang/cargo#11963) - Correct the bug report for `cargo clippy --fix` (rust-lang/cargo#11882) - Stabilize `cargo logout` (rust-lang/cargo#11950) - Add more information to HTTP errors to help with debugging. (rust-lang/cargo#11878) - Use registry.default for login/logout (rust-lang/cargo#11949) - Change -C to be unstable (rust-lang/cargo#11960) --- ### What does this PR try to resolve? Making cargo a workspace. Why doing this? * `rustc-workspace-hack` is primarily for sharing dependencies between rls and cargo, as rls previously depends on cargo. After rls retired, it is no longer the case sharing dependencies. * It's q bit painful that cargo needs to deal with some dependency and licensing complexities. For example, #108665 failed because of the interaction bewteen `windows-sys` and `raw-dylib`. It currenctly blocks cargo's feature `-Zgitxodie` from moving forward. * See rust-lang/cargo#11851 ### Benchmark result I've done a simple benchmark on both keeping or removing entire `rustc-workspace-hack`. It had no significant difference. Both took ~2m30s to finish `./x.py build -j8 src/tools/cargo src/tools/rls src/tools/clippy src/tools/miri src/tools/rustfmt`. Environment info: ``` host: aarch64-apple-darwin os: Mac OS 13.2.1 [64-bit] ``` A sophisticated benchmark may be needed. ### Additional information This depends on prior works from `@Muscraft` and `@ehuss.` Credits to them!
This commit is contained in:
commit
d0f204e4d7
1795
Cargo.lock
1795
Cargo.lock
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
@ -22,12 +22,6 @@ members = [
|
|||||||
"src/tools/remote-test-server",
|
"src/tools/remote-test-server",
|
||||||
"src/tools/rust-installer",
|
"src/tools/rust-installer",
|
||||||
"src/tools/rust-demangler",
|
"src/tools/rust-demangler",
|
||||||
"src/tools/cargo",
|
|
||||||
"src/tools/cargo/crates/credential/cargo-credential-1password",
|
|
||||||
"src/tools/cargo/crates/credential/cargo-credential-macos-keychain",
|
|
||||||
"src/tools/cargo/crates/credential/cargo-credential-wincred",
|
|
||||||
"src/tools/cargo/crates/mdman",
|
|
||||||
# "src/tools/cargo/crates/resolver-tests",
|
|
||||||
"src/tools/rustdoc",
|
"src/tools/rustdoc",
|
||||||
"src/tools/rls",
|
"src/tools/rls",
|
||||||
"src/tools/rustfmt",
|
"src/tools/rustfmt",
|
||||||
@ -106,10 +100,6 @@ miniz_oxide.debug = 0
|
|||||||
object.debug = 0
|
object.debug = 0
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
# See comments in `src/tools/rustc-workspace-hack/README.md` for what's going on
|
|
||||||
# here
|
|
||||||
rustc-workspace-hack = { path = 'src/tools/rustc-workspace-hack' }
|
|
||||||
|
|
||||||
# See comments in `library/rustc-std-workspace-core/README.md` for what's going on
|
# See comments in `library/rustc-std-workspace-core/README.md` for what's going on
|
||||||
# here
|
# here
|
||||||
rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' }
|
rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' }
|
||||||
|
@ -822,7 +822,8 @@ class RustBuild(object):
|
|||||||
if self.use_vendored_sources:
|
if self.use_vendored_sources:
|
||||||
vendor_dir = os.path.join(self.rust_root, 'vendor')
|
vendor_dir = os.path.join(self.rust_root, 'vendor')
|
||||||
if not os.path.exists(vendor_dir):
|
if not os.path.exists(vendor_dir):
|
||||||
sync_dirs = "--sync ./src/tools/rust-analyzer/Cargo.toml " \
|
sync_dirs = "--sync ./src/tools/cargo/Cargo.toml " \
|
||||||
|
"--sync ./src/tools/rust-analyzer/Cargo.toml " \
|
||||||
"--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \
|
"--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \
|
||||||
"--sync ./src/bootstrap/Cargo.toml "
|
"--sync ./src/bootstrap/Cargo.toml "
|
||||||
print('error: vendoring required, but vendor directory does not exist.')
|
print('error: vendoring required, but vendor directory does not exist.')
|
||||||
|
@ -996,11 +996,14 @@ impl Step for PlainSourceTarball {
|
|||||||
// If we're building from git sources, we need to vendor a complete distribution.
|
// If we're building from git sources, we need to vendor a complete distribution.
|
||||||
if builder.rust_info().is_managed_git_subrepository() {
|
if builder.rust_info().is_managed_git_subrepository() {
|
||||||
// Ensure we have the submodules checked out.
|
// Ensure we have the submodules checked out.
|
||||||
|
builder.update_submodule(Path::new("src/tools/cargo"));
|
||||||
builder.update_submodule(Path::new("src/tools/rust-analyzer"));
|
builder.update_submodule(Path::new("src/tools/rust-analyzer"));
|
||||||
|
|
||||||
// Vendor all Cargo dependencies
|
// Vendor all Cargo dependencies
|
||||||
let mut cmd = Command::new(&builder.initial_cargo);
|
let mut cmd = Command::new(&builder.initial_cargo);
|
||||||
cmd.arg("vendor")
|
cmd.arg("vendor")
|
||||||
|
.arg("--sync")
|
||||||
|
.arg(builder.src.join("./src/tools/cargo/Cargo.toml"))
|
||||||
.arg("--sync")
|
.arg("--sync")
|
||||||
.arg(builder.src.join("./src/tools/rust-analyzer/Cargo.toml"))
|
.arg(builder.src.join("./src/tools/rust-analyzer/Cargo.toml"))
|
||||||
.arg("--sync")
|
.arg("--sync")
|
||||||
|
@ -238,8 +238,6 @@ pub struct Build {
|
|||||||
ci_env: CiEnv,
|
ci_env: CiEnv,
|
||||||
delayed_failures: RefCell<Vec<String>>,
|
delayed_failures: RefCell<Vec<String>>,
|
||||||
prerelease_version: Cell<Option<u32>>,
|
prerelease_version: Cell<Option<u32>>,
|
||||||
tool_artifacts:
|
|
||||||
RefCell<HashMap<TargetSelection, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
|
|
||||||
|
|
||||||
#[cfg(feature = "build-metrics")]
|
#[cfg(feature = "build-metrics")]
|
||||||
metrics: metrics::BuildMetrics,
|
metrics: metrics::BuildMetrics,
|
||||||
@ -458,7 +456,6 @@ impl Build {
|
|||||||
ci_env: CiEnv::current(),
|
ci_env: CiEnv::current(),
|
||||||
delayed_failures: RefCell::new(Vec::new()),
|
delayed_failures: RefCell::new(Vec::new()),
|
||||||
prerelease_version: Cell::new(None),
|
prerelease_version: Cell::new(None),
|
||||||
tool_artifacts: Default::default(),
|
|
||||||
|
|
||||||
#[cfg(feature = "build-metrics")]
|
#[cfg(feature = "build-metrics")]
|
||||||
metrics: metrics::BuildMetrics::init(),
|
metrics: metrics::BuildMetrics::init(),
|
||||||
|
@ -7,12 +7,16 @@ use crate::cache::INTERNER;
|
|||||||
use crate::util::output;
|
use crate::util::output;
|
||||||
use crate::{Build, Crate};
|
use crate::{Build, Crate};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
/// For more information, see the output of
|
||||||
|
/// <https://doc.rust-lang.org/nightly/cargo/commands/cargo-metadata.html>
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
struct Output {
|
struct Output {
|
||||||
packages: Vec<Package>,
|
packages: Vec<Package>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
/// For more information, see the output of
|
||||||
|
/// <https://doc.rust-lang.org/nightly/cargo/commands/cargo-metadata.html>
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
struct Package {
|
struct Package {
|
||||||
name: String,
|
name: String,
|
||||||
source: Option<String>,
|
source: Option<String>,
|
||||||
@ -20,25 +24,18 @@ struct Package {
|
|||||||
dependencies: Vec<Dependency>,
|
dependencies: Vec<Dependency>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
/// For more information, see the output of
|
||||||
|
/// <https://doc.rust-lang.org/nightly/cargo/commands/cargo-metadata.html>
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
struct Dependency {
|
struct Dependency {
|
||||||
name: String,
|
name: String,
|
||||||
source: Option<String>,
|
source: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects and stores package metadata of each workspace members into `build`,
|
||||||
|
/// by executing `cargo metadata` commands.
|
||||||
pub fn build(build: &mut Build) {
|
pub fn build(build: &mut Build) {
|
||||||
// Run `cargo metadata` to figure out what crates we're testing.
|
for package in workspace_members(build) {
|
||||||
let mut cargo = Command::new(&build.initial_cargo);
|
|
||||||
cargo
|
|
||||||
.arg("metadata")
|
|
||||||
.arg("--format-version")
|
|
||||||
.arg("1")
|
|
||||||
.arg("--no-deps")
|
|
||||||
.arg("--manifest-path")
|
|
||||||
.arg(build.src.join("Cargo.toml"));
|
|
||||||
let output = output(&mut cargo);
|
|
||||||
let output: Output = serde_json::from_str(&output).unwrap();
|
|
||||||
for package in output.packages {
|
|
||||||
if package.source.is_none() {
|
if package.source.is_none() {
|
||||||
let name = INTERNER.intern_string(package.name);
|
let name = INTERNER.intern_string(package.name);
|
||||||
let mut path = PathBuf::from(package.manifest_path);
|
let mut path = PathBuf::from(package.manifest_path);
|
||||||
@ -57,3 +54,35 @@ pub fn build(build: &mut Build) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes `cargo metadata` to get package metadata of each workspace member.
|
||||||
|
///
|
||||||
|
/// Note that `src/tools/cargo` is no longer a workspace member but we still
|
||||||
|
/// treat it as one here, by invoking an additional `cargo metadata` command.
|
||||||
|
fn workspace_members(build: &Build) -> impl Iterator<Item = Package> {
|
||||||
|
let cmd_metadata = |manifest_path| {
|
||||||
|
let mut cargo = Command::new(&build.initial_cargo);
|
||||||
|
cargo
|
||||||
|
.arg("metadata")
|
||||||
|
.arg("--format-version")
|
||||||
|
.arg("1")
|
||||||
|
.arg("--no-deps")
|
||||||
|
.arg("--manifest-path")
|
||||||
|
.arg(manifest_path);
|
||||||
|
cargo
|
||||||
|
};
|
||||||
|
|
||||||
|
// Collects `metadata.packages` from the root workspace.
|
||||||
|
let root_manifest_path = build.src.join("Cargo.toml");
|
||||||
|
let root_output = output(&mut cmd_metadata(&root_manifest_path));
|
||||||
|
let Output { packages, .. } = serde_json::from_str(&root_output).unwrap();
|
||||||
|
|
||||||
|
// Collects `metadata.packages` from src/tools/cargo separately.
|
||||||
|
let cargo_manifest_path = build.src.join("src/tools/cargo/Cargo.toml");
|
||||||
|
let cargo_output = output(&mut cmd_metadata(&cargo_manifest_path));
|
||||||
|
let Output { packages: cargo_packages, .. } = serde_json::from_str(&cargo_output).unwrap();
|
||||||
|
|
||||||
|
// We only care about the root package from `src/tool/cargo` workspace.
|
||||||
|
let cargo_package = cargo_packages.into_iter().find(|pkg| pkg.name == "cargo").into_iter();
|
||||||
|
packages.into_iter().chain(cargo_package)
|
||||||
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::collections::HashSet;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -120,135 +119,9 @@ impl Step for ToolBuild {
|
|||||||
&self.target,
|
&self.target,
|
||||||
);
|
);
|
||||||
builder.info(&msg);
|
builder.info(&msg);
|
||||||
let mut duplicates = Vec::new();
|
|
||||||
let is_expected = compile::stream_cargo(builder, cargo, vec![], &mut |msg| {
|
|
||||||
// Only care about big things like the RLS/Cargo for now
|
|
||||||
match tool {
|
|
||||||
"rls" | "cargo" | "clippy-driver" | "miri" | "rustfmt" => {}
|
|
||||||
|
|
||||||
_ => return,
|
let mut cargo = Command::from(cargo);
|
||||||
}
|
let is_expected = builder.try_run_quiet(&mut cargo);
|
||||||
let (id, features, filenames) = match msg {
|
|
||||||
compile::CargoMessage::CompilerArtifact {
|
|
||||||
package_id,
|
|
||||||
features,
|
|
||||||
filenames,
|
|
||||||
target: _,
|
|
||||||
} => (package_id, features, filenames),
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
let features = features.iter().map(|s| s.to_string()).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
for path in filenames {
|
|
||||||
let val = (tool, PathBuf::from(&*path), features.clone());
|
|
||||||
// we're only interested in deduplicating rlibs for now
|
|
||||||
if val.1.extension().and_then(|s| s.to_str()) != Some("rlib") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't worry about compiles that turn out to be host
|
|
||||||
// dependencies or build scripts. To skip these we look for
|
|
||||||
// anything that goes in `.../release/deps` but *doesn't* go in
|
|
||||||
// `$target/release/deps`. This ensure that outputs in
|
|
||||||
// `$target/release` are still considered candidates for
|
|
||||||
// deduplication.
|
|
||||||
if let Some(parent) = val.1.parent() {
|
|
||||||
if parent.ends_with("release/deps") {
|
|
||||||
let maybe_target = parent
|
|
||||||
.parent()
|
|
||||||
.and_then(|p| p.parent())
|
|
||||||
.and_then(|p| p.file_name())
|
|
||||||
.and_then(|p| p.to_str())
|
|
||||||
.unwrap();
|
|
||||||
if maybe_target != &*target.triple {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record that we've built an artifact for `id`, and if one was
|
|
||||||
// already listed then we need to see if we reused the same
|
|
||||||
// artifact or produced a duplicate.
|
|
||||||
let mut artifacts = builder.tool_artifacts.borrow_mut();
|
|
||||||
let prev_artifacts = artifacts.entry(target).or_default();
|
|
||||||
let prev = match prev_artifacts.get(&*id) {
|
|
||||||
Some(prev) => prev,
|
|
||||||
None => {
|
|
||||||
prev_artifacts.insert(id.to_string(), val);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if prev.1 == val.1 {
|
|
||||||
return; // same path, same artifact
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the paths are different and one of them *isn't* inside of
|
|
||||||
// `release/deps`, then it means it's probably in
|
|
||||||
// `$target/release`, or it's some final artifact like
|
|
||||||
// `libcargo.rlib`. In these situations Cargo probably just
|
|
||||||
// copied it up from `$target/release/deps/libcargo-xxxx.rlib`,
|
|
||||||
// so if the features are equal we can just skip it.
|
|
||||||
let prev_no_hash = prev.1.parent().unwrap().ends_with("release/deps");
|
|
||||||
let val_no_hash = val.1.parent().unwrap().ends_with("release/deps");
|
|
||||||
if prev.2 == val.2 || !prev_no_hash || !val_no_hash {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... and otherwise this looks like we duplicated some sort of
|
|
||||||
// compilation, so record it to generate an error later.
|
|
||||||
duplicates.push((id.to_string(), val, prev.clone()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if is_expected && !duplicates.is_empty() {
|
|
||||||
eprintln!(
|
|
||||||
"duplicate artifacts found when compiling a tool, this \
|
|
||||||
typically means that something was recompiled because \
|
|
||||||
a transitive dependency has different features activated \
|
|
||||||
than in a previous build:\n"
|
|
||||||
);
|
|
||||||
let (same, different): (Vec<_>, Vec<_>) =
|
|
||||||
duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2);
|
|
||||||
if !same.is_empty() {
|
|
||||||
eprintln!(
|
|
||||||
"the following dependencies are duplicated although they \
|
|
||||||
have the same features enabled:"
|
|
||||||
);
|
|
||||||
for (id, cur, prev) in same {
|
|
||||||
eprintln!(" {}", id);
|
|
||||||
// same features
|
|
||||||
eprintln!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !different.is_empty() {
|
|
||||||
eprintln!("the following dependencies have different features:");
|
|
||||||
for (id, cur, prev) in different {
|
|
||||||
eprintln!(" {}", id);
|
|
||||||
let cur_features: HashSet<_> = cur.2.into_iter().collect();
|
|
||||||
let prev_features: HashSet<_> = prev.2.into_iter().collect();
|
|
||||||
eprintln!(
|
|
||||||
" `{}` additionally enabled features {:?} at {:?}",
|
|
||||||
cur.0,
|
|
||||||
&cur_features - &prev_features,
|
|
||||||
cur.1
|
|
||||||
);
|
|
||||||
eprintln!(
|
|
||||||
" `{}` additionally enabled features {:?} at {:?}",
|
|
||||||
prev.0,
|
|
||||||
&prev_features - &cur_features,
|
|
||||||
prev.1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eprintln!();
|
|
||||||
eprintln!(
|
|
||||||
"to fix this you will probably want to edit the local \
|
|
||||||
src/tools/rustc-workspace-hack/Cargo.toml crate, as \
|
|
||||||
that will update the dependency graph to ensure that \
|
|
||||||
these crates all share the same feature set"
|
|
||||||
);
|
|
||||||
panic!("tools should not compile multiple copies of the same crate");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.save_toolstate(
|
builder.save_toolstate(
|
||||||
tool,
|
tool,
|
||||||
@ -299,7 +172,9 @@ pub fn prepare_tool_cargo(
|
|||||||
|| path.ends_with("rustfmt")
|
|| path.ends_with("rustfmt")
|
||||||
{
|
{
|
||||||
cargo.env("LIBZ_SYS_STATIC", "1");
|
cargo.env("LIBZ_SYS_STATIC", "1");
|
||||||
features.push("rustc-workspace-hack/all-static".to_string());
|
}
|
||||||
|
if path.ends_with("cargo") {
|
||||||
|
features.push("all-static".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 84b7041fd2745ee6b3b4a150314f81aabb78e6b2
|
Subproject commit d0a4cbcee614fdb7ba66e860e603a00a644d71f8
|
@ -7,7 +7,3 @@ license = "Apache-2.0/MIT"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.143", features = ["derive"] }
|
serde = { version = "1.0.143", features = ["derive"] }
|
||||||
serde_json = "1.0.83"
|
serde_json = "1.0.83"
|
||||||
# A noop dependency that changes in the Rust repository, it's a bit of a hack.
|
|
||||||
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
|
|
||||||
# for more information.
|
|
||||||
rustc-workspace-hack = "1.0.0"
|
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "rustc-workspace-hack"
|
|
||||||
version = "1.0.0"
|
|
||||||
license = 'MIT OR Apache-2.0'
|
|
||||||
description = """
|
|
||||||
Hack for the compiler's own build system
|
|
||||||
"""
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "lib.rs"
|
|
||||||
|
|
||||||
# For documentation about what this is and why in the world these dependencies
|
|
||||||
# are appearing, see `README.md`.
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies.winapi]
|
|
||||||
version = "0.3"
|
|
||||||
features = [
|
|
||||||
"accctrl",
|
|
||||||
"aclapi",
|
|
||||||
"basetsd",
|
|
||||||
"cfg",
|
|
||||||
"consoleapi",
|
|
||||||
"errhandlingapi",
|
|
||||||
"evntrace",
|
|
||||||
"fibersapi",
|
|
||||||
"handleapi",
|
|
||||||
"in6addr",
|
|
||||||
"inaddr",
|
|
||||||
"ioapiset",
|
|
||||||
"jobapi",
|
|
||||||
"jobapi2",
|
|
||||||
"knownfolders",
|
|
||||||
"libloaderapi",
|
|
||||||
"lmcons",
|
|
||||||
"memoryapi",
|
|
||||||
"minschannel",
|
|
||||||
"minwinbase",
|
|
||||||
"mstcpip",
|
|
||||||
"mswsock",
|
|
||||||
"namedpipeapi",
|
|
||||||
"ntdef",
|
|
||||||
"ntsecapi",
|
|
||||||
"ntstatus",
|
|
||||||
"objbase",
|
|
||||||
"processenv",
|
|
||||||
"processthreadsapi",
|
|
||||||
"profileapi",
|
|
||||||
"psapi",
|
|
||||||
"schannel",
|
|
||||||
"securitybaseapi",
|
|
||||||
"shellapi",
|
|
||||||
"shlobj",
|
|
||||||
"sspi",
|
|
||||||
"synchapi",
|
|
||||||
"sysinfoapi",
|
|
||||||
"threadpoollegacyapiset",
|
|
||||||
"timezoneapi",
|
|
||||||
"userenv",
|
|
||||||
"winbase",
|
|
||||||
"wincon",
|
|
||||||
"wincrypt",
|
|
||||||
"windef",
|
|
||||||
"winioctl",
|
|
||||||
"winnt",
|
|
||||||
"winreg",
|
|
||||||
"winsock2",
|
|
||||||
"winuser",
|
|
||||||
"ws2def",
|
|
||||||
"ws2ipdef",
|
|
||||||
"ws2tcpip",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bstr = { version = "0.2.17", features = ["default"] }
|
|
||||||
clap = { version = "3.1.1", features = ["derive", "clap_derive"]}
|
|
||||||
curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
|
|
||||||
# Ensure `extra_traits` of libc, which is used transitively by Cargo.
|
|
||||||
libc = { version = "0.2", features = ["extra_traits"] }
|
|
||||||
# Ensure `js` of getrandom, which is (unfortunately) used transitively by Cargo.
|
|
||||||
getrandom = { version = "0.2", features = ["js"] }
|
|
||||||
# Ensure default features of libz-sys, which are disabled in some scenarios.
|
|
||||||
libz-sys = { version = "1.1.2" }
|
|
||||||
# Ensure default features of regex, which are disabled in some scenarios.
|
|
||||||
regex = { version = "1.5.6" }
|
|
||||||
serde_json = { version = "1.0.31", features = ["raw_value", "unbounded_depth"] }
|
|
||||||
syn = { version = "1", features = ['full', 'visit', 'visit-mut'] } # `visit-mut` required by Cargo via `gix`
|
|
||||||
url = { version = "2.0", features = ['serde'] }
|
|
||||||
# Ensure default features of rand, which are disabled in some scenarios.
|
|
||||||
rand = { version = "0.8.5" }
|
|
||||||
|
|
||||||
# Ensure features of `hashbrown`, `smallvec`, and `once_cell`,
|
|
||||||
# which are used transitively by Cargo (via `gix`).
|
|
||||||
hashbrown = { version = "0.12.3", default-features = false, features = ["inline-more"] }
|
|
||||||
once_cell = { version = "1.16.0", default-features = false, features = ["unstable"] }
|
|
||||||
smallvec = { version = "1.10.0", features = ["write"] }
|
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
|
||||||
openssl = { version = "0.10.35", optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
all-static = ['openssl/vendored', 'curl-sys/static-curl', 'curl-sys/force-system-lib-on-osx']
|
|
@ -1,25 +0,0 @@
|
|||||||
# `rustc-workspace-hack`
|
|
||||||
|
|
||||||
This crate is a bit of a hack to make workspaces in rustc work a bit better.
|
|
||||||
The rationale for this existence is a bit subtle, but the general idea is that
|
|
||||||
we want commands like `./x.py build src/tools/{clippy,cargo}` to share as
|
|
||||||
many dependencies as possible.
|
|
||||||
|
|
||||||
Each invocation is a different invocation of Cargo, however. Each time Cargo
|
|
||||||
runs a build it will re-resolve the dependency graph, notably selecting
|
|
||||||
different features sometimes for each build.
|
|
||||||
|
|
||||||
For example, let's say there's a very deep dependency like `winapi` in each of
|
|
||||||
these builds. For Cargo, `winapi` has 33 features enabled. In Clippy, however,
|
|
||||||
`winapi` has 22 features enabled. This means that building Cargo and then the
|
|
||||||
Clippy will actually build winapi twice, which in turn will build duplicates
|
|
||||||
of everything that depends on `winapi`. This is bad!
|
|
||||||
|
|
||||||
The goal of this crate is to solve this problem and ensure that the resolved
|
|
||||||
dependency graph for all of these tools is the same in the various subsets of
|
|
||||||
each tool, notably enabling the same features of transitive dependencies.
|
|
||||||
|
|
||||||
All tools vendored here depend on the `rustc-workspace-hack` crate on crates.io.
|
|
||||||
When on crates.io this crate is an empty crate that is just a noop. We override
|
|
||||||
it, however, in this workspace to this crate here, which means we can control
|
|
||||||
crates in the dependency graph for each of these tools.
|
|
@ -1 +0,0 @@
|
|||||||
// intentionally left blank
|
|
@ -18,6 +18,7 @@ const LICENSES: &[&str] = &[
|
|||||||
"ISC",
|
"ISC",
|
||||||
"Unlicense/MIT",
|
"Unlicense/MIT",
|
||||||
"Unlicense OR MIT",
|
"Unlicense OR MIT",
|
||||||
|
"0BSD",
|
||||||
"0BSD OR MIT OR Apache-2.0", // adler license
|
"0BSD OR MIT OR Apache-2.0", // adler license
|
||||||
"Zlib OR Apache-2.0 OR MIT", // tinyvec
|
"Zlib OR Apache-2.0 OR MIT", // tinyvec
|
||||||
"MIT OR Apache-2.0 OR Zlib", // tinyvec_macros
|
"MIT OR Apache-2.0 OR Zlib", // tinyvec_macros
|
||||||
@ -33,30 +34,35 @@ const LICENSES: &[&str] = &[
|
|||||||
const EXCEPTIONS: &[(&str, &str)] = &[
|
const EXCEPTIONS: &[(&str, &str)] = &[
|
||||||
("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
|
("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
|
||||||
("mdbook", "MPL-2.0"), // mdbook
|
("mdbook", "MPL-2.0"), // mdbook
|
||||||
("openssl", "Apache-2.0"), // cargo, mdbook
|
|
||||||
("colored", "MPL-2.0"), // rustfmt
|
("colored", "MPL-2.0"), // rustfmt
|
||||||
("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde)
|
("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde)
|
||||||
("bytesize", "Apache-2.0"), // cargo
|
|
||||||
("im-rc", "MPL-2.0+"), // cargo
|
|
||||||
("sized-chunks", "MPL-2.0+"), // cargo via im-rc
|
|
||||||
("bitmaps", "MPL-2.0+"), // cargo via im-rc
|
|
||||||
("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), // cargo via pasetors
|
|
||||||
("subtle", "BSD-3-Clause"), // cargo via pasetors
|
|
||||||
("dunce", "CC0-1.0 OR MIT-0"), // cargo via gix (and dev dependency)
|
|
||||||
("imara-diff", "Apache-2.0"), // cargo via gix
|
|
||||||
("sha1_smol", "BSD-3-Clause"), // cargo via gix
|
|
||||||
("unicode-bom", "Apache-2.0"), // cargo via gix
|
|
||||||
("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
|
("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
|
||||||
("snap", "BSD-3-Clause"), // rustc
|
("snap", "BSD-3-Clause"), // rustc
|
||||||
("fluent-langneg", "Apache-2.0"), // rustc (fluent translations)
|
("fluent-langneg", "Apache-2.0"), // rustc (fluent translations)
|
||||||
("self_cell", "Apache-2.0"), // rustc (fluent translations)
|
("self_cell", "Apache-2.0"), // rustc (fluent translations)
|
||||||
// FIXME: this dependency violates the documentation comment above:
|
// FIXME: this dependency violates the documentation comment above:
|
||||||
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
|
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
|
||||||
("similar", "Apache-2.0"), // cargo (dev dependency)
|
|
||||||
("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency)
|
|
||||||
("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
|
("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const EXCEPTIONS_CARGO: &[(&str, &str)] = &[
|
||||||
|
("bitmaps", "MPL-2.0+"),
|
||||||
|
("bytesize", "Apache-2.0"),
|
||||||
|
("dunce", "CC0-1.0 OR MIT-0"),
|
||||||
|
("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"),
|
||||||
|
("im-rc", "MPL-2.0+"),
|
||||||
|
("imara-diff", "Apache-2.0"),
|
||||||
|
("instant", "BSD-3-Clause"),
|
||||||
|
("normalize-line-endings", "Apache-2.0"),
|
||||||
|
("openssl", "Apache-2.0"),
|
||||||
|
("ryu", "Apache-2.0 OR BSL-1.0"),
|
||||||
|
("sha1_smol", "BSD-3-Clause"),
|
||||||
|
("similar", "Apache-2.0"),
|
||||||
|
("sized-chunks", "MPL-2.0+"),
|
||||||
|
("subtle", "BSD-3-Clause"),
|
||||||
|
("unicode-bom", "Apache-2.0"),
|
||||||
|
];
|
||||||
|
|
||||||
const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
|
const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
|
||||||
("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
|
("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
|
||||||
("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
|
("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
|
||||||
@ -156,7 +162,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading",
|
"libloading",
|
||||||
"libz-sys",
|
|
||||||
"litemap",
|
"litemap",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"log",
|
"log",
|
||||||
@ -177,7 +182,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||||||
"perf-event-open-sys",
|
"perf-event-open-sys",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pkg-config",
|
|
||||||
"polonius-engine",
|
"polonius-engine",
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
@ -217,7 +221,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
"stacker",
|
"stacker",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"subtle", // dependency of cargo (via pasetors)
|
|
||||||
"syn",
|
"syn",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
@ -256,7 +259,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||||||
"unicode-security",
|
"unicode-security",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
"vcpkg",
|
|
||||||
"valuable",
|
"valuable",
|
||||||
"version_check",
|
"version_check",
|
||||||
"wasi",
|
"wasi",
|
||||||
@ -333,13 +335,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
|
|||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc",
|
||||||
];
|
];
|
||||||
|
|
||||||
const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
|
|
||||||
// This crate takes quite a long time to build, so don't allow two versions of them
|
|
||||||
// to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
|
|
||||||
// under control.
|
|
||||||
"cargo",
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Dependency checks.
|
/// Dependency checks.
|
||||||
///
|
///
|
||||||
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
|
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
|
||||||
@ -359,8 +354,16 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
|
|||||||
&["rustc_driver", "rustc_codegen_llvm"],
|
&["rustc_driver", "rustc_codegen_llvm"],
|
||||||
bad,
|
bad,
|
||||||
);
|
);
|
||||||
check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad);
|
|
||||||
check_rustfix(&metadata, bad);
|
// Check cargo independently as it has it's own workspace.
|
||||||
|
let mut cmd = cargo_metadata::MetadataCommand::new();
|
||||||
|
cmd.cargo_path(cargo)
|
||||||
|
.manifest_path(root.join("src/tools/cargo/Cargo.toml"))
|
||||||
|
.features(cargo_metadata::CargoOpt::AllFeatures);
|
||||||
|
let cargo_metadata = t!(cmd.exec());
|
||||||
|
let runtime_ids = HashSet::new();
|
||||||
|
check_license_exceptions(&cargo_metadata, EXCEPTIONS_CARGO, runtime_ids, bad);
|
||||||
|
check_rustfix(&metadata, &cargo_metadata, bad);
|
||||||
|
|
||||||
// Check rustc_codegen_cranelift independently as it has it's own workspace.
|
// Check rustc_codegen_cranelift independently as it has it's own workspace.
|
||||||
let mut cmd = cargo_metadata::MetadataCommand::new();
|
let mut cmd = cargo_metadata::MetadataCommand::new();
|
||||||
@ -377,7 +380,6 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
|
|||||||
&["rustc_codegen_cranelift"],
|
&["rustc_codegen_cranelift"],
|
||||||
bad,
|
bad,
|
||||||
);
|
);
|
||||||
check_crate_duplicate(&metadata, &[], bad);
|
|
||||||
|
|
||||||
let mut cmd = cargo_metadata::MetadataCommand::new();
|
let mut cmd = cargo_metadata::MetadataCommand::new();
|
||||||
cmd.cargo_path(cargo)
|
cmd.cargo_path(cargo)
|
||||||
@ -523,40 +525,6 @@ fn check_permitted_dependencies(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prevents multiple versions of some expensive crates.
|
|
||||||
fn check_crate_duplicate(
|
|
||||||
metadata: &Metadata,
|
|
||||||
forbidden_to_have_duplicates: &[&str],
|
|
||||||
bad: &mut bool,
|
|
||||||
) {
|
|
||||||
for &name in forbidden_to_have_duplicates {
|
|
||||||
let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
|
|
||||||
match matches.len() {
|
|
||||||
0 => {
|
|
||||||
tidy_error!(
|
|
||||||
bad,
|
|
||||||
"crate `{}` is missing, update `check_crate_duplicate` \
|
|
||||||
if it is no longer used",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
1 => {}
|
|
||||||
_ => {
|
|
||||||
tidy_error!(
|
|
||||||
bad,
|
|
||||||
"crate `{}` is duplicated in `Cargo.lock`, \
|
|
||||||
it is too expensive to build multiple times, \
|
|
||||||
so make sure only one version appears across all dependencies",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
for pkg in matches {
|
|
||||||
println!(" * {}", pkg.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds a package with the given name.
|
/// Finds a package with the given name.
|
||||||
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
|
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
|
||||||
let mut i = metadata.packages.iter().filter(|p| p.name == name);
|
let mut i = metadata.packages.iter().filter(|p| p.name == name);
|
||||||
@ -606,19 +574,24 @@ fn deps_of_filtered<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
|
fn direct_deps_of<'a>(
|
||||||
|
metadata: &'a Metadata,
|
||||||
|
pkg_id: &'a PackageId,
|
||||||
|
) -> impl Iterator<Item = &'a Package> {
|
||||||
let resolve = metadata.resolve.as_ref().unwrap();
|
let resolve = metadata.resolve.as_ref().unwrap();
|
||||||
let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap();
|
let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap();
|
||||||
node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect()
|
node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_rustfix(metadata: &Metadata, bad: &mut bool) {
|
fn check_rustfix(rust_metadata: &Metadata, cargo_metadata: &Metadata, bad: &mut bool) {
|
||||||
let cargo = pkg_from_name(metadata, "cargo");
|
let cargo = pkg_from_name(cargo_metadata, "cargo");
|
||||||
let compiletest = pkg_from_name(metadata, "compiletest");
|
let cargo_rustfix =
|
||||||
let cargo_deps = direct_deps_of(metadata, &cargo.id);
|
direct_deps_of(cargo_metadata, &cargo.id).find(|p| p.name == "rustfix").unwrap();
|
||||||
let compiletest_deps = direct_deps_of(metadata, &compiletest.id);
|
|
||||||
let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap();
|
let compiletest = pkg_from_name(rust_metadata, "compiletest");
|
||||||
let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap();
|
let compiletest_rustfix =
|
||||||
|
direct_deps_of(rust_metadata, &compiletest.id).find(|p| p.name == "rustfix").unwrap();
|
||||||
|
|
||||||
if cargo_rustfix.version != compiletest_rustfix.version {
|
if cargo_rustfix.version != compiletest_rustfix.version {
|
||||||
tidy_error!(
|
tidy_error!(
|
||||||
bad,
|
bad,
|
||||||
|
Loading…
Reference in New Issue
Block a user