I want to create a custom command that will merge all static libraries into a fat static library using Apple's libtool
command during build. I'm using Xcode generator and CMake 3.19.1. My script is like this:
set( TARGET_OUTPUT_NAME ${CMAKE_BINARY_DIR}/fat-libs/${CMAKE_CFG_INTDIR}/lib${libname}.a )
add_custom_command(
OUTPUT
${TARGET_OUTPUT_NAME}
COMMAND
/usr/bin/libtool -static -o ${TARGET_OUTPUT_NAME} $<TARGET_FILE:${libname}>
$<$<CONFIG:Debug>:${all_dependencies_debug}>
$<$<CONFIG:Release>:${all_dependencies_release}>
DEPENDS
${libname}
COMMENT
"Building merged static library"
)
add_custom_target( ${TARGET_NAME} DEPENDS ${TARGET_OUTPUT_NAME} )
libname
is the name of the target whose dependencies for debug and release are collected into all_dependencies_debug
and all_dependencies_release
lists and should be merged. The contents of those lists may contain actual paths to static libraries or generator expressions (in case dependency is another target, either real or imported).
However, this generates the following script in Xcode:
#!/bin/sh
set -e
if test "$CONFIGURATION" = "Debug"; then :
cd /path/to/build/folder
/usr/bin/libtool -static -o /path/to/build/folder/fat-libs/$CONFIGURATION$EFFECTIVE_PLATFORM_NAME/libMyLib.a /path/to/build/folder/Debug/libMyLib.a $<1:/path/to/first/debug/libSomething.a /path/to/second/debug/libSomething.a> $<0:/path/to/first/release/libSomething.a /path/to/second/release/libSomething.a>
fi
if test "$CONFIGURATION" = "Release"; then :
cd /path/to/build/folder
/usr/bin/libtool -static -o /path/to/build/folder/fat-libs/$CONFIGURATION$EFFECTIVE_PLATFORM_NAME/libMyLib.a /path/to/build/folder/Release/libMyLib.a $<0:/path/to/first/debug/libSomething.a /path/to/second/debug/libSomething.a> $<1:/path/to/first/release/libSomething.a /path/to/second/release/libSomething.a>
fi
This, of course, fails during build because xcode throws syntax error
when parsing $<1:
.
I've also tried adding VERBATIM
, but this only causes $
to be escaped.
Is this a bug in CMake Xcode generator or did I do something wrong?
I've also tried using older versions of CMake (3.18.4), which don't support Modern Apple Build System, but to no avail.
CMake documentation states that COMMAND
part of add_custom_command
should be able to use generator expressions.
Actually, the trick is in using COMMAND_EXPAND_LISTS
.
As explained in this CMake gitlab issue, the correct CMake script is:
set( TARGET_OUTPUT_NAME ${CMAKE_BINARY_DIR}/fat-libs/${CMAKE_CFG_INTDIR}/lib${libname}.a )
add_custom_command(
OUTPUT
${TARGET_OUTPUT_NAME}
COMMAND
/usr/bin/libtool -static -o "${TARGET_OUTPUT_NAME}" "$<TARGET_FILE:${libname}>"
"$<$<CONFIG:Debug>:${all_dependencies_debug}>"
"$<$<CONFIG:Release>:${all_dependencies_release}>"
DEPENDS
${libname}
COMMENT
"Building merged static library"
VERBATIM
COMMAND_EXPAND_LISTS
)
add_custom_target( ${TARGET_NAME} DEPENDS ${TARGET_OUTPUT_NAME} )
First, all parameters must be given in double quotes, in order to ensure that spaces and ;
separator in list are passed through to the add_custom_command
.
Next, the COMMAND_EXPAND_LISTS
will make sure that list given via generator expression (i.e. "$<$<CONFIG:Debug>:${all_dependencies_debug}>"
) will be properly expanded - without this, the semicolons would end-up in the final Xcode build phase script.
Finally, the VERBATIM
is needed to properly escape all other characters that may confuse the Xcode phase build script.
Thank you Brad King for your quick help and response at gitlab issues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With