Our project links to a number of pre-compiled 3rd party libraries, for which we set up “find modules” using find_library()
, find_package_handle_standard_args()
, and add_library(... IMPORTED)
.
On macOS some of these libraries come as separate .a files per architecture (x86_64/arm64). How can we link the right library for the architecture when doing a multi-arch build (CMAKE_OSX_ARCHITECTURES = "x86_64;arm64"
)?
In Xcode we link the libraries using -l<libname>
and using $(CURRENT_ARCH)
as part of the library search path, which works because Xcode builds and links each architecture separately and then uses lipo to merge it, but CMake seems to build and link both architectures in one go using multiple -arch
options (at least when using the Ninja and Clang).
Is there any CMake option we could use for this, or is there maybe a linker option that would allow us to specify per-architecture linker search paths?
Two things come to mind:
- use
lipo
to fuse the libraries together; or
- does
-Xarch_x86_64;x86.lib;-Xarch_arm64;arm64.lib
work at all (by manually crafting the command line; CMake won’t know how to generate these flags).
If the latter does work, I suppose that it’d be possible to enhance IMPORTED
target properties to have this, but it doesn’t sound trivial.
What about creating two imported library targets, one per arch that has the correct binary as its IMPORTED_LOCATION
and sets its OSX_ARCHITRCTURES
to only its arch? And then the find module would publicly expose an interface library that links to both of those.
Thanks for the suggestions! I ended up using lipo
to create a multi-arch library from the existing ones via a custom target like this, which works great:
foreach(arch ${CMAKE_OSX_ARCHITECTURES})
find_library(${LIBRARY_NAME}_LIBRARY_${arch}
NAMES ${LIBRARY_NAME}
PATHS ${LIBRARY_DIR}/${arch}
)
list(APPEND arch_libraries "${${LIBRARY_NAME}_LIBRARY_${arch}}")
endforeach()
set(${LIBRARY_NAME}_LIBRARY "${CMAKE_BINARY_DIR}/libs-gen/${LIBRARY_NAME}-multiarch.a")
if(NOT TARGET ${LIBRARY_NAME}_MULTIARCH)
add_custom_target(${LIBRARY_NAME}_MULTIARCH
DEPENDS ${arch_libraries}
BYPRODUCTS ${${LIBRARY_NAME}_LIBRARY}
COMMAND lipo ${arch_libraries} -create -output "${${LIBRARY_NAME}_LIBRARY}"
)
endif()
add_library(${LIBRARY_NAME} UNKNOWN IMPORTED)
add_dependencies(${LIBRARY_NAME} ${LIBRARY_NAME}_MULTIARCH)
set_target_properties(${LIBRARY_NAME} PROPERTIES IMPORTED_LOCATION "${${LIBRARY_NAME}_LIBRARY}")
@benthevining thank you also for your suggestion. I didn’t try it because I had already gotten the above solution working before I saw yours.
1 Like
Does that work? I’m not familiar with that being a thing that works at least… Then again, not something I’ve dealt with much either.
I’m not entirely sure. But that’s the only way I could come up with to possibly express this in cmake today…
AFAIK, CMake is lacking genexes to do any -Xarch_
wrapping of arguments to handle this.
1 Like