C++ interop not working on Linux?

Hello, I've tried using C++ interop with examples provided by Chatgpt.

The long and short of it is, it doesn't compile. The .hpp file is treated like it's a C header file. If I try to use the cxx interop flag in Package.swift, it's rejected, but if I don't the compilation fails.

Given the errors, I asked Chatgpt and it said there was a mismatch between the compiler (6.2.4) and the build system (5.6).

SwiftC++/Sources/CxxTarget/include/MyCppClass.hpp:6:1: error: unknown type name 'class'
|
| class MyCppClass {
| `- error: unknown type name 'class'

Hello! What exactly do you mean by "it's rejected"? I put together a tiny example following the guide, and it works for me on Ubuntu 24 with both 5.10.1 and 6.2.4.

I did notice a little oddity, though: if the umbrella header is named <target>.hpp instead of <target>.h, the compiler seems to include all headers from include directory, which causes errors due to duplicated declarations. Could someone more familiar with C++ interoperability answer, whether this is expected?

1 Like

Thanks, your code does run.

The main problem with my code was that the Package.swift's first line comment referred to swift-tools-version:5.6 instead of 5.9 or 6.2. I was assuming it was just a comment that would be ignored but that was not the case.

After I got the code working, I found a new issue which is that while integers can pass to Swift just fine, const char pointer and std::string pointer both become optionals e.g.

Optional(0x000055a2706365f4)
Optional(0x000055a2b0226610)

I had to do the following to obtain a Swift string from a const char*:
let cppObject = MyCppClass()
let pBuffer = cppObject.sayHello()!
let swiftStr = String (cString: pBuffer);
print (swiftStr)

I see now. C++ interoperability is available since 5.9, so a package manifest with // swift-tools-version:5.6 will not allow using of this feature.
A comment at the top of the package manifest is not a plain comment, but a declaration of Swift tools version which tells SwiftPM how to parse the manifest.

C string is essentially a pointer to char (char *), so it is imported into Swift as, well, a pointer to char (Unsafe[Mutable]Pointer<CChar>). It's optional (implicitly unwrapped actually), because nothing stops you from returning NULL/nullptr from C++ side, and in this case, value of pointer at the Swift side will be nil. It's no different from C interop behavior, which has been around for long already. Generally, C++ raw pointers (not to be confused with Swift Unsafe[Mutable]Raw[Buffer]Pointer, "raw" in this context means simply untyped pointer) by default will be imported into Swift as Unsafe[Mutable]Pointer.

C++ std::string is imported as it is, using std.string type at Swift side. It isn't converted automatically, but can be converted explicitly into and from Swift.String by one simple call to initializer.

The reference guide is worth reading through; it covers such topics in detail.

1 Like

By the way, I'm getting a lot of compiler warnings on Linux for code that isn't mine e.g.

<unknown>:0: warning: '/usr/lib/swift/CFURLSessionInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFXMLInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
/usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/system_error:233:5: note: function 'error_code' unavailable (cannot import)
231 |     : _M_value(0), _M_cat(&system_category()) { }
232 | 
233 |     error_code(int __v, const error_category& __cat) noexcept
    |     |                   `- note: parameter '__cat' unavailable (cannot import)
    |     `- note: function 'error_code' unavailable (cannot import)
234 |     : _M_value(__v), _M_cat(&__cat) { }
235 | 
    :
246 |     error_code& operator=(const error_code&) = default;
247 | 
248 |     void
    |     `- note: function 'assign' unavailable (cannot import)
249 |     assign(int __v, const error_category& __cat) noexcept
    |                     `- note: parameter '__cat' unavailable (cannot import)
250 |     {
251 |       _M_value = __v;
    :
264 |     /// The error category that this error belongs to.
265 |     [[__nodiscard__]]
266 |     const error_category&
    |     |- note: function 'category' unavailable (cannot import)
    |     `- note: return type unavailable (cannot import)
267 |     category() const noexcept { return *_M_cat; }
268 | 
    :
364 | 
365 |     /// Initialize with the specified value and category.
366 |     error_condition(int __v, const error_category& __cat) noexcept
    |     |                        `- note: parameter '__cat' unavailable (cannot import)
    |     `- note: function 'error_condition' unavailable (cannot import)
367 |     : _M_value(__v), _M_cat(&__cat) { }
368 | 
    :
380 | 
381 |     /// Set the value and category.
382 |     void
    |     `- note: function 'assign' unavailable (cannot import)
383 |     assign(int __v, const error_category& __cat) noexcept
    |                     `- note: parameter '__cat' unavailable (cannot import)
384 |     {
385 |       _M_value = __v;
    :
401 |     /// The error category that this error belongs to.
402 |     [[__nodiscard__]]
403 |     const error_category&
    |     |- note: function 'category' unavailable (cannot import)
    |     `- note: return type unavailable (cannot import)
404 |     category() const noexcept { return *_M_cat; }
405 | 

/usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/typeindex:57:5: note: function 'type_index' unavailable (cannot import)
 55 |   struct type_index
 56 |   {
 57 |     type_index(const type_info& __rhs) noexcept
    |     |          `- note: parameter '__rhs' unavailable (cannot import)
    |     `- note: function 'type_index' unavailable (cannot import)
 58 |     : _M_target(&__rhs) { }
 59 | 
<unknown>:0: warning: '/usr/lib/swift/CFURLSessionInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFXMLInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFURLSessionInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFXMLInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFURLSessionInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFXMLInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFURLSessionInterface/module.map' as a module map name is deprecated, rename it to module.modulemap
<unknown>:0: warning: '/usr/lib/swift/CFXMLInterface/module.map' as a module map name is deprecated, rename it to module.modulemap

Is this normal and expected for 6.2.4?