Reputation: 19150
I'm trying to generate a header with a custom command. The header should be updated on each rebuild, so that the source file which includes it would also be rebuilt. (Actual command is a script, but here is a simplified version.)
Here's my project:
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
set(test_SOURCES test.c)
include_directories("${CMAKE_BINARY_DIR}")
set(VERSION_H_PATH "${CMAKE_BINARY_DIR}/version.h")
message("VERSION_H_PATH: ${VERSION_H_PATH}")
add_custom_command(OUTPUT "${VERSION_H_PATH}" COMMAND "touch" "${VERSION_H_PATH}")
#add_custom_target(GENERATE COMMAND "touch" "${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog GENERATE)
test.c
#include <version.h>
int main()
{
return 0;
}
Now the problem is that the CMakeList.txt
, as presented above, doesn't result in version.h
being created at all. Only after I switch from add_custom_target
to add_custom_command
does it do. But then, if I change the file somehow, next make
doesn't rebuild the project.
Looks like CMake doesn't recognize that test.c
depends on version.h
, although it does explicitly #include
it. What am I doing wrong here?
Upvotes: 4
Views: 9361
Reputation: 19150
OK, actually the question was badly formulated from the beginning. I shouldn't have simplified the generating command as much as I did. But the problems I had seem to have been solved by removing content of build directory and re-running cmake
. For some reason some changes to CMakeLists.txt
are not easy for cmake to understand. So here's the CMakeLists.txt
which does work, and with not too much simplified generator command:
cmake_minimum_required(VERSION 2.8)
set(test_SOURCES test.c)
include_directories("${CMAKE_BINARY_DIR}")
set(VERSION_H_PATH "${CMAKE_BINARY_DIR}/version.h")
message("VERSION_H_PATH: ${VERSION_H_PATH}")
add_custom_target(GENERATE COMMAND "bash" "-c" "[ -e ${VERSION_H_PATH} ] \\|\\| touch ${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog GENERATE)
This appears to work even when using the reserved test
target instead of myprog
.
Upvotes: 0
Reputation: 20336
Change:
add_custom_command(OUTPUT "${VERSION_H_PATH}" COMMAND "touch" "${VERSION_H_PATH}")
#add_custom_target(GENERATE COMMAND "touch" "${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog GENERATE)
Into:
add_custom_command(OUTPUT "${VERSION_H_PATH}" COMMAND ${CMAKE_COMMAND} -E touch "${VERSION_H_PATH}") #More reliable touch, use cmake itself to touch the file
add_custom_target(generate_version_h DEPENDS "${VERSION_H_PATH}")
add_executable(myprog ${test_SOURCES})
add_dependencies(myprog generate_version_h)
See:
DEPENDS:
Reference files and outputs of custom commands created with add_custom_command() command calls in the same directory (CMakeLists.txt file). They will be brought up to date when the target is built.
Make a top-level depend on other top-level targets to ensure that they build before does. A top-level target is one created by one of the add_executable(), add_library(), or add_custom_target() commands (but not targets generated by CMake like install).
By the way, I do not know your specific case, but you might consider using configure_file to generate your header.
Upvotes: 10
Reputation: 65991
The problem seems to be that the name test
used for the executable target is a name reserved by CMake. See policy CMP0037. Using a different name for the executable seems to work as expected with the custom target:
add_custom_target(GENERATE COMMAND "touch" "${VERSION_H_PATH}")
add_executable(testexe ${test_SOURCES})
add_dependencies(testexe GENERATE)
Upvotes: 1
Reputation: 171197
Every custom command needs a driver (something that will depend on its output). In your case, the best driver would be the test
executable, which means you should add the generated file into your executable's sources:
add_executable(test ${test_SOURCES} ${VERSION_H_PATH})
Upvotes: 0