Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Package/ModuleGraph] Allow cyclic package dependencies if they don't introduce a cycle in a build graph #7530

Merged
merged 11 commits into from
May 8, 2024

Conversation

xedin
Copy link
Contributor

@xedin xedin commented May 6, 2024

Motivation:

It should be possible for packages to depend on each other if such dependence doesn't introduce cycles in the build graph.

Modifications:

  • Introduced a new DFS method to walk over graphs that breaks cycles.
  • Replaces use of findCycle + topologicalSort with DFS while building manifest and package graphs. This allows cycles in dependencies to be modeled correctly.
  • Removes some of the redundant data transformations from modules graph.
  • Modifies ResolvedPackage to carry identities of its dependencies instead of resolved dependencies themselves. This helps to simplify logic in createResolvedPackages.
  • Adds detection of target cycles across packages.

Result:

Makes it possible for package A to depend on package B and B to depend on A if their targets don't form a cycle.

xedin added 8 commits May 6, 2024 13:04
…topologicalSort

It's too early to diagnose cycles here because cyclic package-level
dependencies don't necessary lead to cycles in build graph, only
target/product element cycles are important.
`load` builds a list of packages in topological order already
and that's exactly what ModulesGraph wants, let's pass resolved
packages to it directly instead of having to re-build the list.
…dentifier`

Another step towards recursive dependency support - `ResolvedPackage`
identifies its dependencies but refers back to the `ModulesGraph` to
fetch underlying packages. This helps to avoid possible infinite recursion
while building `ResolvedPackage` via existing builder pattern.

There are really only two places where recursive walk over dependencies
is needed - `PluginContextSerializer` and  `ShowDependencies` command,
 both of which have module graph available.
…using package set

Since `packages` is now an identifiable set no additional storage
is needed to find package from a module or a product it contains.
Avoids duplicating the work and allows dependencies to have cyclic
entries because cyclic product and/or target references are the
only problematic cases for the build since they cannot be planned
properly.
It cannot be done sooner because `Package` only knows about
package names of products but doesn't attempt to resolve them
and attempting to build resolved packages with cycles would
result in an infinite recusion because builders are reference
types.
@xedin
Copy link
Contributor Author

xedin commented May 6, 2024

@swift-ci please test

@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

@swift-ci please test

xedin added a commit to xedin/sourcekit-lsp that referenced this pull request May 7, 2024
`ModulesGraph.init` was changed by swiftlang/swift-package-manager#7530
to accept `packages` as a way to avoid having to recompute the full
list of packages by walking roots.
@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

swiftlang/sourcekit-lsp#1233
@swift-ci please test

Copy link
Contributor

@MaxDesiatov MaxDesiatov left a comment

Choose a reason for hiding this comment

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

LGTM modulo the DFS function naming nit

@MaxDesiatov
Copy link
Contributor

@xedin would you mind updating CHANGELOG.md to list this change?

@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

Will do!

@xedin xedin force-pushed the fix-cross-package-cycles branch from e2525b3 to e3a16d4 Compare May 7, 2024 18:55
@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

swiftlang/sourcekit-lsp#1233
@swift-ci please test

@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

swiftlang/sourcekit-lsp#1233
@swift-ci please test Windows platform

@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

@MaxDesiatov All done!

@MaxDesiatov MaxDesiatov enabled auto-merge (squash) May 7, 2024 19:19
@MaxDesiatov
Copy link
Contributor

Windows failure seems to be spurious

@MaxDesiatov
Copy link
Contributor

@swift-ci test windows

@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

swiftlang/sourcekit-lsp#1233
@swift-ci please test Windows platform

2 similar comments
@xedin
Copy link
Contributor Author

xedin commented May 7, 2024

swiftlang/sourcekit-lsp#1233
@swift-ci please test Windows platform

@xedin
Copy link
Contributor Author

xedin commented May 8, 2024

swiftlang/sourcekit-lsp#1233
@swift-ci please test Windows platform

@MaxDesiatov MaxDesiatov merged commit 8b12909 into swiftlang:main May 8, 2024
5 checks passed
xedin added a commit to xedin/swift-package-manager that referenced this pull request May 8, 2024
… introduce a cycle in a build graph (swiftlang#7530)

It should be possible for packages to depend on each other if such
dependence doesn't introduce cycles in the build graph.

- Introduced a new DFS method to walk over graphs that breaks cycles.
- Replaces use of `findCycle` + `topologicalSort` with `DFS` while
building manifest and package graphs. This allows cycles in dependencies
to be modeled correctly.
- Removes some of the redundant data transformations from modules graph.
- Modifies `ResolvedPackage` to carry identities of its dependencies
instead of resolved dependencies themselves. This helps to simplify
logic in `createResolvedPackages`.
- Adds detection of target cycles across packages.

Makes it possible for package A to depend on package B and B to depend
on A if their targets don't form a cycle.

(cherry picked from commit 8b12909)
xedin added a commit to xedin/swift-package-manager that referenced this pull request May 8, 2024
… introduce a cycle in a build graph (swiftlang#7530)

It should be possible for packages to depend on each other if such
dependence doesn't introduce cycles in the build graph.

- Introduced a new DFS method to walk over graphs that breaks cycles.
- Replaces use of `findCycle` + `topologicalSort` with `DFS` while
building manifest and package graphs. This allows cycles in dependencies
to be modeled correctly.
- Removes some of the redundant data transformations from modules graph.
- Modifies `ResolvedPackage` to carry identities of its dependencies
instead of resolved dependencies themselves. This helps to simplify
logic in `createResolvedPackages`.
- Adds detection of target cycles across packages.

Makes it possible for package A to depend on package B and B to depend
on A if their targets don't form a cycle.

(cherry picked from commit 8b12909)
xedin added a commit to xedin/sourcekit-lsp that referenced this pull request May 8, 2024
`ModulesGraph.init` was changed by swiftlang/swift-package-manager#7530
to accept `packages` as a way to avoid having to recompute the full
list of packages by walking roots.

(cherry picked from commit 2270631)
furby-tm pushed a commit to wabiverse/swift-package-manager that referenced this pull request May 15, 2024
… introduce a cycle in a build graph (swiftlang#7530)

### Motivation:

It should be possible for packages to depend on each other if such
dependence doesn't introduce cycles in the build graph.

### Modifications:

- Introduced a new DFS method to walk over graphs that breaks cycles.
- Replaces use of `findCycle` + `topologicalSort` with `DFS` while
building manifest and package graphs. This allows cycles in dependencies
to be modeled correctly.
- Removes some of the redundant data transformations from modules graph.
- Modifies `ResolvedPackage` to carry identities of its dependencies
instead of resolved dependencies themselves. This helps to simplify
logic in `createResolvedPackages`.
- Adds detection of target cycles across packages.

### Result:

Makes it possible for package A to depend on package B and B to depend
on A if their targets don't form a cycle.
furby-tm pushed a commit to wabiverse/swift-package-manager that referenced this pull request May 15, 2024
… introduce a cycle in a build graph (swiftlang#7530)

### Motivation:

It should be possible for packages to depend on each other if such
dependence doesn't introduce cycles in the build graph.

### Modifications:

- Introduced a new DFS method to walk over graphs that breaks cycles.
- Replaces use of `findCycle` + `topologicalSort` with `DFS` while
building manifest and package graphs. This allows cycles in dependencies
to be modeled correctly.
- Removes some of the redundant data transformations from modules graph.
- Modifies `ResolvedPackage` to carry identities of its dependencies
instead of resolved dependencies themselves. This helps to simplify
logic in `createResolvedPackages`.
- Adds detection of target cycles across packages.

### Result:

Makes it possible for package A to depend on package B and B to depend
on A if their targets don't form a cycle.
xedin added a commit to xedin/swift-package-manager that referenced this pull request May 18, 2024
…manifests

Follow-up to swiftlang#7530

Otherwise it might be suprising for package authors to discover that
their packages cannot be used with older tools because they inadvertently
introduced a cyclic dependency in a new version.
xedin added a commit to xedin/swift-package-manager that referenced this pull request May 20, 2024
…manifests

Follow-up to swiftlang#7530

Otherwise it might be suprising for package authors to discover that
their packages cannot be used with older tools because they inadvertently
introduced a cyclic dependency in a new version.
xedin added a commit that referenced this pull request May 22, 2024
#7579)

…manifests

### Motivation:

Follow-up to #7530

Otherwise it might be suprising for package authors to discover that
their packages cannot be used with older tools because they
inadvertently introduced a cyclic dependency in a new version.

### Modifications:

`ModulesGraph.load` has been adjusted to run `findCycle` some of the
root manifests support tools version that is older than 6.0. New
diagnostic was added to help guide package authors to update their
versions if they have cyclic package-level dependencies.

### Result:

Attempts to introduce cyclic package-level dependencies to manifests
that support tools-versions less than 6.0 would result in a failure.
xedin added a commit to xedin/swift-package-manager that referenced this pull request May 29, 2024
… introduce a cycle in a build graph (swiftlang#7530)

It should be possible for packages to depend on each other if such
dependence doesn't introduce cycles in the build graph.

- Introduced a new DFS method to walk over graphs that breaks cycles.
- Replaces use of `findCycle` + `topologicalSort` with `DFS` while
building manifest and package graphs. This allows cycles in dependencies
to be modeled correctly.
- Removes some of the redundant data transformations from modules graph.
- Modifies `ResolvedPackage` to carry identities of its dependencies
instead of resolved dependencies themselves. This helps to simplify
logic in `createResolvedPackages`.
- Adds detection of target cycles across packages.

Makes it possible for package A to depend on package B and B to depend
on A if their targets don't form a cycle.

(cherry picked from commit 8b12909)
xedin added a commit to xedin/sourcekit-lsp that referenced this pull request May 29, 2024
`ModulesGraph.init` was changed by swiftlang/swift-package-manager#7530
to accept `packages` as a way to avoid having to recompute the full
list of packages by walking roots.

(cherry picked from commit 2270631)
(cherry picked from commit b13244f)
xedin added a commit that referenced this pull request May 30, 2024
…don't introduce a cycle in a build graph (#7541)

- Explanation:

   It should be possible for packages to depend on each other if such
    dependence doesn't introduce cycles in the build graph.

- Introduced a new DFS method to walk over graphs that breaks cycles.
    - Replaces use of `findCycle` + `topologicalSort` with `DFS` while
building manifest and package graphs. This allows cycles in dependencies
    to be modeled correctly.
- Removes some of the redundant data transformations from modules graph.
    - Modifies `ResolvedPackage` to carry identities of its dependencies
    instead of resolved dependencies themselves. This helps to simplify
    logic in `createResolvedPackages`.
    - Adds detection of target cycles across packages.

Makes it possible for package A to depend on package B and B to depend
    on A if their targets don't form a cycle.

- Scope: Package graph

- Main Branch PRs:
#7530

- Risk: Low

- Reviewed By: @MaxDesiatov    

- Testing: Added new test-cases to the test suite
xedin added a commit to xedin/swift-package-manager that referenced this pull request May 31, 2024
…manifests

Follow-up to swiftlang#7530

Otherwise it might be suprising for package authors to discover that
their packages cannot be used with older tools because they inadvertently
introduced a cyclic dependency in a new version.

(cherry picked from commit 3098b2d)
xedin added a commit that referenced this pull request Jun 1, 2024
… 6.0 … (#7617)

…manifests

- Explanation:

Follow-up to #7530

Otherwise it might be surprising for package authors to discover that
their packages cannot be used with older tools because they
inadvertently introduced a cyclic dependency in a new version.

- Scope: dependency resolution.

- Main Branch PR:
#7579

- Resolves: rdar://126217172

- Risk: Low

- Reviewed By: @bnbarham      

- Testing: New tests added to the test suite.

(cherry picked from commit 3098b2d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants