[CMake] Relink on library rebuild dilema

Michael Hertling mhertling at online.de
Sat Nov 27 01:13:08 EST 2010


On 11/26/2010 05:00 PM, Sebastian Schaetz wrote:
> Hi,
> 
> I have a somewhat weird setup to build binaries for the Cell processor:
> 
> |-- CMakeLists.txt
> |-- kernels
> |   |-- CMakeLists.txt
> |   `-- kernel.cpp
> `-- main.cpp
> 
> From the main.cpp in the root directory the executable is built. 
> 
> In the kernels folder strange things (have to) happen: first the kernel.cpp is
> compiled with a custom compiler (I use a combination of SET, CMAKE_C_COMPILER
> and ADD_EXECUTABLE), then this binary is converted into a library using a custom
> POST_BUILD command that calls a special tool to do just that. If the binary is
> called kernel_executable_bin, the custom command generates a file
> libkernel_executable.a
> 
> Now I have to link this library to my main executable (built from main.cpp).
> What I did so far is to put in the kernels/CMakeLists.txt file:
> 
> add_dependencies(main_target kernel_executable_bin)
> 
> and in the /CMakeLists.txt file:
> 
> link_directories("${CMAKE_CURRENT_BINARY_DIR}/kernels/")
> target_link_libraries(main_target kernel_executable)
> 
> This works as expected for one ugly flaw: if I only change kernels/kernel.cpp it
> won't relink the main_target. I have thus far been unsuccessful in getting this
> to work. I've tried various combinations of add_library(STATIC IMPORTED) and
> add_custom_target(DEPENDS) but it won't work.
> 
> Any ideas would be greatly appreciated.

Despite TARGET_LINK_LIBRARIES(), there's no dependency of main_target
on libkernel_executable.a, so main_target isn't relinked if the kernel
stuff is rebuilt. Nevertheless, there're some approaches I could offer:

1) In the top-level CMakeLists.txt, you might say

SET_SOURCE_FILES_PROPERTIES(
    main.cpp PROPERTIES OBJECT_DEPENDS
    ${CMAKE_CURRENT_BINARY_DIR}/kernels/libkernel_executable.a
)

When libkernel_executable.a has changed, this results in recompiling
main.cpp - a penalty - and the desired relinking of main_target. If
main.cpp's recompilation is expensive you may possibly add an empty
cpp file to main_target's sources and impose the property on that.

2) In kernels/CMakeLists.txt, add the following lines

FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/empty.c)
ADD_LIBRARY(empty STATIC empty.c)
ADD_CUSTOM_COMMAND(TARGET kernel_executable_bin POST_BUILD COMMAND
    ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/empty.c
)

or enhance the custom command which creates libkernel_executable.a from
kernel_executable_bin by the "cmake -E touch" shown above. Finally, in
the top-level CMakeLists.txt, say:

TARGET_LINK_LIBRARIES(main_target kernel_executable empty)

When kernels/kernel.cpp has changed the kernel_executable_bin and
libkernel_executable.a are rebuilt as usual, but kernels/empty.c is
touched by the way. This results in rebuilding libempty.a which in turn
makes main_target be relinked since it depends on the empty library. If
there's trouble with an empty static library just write some dummy code
in kernels/empty.c that you don't refer to from anywhere in the project.

3) If you get along with Makefiles you may possibly use a script in
junction with the RULE_LAUNCH_LINK target property to generate the
libkernel_executable.a from kernel_executable_bin as an actual
target like

ADD_LIBRARY(kernel_executable STATIC "")
ADD_DEPENDENCIES(kernel_executable kernel_executable_bin)

so the TARGET_LINK_LIBRARIES(main_target kernel_executable) in the
top-level CMakeLists.txt should be sufficient to trigger the linker.

'hope that helps.

Regards,

Michael


More information about the CMake mailing list