Skip to content

Commit a5b5582

Browse files
Merge #8812
8812: fix: fix dependencies of build scripts r=jonas-schievink a=jonas-schievink Previously, we added a dependency for all targets in a package to the package's library target. This is correct for most targets, except build scripts, which run before the library crate is built. This PR removes the incorrect dependency on the library target. We also used to treat all dependencies the same, which led to build scripts being able to use regular dependencies as well as dev-dependencies. This is also fixed by this PR, and build scripts only depend on build-dependencies. Incorrect dependency graph: ![screenshot-2021-05-11-23:35:01](https://user-images.githubusercontent.com/1786438/117975228-c2066a80-b32e-11eb-8f01-1e3ea904a608.png) Fixed graph after this PR: ![screenshot-2021-05-12-14:29:31](https://user-images.githubusercontent.com/1786438/117975253-c9c60f00-b32e-11eb-8f6c-9e42d4e32468.png) Co-authored-by: Jonas Schievink <[email protected]>
2 parents 9a431c2 + a272cdf commit a5b5582

File tree

3 files changed

+57
-13
lines changed

3 files changed

+57
-13
lines changed

crates/project_model/src/cargo_workspace.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,32 @@ pub struct RustAnalyzerPackageMetaData {
119119
pub struct PackageDependency {
120120
pub pkg: Package,
121121
pub name: String,
122+
pub kind: DepKind,
123+
}
124+
125+
#[derive(Debug, Clone, Eq, PartialEq)]
126+
pub enum DepKind {
127+
/// Available to the library, binary, and dev targets in the package (but not the build script).
128+
Normal,
129+
/// Available only to test and bench targets (and the library target, when built with `cfg(test)`).
130+
Dev,
131+
/// Available only to the build script target.
132+
Build,
133+
}
134+
135+
impl DepKind {
136+
fn new(list: &[cargo_metadata::DepKindInfo]) -> Self {
137+
for info in list {
138+
match info.kind {
139+
cargo_metadata::DependencyKind::Normal => return Self::Normal,
140+
cargo_metadata::DependencyKind::Development => return Self::Dev,
141+
cargo_metadata::DependencyKind::Build => return Self::Build,
142+
cargo_metadata::DependencyKind::Unknown => continue,
143+
}
144+
}
145+
146+
Self::Normal
147+
}
122148
}
123149

124150
/// Information associated with a package's target
@@ -144,6 +170,7 @@ pub enum TargetKind {
144170
Example,
145171
Test,
146172
Bench,
173+
BuildScript,
147174
Other,
148175
}
149176

@@ -155,6 +182,7 @@ impl TargetKind {
155182
"test" => TargetKind::Test,
156183
"bench" => TargetKind::Bench,
157184
"example" => TargetKind::Example,
185+
"custom-build" => TargetKind::BuildScript,
158186
"proc-macro" => TargetKind::Lib,
159187
_ if kind.contains("lib") => TargetKind::Lib,
160188
_ => continue,
@@ -301,7 +329,11 @@ impl CargoWorkspace {
301329
continue;
302330
}
303331
};
304-
let dep = PackageDependency { name: dep_node.name, pkg };
332+
let dep = PackageDependency {
333+
name: dep_node.name,
334+
pkg,
335+
kind: DepKind::new(&dep_node.dep_kinds),
336+
};
305337
packages[source].dependencies.push(dep);
306338
}
307339
packages[source].active_features.extend(node.features);

crates/project_model/src/workspace.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
66

77
use anyhow::{Context, Result};
88
use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
9+
use cargo_workspace::DepKind;
910
use cfg::CfgOptions;
1011
use paths::{AbsPath, AbsPathBuf};
1112
use proc_macro_api::ProcMacroClient;
@@ -407,23 +408,25 @@ fn cargo_to_crate_graph(
407408
}
408409
}
409410

410-
pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
411+
pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
411412
}
412413
}
413414

414415
// Set deps to the core, std and to the lib target of the current package
415-
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
416+
for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
416417
if let Some((to, name)) = lib_tgt.clone() {
417-
if to != from {
418+
if to != *from && *kind != TargetKind::BuildScript {
419+
// (build script can not depend on its library target)
420+
418421
// For root projects with dashes in their name,
419422
// cargo metadata does not do any normalization,
420423
// so we do it ourselves currently
421424
let name = CrateName::normalize_dashes(&name);
422-
add_dep(&mut crate_graph, from, name, to);
425+
add_dep(&mut crate_graph, *from, name, to);
423426
}
424427
}
425428
for (name, krate) in public_deps.iter() {
426-
add_dep(&mut crate_graph, from, name.clone(), *krate);
429+
add_dep(&mut crate_graph, *from, name.clone(), *krate);
427430
}
428431
}
429432
}
@@ -434,8 +437,17 @@ fn cargo_to_crate_graph(
434437
for dep in cargo[pkg].dependencies.iter() {
435438
let name = CrateName::new(&dep.name).unwrap();
436439
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
437-
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
438-
add_dep(&mut crate_graph, from, name.clone(), to)
440+
for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
441+
if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript {
442+
// Only build scripts may depend on build dependencies.
443+
continue;
444+
}
445+
if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript {
446+
// Build scripts may only depend on build dependencies.
447+
continue;
448+
}
449+
450+
add_dep(&mut crate_graph, *from, name.clone(), to)
439451
}
440452
}
441453
}
@@ -472,7 +484,7 @@ fn handle_rustc_crates(
472484
pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
473485
public_deps: &[(CrateName, CrateId)],
474486
cargo: &CargoWorkspace,
475-
pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<CrateId>>,
487+
pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<(CrateId, TargetKind)>>,
476488
) {
477489
let mut rustc_pkg_crates = FxHashMap::default();
478490
// The root package of the rustc-dev component is rustc_driver, so we match that
@@ -541,13 +553,13 @@ fn handle_rustc_crates(
541553
if !package.metadata.rustc_private {
542554
continue;
543555
}
544-
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
556+
for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() {
545557
// Avoid creating duplicate dependencies
546558
// This avoids the situation where `from` depends on e.g. `arrayvec`, but
547559
// `rust_analyzer` thinks that it should use the one from the `rustcSource`
548560
// instead of the one from `crates.io`
549-
if !crate_graph[from].dependencies.iter().any(|d| d.name == name) {
550-
add_dep(crate_graph, from, name.clone(), to);
561+
if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
562+
add_dep(crate_graph, *from, name.clone(), to);
551563
}
552564
}
553565
}

crates/rust-analyzer/src/cargo_target_spec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl CargoTargetSpec {
159159
TargetKind::Lib => {
160160
buf.push("--lib".to_string());
161161
}
162-
TargetKind::Other => (),
162+
TargetKind::Other | TargetKind::BuildScript => (),
163163
}
164164
}
165165
}

0 commit comments

Comments
 (0)