CMake Rebuilding all files when only one has changed

I am porting a project to CMake from plain Makefiles.

There is tool used to generate header files at build time. The line in the Makefile looks like this:

%.o:%.cpp
      foo $<
      compile command

So, every time a file get compiled, this tool is run beforehand, and only for the files that were changed. The output file of the command is called $<.sd

I’m having trouble replicating this behavior in CMake. Below is the CMakelists.txt. The problem is that the tool is run for all source files, not just the file that changed, and because a new header is generated, all the source files are re-built.

Sorry if a similar question has already been asked. I appreciate any help. I am a new user, so I can’t upload the file, otherwise I do that.

cmake_minimum_required(VERSION 3.10)

set(SRCS CigiAerosolRespV3.cpp
CigiAnimationStopV3.cpp
CigiAnimationTable.cpp
CigiArtPartCtrlV1.cpp
CigiArtPartCtrlV2.cpp
CigiArtPartCtrlV3.cpp
CigiAtmosCtrl.cpp
CigiBaseAerosolResp.cpp
CigiBaseArtPartCtrl.cpp
CigiBaseCircleSymbolData.cpp
CigiBaseCollDetSegResp.cpp
CigiBaseCollDetVolDef.cpp
CigiBaseCollDetVolResp.cpp
CigiBaseConfClampEntityCtrl.cpp
CigiBaseEntityCtrl.cpp
CigiBaseEnvCondReq.cpp
CigiBaseEnvCtrl.cpp
CigiBaseEnvRgnCtrl.cpp
CigiBaseEventNotification.cpp
CigiBaseHatHotReq.cpp
CigiBaseIGCtrl.cpp
CigiBaseLosResp.cpp
CigiBaseLosSegReq.cpp
CigiBaseLosVectReq.cpp
CigiBaseMaritimeSurfaceCtrl.cpp
CigiBaseMaritimeSurfaceResp.cpp
CigiBaseMotionTrackCtrl.cpp
CigiBasePositionReq.cpp
CigiBasePositionResp.cpp
CigiBaseSensorCtrl.cpp
CigiBaseSensorResp.cpp
CigiBaseShortArtPartCtrl.cpp
CigiBaseShortSymbolCtrl.cpp
CigiBaseSOF.cpp
CigiBaseSpecEffDef.cpp
CigiBaseSymbolCircleDef.cpp
CigiBaseSymbolClone.cpp
CigiBaseSymbolCtrl.cpp
CigiBaseSymbolLineDef.cpp
CigiBaseSymbolSurfaceDef.cpp
CigiBaseSymbolTextDef.cpp
CigiBaseTerrestrialSurfaceCtrl.cpp
CigiBaseTrajectoryDef.cpp
CigiBaseViewCtrl.cpp
CigiBaseViewDef.cpp
CigiBaseWaveCtrl.cpp
CigiBaseWeatherCondResp.cpp
CigiBaseWeatherCtrl.cpp
CigiCelestialCtrl.cpp
CigiCircleSymbolDataV3_3.cpp
CigiCollDetSegDefV1.cpp
CigiCollDetSegDefV2.cpp
CigiCollDetSegDefV3.cpp
CigiCollDetSegRespV1.cpp
CigiCollDetSegRespV2.cpp
CigiCollDetSegRespV3.cpp
CigiCollDetVolDefV2.cpp
CigiCollDetVolDefV3.cpp
CigiCollDetVolRespV2.cpp
CigiCollDetVolRespV3.cpp
CigiCompCtrlV1.cpp
CigiCompCtrlV2.cpp
CigiCompCtrlV3_3.cpp
CigiCompCtrlV3.cpp
CigiConfClampEntityCtrlV3.cpp
CigiDefaultPacket.cpp
CigiEarthModelDefV3.cpp
CigiEntityCtrlV1.cpp
CigiEntityCtrlV2.cpp
CigiEntityCtrlV3_3.cpp
CigiEntityCtrlV3.cpp
CigiEnvCondReqV3.cpp
CigiEnvCtrlV1.cpp
CigiEnvCtrlV2.cpp
CigiEnvRgnCtrlV3.cpp
CigiEventNotificationV3.cpp
CigiHatHotReqV3_2.cpp
CigiHatHotReqV3.cpp
CigiHatHotRespV3_2.cpp
CigiHatHotRespV3.cpp
CigiHatHotXRespV3_2.cpp
CigiHatHotXRespV3.cpp
CigiHatReqV1.cpp
CigiHatReqV2.cpp
CigiHatRespV1.cpp
CigiHatRespV2.cpp
CigiHostSession.cpp
CigiHotReqV2.cpp
CigiHotRespV2.cpp
CigiIGCtrlV1.cpp
CigiIGCtrlV2.cpp
CigiIGCtrlV3_2.cpp
CigiIGCtrlV3_3.cpp
CigiIGCtrlV3.cpp
CigiIGMsgV2.cpp
CigiIGMsgV3.cpp
CigiIGSession.cpp
CigiIncomingMsg.cpp
CigiIO.cpp
CigiLosRespV1.cpp
CigiLosRespV2.cpp
CigiLosRespV3_2.cpp
CigiLosRespV3.cpp
CigiLosSegReqV1.cpp
CigiLosSegReqV2.cpp
CigiLosSegReqV3_2.cpp
CigiLosSegReqV3.cpp
CigiLosVectReqV1.cpp
CigiLosVectReqV2.cpp
CigiLosVectReqV3_2.cpp
CigiLosVectReqV3.cpp
CigiLosXRespV3_2.cpp
CigiLosXRespV3.cpp
CigiMaritimeSurfaceCtrlV3.cpp
CigiMaritimeSurfaceRespV3.cpp
CigiMessage.cpp
CigiMotionTrackCtrlV3.cpp
CigiOutgoingMsg.cpp
CigiPositionReqV3.cpp
CigiPositionRespV3.cpp
CigiRateCtrlV1.cpp
CigiRateCtrlV2.cpp
CigiRateCtrlV3_2.cpp
CigiRateCtrlV3.cpp
CigiSensorCtrlV1.cpp
CigiSensorCtrlV2.cpp
CigiSensorCtrlV3.cpp
CigiSensorRespV1.cpp
CigiSensorRespV2.cpp
CigiSensorRespV3.cpp
CigiSensorXRespV3.cpp
CigiSession.cpp
CigiShortArtPartCtrlV3.cpp
CigiShortCompCtrlV3_3.cpp
CigiShortCompCtrlV3.cpp
CigiShortSymbolCtrlV3_3.cpp
CigiSOFV1.cpp
CigiSOFV2.cpp
CigiSOFV3_2.cpp
CigiSOFV3.cpp
CigiSpecEffDefV1.cpp
CigiSpecEffDefV2.cpp
CigiSwapping.cpp
CigiSymbolCircleDefV3_3.cpp
CigiSymbolCloneV3_3.cpp
CigiSymbolCtrlV3_3.cpp
CigiSymbolLineDefV3_3.cpp
CigiSymbolSurfaceDefV3_3.cpp
CigiSymbolTextDefV3_3.cpp
CigiTerrestrialSurfaceCtrlV3.cpp
CigiTerrestrialSurfaceRespV3.cpp
CigiTrajectoryDefV1.cpp
CigiTrajectoryDefV2.cpp
CigiTrajectoryDefV3.cpp
CigiVertexSymbolDataV3_3.cpp
CigiViewCtrlV1.cpp
CigiViewCtrlV2.cpp
CigiViewCtrlV3.cpp
CigiViewDefV1.cpp
CigiViewDefV2.cpp
CigiViewDefV3.cpp
CigiWaveCtrlV3.cpp
CigiWeatherCondRespV3.cpp
CigiWeatherCtrlV1.cpp
CigiWeatherCtrlV2.cpp
CigiWeatherCtrlV3.cpp)


