Import of C++ module appears within extern "C" language linkage specification

I am trying to mix a C library and a C++ library inside the same Swift package. In one of my C dependencies, there is an "ifdef cplusplus extern C" block surrounding the whole header.

This upsets Swift, erroring out with import of C++ module 'CGlad' appears within extern "C" language linkage specification. It then points to where the extern C block is in the header.

If I replace all my swiftSettings: [.interoperabilityMode(.Cxx)] blocks with swiftSettings: [.interoperabilityMode(.C)] then the C library works fine.

Is mixing C and C++ not supported? Or is that extern C block not supposed to break Swift?

I think @hyp can speak to the latter, but you will encounter differences of LinkageSpecDecls aka extern "C" a lot in code when importing with C++-Interop. We have fixed several bugs related to this over the last year+.

Clang (and Swift by extension) typically allow you to use extern "C" specifiers in C++ headers when you need to mix C and C++. However, certain #include directives inside of extern "C" blocks might be prohibited, like in your case. This is intentional, as in that case an #include doesn't textually include the referenced header file, but rather it loads up a module that was already parsed using the C++ language mode for the referenced header.

The code for the C dependency that's breaking you should be fixed. All the #include directives used by the headers should be moved outside of the extern "C" block. It might also be necessary to "sink" the extern "C" specifier into the sources of the included headers themselves instead. That should resolve the issue.

1 Like

Indeed, since it's generated code I was able to copy paste the whole included header in place of the include directive and it works. I get that when importing a C module, the include directives don't actually include the file as they would normally. I'll keep that in mind thanks!

1 Like

I am now trying to write unit tests for my library that depends on C++ code.

When I make an executable it works fine, however in the test target I have the following error:

/home/natinusala/Crayon/Sources/CCrayon/include/graphics.h:19:8: error: expected identifier or '('
extern "C" void gladLoadGLLoaderFromGLFW();

The library, executable and test targets all have .interoperabilityMode(.Cxx) in swiftSettings. However it looks like the test target is compiled with C interop instead...?

Am I missing something? Or are test targets not compatible with CXX interop yet?

1 Like