Skip to content

Output Swift Build PIF JSON for Graphviz visualization #8539

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

Merged
merged 7 commits into from
Apr 24, 2025

Conversation

pmattos
Copy link
Contributor

@pmattos pmattos commented Apr 21, 2025

Motivation:

Improve visualization/debuggability of the PIF JSON sent over to Swift Build (when using the new --build-system swiftbuild option).

Modifications:

This PR introduces the --print-pif-manifest-graph option to write out the PIF JSON sent to Swift Build as a Graphviz file file. This follows a similar design we used for the existing --print-manifest-job-graph option.

All the serialization happens in the new DotPIFSerializer.swift file, with this function as the entry point:

func writePIF(_ workspace: PIF.Workspace, toDOT outputStream: OutputByteStream)

Result:

With Graphviz tool installed (i.e., provides the dot command below), we can then run commands like this:

swift build --build-system swiftbuild --print-pif-manifest-graph | dot -Tpng > PIF.png; open PIF.png

A few quick examples:

Sample Executable

(mkdir Foo; cd Foo; swift package init --name Foo --type executable)
swift build --build-system swiftbuild --package-path Foo --print-pif-manifest-graph | dot -Tpng > Foo.png
digraph PIF {
  dpi=400;
  "Workspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Foo" [label="<workspace>\nWorkspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Foo", shape=box3d, color=black, fontname="SF Mono Light", fontsize=7];
  "Workspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Foo" -> "PACKAGE:foo" [color=lightskyblue];
  "PACKAGE:foo" [label="<project>\nPACKAGE:foo", shape=box3d, color=gray56, fontname="SF Mono Light", fontsize=7];
  "PACKAGE:foo" -> "PACKAGE-PRODUCT:Foo" [color=lightskyblue];
  "PACKAGE-PRODUCT:Foo" [label="<target>\nPACKAGE-PRODUCT:Foo\nproduct type: executable\nsources: 1 source file", shape=box, color=gray88, fontname="SF Mono Light", fontsize=5];
  "PACKAGE:foo" -> "PACKAGE-TARGET:Foo-1DD02E5F-testable" [color=lightskyblue];
  "PACKAGE-TARGET:Foo-1DD02E5F-testable" [label="<target>\nPACKAGE-TARGET:Foo-1DD02E5F-testable\nproduct type: objectFile\nsources: 1 source file", shape=box, color=gray88, fontname="SF Mono Light", fontsize=5];
  "Workspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Foo" -> "AGGREGATE" [color=lightskyblue];
  "AGGREGATE" [label="<project>\nAGGREGATE", shape=box3d, color=gray56, fontname="SF Mono Light", fontsize=7];
  "AGGREGATE" -> "ALL-INCLUDING-TESTS" [color=lightskyblue];
  "ALL-INCLUDING-TESTS" [label="<aggregate target>\nALL-INCLUDING-TESTS", shape=folder, color=gray88, fontname="SF Mono Light", fontsize=5, style=bold];
  "ALL-INCLUDING-TESTS" -> "PACKAGE-PRODUCT:Foo" [color=gray40, style=dotted];
  "ALL-INCLUDING-TESTS" -> "PACKAGE-TARGET:Foo-1DD02E5F-testable" [color=gray40, style=dotted];
  "AGGREGATE" -> "ALL-EXCLUDING-TESTS" [color=lightskyblue];
  "ALL-EXCLUDING-TESTS" [label="<aggregate target>\nALL-EXCLUDING-TESTS", shape=folder, color=gray88, fontname="SF Mono Light", fontsize=5, style=bold];
  "ALL-EXCLUDING-TESTS" -> "PACKAGE-PRODUCT:Foo" [color=gray40, style=dotted];
  "ALL-EXCLUDING-TESTS" -> "PACKAGE-TARGET:Foo-1DD02E5F-testable" [color=gray40, style=dotted];
}

Sample Library

