Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cmake does not rebuild dependent after prerequisite changes

I have the following dependency diagram

a.txt <- prereq <- stamp <- dest

where prereq and dest are targets, and a.txt and stamp are files. I want stamp to be updated whenever a.txt changes.

To achieve that, I have the following CMakeLists.txt file:

 cmake_minimum_required(VERSION 3.6)
 project(sample)

 # variable holding location of stamp and a.txt file
 set(STAMP ${CMAKE_CURRENT_SOURCE_DIR}/stamp)
 set(ATXT ${CMAKE_CURRENT_SOURCE_DIR}/a.txt)

 add_custom_target(
         prereq
         DEPENDS ${ATXT}
 )


 add_custom_command(
         OUTPUT ${STAMP}
         COMMAND ${CMAKE_COMMAND} -E echo "Update stamp."
         COMMAND ${CMAKE_COMMAND} -E touch ${STAMP}
         DEPENDS prereq
 )

 add_custom_target(dest ALL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/stamp)

Initially, I have the following files

$ ls
a.txt
CMakeLists.txt

After running cmake and make for the first time we get the expected behavior,

$ cmake .
$  make
[  0%] Built target prereq
[100%] Generating stamp
Update stamp.
[100%] Built target dest

However, after touching a.txt, I would expect stamp to get updated, but it does not.

$ touch a.txt
$ make
[  0%] Built target prereq
[100%] Built target dest

Is this a bug in cmake or is this the expected behavior? How can we force cmake to run the touch command every time prereq changes?

like image 332
D R Avatar asked Oct 16 '25 20:10

D R


1 Answers

DEPENDS in add_custom_target() and add_custom_command() calls are behaving differently.

Just move ATXT as dependency of your add_custom_command(OUTPUT ${STAMP} ...) call should solve the problem, because naming non-output files in add_custom_target() won't work.

See add_custom_command() documentation:

DEPENDS: Specify files on which the command depends. If any dependency is an OUTPUT of another custom command in the same directory (CMakeLists.txt file) CMake automatically brings the other custom command into the target in which this command is built. If DEPENDS is not specified the command will run whenever the OUTPUT is missing.

See add_custom_target() documentation:

DEPENDS: Reference files and outputs of custom commands created with add_custom_command() command calls in the same directory (CMakeLists.txt file).

The DEPENDS parameter in add_custom_target() is only meant to determine target/custom call dependencies.

Edit: Alternatives for "Late Dependency Injection"

  1. If you are in the same CMakeLists.txt file you can APPEND dependencies to a previous custom command OUTPUT:

    add_custom_command(
        OUTPUT ${STAMP}
        COMMAND ${CMAKE_COMMAND} -E echo "Update stamp."
        COMMAND ${CMAKE_COMMAND} -E touch ${STAMP}
    )
    
    add_custom_target(dest ALL DEPENDS ${STAMP})
    
    add_custom_command(
        OUTPUT ${STAMP}
        DEPENDS ${ATXT}
        APPEND
    )
    
  2. You can add some dummy output to have a custom command for your prereq target, but to retrigger the build of dest you need to touch some of the inputs or remove the output of dest (add_dependencies() itself does not re-trigger a custom target, it just makes sure one is called before the other):

    add_custom_command(
        OUTPUT ATxtCheck
        COMMAND ${CMAKE_COMMAND} -E remove ${STAMP}
        COMMAND ${CMAKE_COMMAND} -E touch ATxtCheck
        DEPENDS ${ATXT}
    )
    
    add_custom_target(prereq DEPENDS ATxtCheck)
    
    add_custom_command(
        OUTPUT ${STAMP}
        COMMAND ${CMAKE_COMMAND} -E echo "Update stamp."
        COMMAND ${CMAKE_COMMAND} -E touch ${STAMP}
        DEPENDS prereq
    )
    
    add_custom_target(dest ALL DEPENDS ${STAMP})
    

References

  • Why does CMake make a distinction between a "target" and a "command"?
  • cmake: struggling with add_custom_command dependencies
like image 100
Florian Avatar answered Oct 18 '25 11:10

Florian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!