Skip to content

Add swift.emit_symbol_graph feature#838

Merged
brentleyjones merged 2 commits intobazelbuild:masterfrom
jpsim:add-swift.emit_symbol_graph-feature
Jun 2, 2022
Merged

Add swift.emit_symbol_graph feature#838
brentleyjones merged 2 commits intobazelbuild:masterfrom
jpsim:add-swift.emit_symbol_graph-feature

Conversation

@jpsim
Copy link
Copy Markdown
Contributor

@jpsim jpsim commented Jun 1, 2022

That emits the symbol graph for the Swift target to bazel-bin.

Symbol graphs can then be fed to tools such as DocC or jazzy to generate documentation for a target.

For example, for Envoy Mobile:

$ ./bazelw build //library/swift:ios_lib --config=ios
$ "$(xcrun --find docc)" convert \
  --index \
  --fallback-display-name Envoy \
  --fallback-bundle-identifier io.envoyproxy.EnvoyMobile \
  --fallback-bundle-version 0.4.6 \
  --output-dir Envoy.doccarchive \
  --transform-for-static-hosting \
  --additional-symbol-graph-dir bazel-bin/library/swift/ios_lib.symbolgraph

That emits the symbol graph for the Swift target to `bazel-bin`.

Symbol graphs can then be fed to tools such as DocC or jazzy to generate
documentation for a target.