(mkdir Bar; cd Bar; swift package init --name Bar --type library)
swift build --build-system swiftbuild --package-path Bar --print-pif-manifest-graph | dot -Tpng > Bar.png
digraph PIF {
  dpi=400;
  "Workspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Bar" [label="<workspace>\nWorkspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Bar", shape=box3d, color=black, fontname="SF Mono Light", fontsize=7];
  "Workspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Bar" -> "PACKAGE:bar" [color=lightskyblue];
  "PACKAGE:bar" [label="<project>\nPACKAGE:bar", shape=box3d, color=gray56, fontname="SF Mono Light", fontsize=7];
  "PACKAGE:bar" -> "PACKAGE-PRODUCT:BarTests" [color=lightskyblue];
  "PACKAGE-PRODUCT:BarTests" [label="<target>\nPACKAGE-PRODUCT:BarTests\nproduct type: unitTest\nsources: 1 source file\nframeworks: 1 linked target", shape=box, color=gray88, fontname="SF Mono Light", fontsize=5];
  "PACKAGE-PRODUCT:BarTests" -> "PACKAGE-TARGET:Bar" [color=gray40, style=filled];
  "PACKAGE:bar" -> "PACKAGE-PRODUCT:Bar" [color=lightskyblue];
  "PACKAGE-PRODUCT:Bar" [label="<target>\nPACKAGE-PRODUCT:Bar\nproduct type: packageProduct\nframeworks: 1 linked target", shape=box, color=gray88, fontname="SF Mono Light", fontsize=5];
  "PACKAGE-PRODUCT:Bar" -> "PACKAGE-TARGET:Bar" [color=gray40, style=filled];
  "PACKAGE:bar" -> "PACKAGE-PRODUCT:Bar-1DAB67D8-dynamic" [color=lightskyblue];
  "PACKAGE-PRODUCT:Bar-1DAB67D8-dynamic" [label="<target>\nPACKAGE-PRODUCT:Bar-1DAB67D8-dynamic\nproduct type: dynamicLibrary\nframeworks: 1 linked target\nsources: 0 source files", shape=box, color=gray88, fontname="SF Mono Light", fontsize=5];
  "PACKAGE-PRODUCT:Bar-1DAB67D8-dynamic" -> "PACKAGE-TARGET:Bar" [color=gray40, style=filled];
  "PACKAGE:bar" -> "PACKAGE-TARGET:Bar" [color=lightskyblue];
  "PACKAGE-TARGET:Bar" [label="<target>\nPACKAGE-TARGET:Bar\nproduct type: objectFile\nsources: 1 source file", shape=box, color=gray88, fontname="SF Mono Light", fontsize=5];
  "PACKAGE:bar" -> "PACKAGE-TARGET:Bar-1DAB67D8-dynamic" [color=lightskyblue];
  "PACKAGE-TARGET:Bar-1DAB67D8-dynamic" [label="<target>\nPACKAGE-TARGET:Bar-1DAB67D8-dynamic\nproduct type: dynamicLibrary\nsources: 1 source file", shape=box, color=gray88, fontname="SF Mono Light", fontsize=5];
  "Workspace:/Users/pmattos/SwiftPM/graphviz-for-pif/Bar" -> "AGGREGATE" [color=lightskyblue];
  "AGGREGATE" [label="<project>\nAGGREGATE", shape=box3d, color=gray56, fontname="SF Mono Light", fontsize=7];
  "AGGREGATE" -> "ALL-INCLUDING-TESTS" [color=lightskyblue];
  "ALL-INCLUDING-TESTS" [label="<aggregate target>\nALL-INCLUDING-TESTS", shape=folder, color=gray88, fontname="SF Mono Light", fontsize=5, style=bold];
  "ALL-INCLUDING-TESTS" -> "PACKAGE-PRODUCT:BarTests" [color=gray40, style=dotted];
  "ALL-INCLUDING-TESTS" -> "PACKAGE-PRODUCT:Bar" [color=gray40, style=dotted];
  "ALL-INCLUDING-TESTS" -> "PACKAGE-TARGET:Bar" [color=gray40, style=dotted];
  "AGGREGATE" -> "ALL-EXCLUDING-TESTS" [color=lightskyblue];
  "ALL-EXCLUDING-TESTS" [label="<aggregate target>\nALL-EXCLUDING-TESTS", shape=folder, color=gray88, fontname="SF Mono Light", fontsize=5, style=bold];
  "ALL-EXCLUDING-TESTS" -> "PACKAGE-PRODUCT:Bar" [color=gray40, style=dotted];
  "ALL-EXCLUDING-TESTS" -> "PACKAGE-TARGET:Bar" [color=gray40, style=dotted];
}

///
/// * [DOT command line](https://graphviz.org/doc/info/command.html)
/// * [DOT language specs](https://graphviz.org/doc/info/lang.html)
func writePIF(_ workspace: PIF.Workspace, toDOT outputStream: OutputByteStream) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the main entry point for construction the Graphviz compatible PIF graph.

@pmattos
Copy link
Contributor Author

pmattos commented Apr 21, 2025

@swift-ci test

@pmattos
Copy link
Contributor Author

pmattos commented Apr 21, 2025

@swift-ci please test

@pmattos pmattos force-pushed the pmattos/graphviz-for-pif branch from 7932159 to 4a5319b Compare April 21, 2025 20:47
@pmattos
Copy link
Contributor Author

