Link shared library with Swift

I have a s hared library in C++ that was built with GNU Libtool, and I want to bundle it with my Swift app and call it from the app. How can I bundle it and call it?

Answered by DTS Engineer in 841504022

There are two parts to this:

  • Calling C++ from Swift.

  • Embedding a dynamic library in your app.

Modern versions of Swift have the ability to call C++ code directly. See Swift > Mixing Swift and C++. There are a wide range of caveats, but the biggest one is that the C++ headers must be modular. That’s not all that common and, if it’s not the case here, you’ll need to sort that out first.

As to how you bundle a built library in your app, that very much depends on what platform you’re targeting. Is this macOS? Or iOS? Or both?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

There are two parts to this:

  • Calling C++ from Swift.

  • Embedding a dynamic library in your app.

Modern versions of Swift have the ability to call C++ code directly. See Swift > Mixing Swift and C++. There are a wide range of caveats, but the biggest one is that the C++ headers must be modular. That’s not all that common and, if it’s not the case here, you’ll need to sort that out first.

As to how you bundle a built library in your app, that very much depends on what platform you’re targeting. Is this macOS? Or iOS? Or both?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I’m targeting macOS for this particular app.

Accepted Answer

Thanks for confirming that.

The platform matters because third-party dynamic libraries are only supported on macOS. On iOS and its child platforms you can’t share a .dylib. You have wrap it up as a .framework, which complicates things.

I think your best path forward here is gonna be:

  1. Modularise the headers.

  2. Build an XCFramework containing those headers and your pre-built .dylib.

  3. Either use the XCFramework directly, or wrap it up as a Swift package with a binary artefact (per SE-0272).

An alternative path would be to create a Swift package for the C++ source code and then build everything that way. That offers more flexibility, but you have to figure out how to build the code outside of its native build system, which could be challenging.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Two questions:

  1. Is it a problem if my shared library has a .so extension?

  2. I’m curious: how could I do this with a multiplatform SwiftUI app that runs on iOS and macOS? how would the code be packaged into a .framework file?

Is it a problem if my shared library has a .so extension?

On the Mac, no. It’s weird though. And you’re gonna have to do sufficient customisation here that changing the file name extension will be the least of your problems (-:

On iOS, shared libraries are not supported [1] regardless of their extension.

how would the code be packaged into a .framework file?

It’s not a file but a bundle structure. Notably, the bundle structure is different on iOS and macOS. See Placing Content in a Bundle.

There isn’t a specific tool that wraps a shared library as a framework. Most folks create frameworks using Xcode. If you’re using an external build system, my general advice is that you do what Xcode does. In fact, the way I usually handle this is to create a Xcode project for the framework, built it, and then copy the structure that Xcode generated.

IMPORTANT That doesn’t mean building your final framework with Xcode. Rather, it’s about using Xcode to generate a framework that you can use as a template.

Note that Xcode knows the correct layout for iOS and macOS and will do the right thing depending on the target platform.

Finally, if you’re heading off down this path it’s very likely you’ll need the conceptual underpinnings from An Apple Library Primer. It includes a reference to Dynamic Library Identification, which is gonna be important.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Specifically, iOS supports:

  • Third-party shared libraries embedded within a framework bundle.

  • Embedded Swift system libraries

The latter is only relevant if you target systems prior to iOS 12.3 or earlier.

Would it be easier to create a static library and use that instead of using a shared library?

Would it be easier to create a static library … ?

In some respects yes, but mostly no.

A static library certainly helps on the iOS side of things. The resulting code gets linked directly into the client, so you don’t have to worry about putting it into a .framework wrapper.

You can also create a mergeable library, which can be used as either a dynamic library or a shared library. I have links to info about that in An Apple Library Primer.

However, it doesn’t help with other stuff. You still need to modularise your headers and find a way to get Swift to use that module.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

How exactly would I modularize my headers?

See the Clang > Modules documentation.

https://clang.llvm.org/docs/Modules.html

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Link shared library with Swift
 
 
Q