For example, for [Envoy Mobile](https://github.com/envoyproxy/envoy-mobile):

```
$ ./bazelw build //library/swift:ios_lib --config=ios
$ "$(xcrun --find docc)" convert \
  --index \
  --fallback-display-name \
  Envoy \
  --fallback-bundle-identifier \
  io.envoyproxy.EnvoyMobile \
  --fallback-bundle-version \
  0.4.6 \
  --output-dir \
  Envoy.doccarchive \
  --transform-for-static-hosting \
  --additional-symbol-graph-dir \
  bazel-bin/library/swift/ios_lib.symbolgraph
```
@thii
Copy link
Copy Markdown
Member

thii commented Jun 1, 2022

Do you think the symbol graph should be part of the direct outputs? (that I think would probably make it easier for other rules to consume)

@jpsim
Copy link
Copy Markdown
Contributor Author

jpsim commented Jun 1, 2022

Do you think the symbol graph should be part of the direct outputs?

I'm not strongly opposed, but in my mind the symbol graph files are more of a byproduct of the build than an output, similar to the index store files. Is there a formal definition of what a "direct output" is? That could help determine if this fits or not.

The other aspect is that we have control over the output directory for symbol graph files but the files themselves are picked by the compiler. The other entries in the direct outputs all appear to be files.

Copy link
Copy Markdown
Collaborator

@brentleyjones brentleyjones left a comment

Choose a reason for hiding this comment

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

Look good! I'll wait for another approval before merging though.

@Augustyniak
Copy link
Copy Markdown

unrelated observation: looking at the documentation page you generated I realized that our mocks are public 🤔

@jpsim
Copy link
Copy Markdown
Contributor Author

jpsim commented Jun 1, 2022

Yes the Envoy Mobile mocks are in the same framework for ease of distribution, but that’s something we should fix when we redesign the API.

@thii
Copy link
Copy Markdown
Member

thii commented Jun 2, 2022

Is there a formal definition of what a "direct output" is? That could help determine if this fits or not.

In my understanding, it's an output returned by the build by default (that is, what gets printed out at the end of the build).

If the symbol graph is just an intermediate output, Bazel might not produce the output if the build is a cached build or if you build with --remote_download_toplevel.

The other aspect is that we have control over the output directory for symbol graph files but the files themselves are picked by the compiler. The other entries in the direct outputs all appear to be files.

An output can also be a directory (a tree artifact).

I see that you just added the symbol graph output to the OutputGroupInfo provider that swift_library returns, so I think this is good for now. (The only downside is that these kinds of outputs have to be requested via the --output_groups command-line option, see the example below.)

bazel build --features=swift.emit_symbol_graph --output_groups=+swift_symbol_graph //examples/apple/objc_interop:Printer

INFO: Invocation ID: d11be84f-b35d-45b9-b421-95b72ccc399d
INFO: Analyzed target //examples/apple/objc_interop:Printer (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //examples/apple/objc_interop:Printer up-to-date:
  bazel-bin/examples/apple/objc_interop/Printer-Swift.h
  bazel-bin/examples/apple/objc_interop/examples_apple_objc_interop_Printer.swiftdoc
  bazel-bin/examples/apple/objc_interop/examples_apple_objc_interop_Printer.swiftmodule
  bazel-bin/examples/apple/objc_interop/examples_apple_objc_interop_Printer.swiftsourceinfo
  bazel-bin/examples/apple/objc_interop/libPrinter.a
  bazel-bin/examples/apple/objc_interop/Printer.symbolgraph
INFO: Elapsed time: 0.202s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action

)
args.add(
"-emit-symbol-graph-dir",
prerequisites.symbol_graph_directory.path,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assume the build time penalty to generate this is pretty irrelevant, right?

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.

Regardless it's behind a feature flag, similar to indexing while building.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah just out of curiosity. If it has a big impact, it might be worth documenting it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure if my methodology is correct, but I see a 2% hit to overall build times with the feature enabled:

$ hyperfine \
  --warmup 5 \
  --prepare "bazel clean && sleep 0.5" \
  "bazel build --features=swift.emit_symbol_graph --output_groups=+swift_symbol_graph //examples/apple/objc_interop:Printer" \
  "bazel build //examples/apple/objc_interop:Printer"
Benchmark 1: bazel build --features=swift.emit_symbol_graph --output_groups=+swift_symbol_graph //examples/apple/objc_interop:Printer
  Time (mean ± σ):     12.694 s ±  0.390 s    [User: 0.063 s, System: 0.055 s]
  Range (min … max):   12.379 s … 13.643 s    10 runs
 
Benchmark 2: bazel build //examples/apple/objc_interop:Printer
  Time (mean ± σ):     12.504 s ±  0.258 s    [User: 0.062 s, System: 0.051 s]
  Range (min … max):   12.105 s … 12.907 s    10 runs
 
Summary
  'bazel build //examples/apple/objc_interop:Printer' ran
    1.02 ± 0.04 times faster than 'bazel build --features=swift.emit_symbol_graph --output_groups=+swift_symbol_graph //examples/apple/objc_interop:Printer'

Since it's opt-in I don't see this needing a perf warning.

Copy link
Copy Markdown
Contributor Author

@jpsim jpsim Jun 2, 2022

Choose a reason for hiding this comment

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

Mind you, I edited Printer.swift to artificially make its compile time longer by adding a bunch of 2 * 2 * 2 * 2.0 / 2 + 2 statements to make the compiler work harder, taking ~6s in the Swift Compile step.

Without that artificial bloat, I can't measure a difference on a file that small:

Benchmark 1: bazel build --features=swift.emit_symbol_graph --output_groups=+swift_symbol_graph //examples/apple/objc_interop:Printer
  Time (mean ± σ):      6.222 s ±  0.189 s    [User: 0.076 s, System: 0.065 s]
  Range (min … max):    6.013 s …  6.563 s    10 runs
 
Benchmark 2: bazel build //examples/apple/objc_interop:Printer
  Time (mean ± σ):      6.228 s ±  0.217 s    [User: 0.074 s, System: 0.062 s]
  Range (min … max):    5.911 s …  6.587 s    10 runs
 
Summary
  'bazel build --features=swift.emit_symbol_graph --output_groups=+swift_symbol_graph //examples/apple/objc_interop:Printer' ran
    1.00 ± 0.05 times faster than 'bazel build //examples/apple/objc_interop:Printer'

@brentleyjones brentleyjones merged commit 3bc7bc1 into bazelbuild:master Jun 2, 2022
@jpsim jpsim deleted the add-swift.emit_symbol_graph-feature branch June 2, 2022 12:48
@jpsim
Copy link
Copy Markdown
Contributor Author

jpsim commented Jun 2, 2022

Thanks for the reviews, everyone! I may revisit @thii's comment (#838 (comment)) after we use this some more but for now at least I can generate docs for my project.

jpsim added a commit to envoyproxy/envoy-mobile that referenced this pull request Jun 2, 2022
And include in GitHub release artifacts

Updates rules_swift to pull in bazelbuild/rules_swift#838

When users open the archive, they'll have rich docs they can explore
using Xcode's documentation navigator.

When we update to Xcode 13.4, we'll be able to generate HTML docs with
this approach and publish to the documentation website.

Signed-off-by: JP Simard <jp@jpsim.com>
jpsim added a commit to envoyproxy/envoy-mobile that referenced this pull request Jun 2, 2022
And include in GitHub release artifacts

Updates rules_swift to pull in bazelbuild/rules_swift#838

When users open the archive, they'll have rich docs they can explore
using Xcode's documentation navigator.

When we update to Xcode 13.4, we'll be able to generate HTML docs with
this approach and publish to the documentation website.

Signed-off-by: JP Simard <jp@jpsim.com>
jpsim added a commit to envoyproxy/envoy-mobile that referenced this pull request Jun 3, 2022
And include in GitHub release artifacts

Updates rules_swift to pull in
bazelbuild/rules_swift#838

When users open the archive, they'll have rich docs they can explore
using Xcode's documentation navigator.

When we update to Xcode 13.4, we'll be able to generate HTML docs with
this approach and publish to the documentation website. Here's a demo of
what that static site looks like:
https://envoy-mobile-docc-demo.netlify.app/documentation/envoy/

https://user-images.githubusercontent.com/474794/171704142-993072a3-fbc2-4db6-9c70-65e9e1a47aac.mp4

Risk Level: Low
Testing: Local, CI
Docs Changes: Added
Release Notes: Added

Signed-off-by: JP Simard <jp@jpsim.com>
jpsim added a commit to envoyproxy/envoy that referenced this pull request Nov 29, 2022
And include in GitHub release artifacts

Updates rules_swift to pull in
bazelbuild/rules_swift#838

When users open the archive, they'll have rich docs they can explore
using Xcode's documentation navigator.

When we update to Xcode 13.4, we'll be able to generate HTML docs with
this approach and publish to the documentation website. Here's a demo of
what that static site looks like:
https://envoy-mobile-docc-demo.netlify.app/documentation/envoy/

https://user-images.githubusercontent.com/474794/171704142-993072a3-fbc2-4db6-9c70-65e9e1a47aac.mp4

Risk Level: Low
Testing: Local, CI
Docs Changes: Added
Release Notes: Added

Signed-off-by: JP Simard <jp@jpsim.com>
tymurmustafaiev pushed a commit to tymurmustafaiev/rules_swift that referenced this pull request Jul 19, 2023
That emits the symbol graph for the Swift target to `bazel-bin`.

Symbol graphs can then be fed to tools such as DocC or jazzy to generate
documentation for a target.

For example, for [Envoy Mobile](https://github.com/envoyproxy/envoy-mobile):

```
$ ./bazelw build //library/swift:ios_lib --config=ios
$ "$(xcrun --find docc)" convert \
  --index \
  --fallback-display-name \
  Envoy \
  --fallback-bundle-identifier \
  io.envoyproxy.EnvoyMobile \
  --fallback-bundle-version \
  0.4.6 \
  --output-dir \
  Envoy.doccarchive \
  --transform-for-static-hosting \
  --additional-symbol-graph-dir \
  bazel-bin/library/swift/ios_lib.symbolgraph
```
brentleyjones pushed a commit to bazelbuild/rules_apple that referenced this pull request Sep 7, 2023
# Summary

Closes #1420 

This adds support for building `.doccarchive` for rules_apple targets.
It uses the
[symbol_graph](bazelbuild/rules_swift#838)
feature from `rules_swift` to collect the symbol graph. It then invokes
`xcrun` to find `docc` and create the `.doccarchive`.

Example:

```python
docc_archive(
    name = "HelloWorldSwift.doccarchive",
    dep = ":HelloWorldSwift",
    fallback_bundle_identifier = "com.example.hello-world-swift",
    fallback_bundle_version = "1.0.0",
    fallback_display_name = "HelloWorldSwift",
)
```

Build it:

```sh
bazel build //examples/ios/HelloWorldSwift:HelloWorldSwift.doccarchive
xed  bazel-bin/examples/ios/HelloWorldSwift/HelloWorldSwift.doccarchive
```

Preview the docs:

```sh
bazel run //examples/ios/HelloWorldSwift:HelloWorldSwift.doccarchive
```
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.

5 participants