[Solved] Swift class is not exported in module header for C++

Hi all!
I'm trying the cxx interoperability feature.

I have a Swift file like this.

public class MyClass {
    public func speak() {
        print("Hello, 334")
    }
}

Then, I want to export a module header so that I can use this Swift class from a C++ class. So I executed the following command.

xcrun swiftc -c MyClass.swift -emit-objc-header -module-name MySwiftModule -enable-experimental-cxx-interop

However, the exported module header MySwiftModule.h does not contain MyClass. The exported file ends with the following code.

#if defined(__OBJC__)
#endif
#if defined(__cplusplus)
#endif
#if __has_attribute(external_source_symbol)
# pragma clang attribute pop
#endif
#pragma clang diagnostic pop
#endif

How can I export a Swift class in the module header for C++? Thank you for your help!

(versions)

% xcrun swift -v
Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
Target: arm64-apple-macosx13.0

At the moment you need to annotate the class with the @_expose(Cxx) attribute, and then it should be added to the generated header:

@_expose(Cxx)
public class MyClass {

This requirement will go away in the very near future.

1 Like

Also note that Swift 5.7 does not support this functionality. You will want to try this on a Swift-5.8 or main align toolchain downloaded from swift.org.

1 Like

If that's a practical need and you need it today – you can call swift from C++ (and back) via Obj-C inter-op (the class would have to be NSObject subclass) or via registering swift callback (either as convention (c) with a C function pointer, or a normal if you can tolerate using "blocks" on the C side). Ask here or privately if you are new to this and want to know details of those alternatives.

Using Swift 5.8 toolchain and adding @_expose(Cxx) made the module header contain the Swift class for C++, and I succeeded in calling a Swift class from a C++ class.
Thank you for your advices!

(Just for those who has visited here)
The Swift file became

@_expose(Cxx)
public class MyClass {
    public init() { /* just make it public */ }

    public func speak() {
        print("Hello, 334")
    }
}

The module header generation command is

xcrun --toolchain swift swiftc -c MyClass.swift -emit-objc-header -module-name MySwiftModule -enable-experimental-cxx-interop

And to call the Swift class from a C++ class,

#include "MyCppClass.hpp"
#include "MySwiftModule.h"

void MyCppClass::someFunc() const {
    MySwiftModule::MyClass myObj = MySwiftModule::MyClass::init();
    myObj.speak();
}

Great!

An additional side note, in case you run into this: if you try to call an overriden speak function in the subclass of MyClass, the generated C++ header will not do correct a virtual dispatch through the vtable, and will invoke the base speak function instead. I'm working on fixing this right now ([interop][SwiftToCxx] dispatch Swift class methods correctly using th… by hyp · Pull Request #63560 · apple/swift · GitHub).

1 Like