Skip to content

Add macOS universal binary support - #735

Open
occash wants to merge 1 commit into
conan-io:develop2from
occash:feature/macos-universal-binaries
Open

Add macOS universal binary support#735
occash wants to merge 1 commit into
conan-io:develop2from
occash:feature/macos-universal-binaries

Conversation

@occash

@occash occash commented Jul 23, 2026

Copy link
Copy Markdown

Motivation

Universal macOS builds currently get a warning from the provider, and the build only links if every dependency happens to be universal. Conan 2.2.0's preliminary fat binaries support helps, but not every recipe supports it (OpenSSL is the usual blocker). The Conan docs themselves call one binary per architecture the more reliable path. This PR automates that path: one conan install per architecture merged with lipo.

How it works

The PR adds one new option, CONAN_OSX_UNIVERSAL_BINARIES, off by default. Nothing changes unless it is enabled:

cmake -B build -S . -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=[path-to]/conan_provider.cmake \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
      -DCONAN_OSX_UNIVERSAL_BINARIES=ON

With the option on and two architectures requested, the provider does three things:

  1. It runs conan install twice, once per architecture.
  2. Each install copies its dependencies into the build directory using Conan's full_deploy deployer. This also makes the generated CMake files point at those copies instead of the Conan cache.
  3. It merges the second architecture's copy into the first one (the primary) in place with lipo. After that, everything find_package resolves is universal.

The merge handles each file by case:

  • identical on both sides (most headers, resources, prebuilt universal artifacts): shared from the primary tree as-is
  • Mach-O: lipo -create into the primary counterpart, with the expected slices verified before and after each merge
  • generated headers that legitimately differ per architecture replaced by a small __aarch64__/__x86_64__ dispatcher, with both variants kept alongside
  • headers or binaries that exist for only one architecture: errors

Repeated configures skip the installs and the merge while nothing relevant changed. A quick conan lock create probe re-resolves the dependency graph each configure, so updated pins and version ranges are picked up, and everything else (conanfile, profiles, install arguments) is hashed into a small stamp file. The probed lockfile also feeds both installs, which guarantees the two architectures resolve identical versions. Delete <build>/conan-universal-stamp.txt to force a rerun.

Requires Conan 2.1.0 or later. macOS targets only, and exactly the arm64 plus x86_64 pair. Anything else fails with a clear message.

@CLAassistant

CLAassistant commented Jul 23, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@memsharded memsharded left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @occash

Thanks very much for your contribution!

I have been checking with the team, and at the moment this seems to add a lot of new code and complexity to maintain for the use case, so it wouldn't be planned to add it as is, here in the cmake-conan functionality.

It sounds that decoupling or dividing the problem into pieces would be a bit more approachable. There is already some work in conan-io/conan-extensions#58, not sure why it wasn't followed up, likely it is on our side because of not enough priority (deployers can also be user-defined, so not a priority to provide our own deployers).

The good news is that the providers doesn't need to be built-in, as the best approach is actually to have a copy in your repos, then it is very easy to work with a fork of cmake-conan for the functionality you need, so if you need this for your projects just working with your conan_provider.cmake fork is trivial.

@occash

occash commented Jul 27, 2026

Copy link
Copy Markdown
Author

Thanks for checking with the team and for the clear explanation. Makes sense. We are maintaining our own conan_provider.cmake copy internally, so the fork approach works for us.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants