Multiplatform Swift, with C++ dependencies via XCFramework, apt and vcpkg

I have a playground project: opinionated ZeroMQ bindings for Swift, szq. Among other things, it is a good excuse to see how far Swift and C++ interop gets across platforms.

ZeroMQ is a C++ library with a C API, and Swift talks to it directly. The library builds and runs its tests on macOS, Linux, and Windows.

The interesting part is not primarily the Swift code, even if it is for me. It is where the C++ dependency comes from on each platform.

One dependency, three sources

The package depends on ZeroMQ, so it needs to be available on every platform. In theory, we could use vcpkg everywhere, and in some scenarios that might be the best choice.

But there is no package manager that is the right choice everywhere. So I do not force one. Each platform uses what fits.

Apple platforms: an XCFramework

For macOS and iOS I use a prebuilt XCFramework that I build and publish myself, libzmq-xcf. It ships as a binary target, so consumers get a working ZeroMQ automatically via SPM, the Swift Package Manager.

I could use vcpkg here too. But on Apple platforms the XCFramework is imho the better solution.

Linux: the system package manager

On Ubuntu and Debian, ZeroMQ is one line away:

apt install libzmq3-dev

The CI runs on Ubuntu 24.04 and does exactly this.

I could use vcpkg , and I may use it in the future. But for Swift on the server, using system packages without the requirement of setting up vcpkg, is a good option.

Windows: vcpkg

It was surprising for me that this even works at all, but I am very excited about it!

Windows does not provide ZeroMQ as a system package, so vcpkg does the job:

vcpkg install zeromq:x64-windows-static-md

The static triplet keeps things simple. With a dynamic build you also have to put the DLL on PATH before the tests can run.

CI

The GitHub Actions workflow is a matrix over the three operating systems. Each job installs the dependency its own way:

  • macOS: nothing, the XCFramework comes via the Swift package manager

  • Linux: apt install libzmq3-dev

  • Windows: set VCPKG_ROOT and the triplet, then install ZeroMQ with vcpkg.

Same Swift code, same tests, three dependency sources.

Multi-platform Swift with interop

Swift and C++ interop can work well across platforms. You do not need one package manager everywhere to make it work even if that is possible with vcpkg, and for Linux and Windows it might make sense to unify the build. For Mac, imho, a XCFramework is always the better solution.

Disclaimer

This post was written by a human. AI has only been used for language polishing.


If you find this page useful, donate a coffee to the C++ user group of Stockholm, SwedenCpp