Skip to content

Commit 6375a24

Browse files
committed
crate_universe: synthesize build-script edge at render time
A library/binary/proc-macro built from a crate with a build script depends on that crate's own build_script_build target. That edge was recorded as a self-referential entry in common_attrs.deps, which also feeds workspace_member_deps() and produced a spurious crate-hub alias for any workspace member that is a library with a build script (issue #4089). Stop recording the self-edge in common_attrs.deps (reserved for cross-crate deps) and instead synthesize the build_script_build edge during rendering from the presence of the build-script target. workspace_member_deps() then naturally excludes it with no filtering. Upstream issue: #4089
1 parent fb01b69 commit 6375a24

3 files changed

Lines changed: 49 additions & 35 deletions

File tree

crate_universe/src/context.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,13 +406,16 @@ mod test {
406406
let context = mock_context_workspace_build_scripts_deps();
407407
let workspace_member_deps = context.workspace_member_deps();
408408

409+
// `child` is a workspace member with a build script. Its library's edge
410+
// to its own `build_script_build` target is not a cross-crate dependency
411+
// and is no longer recorded in `common_attrs.deps`, so only the build
412+
// script's own deps (`tonic`/`tonic-build`) are collected here.
409413
assert_eq! {
410414
workspace_member_deps
411415
.iter()
412416
.map(|dep| (&dep.id, context.has_duplicate_workspace_member_dep_by_alias(dep)))
413417
.collect::<Vec<_>>(),
414418
[
415-
(&CrateId::new("child".to_owned(), Version::new(0, 1, 0)), false),
416419
(&CrateId::new("tonic".to_owned(), Version::new(0, 4, 3)), false),
417420
(&CrateId::new("tonic-build".to_owned(), Version::new(0, 4, 2)), false),
418421
],

crate_universe/src/context/crate_context.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ impl CrateContext {
431431
.unwrap_or_default();
432432

433433
// Gather all "common" attributes
434-
let mut common_attrs = CommonAttributes {
434+
let common_attrs = CommonAttributes {
435435
crate_features,
436436
deps,
437437
deps_dev,
@@ -494,21 +494,13 @@ impl CrateContext {
494494
_ => None,
495495
});
496496

497-
let build_script_attrs = if let Some(target) = build_script_target {
498-
// Track the build script dependency
499-
common_attrs.deps.insert(
500-
CrateDependency {
501-
id: current_crate_id,
502-
target: target.crate_name.clone(),
503-
alias: None,
504-
local_path: match source_annotations.get(&annotation.node.id) {
505-
Some(SourceAnnotation::Path { path }) => Some(path.clone()),
506-
_ => None,
507-
},
508-
},
509-
None,
510-
);
511-
497+
let build_script_attrs = if build_script_target.is_some() {
498+
// A library/binary/proc-macro built from this crate depends on its
499+
// own build script; that edge is synthesized at render time from the
500+
// presence of the build-script target (see Renderer). It is
501+
// deliberately not recorded as a self-referential entry in
502+
// `common_attrs.deps`, which is reserved for cross-crate
503+
// dependencies and feeds workspace-member alias generation.
512504
let build_deps = annotation.deps.build_deps.clone().map(new_crate_dep);
513505
let build_link_deps = annotation.deps.build_link_deps.clone().map(new_crate_dep);
514506
let build_proc_macro_deps = annotation

crate_universe/src/rendering.rs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -682,13 +682,7 @@ impl Renderer {
682682
) -> Result<RustProcMacro> {
683683
Ok(RustProcMacro {
684684
name: target.crate_name.clone(),
685-
deps: SelectSet::new(
686-
self.make_deps(
687-
krate.common_attrs.deps.clone(),
688-
krate.common_attrs.extra_deps.clone(),
689-
),
690-
platforms,
691-
),
685+
deps: SelectSet::new(self.make_target_deps(krate), platforms),
692686
proc_macro_deps: SelectSet::new(
693687
self.make_deps(
694688
krate.common_attrs.proc_macro_deps.clone(),
@@ -709,13 +703,7 @@ impl Renderer {
709703
) -> Result<RustLibrary> {
710704
Ok(RustLibrary {
711705
name: target.crate_name.clone(),
712-
deps: SelectSet::new(
713-
self.make_deps(
714-
krate.common_attrs.deps.clone(),
715-
krate.common_attrs.extra_deps.clone(),
716-
),
717-
platforms,
718-
),
706+
deps: SelectSet::new(self.make_target_deps(krate), platforms),
719707
proc_macro_deps: SelectSet::new(
720708
self.make_deps(
721709
krate.common_attrs.proc_macro_deps.clone(),
@@ -742,10 +730,7 @@ impl Renderer {
742730
.iter()
743731
.any(|rule| matches!(rule, Rule::ProcMacro(_)));
744732

745-
let mut deps = self.make_deps(
746-
krate.common_attrs.deps.clone(),
747-
krate.common_attrs.extra_deps.clone(),
748-
);
733+
let mut deps = self.make_target_deps(krate);
749734
let mut proc_macro_deps = self.make_deps(
750735
krate.common_attrs.proc_macro_deps.clone(),
751736
krate.common_attrs.extra_proc_macro_deps.clone(),
@@ -870,6 +855,40 @@ impl Renderer {
870855
aliases
871856
}
872857

858+
/// Render the `deps` for a crate's library/binary/proc-macro target,
859+
/// including an edge to the crate's own build script when one is present. A
860+
/// crate with a build script depends on its `build_script_build` target for
861+
/// the script's generated outputs. This edge is synthesized here rather than
862+
/// recorded as a self-referential entry in `common_attrs.deps`, which is
863+
/// reserved for cross-crate dependencies.
864+
fn make_target_deps(&self, krate: &CrateContext) -> Select<BTreeSet<Label>> {
865+
let mut deps = self.make_deps(
866+
krate.common_attrs.deps.clone(),
867+
krate.common_attrs.extra_deps.clone(),
868+
);
869+
if let Some(label) = self.build_script_label(krate) {
870+
deps.insert(label, None);
871+
}
872+
deps
873+
}
874+
875+
/// The label of a crate's own build script target, if it defines one.
876+
fn build_script_label(&self, krate: &CrateContext) -> Option<Label> {
877+
let build_script_name = krate.targets.iter().find_map(|target| match target {
878+
Rule::BuildScript(attrs) => Some(&attrs.crate_name),
879+
_ => None,
880+
})?;
881+
let label = match (&krate.repository, self.config.vendor_mode) {
882+
// In local vendor mode, we use paths within the repo.
883+
(Some(SourceAnnotation::Path { path }), Some(VendorMode::Local)) => {
884+
Label::from_str(&format!("//{}:{}", path, build_script_name)).unwrap()
885+
}
886+
// Otherwise construct the label of the crate's own build script.
887+
_ => self.crate_label(&krate.name, &krate.version.to_string(), build_script_name),
888+
};
889+
Some(label)
890+
}
891+
873892
fn make_deps(
874893
&self,
875894
deps: Select<BTreeSet<CrateDependency>>,

0 commit comments

Comments
 (0)