Skip to content

Add cxx interop support to symbolgraph-extract #7610

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 4 commits into from
Jun 3, 2024

Conversation

rauhul
Copy link
Member

@rauhul rauhul commented May 29, 2024

In order to extract symbol graphs for modules with transitive imports on C++ modules we need parse headers in C++ interop mode using the option: -cxx-interoperability-mode=default. This commit updates swift-symbolgraph-extract to pass the option when there is a C++ module in the import graph.

This option is a new addition to swift-symbolgraph-extract added in swiftlang/swift#73963.

Prior to this option's introduction, extracting the symbol graph for C++ dependent modules would fail with an error similar to: "unknown type name 'namespace'".

With this SwiftPM commit and swift-symbolgraph-extract prior to swiftlang/swift#73963, users will instead see an argument parsing error like: "unknown option -cxx-interoperability-mode".

With this change and swift-symbolgraph-extract change in swiftlang/swift#73963, the symbol graph is extracted properly.

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.

Would you mind adding a test to make sure this doesn't regress in the future/

@MaxDesiatov MaxDesiatov added the needs tests This change needs test coverage label May 30, 2024
Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

This logic mostly duplicates the existing solution that forwards the C++ interop compat version flag to the test discovery target: https://github.com/apple/swift-package-manager/blob/8d419298fe880c44692a757c92ee5ab5d3b6d6f3/Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift#L555-L574