set(SD_FILES ${CMAKE_CURRENT_SOURCE_DIR}/CigiAerosolRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiAnimationStopV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiAnimationTable
${CMAKE_CURRENT_SOURCE_DIR}/CigiArtPartCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiArtPartCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiArtPartCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiAtmosCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseAerosolResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseArtPartCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseCircleSymbolData
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseCollDetSegResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseCollDetVolDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseCollDetVolResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseConfClampEntityCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseEntityCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseEnvCondReq
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseEnvCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseEnvRgnCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseEventNotification
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseHatHotReq
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseIGCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseLosResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseLosSegReq
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseLosVectReq
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseMaritimeSurfaceCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseMaritimeSurfaceResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseMotionTrackCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBasePositionReq
${CMAKE_CURRENT_SOURCE_DIR}/CigiBasePositionResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSensorCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSensorResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseShortArtPartCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseShortSymbolCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSOF
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSpecEffDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSymbolCircleDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSymbolClone
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSymbolCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSymbolLineDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSymbolSurfaceDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseSymbolTextDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseTerrestrialSurfaceCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseTrajectoryDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseViewCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseViewDef
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseWaveCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseWeatherCondResp
${CMAKE_CURRENT_SOURCE_DIR}/CigiBaseWeatherCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiCelestialCtrl
${CMAKE_CURRENT_SOURCE_DIR}/CigiCircleSymbolDataV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetSegDefV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetSegDefV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetSegDefV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetSegRespV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetSegRespV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetSegRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetVolDefV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetVolDefV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetVolRespV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiCollDetVolRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiCompCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiCompCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiCompCtrlV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiCompCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiConfClampEntityCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiDefaultPacket
${CMAKE_CURRENT_SOURCE_DIR}/CigiEarthModelDefV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiEntityCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiEntityCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiEntityCtrlV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiEntityCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiEnvCondReqV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiEnvCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiEnvCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiEnvRgnCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiEventNotificationV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatHotReqV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatHotReqV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatHotRespV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatHotRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatHotXRespV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatHotXRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatReqV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatReqV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatRespV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiHatRespV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiHostSession
${CMAKE_CURRENT_SOURCE_DIR}/CigiHotReqV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiHotRespV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGCtrlV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGCtrlV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGMsgV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGMsgV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiIGSession
${CMAKE_CURRENT_SOURCE_DIR}/CigiIncomingMsg
${CMAKE_CURRENT_SOURCE_DIR}/CigiIO
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosRespV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosRespV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosRespV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosSegReqV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosSegReqV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosSegReqV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosSegReqV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosVectReqV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosVectReqV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosVectReqV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosVectReqV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosXRespV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiLosXRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiMaritimeSurfaceCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiMaritimeSurfaceRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiMessage
${CMAKE_CURRENT_SOURCE_DIR}/CigiMotionTrackCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiOutgoingMsg
${CMAKE_CURRENT_SOURCE_DIR}/CigiPositionReqV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiPositionRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiRateCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiRateCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiRateCtrlV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiRateCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSensorCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiSensorCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiSensorCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSensorRespV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiSensorRespV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiSensorRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSensorXRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSession
${CMAKE_CURRENT_SOURCE_DIR}/CigiShortArtPartCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiShortCompCtrlV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiShortCompCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiShortSymbolCtrlV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSOFV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiSOFV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiSOFV3_2
${CMAKE_CURRENT_SOURCE_DIR}/CigiSOFV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSpecEffDefV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiSpecEffDefV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiSwapping
${CMAKE_CURRENT_SOURCE_DIR}/CigiSymbolCircleDefV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSymbolCloneV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSymbolCtrlV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSymbolLineDefV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSymbolSurfaceDefV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiSymbolTextDefV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiTerrestrialSurfaceCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiTerrestrialSurfaceRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiTrajectoryDefV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiTrajectoryDefV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiTrajectoryDefV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiVertexSymbolDataV3_3
${CMAKE_CURRENT_SOURCE_DIR}/CigiViewCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiViewCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiViewCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiViewDefV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiViewDefV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiViewDefV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiWaveCtrlV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiWeatherCondRespV3
${CMAKE_CURRENT_SOURCE_DIR}/CigiWeatherCtrlV1
${CMAKE_CURRENT_SOURCE_DIR}/CigiWeatherCtrlV2
${CMAKE_CURRENT_SOURCE_DIR}/CigiWeatherCtrlV3)