pmattos commented Apr 21, 2025

@swift-ci please test

@pmattos
Copy link
Contributor Author

pmattos commented Apr 21, 2025

@swift-ci test windows

@pmattos
Copy link
Contributor Author

pmattos commented Apr 22, 2025

@swift-ci test macOS

@pmattos
Copy link
Contributor Author

pmattos commented Apr 22, 2025

@swift-ci test linux

@pmattos
Copy link
Contributor Author

pmattos commented Apr 22, 2025

@swift-ci please test

@pmattos
Copy link
Contributor Author

pmattos commented Apr 22, 2025

@swift-ci test self hosted windows

1 similar comment
@pmattos
Copy link
Contributor Author

pmattos commented Apr 22, 2025

@swift-ci test self hosted windows

@pmattos
Copy link
Contributor Author

pmattos commented Apr 22, 2025

@swift-ci test windows

@@ -205,6 +206,7 @@ public enum PIF {
}
}

// FIXME: Delete this (rdar://149003797).
Copy link
Member

Choose a reason for hiding this comment

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

thought: Maybe this can be a GH issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point Chris. Done: #8552


if printPIFManifestGraphviz {
// Print dot graph to stdout.
writePIF(topLevelObject.workspace, toDOT: stdoutStream)
Copy link
Member

Choose a reason for hiding this comment

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

question: How will the output look if there are other things going to stdout, like the build logs, and error messages? Maybe it will be better to have the option specify a file where the dot should go?

Copy link
Contributor Author

@pmattos pmattos Apr 23, 2025

Choose a reason for hiding this comment

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

I was under the impression that all build logs, warnings, and errors go to stderr now, right? I mean when using --build-system swiftbuild option.

I think sending out to stdout provides a slightly better Unix-ish DX, following what we already do in the existing --print-manifest-job-graph option.

Copy link
Contributor Author

@pmattos pmattos Apr 23, 2025

Choose a reason for hiding this comment

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

To be clear, this is how stdout looks like if do not abort the build process (ie, right after printing out the Graphiz):

$ swift build --build-system swiftbuild --vv --print-pif-manifest-graph 2> /dev/null                      
digraph PIF {
  ...
}
Building for debugging...
100%: 
Build complete! (0.49424425 seconds)

Even on --very-verbose mode all stdout "noise" only happens after printing out the Graphiz, so aborting the build there provides a nice workaround for this now. Luckily, all build output before digraph goes instead to stderr, which won't mess up with dot parsing.

With the build abort in place, it then looks like this:

$ swift build --build-system swiftbuild --vv --print-pif-manifest-graph 2> /dev/null                      
digraph PIF {
  ...
}

PS. The existing --print-manifest-job-graph option follows a very similar logic.

@@ -969,6 +969,7 @@ extension ProjectModel.BuildSettings.Platform {
case .windows: .windows
case .wasi: .wasi
case .openbsd: .openbsd
case .freebsd: .freebsd
Copy link
Member

Choose a reason for hiding this comment

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

question Does FreeBSD support belong as a separate PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that's already merged and the diff is just showing this because this PR is branched off an older main.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had that in another PR... but never landed it. Anyway, I will send out a dedicated PR for this ;)

This how the file looks like in main:

default: preconditionFailure("Unexpected platform: \(platform.name)")

Copy link
Contributor Author

@pmattos pmattos Apr 23, 2025

Choose a reason for hiding this comment

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

Here you go: #8550

@jakepetroules
Copy link
Contributor

@swift-ci test windows

@pmattos pmattos force-pushed the pmattos/graphviz-for-pif branch from dc33b1f to 2b263cd Compare April 24, 2025 00:26
@pmattos
Copy link
Contributor Author

pmattos commented Apr 24, 2025

@swift-ci test

@pmattos
Copy link
Contributor Author

pmattos commented Apr 24, 2025

@swift-ci test self hosted windows

@pmattos
Copy link
Contributor Author

pmattos commented Apr 24, 2025

@swift-ci test windows

@pmattos pmattos enabled auto-merge (squash) April 24, 2025 16:25
@pmattos pmattos merged commit b842488 into main Apr 24, 2025
6 checks passed
@pmattos pmattos deleted the pmattos/graphviz-for-pif branch April 24, 2025 20:42
pmattos added a commit that referenced this pull request Apr 30, 2025
### Motivation:

Fix a minor cmake build issue I introduced in pull request #8539. 

### Modifications:

Add missing Swift file to `Sources/SwiftBuildSupport/CMakeLists.txt`.
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.

3 participants