Search code examples
c++linuxcmakecmake-custom-command

CMake: add_custom_command with PRE_BUILD does not work


In the following CMakeLists.txt file, although I have set an add_custom_command command with PRE_BUILD option, the custom command is not always executed before making the main executable:

cmake_minimum_required(VERSION 2.8)
project(VersioningTest)

set(MAJOR 1)
set(MINOR 0)
set(PATCH 0)

set(PRODUCT App-${MAJOR}-${MINOR}-${PATCH})

ADD_EXECUTABLE(${PRODUCT}
                main.cpp
                Engine.cpp)

add_custom_command(TARGET ${PRODUCT} PRE_BUILD
                COMMAND ${CMAKE_COMMAND}
                -DMAJOR=${MAJOR}
                -DMINOR=${MINOR}
                -DPATCH=${PATCH}
                -P ${CMAKE_SOURCE_DIR}/SetVersion.cmake
                WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
                COMMENT "setting version...")

So I decided to replace add_custom_command with add_custom_target and add_dependencies:

add_custom_target(SetVersion
                COMMAND ${CMAKE_COMMAND}
                -DMAJOR=${MAJOR}
                -DMINOR=${MINOR}
                -DPATCH=${PATCH}
                -P ${CMAKE_SOURCE_DIR}/SetVersion.cmake
                WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
                COMMENT "setting version...")

add_dependencies(${PRODUCT} SetVersion)

And it worked. Now the SetVersion.cmake file is executed everytime before making the main executable. What's wrong with add_custom_command in my CMake file?

The content of SetVersion.cmake file:

EXECUTE_PROCESS(
    COMMAND svn info ${CMAKE_SOURCE_DIR}
    COMMAND grep Revision
    OUTPUT_VARIABLE REVISION
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

EXECUTE_PROCESS(
     COMMAND svn diff ${CMAKE_SOURCE_DIR}
     OUTPUT_VARIABLE SVNDIFF
     OUTPUT_STRIP_TRAILING_WHITESPACE
 )

if(SVNDIFF STREQUAL "")
    set(LOCALCHANGES 0)
    message("No local changes detected")
else(SVNDIFF STREQUAL "")
    set(LOCALCHANGES 1)
    message("Local changes detected!")
endif(SVNDIFF STREQUAL "")

configure_file(${CMAKE_SOURCE_DIR}/version.h.in ${CMAKE_SOURCE_DIR}/version.h)
message("Version set") # For testing only

And the content of version.h.in:

#define MAJOR_VERSION "${MAJOR}"
#define MINOR_VERSION "${MINOR}"
#define PATCH_VERSION "${PATCH}"
#define REVISION "${REVISION}"
#define LOCALCHANGES "${LOCALCHANGES}"

Solution

  • It depends on the CMake generator you use. Here is the relevant section from the add_custom_command documentation:

    This option has unique behavior for the Visual Studio Generators. 
    When using one of the Visual Studio generators, 
    the command will run before any other rules are executed within the target. 
    With all other generators, this option behaves the same as PRE_LINK instead.
    

    Under OS X PRE_BUILD also seems to work for Xcode, which is not documented properly.