Falko's Blog

How to use vcpkg with universal binaries on macOS

Vcpkg is a great tool to build the dependencies for your cmake c++ project. Unfortunately - at the time of this writing - it does not support building libraries as universal binaries for macOS.

In this post, I will write about how I used the tool lipo-dir-merge together with vcpkg to install a universal binary version of libcurl. Then I’ll link a simple example app against it.

Installing libcurl via vcpkg

Vcpkg doesn’t support universal binaries yet. However, you can use it to build the x86 and the ARM version of libraries by specifying a triplet. Let’s use this to install the two versions of libcurl:

$ cd /path/to/vcpkg/

$ ./vcpkg install --triplet=x64-osx curl
... Lots of text ...

$ ./vcpkg install --triplet=arm64-osx curl
... Lots of text ...

Vcpkg will install each version of libcurl into a separate directory tree under installed:

$ cd installed
$ ls -1

Merging both versions into a universal binary

Using lipo-dir-merge, we can now merge the content of arm64-osx and x64-osx into a single directory containing the universal binary version of the libraries. lipo-dir-merge does so by traversing both directory trees, copying all files from the first tree. When a static library is encountered, it merges it with the one from the second tree.

While in the /path/to/vcpkg/installed directory, run the following command:

$ python3 /path/to/lipo-dir-merge.py arm64-osx x64-osx uni-osx

Which will create a new uni-osx directory:

$ ls -1

How to use the universal library in a commandline app

This example uses the exmpl-cmake-universal-app project, which links against libcurl and simply prints the version of the curl library upon start. After downloading it, you can use the standard cmake workflow to build the app. Just make sure to include the installed/uni-osx directory in the CMAKE_PREFIX_PATH and set the VCPKG_TARGET_TRIPLET properly.

$ cd /path/to/exmpl-cmake-universal-app
$ mkdir build && cd build
$ cmake -DCMAKE_PREFIX_PATH=/path/to/vcpkg/installed/uni-osx -DVCPKG_TARGET_TRIPLET=uni-osx ..
$ make
$ lipo -info exmpl-app
Architectures in the fat file: exmpl-app are: x86_64 arm64
$ ./exmpl-app 
CURL version is: libcurl/8.2.0-DEV SecureTransport zlib/1.2.13

As you can see from the lipo -info command, the resulting binary is indeed universal.