@_expose attribute not working

In my experiments with the cxx-interop and the latest toolchain (January 28) I tried to expose a Swift function to c++. I found the @_expose attribute is available in this release and compiled an ultra simple Swift library named "MySwiftLib":

// swift-tools-version: 5.7

import PackageDescription

let package = Package(
    name: "SwiftCXXInteropExample",
    platforms: [
        .macOS(.v12),
    ],
    products: [
        .library(name: "MySwiftLib", type: .dynamic, targets: ["MySwiftLib"])
    ],
    dependencies: [],
    targets: [
        .target(name: "MySwiftLib", swiftSettings: [.unsafeFlags(["-enable-experimental-cxx-interop"])])
    ]
)
// Ultra simple Swift library
// file.swift

import Foundation

@_expose(Cxx, "my_exposed_swift_add")
func my_swift_add(a: Int64, b: Int64) -> Int64 {
    return a + b
}

The swift build ran ok and I expected to find the "my_swift_add" function signature in the generated MySwiftLib-Swift.h header and the corresponding c++ symbol in the libMySwiftLib.dylib.

The MySwiftLib-Swift.h contain the library namespace MySwiftLib but not the function signature.

namespace MySwiftLib __attribute__((swift_private)) SWIFT_SYMBOL_MODULE("MySwiftLib") {


} // namespace MySwiftLib

The dylib seems to include only the Swift function mangled signature.

admin@mbam1 debug % nm -gU libMySwiftlib.dylib
0000000000003118 T _$s10MySwiftLib12my_swift_add1a1bs5Int64VAF_AFtF
admin@mbam1 

Whatever I use the @_expose attribute or not make no difference.

Is I miss something ?

Thanks

What happens if you declare the function public? If C++ interop symbol visibility is anything like Obj-C interop (I haven't verified this myself), a declaration needs to be public to be generated into the header file.

Thanks Tony for the hint, public make a difference. The function now appear in the header !

namespace MySwiftLib __attribute__((swift_private)) SWIFT_SYMBOL_MODULE("MySwiftLib") {


inline int64_t my_exposed_swift_add(int64_t a, int64_t b) noexcept SWIFT_SYMBOL("s:10MySwiftLib12my_swift_add1a1bs5Int64VAF_AFtF") SWIFT_WARN_UNUSED_RESULT {
  return _impl::$s10MySwiftLib12my_swift_add1a1bs5Int64VAF_AFtF(a, b);
}

It seem the @_expose attribute is required even if we don't want to expose a different function name.
Now I can go further and try to link and call the function from c++ side.

Thanks !

2 Likes

For those who might be interested. I finally managed to call my simple Swift function from C++ using the lastest toolchain.

#include <iostream>
#include <stdint.h>
#include "MySwiftLib-Swift.h"

int main(int argc, const char * argv[]) {
    
    int64_t result = MySwiftLib::my_exposed_swift_add(2, 7);
    
    std::cout << "Hello, World! " << result << "\n";
    return 0;
}

// output
// Hello, World! 9


A big thank you to the Swift team and the cxx-interop group !!

The upcoming possibilities and benefits from a Swift <-> C++ interop is simply fantastic and opens up a universe of possibilities !!

Will we be able to use for production when Swift 5.8 release ?

1 Like