Importing C++ methods that return `const char *` without modifying headers?

Hello all!

As I start working with C++ interop, I've run up against a chafing point. C++ methods which return const char * are inaccessible by default; attempting to call one will throw a compiler error:

error: value of type 'lldb.SBPlatform' has no member 'GetName'
note: C++ method 'GetName' that returns a pointer of type 'Optional' is unavailable

This does make sense, since the Swift compiler cannot guarantee that the pointer returned isn't dependent on the lifetime of the receiver and whatnot.

The C++ interop docs briefly mention the SWIFT_RETURNS_INDEPENDENT_VALUE annotation as a potential way around this, by marking explicitly that a method returns a pointer that is safe in this circumstance.

However, here's my issue: I'm wrapping an existing C++ library (via SPM's .systemLibrary(); specifically, LLDB's public API). I could annotate all of the methods which return const char * strings (which is a lot of methods; LLDB uses them everywhere.) But it'd be great if I didn't need to modify the headers themselves, in cases where I update the headers over time from upstream changes.

I had hope that the APINotes functionality in Clang for Swift/ObjC interop would help here, but it doesn't seem that anything within that feature will work. I don't see any way to add compiler attribute annotations from APINotes, and the docs for them in both the Clang documentation and Swift repository documentation don't even mention C++ (which is understandable).

Okay, all that aside, finally my question: Is there a good way to make such APIs available via C++ interop without modifying the original headers, or will I just need to start wrapping these APIs in either additional C++ or C wrappers?

(note: LLDB's APIs may not be safe to annotate with SWIFT_RETURNS_INDEPENDENT_VALUE in this circumstance, I haven't checked its implementation yet; so this might be moot anyway, unless there's additional annotations that can help.)

Thanks, y'all!

1 Like

Out of curiosity what sort of lldb plugin are you building with Swift? I have a mostly complete one on the svd2lldb branch of apple/swift-mmio for register debugging

Not so much plugin, but a CLI tool that provides a Debug Adapter Protocol wrapper for LLDB (not to be confused with lldb-dap).

It's used in the Swift / C / C++ / ObjC extension for Nova, and powers its debugging support with LLDB. I'd previously wrapped the LLDB C++ API with ObjC++, then used that from Swift. But the hope of moving all of the code to Swift now that we have C++ interop is an exciting prospect.

You don’t have to modify the original headers, you could add your own headers.

You don’t have to modify the original headers, you could add your own headers.

Yes, totally possible. Since I'm using it via an SPM .systemLibrary() target, I could rewrite the headers being included.

However, I was hoping to avoid that if at all possible since from time to time I'll need to sync up those headers with the upstream LLDB project. They don't change that often, but re-applying the bridging annotations every time is something I'd rather avoid if I can.

If I can't avoid it, then that is likely the best path for including the bridging annotations. I was just hoping there was some mechanism in place in the toolchain as it stands similar to APINotes that would help out here. :smiley: