is there a way to exclude @_exported
symbols from symbol graphs?
APIs exposed via @_exported import
are included in the module's symbol graph because they're part of the module's API. You can't opt-out of this behavior right now. Can you elaborate on why you would want to omit symbols that come from @_exported import
?
i need to know which module (and eventually, which package) symbols really belong to. if symbols from ReexportedModule
show up in ImportingModule
, they will be duplicated between the documentation for ReexportedModule
and ImportingModule
.
aside from the duplication, they also have identical USRs, which causes a whole host of problems related to ID collisions. if we solve this problem by uniquing based on symbol ID, then this opens up the possibility that symbols could be “kidnapped” from their original namespace and moved to a package+module scope they are not originally from.
An issue was opened in Swift-DocC to track this as well: `@_exported import`s should not emit symbols from external dependencies · Issue #331 · apple/swift-docc · GitHub.
In the kind of setup the mentioned project has, where a module A export-imports a module B and documentation B is being published independently, it would make sense for DocC to recognize that and instead of re-emitting B's symbols in A's documentation, to instead have A link to B in some way. This is something that should happen automatically when building documentation for multiple targets at once (e.g., via Allow combined documentation of multiple targets · Issue #255 · apple/swift-docc · GitHub).
In cases where you're not building A and B together (e.g., B is dynamically linked), and thus the build system doesn't know whether you'll be publishing documentation for B, it would still be good to provide extra flexibility to exclude B's symbols. @QuietMisdreavus has been toying with the idea of a @_hidden
attribute that you'd attach to @_exported
imports to indicate that the symbols should be excluded from the build.
Hello, is there anything new on that topic? I posted another report in the GitHub issue, that I copy below:
Hello, I meet the same problem, which is that when module A exports module B, DocC includes all symbols of module B in the documentation for module A.
I find this really annoying, given:
- The documentation of the module B is already available on its own.
- The documentation of symbols specific to the module A are very difficult to find in the merged documentation.
In the context of a private local package developed for an application that exports a public library package, this merging has even less meaning. The local package is obviously not the home for the library symbols! In the end, efforts of documenting the local package are hindered by the impossibility to get a focused doc :-/ This is really contrarian to the goals of DocC.
Looking at the Composable Architecture mentioned in the OP, I can see that:
- The documentation hosted on SPI does not show exported symbols: Documentation
- When I download the TCA sources and build the doc with Xcode, exported symbols are visible (this issue).
I could not spot the cause of this difference. No special @
directive in the DocC files. No specific configuration in .spi.yml
.
But my main concern in the Xcode documentation window. Has anyone a clue for hiding exported symbols in the Xcode documentation window?
This is because SPI is using swift-docc-plugin, which is then relying on swift-symbolgraph-extract, and the tool doesn’t really extract re-exported symbols yet (that’s a regression, see apple/swift#59920).
In Swift 5.8+ you can use the @_documentation(visibility:)
annotation to prevent the documentation from being exported.
For older Swift versions, use a dedicated exports.swift
in every target, wrap all @_exported import
s with an #if !BUILD_DOCC
directive, and explicitly import everywhere else. Combining these two is exactly what Vapor did to provide easy access to external utilities while not messing up the documentation.
Thank you @stevapple,
It does not quite work as expected :-)
In Swift 5.8+ you can use the
@_documentation(visibility:)
annotation to prevent the documentation from being exported.
When I do so, building the documentation of an application that imports the said modules generates build errors (from both Xcode 15.0.1 and Xcode 15.1.0-Beta.2).
// In module FlowErrorUI
@_documentation(visibility: internal) @_exported import FlowErrorCore
Errors
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/docc convert...
error: Symbol with identifier 's:13FlowErrorCore03AnyaB7HandlerV' couldn't be found (in target 'FlowErrorUI' from project 'FlowError')
error: Symbol with identifier 's:13FlowErrorCore0aB0C' couldn't be found (in target 'FlowErrorUI' from project 'FlowError')
error: Symbol with identifier 's:13FlowErrorCore03AnyaB7HandlerV' couldn't be found
error: Symbol with identifier 's:13FlowErrorCore0aB0C' couldn't be found
Error: An error was encountered while compiling documentation
I'm not sure what those mangled identifiers are.
For older Swift versions, use a dedicated
exports.swift
in every target, wrap all@_exported import
s with an#if !BUILD_DOCC
directive, and explicitly import everywhere else. Combining these two is exactly what Vapor did to provide easy access to external utilities while not messing up the documentation.
Looks promising The correct condition is
#if !BUILDING_DOCC
, according to this Vapor commit.
This does not work either. Building the doc for the main app still includes undesired symbols in the documentations visible in the Xcode doc viewer. The #error
directive below is not triggered.
#if !BUILDING_DOCC
@_exported import FlowErrorCore
#else
#error("lol")
#endif
You don’t actually hide the documentation in Xcode by doing so. Neither BUILD_DOCC
nor BUILDING_DOCC
is specially recognized by the compiler. They’re just randomly picked flag names that allow CI to opt out of those unwanted documentations. You’re, at least, able to set the flag with xcodebuild
, and whether there’s a way to set it for Xcode IDE is unexplored.
For dealing with Xcode, @_documentation
should be preferred. I failed to convey that even if you chose this path, explicit imports in every file is also required (not for compiling the program, but the documentation). You may first make sure that your program builds with the second approach, and then update the @_exported import
declarations in exports.swift
.
Oh, OK. So this technique does not quite apply when the goal is to have the Xcode documentation viewer avoid displaying the undesired exported documentations.
I failed to convey that even if you chose this path, explicit imports in every file is also required (not for compiling the program, but the documentation).
Even when the importing module explicitly imports the exported module in every one of its files, I still get the same DocC build errors with @_documentation(visibility: internal)
.
Quite a journey, and still not there
This is a known issue, tracked at Documentation Symbol Graph Generation failing on macOS · Issue #69094 · apple/swift · GitHub
You should be able to set a bid flag to hit the other path
i am once again running into this issue when using -emit-symbol-graph
with swift build
. it seems that while swift symbolgraph-extract
(correctly) skips the re-exported symbols, swift build
does no such thing by default.
how do you get swift build
to not duplicate all of these symbols?