Updated plan for supporting C++ interoperability in Swift package manager in the Swift 5.9 release

The initial pitched plan for how C++ interoperability should be support in Swift package manager in Swift 5.9 uncovered several issues. Most notably we do not have any officially supported feature that lets a Swift module import a C++ module without exposing that fact to its dependencies. As such, any client that wants to import a Swift target that enables C++ interoperability must also enable C++ interoperability. Unfortunately after some discussions we reached the conclusion that we will not be able to provide an alternative solution for this issue in Swift 5.9 . Therefore, I would like to propose a new, more limited plan for how C++ interoperability is going to be supported in Swift 5.9 .

Proposed guidance

Here's the updated proposed guidance we would like to document on the Swift website:

Enabling C++ interoperability for a SwiftPM target will need other targets that depend on such a target to enable C++ interoperability as well.

If you’d like to vend a package with a target that enables C++ interoperability, we recommend:

  • Communicating to clients that they have to enable C++ interoperability when depending on targets from such package.

  • Bumping up the major version, if you adopt C++ interoperability in an existing package. This will avoid breaking existing clients of the package.

Here's a target diagram illustrating how C++ interoperability will propagate through a Swift PM target graph:

Getting there in Swift 5.9

In Swift 5.9, We would like to augment the Swift compiler to always report an error when a Swift module that doesn't have C++ interoperability enabled imports another Swift module that has C++ interoperability enabled, except if the imported module is built with library evolution enabled.

Additionally, we still require the following SwiftPM fix:

Vision for beyond Swift 5.9

In order to allow a Swift target to import C++ clang modules without forcing C++ interoperability onto the dependencies of such Swift target, we would like to see Swift officially support the following features:

  • internal imports.
  • resilience / library-evolution support for all supported platforms.
    • build setting that enables it in SwiftPM as well.

This request is tracked by the following tracking issue on GitHub:

Summary

The C++ interoperability workgroup investigated potential options for supporting C++ interoperability in SwiftPM in Swift 5.9 . After getting the feedback on the initial plan, we've put together an updated proposed guidance for SwiftPM. This guidance clearly states the constraints imposed by C++ interoperability, most notably that Swift package manager targets that enable C++ interoperability force their dependencies to enable C++ interoperability as well.

10 Likes

An important note about the impact of this is that packages cannot transparently add C++ modules without breaking changes. That is, adding C++ to a module must be done in a semver major. I think that's fine, we should just make sure we're clear about that requirement.

3 Likes

I worry that “internal imports” are not going to solve the problem either, because of debugging. In the debugger, the expression evaluator gets a single context by default, which is supposed to work for any frame you stop in with debug info. Will that context have C++ enabled or not? Library evolution mode does not solve this problem; it’s all about debug info.

2 Likes

I believe that debugging is already a problem, as you now can import a module that doesn't enable interoperability into something that does enable interoperability, and as such the debugger has to deal with ambiguities there today. Some of the debugging experts in the C++ interoperability workgroup (@augusto2112 , @Adrian_Prantl) have ideas for how LLDB could potentially handle this in the future.

2 Likes