add_library(CIGILIB STATIC ${SRCS}) 

foreach(FILE ${SD_FILES})
    set(CPP_FILE "${FILE}.cpp")
    set(SYM_DICT_FILE "${FILE}.sd")
    
   add_custom_command(
                        OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${SYM_DICT_FILE}
                        COMMAND sdscan.py ${CPP_FILE}  
                        DEPENDS ${CPP_FILE}
                        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                      )
    set_source_files_properties(${CPP_FILE} PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SYM_DICT_FILE})
    
endforeach()

target_include_directories (CIGILIB PRIVATE ./include ${CMAKE_CURRENT_BINARY_DIR})

If you use the Ninja generator, ninja -d explain should output why it is rerunning each command.

I suspect the issue here is that if foo generates a header given A.cpp that B.cpp also uses, if they are run out-of-order, B discovers the A.cpp-based generated header. If A.o happens to be built second, B is now out-of-date. Basically, something is not complete about your dependencies and the compilation of various sources is not as independent as the CMakeLists.txt implies they are (there’s some hidden header dependency between running sdscan.py and the compilation of other sources). CMake really wants this to be explicit given its model (but cannot, unfortunately diagnose them), but I suspect you’ve just been getting lucky in your old makefile (or it never supported parallel builds).

Thanks for your reply. I will try to use Ninja to understand why each command is being run.

I’ll note that GNU Make does have the same capability (I forget the flag off-hand), but it is nowhere near as concise and just harder to figure out what’s going on.

I found the problem. It was a misunderstanding of how to use add_custom_command. I removed the set_source_properties line, and moved the add_library to after the for loop. Then, I added all the files I want generated as sources for the library. It works as expected now. Thanks for the help.

For me the problem was because of keyboard layout. I was using turkish keyboard as an option, in files where cmake was caching dependencies, all letter was uppercased, and a turkish character was not same as uppercased one.