Home > database >  VS16 doesn't expand CMake generator expressions
VS16 doesn't expand CMake generator expressions

Time:07-11

I'm using CMake for generating cross-platform build configuration. And for project to work I need to copy additional precompiled libraries to binaries directory. So, I use such script to build this project:

cmake_minimum_required(VERSION 3.17)
project(foo)

add_executable(bar foobar.cpp)

# Doing some logic to find library files... 
list(APPEND DBG_LIBRARIES_LIST "lib1" "lib2")
list(APPEND REL_LIBRARIES_LIST "lib1" "lib2")

# Joining all libraries with " " character to be parsed as different program arguments
list(JOIN DBG_LIBRARIES_LIST " " DEBUG_LIBRARIES)
list(JOIN REL_LIBRARIES_LIST " " RELEASE_LIBRARIES)

add_custom_command(TARGET bar POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<IF:$<CONFIG:Debug>,${DEBUG_LIBRARIES},${RELEASE_LIBRARIES}>
        $<TARGET_FILE_DIR:estareng>
)

After I generate such project on Windows using VS16 my post-build events contain such line:

cmake -E copy_if_different "lib1 lib2" some\proj\dir

If I try to join list using $<JOIN:$<IF:$<CONFIG:Debug>,${DEBUG_LIBRARIES_LIST},${RELEASE_LIBRARIES_LIST}>," "> I just get raw generator expression in post-build events.

NOTE: On GNU/Linux it works fine both using makefiles or Ninja

CodePudding user response:

This ought to work:

cmake_minimum_required(VERSION 3.18)
project(test)

add_executable(bar foobar.cpp)

list(APPEND DBG_LIBRARIES "lib1" "lib2")
list(APPEND REL_LIBRARIES "lib1" "lib2")

add_custom_command(
  TARGET bar POST_BUILD
  COMMAND "${CMAKE_COMMAND}" -E copy_if_different
          "$<IF:$<CONFIG:Debug>,${DBG_LIBRARIES},${REL_LIBRARIES}>"
          "$<TARGET_FILE_DIR:bar>"
  COMMAND_EXPAND_LISTS
  VERBATIM
)

With VERBATIM set, each argument to COMMAND is considered a single command line argument, even if there are spaces or semicolons inside. Without this option, the interpretation of arguments to COMMAND is platform-specific. As you have noticed, this sometimes means word splitting on spaces while other times it does not.

Lesson 1: You should always use the VERBATIM option with add_custom_command.

Yet, do not forget that CMake's own argument splitting runs before this happens. So without double quotes around $<IF:...>, the semicolons in DBG_LIBRARIES and REL_LIBRARIES would split this into many arguments to add_custom_command, none of which is a complete generator expression. This is why you see "raw" generator expressions on your command lines.

Lesson 2: Always wrap single arguments with variable expansions in double quotes.

Finally, we pass COMMAND_EXPAND_LISTS so that any argument which contains a ; after generator expression processing gets split on the ; into multiple arguments.

  • Related