Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configuration-specific add_custom_command with Xcode generator

Tags:

c++

xcode

cmake

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.

like image 605
DoDo Avatar asked Dec 09 '20 17:12

DoDo


1 Answers

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.

like image 97
DoDo Avatar answered Oct 19 '22 23:10

DoDo