Skip to content

Instantly share code, notes, and snippets.

@ovaar
Last active February 13, 2024 10:09
Show Gist options
  • Save ovaar/2106071841f1e917f89d10f6d3095638 to your computer and use it in GitHub Desktop.
Save ovaar/2106071841f1e917f89d10f6d3095638 to your computer and use it in GitHub Desktop.
Conan Macos Universal Binaries recipe
from conan import ConanFile
from conan.tools.apple import is_apple_os
from conans import tools
from conan.errors import ConanException
from pathlib import Path
import os
import glob
import shutil
import json
class OsxUniversalConan(ConanFile):
name = "{PACKAGE_NAME}"
version = "{PACKAGE_VERSION}"
url = "None"
license = "None"
settings = "os", "arch", "compiler", "build_type"
no_copy_source = True
_config_cache=None
@property
def osx_multi_archs(self):
if self._config_cache is None:
path = self.lipo_folder / "config.json"
_config_cache = json.loads(path.read_text())
return _config_cache
@property
def osx_archs(self):
return list(self.osx_multi_archs.keys())
@property
def osx_revisions(self):
return list(self.osx_multi_archs.values())
@property
def universal_folder(self):
return os.path.join(self.package_folder, "universal")
def lipo(self, filepath):
lipo_args = []
# lipo -create -arch arm64 $dylib -arch x86_64 x86_64/$(basename $dylib) -output package_folder/$(basename $dylib);
for arch, rev in self.osx_multi_archs.items():
abs_path:Path = Path(self.lipo_folder) / rev / filepath
abs_path.resolve()
lipo_args.append(f"-arch {tools.to_apple_arch(arch)} {str(abs_path.resolve())}")
output_file:Path = Path(self.package_folder) / filepath
if output_file.exists():
output_file.unlink()
cmd = f"lipo -create {' '.join(lipo_args)} -output {str(output_file.resolve())}"
self.output.info(cmd)
self.run(cmd)
def package(self):
if not is_apple_os(self):
raise ConanException("Universal OSX binaries can only be built on macos!")
# pkgName/package/.lipo/
self.lipo_folder=Path(self.package_folder) / ".." / ".lipo"
if not self.lipo_folder.exists():
raise ConanException("Failed to create Universal Binary package, '.lipo' temporary folder does not exist!")
src:Path = self.lipo_folder / self.info.package_id()
# Conan clears the package_folder, so copy the .lipo temporary directory
shutil.copytree(src=str(src), dst=self.package_folder, dirs_exist_ok=True)
self._lib_files=glob.glob(f"{str(src)}/lib/**/*.a", recursive=True)
self._lib_files.extend(glob.glob(f"{str(src)}/lib/**/*.dylib", recursive=True))
for i, f in enumerate(self._lib_files):
self._lib_files[i] = os.path.relpath(f, str(src))
# Run lipo to combine packages
for filename in self._lib_files:
self.lipo(filename)
def package_info(self):
self.cpp_info.includedirs = ["include"]
self.cpp_info.libs = tools.collect_libs(self)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment