mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +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/rust-installer",
|
||||
"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/rls",
|
||||
"src/tools/rustfmt",
|
||||
@ -106,10 +100,6 @@ miniz_oxide.debug = 0
|
||||
object.debug = 0
|
||||
|
||||
[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
|
||||
# here
|
||||
rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' }
|
||||
|
@ -822,7 +822,8 @@ class RustBuild(object):
|
||||
if self.use_vendored_sources:
|
||||
vendor_dir = os.path.join(self.rust_root, 'vendor')
|
||||
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 ./src/bootstrap/Cargo.toml "
|
||||
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 builder.rust_info().is_managed_git_subrepository() {
|
||||
// Ensure we have the submodules checked out.
|
||||
builder.update_submodule(Path::new("src/tools/cargo"));
|
||||
builder.update_submodule(Path::new("src/tools/rust-analyzer"));
|
||||
|
||||
// Vendor all Cargo dependencies
|
||||
let mut cmd = Command::new(&builder.initial_cargo);
|
||||
cmd.arg("vendor")
|
||||
.arg("--sync")
|
||||
.arg(builder.src.join("./src/tools/cargo/Cargo.toml"))
|
||||
.arg("--sync")
|
||||
.arg(builder.src.join("./src/tools/rust-analyzer/Cargo.toml"))
|
||||
.arg("--sync")
|
||||
|
@ -238,8 +238,6 @@ pub struct Build {
|
||||
ci_env: CiEnv,
|
||||
delayed_failures: RefCell<Vec<String>>,
|
||||
prerelease_version: Cell<Option<u32>>,
|
||||
tool_artifacts:
|
||||
RefCell<HashMap<TargetSelection, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
|
||||
|
||||
#[cfg(feature = "build-metrics")]
|
||||
metrics: metrics::BuildMetrics,
|
||||
@ -458,7 +456,6 @@ impl Build {
|
||||
ci_env: CiEnv::current(),
|
||||
delayed_failures: RefCell::new(Vec::new()),
|
||||
prerelease_version: Cell::new(None),
|
||||
tool_artifacts: Default::default(),
|
||||
|
||||
#[cfg(feature = "build-metrics")]
|
||||
metrics: metrics::BuildMetrics::init(),
|
||||
|
@ -7,12 +7,16 @@ use crate::cache::INTERNER;
|
||||
use crate::util::output;
|
||||
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 {
|
||||
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 {
|
||||
name: String,
|
||||
source: Option<String>,
|
||||
@ -20,25 +24,18 @@ struct Package {
|
||||
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 {
|
||||
name: 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) {
|
||||
// Run `cargo metadata` to figure out what crates we're testing.
|
||||
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 {
|
||||
for package in workspace_members(build) {
|
||||
if package.source.is_none() {
|
||||
let name = INTERNER.intern_string(package.name);
|
||||
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::fs;
|
||||
use std::path::PathBuf;
|
||||
@ -120,135 +119,9 @@ impl Step for ToolBuild {
|
||||
&self.target,
|
||||
);
|
||||
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 (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");
|
||||
}
|
||||
let mut cargo = Command::from(cargo);
|
||||
let is_expected = builder.try_run_quiet(&mut cargo);
|
||||
|
||||
builder.save_toolstate(
|
||||
tool,
|
||||
@ -299,7 +172,9 @@ pub fn prepare_tool_cargo(
|
||||
|| path.ends_with("rustfmt")
|
||||
{
|
||||
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]
|
||||
serde = { version = "1.0.143", features = ["derive"] }
|
||||
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",
|
||||
"Unlicense/MIT",
|
||||
"Unlicense OR MIT",
|
||||
"0BSD",
|
||||
"0BSD OR MIT OR Apache-2.0", // adler license
|
||||
"Zlib OR Apache-2.0 OR MIT", // tinyvec
|
||||
"MIT OR Apache-2.0 OR Zlib", // tinyvec_macros
|
||||
@ -33,30 +34,35 @@ const LICENSES: &[&str] = &[
|
||||
const EXCEPTIONS: &[(&str, &str)] = &[
|
||||
("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
|
||||
("mdbook", "MPL-2.0"), // mdbook
|
||||
("openssl", "Apache-2.0"), // cargo, mdbook
|
||||
("colored", "MPL-2.0"), // rustfmt
|
||||
("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
|
||||
("snap", "BSD-3-Clause"), // rustc
|
||||
("fluent-langneg", "Apache-2.0"), // rustc (fluent translations)
|
||||
("self_cell", "Apache-2.0"), // rustc (fluent translations)
|
||||
// FIXME: this dependency violates the documentation comment above:
|
||||
("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)
|
||||
];
|
||||
|
||||
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)] = &[
|
||||
("cranelift-bforest", "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",
|
||||
"libc",
|
||||
"libloading",
|
||||
"libz-sys",
|
||||
"litemap",
|
||||
"lock_api",
|
||||
"log",
|
||||
@ -177,7 +182,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"perf-event-open-sys",
|
||||
"petgraph",
|
||||
"pin-project-lite",
|
||||
"pkg-config",
|
||||
"polonius-engine",
|
||||
"ppv-lite86",
|
||||
"proc-macro-hack",
|
||||
@ -217,7 +221,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"stable_deref_trait",
|
||||
"stacker",
|
||||
"static_assertions",
|
||||
"subtle", // dependency of cargo (via pasetors)
|
||||
"syn",
|
||||
"synstructure",
|
||||
"tempfile",
|
||||
@ -256,7 +259,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"unicode-security",
|
||||
"unicode-width",
|
||||
"unicode-xid",
|
||||
"vcpkg",
|
||||
"valuable",
|
||||
"version_check",
|
||||
"wasi",
|
||||
@ -333,13 +335,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
|
||||
"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.
|
||||
///
|
||||
/// `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"],
|
||||
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.
|
||||
let mut cmd = cargo_metadata::MetadataCommand::new();
|
||||
@ -377,7 +380,6 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
|
||||
&["rustc_codegen_cranelift"],
|
||||
bad,
|
||||
);
|
||||
check_crate_duplicate(&metadata, &[], bad);
|
||||
|
||||
let mut cmd = cargo_metadata::MetadataCommand::new();
|
||||
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.
|
||||
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
|
||||
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 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) {
|
||||
let cargo = pkg_from_name(metadata, "cargo");
|
||||
let compiletest = pkg_from_name(metadata, "compiletest");
|
||||
let cargo_deps = direct_deps_of(metadata, &cargo.id);
|
||||
let compiletest_deps = direct_deps_of(metadata, &compiletest.id);
|
||||
let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap();
|
||||
let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap();
|
||||
fn check_rustfix(rust_metadata: &Metadata, cargo_metadata: &Metadata, bad: &mut bool) {
|
||||
let cargo = pkg_from_name(cargo_metadata, "cargo");
|
||||
let cargo_rustfix =
|
||||
direct_deps_of(cargo_metadata, &cargo.id).find(|p| p.name == "rustfix").unwrap();
|
||||
|
||||
let compiletest = pkg_from_name(rust_metadata, "compiletest");
|
||||
let compiletest_rustfix =
|
||||
direct_deps_of(rust_metadata, &compiletest.id).find(|p| p.name == "rustfix").unwrap();
|
||||
|
||||
if cargo_rustfix.version != compiletest_rustfix.version {
|
||||
tidy_error!(
|
||||
bad,
|
||||
|
Loading…
Reference in New Issue
Block a user