Annotating a module as C-only?

As we've been trying to use C++ interop a bit more, we've found a situation where we were surprised that a downstream module (which declares C interop mode, node C++) would be compiled with a C++ context which causes a bunch of breakage for us.

Is it intended that a consuming library can redefine the context that a consumed library is built with? This seems like it could cause a ton of issues for downstream libraries that are actually not intended to be compiled with a C++ context at all. I've created a small repository to demonstrate the situation here.

Is there some what to say that a given target is C-only even when it is being consumed by a target that requires C++ interop? I've tried noodling with the module map in the C-only target but that doesn't seem to do much, however I'll be the first to admin that my modulemap knowledge is pretty low.

Looking forward to the discussion, thanks!

When C++ interoperability is turned on, the compiler imports all C-based language dependencies needed by the target using either the C++ or the Objective-C++ language mode. There's currently no way to mark a dependency as C only, as the compiler can only import dependencies in one interoperability mode. We have started thinking about some alternative solutions where the compiler could treat some dependencies as C or C++ only. It's probably technically solvable, however, we're not currently prioritizing fixing this issue.

As it stands today, there's currently no perfect solution to the situation where an external dependency requires C because of this. Some existing Swift packages need to adapt their headers to be compatible with C++ mode, and some have started doing that already.

1 Like

Got'cha, thanks @Alex_L. We are in the position where bridging certain things from Windows creates a larger shock since the Windows headers have very different types/signatures when __cplusplus is defined. Glad to know there are some folks thinking about this, but for the time being it sounds like our only option is really to just ensure that we handle the C and CPP types.

One last question @Alex_L... should we expect the interop flag to be super viral?

Meaning if we have an main package which does not declare any interop status which relies on two other packages (A and B) where package B does have a library or two which declare the need for C++ interop, but package A's libraries have no interop specification, should I expect any dependencies in package A to be compiled with interop enabled by default since things in package A need it?

I would find that, a bit surprising, but I could reasonably understand that if something in package B declared interop needs that all of it's dependencies are compiled with C++ interop in mind. We are observing the behavior where we turn interop on in very specific libraries, but for some reason see C++ issues in a totally different package which is included by something which does not declare an interop status.

Package A does not need to have interoperability enabled, but the main package must have C++ interoperability enabled to be able to use B, as using C++ interoperability is viral. Once main enables C++ interoperability, the C-based dependencies of A will be imported in C++ mode as well as Main needs to import A, and thus transitively it needs to import C-based dependencies of A. Basically, when you're building A by itself, the headers that A imports do not need to support C++, however, once you start importing A into Main, then the headers that A imports must support C++ as well.

1 Like