I think it's worth extracting and reusing it.

}
}
if cxxInterop {
commandLine += ["-cxx-interoperability-mode=default"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Some projects use a non-default compat version (e.g. swift-5.9), we should forward the actual version here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I dont see anything in SwiftPM that currents sets a non-"default" value and based on the PackageModel I dont see how a user can even select a "non-default compat version"

Copy link
Member Author

Choose a reason for hiding this comment

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

It seems like this support was removed in #6583

Copy link
Contributor

Choose a reason for hiding this comment

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

It is still possible to pass a custom C++ interop compat version, for example:

            swiftSettings: [
                .unsafeFlags(["-cxx-interoperability-mode=upcoming-swift"])
            ]

@rauhul rauhul force-pushed the cxx-swift-symbolgraph-extract branch 2 times, most recently from 345fe41 to f9bb69f Compare May 31, 2024 00:31
@rauhul
Copy link
Member Author

rauhul commented May 31, 2024

@MaxDesiatov @egorzhdan @daniel-grumberg I've refactored this with (a lot of) guidance from @neonichu, please take another look

@rauhul
Copy link
Member Author

rauhul commented May 31, 2024

Using:

  • This branch rebased on rel/6.0
  • A local copy of swift-symbolgraph-extract with support for cxx interop
  • A local copy of swift-mmio with swift-docc-plugin

Via:

DOCC_EXEC=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/docc SWIFT_EXEC=/Volumes/Developer/org.swift/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/bin/swiftc .build/debug/swift-package --package-path /Users/rauhul/Developer/org.swift/swift-mmio generate-documentation

I am able to properly generate docs.


Running based on main, I see the following errors unrelated to this change:

/Volumes/Developer/org.swift/swift-mmio/.build/arm64-apple-macosx/debug/MMIO-tool.build/module.modulemap:1:8: error: redefinition of module 'MMIO'
module MMIO {
       ^
/Volumes/Developer/org.swift/swift-mmio/.build/arm64-apple-macosx/debug/MMIO.build/module.modulemap:1:8: note: previously defined here
module MMIO {
       ^

When running swift-package dump-symbol-graph, I see a crash in swift-symbolgraph-extract in llvm::DenseMapBase::FindAndConstruct after very deep recursion in Module.cpp::collectExportedImports.

I think both of these issues are unrelated to my change here and should be handled independently.

rauhul added 2 commits May 31, 2024 00:05
In order to extract symbol graphs for modules with transitive imports on
cxx modules we need parse headers in cxx mode using the option:
`-cxx-interoperability-mode=default`. This commit updates
`swift-symbolgraph-extract` to pass the option when there is a Cxx
module in the import graph.

This option is a new addition to `swift-symbolgraph-extract` added in
swiftlang/swift#73963.

Prior to this option's introduction, extracting the symbol graph for cxx
dependent modules would fail with an error similar to:
"unknown type name 'namespace'".

With this SwiftPM commit and `swift-symbolgraph-extract` _prior_ to
73963, users will instead see an argument parsing error like: "unknown
option -cxx-interoperability-mode".

With this change and `swift-symbolgraph-extract` 73963, the symbol graph
is extracted properly.
@rauhul rauhul force-pushed the cxx-swift-symbolgraph-extract branch from 4dcd4e4 to 9e5cfa2 Compare May 31, 2024 07:10
Comment on lines 639 to 640
/// If the current module or any of its linked dependencies requires cxx
/// interop, cxx interop will be enabled on the current module.
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't actually want to implicitly enable C++ interop for anything other than the test discovery target or the symbolgraph target.
One of the reasons for that is that C++ interop is incompatible with Swift's library evolution. If a dependency of your project uses C++ internally, without re-exporting any C++ symbols, you don't need to enable C++ interop and can keep library evolution enabled.

Comment on lines 1984 to 1987
try XCTAssertMatch(
result.target(for: "swiftLib2").swiftTarget().compileArguments(),
[.anySequence, "-cxx-interoperability-mode=default", "-Xcc", "-std=c++20", .anySequence]
)
Copy link
Contributor

Choose a reason for hiding this comment

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

This assertion needs to be reversed: unless the Swift target explicitly enables C++ interop, we should not pass these flags to the compiler.

@rauhul
Copy link
Member Author

rauhul commented May 31, 2024

@swift-ci test

@rauhul
Copy link
Member Author

rauhul commented May 31, 2024

@swift-ci smoke test

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

LGTM from the perspective of C++ interop.
I would probably wait for someone from the SwiftPM side of things to give a thumbs up as well before merging 😉

Comment on lines +633 to +636
var args = [String]()
args += try self.cxxInteroperabilityModeArguments(
propagateFromCurrentModuleOtherSwiftFlags: true)
return args
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be simplified to just return self.cxxInteroperabilityModeArguments(propagateFromCurrentModuleOtherSwiftFlags: true)?

Copy link
Member Author

Choose a reason for hiding this comment

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

A follow up PR adds to args so I'd like to leave this as is


/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
public func symbolGraphExtractArguments() throws -> [String] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public func symbolGraphExtractArguments() throws -> [String] {
package func symbolGraphExtractArguments() throws -> [String] {


/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
public func symbolGraphExtractArguments() throws -> [String] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public func symbolGraphExtractArguments() throws -> [String] {
package func symbolGraphExtractArguments() throws -> [String] {

@@ -207,6 +207,20 @@ public final class ClangTargetBuildDescription {
}
}

/// Determines the arguments needed to run `swift-symbolgraph-extract` for
/// this module.
public func symbolGraphExtractArguments() throws -> [String] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public func symbolGraphExtractArguments() throws -> [String] {
package func symbolGraphExtractArguments() throws -> [String] {

@rauhul
Copy link
Member Author

rauhul commented Jun 3, 2024

@MaxDesiatov do you mind if I fix the public -> package change in my follow up PR here #7621

func cxxInteroperabilityModeAndStandard(
for module: ResolvedModule
) -> [String]? {
let scope = self.buildParameters.createScope(for: module)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this correct to use buildParameters of the context here for dependency scopes? What if if this i.e. executable target that has a plugin or a macro dependency and that in turn has other dependencies, we'd use "destination" parameters for their scope, which seems counter-intuitive?

It seems like we need to avoid adding new uses of recursiveTargetDependencies() in this context when build parameters are involved, because they are strongly connected to a destination, and instead traverse a build plan graph and use TargetDependencyDescription.

Copy link
Member Author

@rauhul rauhul Jun 3, 2024

Choose a reason for hiding this comment

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

I'd rather not change this logic in this PR, im simply moving the existing code such that symbol graph can use it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, I'm mentioning this because of the comment - Move logic from PackageBuilder here., I don't think that would be possible to do because of this.

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess the point of that comment is to say, we should not throw away the typed interop information at that layer and try to recover it here by parsing flags, we should instead determine the flags at this layer

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe you could do the same thing as .SWIFT_VERSION and add a new declaration for assigments like that which means that you won't need to deal with prefixes here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't mean it has to be in this PR, just an idea how to avoid having to prefix match things...

Copy link
Contributor

@xedin xedin left a comment

Choose a reason for hiding this comment

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

Conditional onpackage changes Max suggested.

@rauhul rauhul merged commit 73b0b26 into main Jun 3, 2024
5 checks passed
@rauhul rauhul deleted the cxx-swift-symbolgraph-extract branch June 3, 2024 17:58
rauhul added a commit that referenced this pull request Jun 12, 2024
In order to extract symbol graphs for modules with transitive imports on
C++ modules we need parse headers in C++ interop mode using the option:
`-cxx-interoperability-mode=default`. This commit updates
`swift-symbolgraph-extract` to pass the option when there is a C++
module in the import graph.

This option is a new addition to `swift-symbolgraph-extract` added in
swiftlang/swift#73963.

Prior to this option's introduction, extracting the symbol graph for C++
dependent modules would fail with an error similar to: "unknown type
name 'namespace'".

With this SwiftPM commit and `swift-symbolgraph-extract` _prior_ to
swiftlang/swift#73963, users will instead see an argument parsing error
like: "unknown option -cxx-interoperability-mode".

With this change and `swift-symbolgraph-extract` change in
swiftlang/swift#73963, the symbol graph is extracted properly.
rauhul added a commit that referenced this pull request Jun 13, 2024
In order to extract symbol graphs for modules with transitive imports on
C++ modules we need parse headers in C++ interop mode using the option:
`-cxx-interoperability-mode=default`. This commit updates
`swift-symbolgraph-extract` to pass the option when there is a C++
module in the import graph.

This option is a new addition to `swift-symbolgraph-extract` added in
swiftlang/swift#73963.

Prior to this option's introduction, extracting the symbol graph for C++
dependent modules would fail with an error similar to: "unknown type
name 'namespace'".

With this SwiftPM commit and `swift-symbolgraph-extract` _prior_ to
swiftlang/swift#73963, users will instead see an argument parsing error
like: "unknown option -cxx-interoperability-mode".

With this change and `swift-symbolgraph-extract` change in
swiftlang/swift#73963, the symbol graph is extracted properly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C++ interop needs tests This change needs test coverage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants