Skip to content

Fix dependency diagnostics for dynamic target variants#1457

Merged
owenv merged 1 commit into
swiftlang:mainfrom
yimajo:fix-dynamic-target-dependency-diagnostics
Jun 17, 2026
Merged

Fix dependency diagnostics for dynamic target variants#1457
owenv merged 1 commit into
swiftlang:mainfrom
yimajo:fix-dynamic-target-dependency-diagnostics

Conversation

@yimajo

@yimajo yimajo commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Problem

A missing target dependency warning or error can be emitted during dependency scanning even when the target dependency is configured correctly.

Example warning:

warning: 'FirebaseCore' is missing a dependency on 'FirebaseCoreInternal' because dependency scan of 'FIRHeartbeatLogger.m' discovered a dependency on 'FirebaseCoreInternal'

In this case, FirebaseCore does have a dependency on FirebaseCoreInternal, but the warning can still be emitted.
This issue can be reproduced with a small test case.

The problem happens when the dependent target is replaced with a dynamic variant. swift-build has logic that changes targets to be dynamically linked, and dependency validation needs to use the result of that transformation.

Cause

BuildOperation.transitiveDependencyExists(target:antecedent:) checks whether target can reach antecedent using the dependency graph built from BuildDescription.targetDependencies.

However, BuildDescription.targetDependencies was populated with buildGraph.targetDependenciesByGuid, which represents the pre-dynamic-linkage target graph.

As a result, even when the actual task was executed for a post-dynamic-linkage target, the dependency graph used for reachability checks was still based on the pre-dynamic-linkage target.

This caused the reachability check from the post-dynamic-linkage target to its dependency target to fail, and swift-build could emit a missing target dependency warning/error even though the target dependency was configured correctly.

Changes

Add GlobalProductPlan.targetDependenciesByGuid

This PR adds targetDependenciesByGuid to GlobalProductPlan.

This property builds target dependency relationships from GlobalProductPlan.allTargets and
GlobalProductPlan.resolvedDependencies(of:), so the relationships are based on the post-dynamic-linkage target graph.

BuildDescription construction now passes GlobalProductPlan.targetDependenciesByGuid instead of TargetBuildGraph.targetDependenciesByGuid.

This makes dependency validation use the same post-dynamic-linkage target graph when the dependent target has been replaced with a dynamic variant.

Build definingTargetsByModuleName from GlobalProductPlan

The dependency target can also be a post-dynamic-linkage target.

For that reason, definingTargetsByModuleName, which is used to resolve a dependency target from a module name, is now built from plan.globalProductPlan.allTargets instead of buildGraph.allTargets.

Test case

The regression test sets up a dynamically linked embedded framework named macOSFwk.

App
├── macOSFwk
│   └── PackageLibProduct
│        └── Common
│            └── Core
└── PackageLibProduct2
      └── Common
          └── Core

In this configuration, both Common and Core have diamond linkage, so swift-build replaces them with dynamic variants.

App
├── macOSFwk
│   └── PackageLibProduct
│        └── Common-dynamic
│            └── Core-dynamic
└── PackageLibProduct2
      └── Common-dynamic
          └── Core-dynamic

Common contains import Core, so dependency scanning detects a module dependency from Common to Core.

Before this PR, the actual task was executed as Common-dynamic, but the dependency graph used for the reachability check was built from the pre-dynamic-linkage buildGraph.targetDependenciesByGuid. Therefore, dependency validation could not look up dependency relationships starting from Common-dynamic.

Also, definingTargetsByModuleName, which is used to resolve the dependency target from the module name, was not built from GlobalProductPlan. Therefore, it treated the dependency target as the pre-dynamic-linkage Core instead of the post-dynamic-linkage Core-dynamic.

As a result, a warning or error could be emitted even though the target dependency was configured correctly.

Not addressed in this PR

After this change, BuildDescription construction no longer uses TargetBuildGraph.targetDependenciesByGuid. This PR keeps it in place because it is a public API. If reviewers think it should be removed, please let me know.

@yimajo

yimajo commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

@swift-ci test

@owenv owenv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great, thanks!

@owenv

owenv commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

@swift-ci test

@owenv

owenv commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Linux CI may temporarily fail until swiftlang/swift#89917 lands in a toolchain.

@owenv

owenv commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

@swift-ci test

@owenv

owenv commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

@yimajo could you please rebase this on main? I think that will resolve the CI issues now that we have a workaround in place for the SIL verification crash

@yimajo yimajo force-pushed the fix-dynamic-target-dependency-diagnostics branch from bb8cefb to df71c8b Compare June 17, 2026 01:24
@yimajo

yimajo commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

@swift-ci test

@yimajo yimajo requested a review from owenv June 17, 2026 01:26
@owenv

owenv commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

@swift-ci test

@owenv owenv merged commit cda733a into swiftlang:main Jun 17, 2026
110 of 126 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants