1

I am trying to figure out how to copy some libs depending on the config in cmake.

I tried this:

add_custom_command(TARGET Myapp
  POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy_if_different
  $<$<CONFIG:Debug>:${_LIBS_DEBUG}> 
  $<$<CONFIG:Release>:${_LIBS_RELEASE}> 
  $<TARGET_FILE_DIR:MyApp>)

It copies libs in Debug but not in release:

  1. Is this supposed to be legal and should work?
  2. If it is not legal (I do not get error), how can I achieve the same effect?
Germán Diago
  • 7,473
  • 1
  • 36
  • 59
  • Looks legal to me, if `_LIBS...` only contains a single file. If not add an `foreach()` loop around the `add_custom_command()`. And do we talk about a makefile environment? Because you e.g. need to know that the default configuration is just empty. Could you please add the command line you used to generate the build environment? Alternatively are the libs also build with CMake? Then you could have a generic `_LIBS` list containing generator expressions like `$`. – Florian Apr 29 '16 at 10:27
  • My command line is targeting Visual studio, so there is no -DCMAKE_BUILD_TYPE in it. I am compiling a set of 46 projects all with CMake, but the libs I want to install are just strings pointing to libraries and not part of my project. – Germán Diago Apr 29 '16 at 10:31
  • 2
    Thanks for the additional information. Just a guess: have you tried to remove the space/newline between the two generator expressions? What I normally do to debug those case is to add another `COMMAND` before the actual line in question that just echos the command line. In your case `COMMAND ${CMAKE_COMMAND} -E echo $<$:${_LIBS_DEBUG}>$<$:${_LIBS_RELEASE}> $`. Maybe also add an `COMMAND ${CMAKE_COMMAND} -E echo Copying libs for config $` to verify the config's name. – Florian Apr 29 '16 at 10:38

2 Answers2

2

Turning my comments into an answer

What I normally do to debug those case is to add another COMMAND before the actual line in question that just echos the command line. In your case:

COMMAND ${CMAKE_COMMAND} -E echo 
    $<$<CONFIG:Debug>:${_LIBS_DEBUG}>
    $<$<CONFIG:Release>:${_LIBS_RELEASE}> 

I've run this a few tests and you will see that the $<1:...> and $<0:...> expressions are not evaluated.

So seeing this I was searching CMake's bug tracker database and this is a known issue and yet (as for CMake 3.5.2) unresolved: 0009974: CMake should support custom commands that can vary by configuration.

There are several ways proposed in this ticket that do work with existing versions of CMake.


In your case - until this issue is resolved and if you want to have it shell independent - I would do it the "old way" and call a CMake script:

CopyLibsByConfig.cmake.in

if (_CONFIG STREQUAL "Debug")
    file(COPY @_LIBS_DEBUG@ DESTINATION "${_DEST_PATH}")
else()
    file(COPY @_LIBS_RELEASE@ DESTINATION "${_DEST_PATH}")
endif()

CMakeLists.txt

...
configure_file(CopyLibsByConfig.cmake.in CopyLibsByConfig.cmake @ONLY)
add_custom_command(TARGET MyApp
  POST_BUILD
  COMMAND ${CMAKE_COMMAND} 
    -D _CONFIG=$<CONFIG> 
    -D _DEST_PATH="$<TARGET_FILE_DIR:MyApp>"
    -P "${CMAKE_CURRENT_BINARY_DIR}/CopyLibsByConfig.cmake"
)

But the solution can very much depend on the files you want to copy to your binary output folder. And there are a lot of way doing it, like using install():

install(FILES ${_LIBS_DEBUG} CONFIGURATIONS Debug DESTINATION $<TARGET_FILE_DIR:MyApp>)
install(FILES ${_LIBS_RELEASE} CONFIGURATIONS Release DESTINATION $<TARGET_FILE_DIR:MyApp>)

set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)

Obviously that's not the way install() is meant to be used, so consider using the INSTALL or PACKAGE targets properly to distribute your application and all its dependencies.

And if we are talking about Visual Studio runtime DLLs you most likely want to take a look at the InstallRequiredSystemLibraries CMake module.

Florian
  • 39,996
  • 9
  • 133
  • 149
  • Thanks. That helped. I am packaging my app already with install + an installer. But my use case right now is to add copied libraries to the destination exe folder in order to support proper debugging when working. So the custom command is the right thing to do. – Germán Diago May 01 '16 at 15:52
0

Other solution is to use generator expression.

For example I have cppzmq (shared library) and cppzmq-static (static library with static dependencies). I would like to have faster debug builds so I use cppzmq in Debug build and in (other) e.g. release I want one big fat exec.

target_link_libraries(CommunicationCommonLib PUBLIC
    $<IF:$<CONFIG:Debug>,cppzmq,cppzmq-static>
    Dexode::EventBus
    gcpp
    protobuf::libprotobuf
    )
Gelldur
  • 11,187
  • 7
  • 57
  • 68