21

I have an existing cmake file that generates a .so library. I want to modify it so that it will then make a copy of the .so named something else. This is roughly what I have:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7)
PROJECT(test1)

SET(TEST_SOURCES f1.c)
ADD_LIBRARY(test SHARED ${TEST_SOURCES})
ADD_CUSTOM_COMMAND(
    OUTPUT custom1
    COMMAND cp libtest.so custom1
    DEPENDS libtest.so)

I realise there are better ways than hardcoding the library name, I'm just doing this while I try and figure out how to make it work at all. What's the thing I'm missing that will cause my copy/rename custom command to run? Note: this is not an install-time thing. Thanks

gimmeamilk
  • 2,016
  • 5
  • 24
  • 36

3 Answers3

24

I'd stick with your original idea of using add_custom_command. However, I'd recommend you use the add_custom_command(TARGET ...) form rather than add_custom_command(OUTPUT ...).

The OUTPUT version is designed to have the output file used as a source file in a different CMake target in the same CMakeLists.txt. The custom command is invoked when this target is built (right at the start), since the target needs the file to exist at that point.

In your case, no target depends on your file - it's a product of the build process.

If you use add_custom_command(TARGET ...), this guarantees the command is executed every time the target is rebuilt. Using add_custom_target requires you to remember to build this if the original target (test in this case) is updated. It also needlessly adds to your list of targets - maybe not an issue for a tiny project, but it can be for larger projects.

Here's how I'd set up the command:

SET(COPY_TO_PATH custom1)
ADD_CUSTOM_COMMAND(TARGET test POST_BUILD
                   COMMAND ${CMAKE_COMMAND} -E copy
                       $<TARGET_FILE:test>
                       ${COPY_TO_PATH}
                   COMMENT "Copying 'test' library to '${COPY_TO_PATH}'")

This adds the command as a post-build event of test's. As you rightly identified, hard-coding library names isn't great; hence CMake provides "generator expressions" to handle this. The generator expression $<TARGET_FILE:test> resolves to the full path of the library created by test, regardless of platform or compiler. Note that generator expressions can only be used in the COMMAND argument; you couldn't use them in the COMMENT part for example.

The actual command is invoking CMake itself (${CMAKE_COMMAND}) with its -E command line option. This provides a cross-platform way to achieve the copy, since cp isn't a Windows command. To see all -E options, run cmake -E help.

Fraser
  • 74,704
  • 20
  • 238
  • 215
13
add_custom_target(CopyAndRename
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/test.so ${CMAKE_BINARY_DIR}/SomeThingElse.so
)

add_custom_target introduces a new target named CopyAndRename. You can run it with:

cmake CopyAndRename
Vertexwahn
  • 7,709
  • 6
  • 64
  • 90
9

You may consider using configure_file

configure_file("path-to-your-so-file.so" "new-path-to-your-so-file.so" COPYONLY)
NewBee
  • 1,331
  • 12
  • 13
  • Take notice that this command also creates a link between source and destination file and, in the futue, if the source file is modified copying will be redone. This might be wanted, or might not. – Dino Saric May 13 '21 at 11:02
  • @DinoSaric may u provide a link for your information? I do not think configure_file just create a link between source and dest file. It copies source file to dest. And I think this is the simplest way to copy file with CMAKE. – NewBee May 18 '21 at 08:38
  • Yes, it will copy, but if the input file is modified in the future, CMake will reconfigure and copy the file to the output. From [here](https://cmake.org/cmake/help/latest/command/configure_file.html): If the input file is modified the build system will re-run CMake to re-configure the file and generate the build system again. The generated file is modified and its timestamp updated on subsequent cmake runs only if its content is changed. – Dino Saric May 19 '21 at 09:53