Search code examples
c++cmakecode-generationodb

How to add code generation step in CMake build process only for changed header files?


I'm writing C++ application using ODB which requires code generation. I'm using the following CMake script.

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

CMAKE_POLICY(SET CMP0015 NEW)

PROJECT(odb_poc)

INCLUDE_DIRECTORIES(
    ${CMAKE_SOURCE_DIR}/src/
    ${CMAKE_SOURCE_DIR}/generated/)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")

MACRO(ODB_GENERATE header)
    SET(cxxFile "${CMAKE_SOURCE_DIR}/generated/${header}-odb.cxx")
    SET(hxxFile "${CMAKE_SOURCE_DIR}/generated/${header}-odb.hxx")
    SET(ixxFile "${CMAKE_SOURCE_DIR}/generated/${header}-odb.ixx")
    SET(sqlFile "${CMAKE_SOURCE_DIR}/generated/${header}.sql")

    SET(ODB_GENERATED_FILES "${cxxFile} ${hxxFile} ${ixxFile} ${sqlFile}")

    ADD_CUSTOM_COMMAND(
        OUTPUT ${ODB_GENERATED_FILES}
        COMMAND odb -o ${CMAKE_SOURCE_DIR}/generated/ --std c++14 -d pgsql --generate-query --generate-schema
                --show-sloc ${CMAKE_SOURCE_DIR}/src/${header}.hpp
        DEPENDS ${CMAKE_SOURCE_DIR}/src/${header}.hpp
        COMMENT "Generate database support code for ${header}.hpp")

    ADD_CUSTOM_TARGET(RunGenerator-${header} DEPENDS ${ODB_GENERATED_FILES}
                      COMMENT "Checking if re-generation is required for ${header}.hpp")

    ADD_DEPENDENCIES(${CMAKE_PROJECT_NAME} RunGenerator-${header})
ENDMACRO()

ADD_EXECUTABLE(${CMAKE_PROJECT_NAME}
    src/main.cpp
    src/house.hpp
    src/person.hpp
    src/servkeys.hpp
    generated/house-odb.cxx
    generated/person-odb.cxx
    generated/servkeys-odb.cxx)

TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME}
    odb
    odb-pgsql)

ODB_GENERATE(house)
ODB_GENERATE(person)
ODB_GENERATE(servkeys)

The problem is that each time one of the header files from which database support code is generated by ODB is changed, the code for all files is regenerated. Here is the output from the build process:

14:11:03: Running steps for project odb_poc...
14:11:03: Starting: "/usr/bin/cmake" --build . --target all
[ 10%] Generate database support code for person.hpp
person-odb.hxx: 220
person-odb.ixx: 46
person-odb.cxx: 625
total: 891
[ 20%] Checking if re-generation is required for person.hpp
[ 20%] Built target RunGenerator-person
[ 30%] Generate database support code for house.hpp
house-odb.hxx: 205
house-odb.ixx: 46
house-odb.cxx: 580
total: 831
[ 40%] Checking if re-generation is required for house.hpp
[ 40%] Built target RunGenerator-house
[ 50%] Generate database support code for servkeys.hpp
servkeys-odb.hxx: 563
servkeys-odb.ixx: 46
servkeys-odb.cxx: 1477
total: 2086
[ 60%] Checking if re-generation is required for servkeys.hpp
[ 60%] Built target RunGenerator-servkeys
Scanning dependencies of target odb_poc
[ 70%] Building CXX object CMakeFiles/odb_poc.dir/src/main.cpp.o
[ 80%] Building CXX object CMakeFiles/odb_poc.dir/generated/house-odb.cxx.o
[ 90%] Building CXX object CMakeFiles/odb_poc.dir/generated/person-odb.cxx.o
[100%] Building CXX object CMakeFiles/odb_poc.dir/generated/servkeys-odb.cxx.o
Linking CXX executable odb_poc
[100%] Built target odb_poc
14:11:06: The process "/usr/bin/cmake" exited normally.
14:11:06: Elapsed time: 00:04.

How to change CMake script in such way that code only for changed header is regenerated?


Solution

  • I removed the quotes from this line:

    SET(ODB_GENERATED_FILES "${cxxFile} ${hxxFile} ${ixxFile} ${sqlFile}")
    

    changing it to:

    SET(ODB_GENERATED_FILES ${cxxFile} ${hxxFile} ${ixxFile} ${sqlFile})
    

    and this solves the problem.