Universal Binaries contain native instructions for multiple target architectures like x86_64 and arm64 to run your app both on Intel Mac and Apple silicon machines. When using Conan there are a few common build systems, or native build tool generators, when creating packages from the Conan Center Index(CCI) like: CMake, Autotools, Pkgconfig, b2 (Boost Build) and Make. Some of these build tools have build-in support when it comes to building Universal Binaries.
Lets start with some of the easy examples how to enable Universal builds in conan.
CMake
The CMake toolchain generator exposes the CMAKE_OSX_ARCHITECTURES flag to set the target architectures.
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
from conan.tools.apple import is_apple_os
class PackageConan(ConanFile):
def generate(self):
tc = CMakeToolchain(self)
if is_apple_os(self):
tc.blocks["apple_system"].values["cmake_osx_architectures"] = "x86_64;arm64"
tc.generate()
Autotools
Autotools allows you to set the target architectures via extra_cflags
.
from conan import ConanFile
from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.apple import is_apple_os
class PackageConan(ConanFile):
def generate(self):
tc = AutotoolsToolchain(self)
if is_apple_os(self):
tc.extra_cflags.append("-arch x86_64 -arch arm64")
tc.generate()
Other build tools
For other build tools that, I am less experienced with or have not found an easy solution for, I wrote a wrapper Conan recipe. This wrapper Conanfile takes the build output of a x86_64 and armv8 package and combines them using lipo
.
A script writes the hashes of the built packages that will be combined to a json file. When building the “universal” conan recipe it loads the json files and combines the build output of those two packages, for example “arch=x86_64 AND build_type=Release” with “arch=armv8 AND build_type=Release”, in a temporary directory that will be merged with the package_folder once done. The advantage of this approach is that you can update the original recipe from CCI without migrating the universal binaries merge logic to the updated recipe.
See this Github Gist for the conanfile template.
Verifying Universal Binaries output
cd ~/.conan/data/<packagename>/_/_/package/<hash>/lib
lipo -archs <libname>.a
# x86_64 arm64
lipo -archs <libname>.dylib
# x86_64 arm64