Custom command not re-run when dependencies change

Hi,
I have been trying to make this work for hours now, but I can’t find the
problem. I have a command that generates a coverage report. Naturally, I
want this report to be re-generated when the unit tests are updated. But
it just won’t work.

Here’s the code:

add_custom_target (all_unit_tests COMMENT "Meta-Target for all unit tests.")

add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/html/index.html
                     # Run tests.
                     COMMAND ${CMAKE_CTEST_COMMAND} -j 
${PEPR_COVERAGE_PARALLEL_LEVEL} --output-on-failure
                     # Create output directory.
                     COMMAND ${CMAKE_COMMAND} -E make_directory 
${PROJECT_BINARY_DIR}/html/
                     # Run gcovr and create HTML report.
                     COMMAND ${GCOVR_COMMAND} ${PEPR_GCOVR_ARGUMENTS} 
--html-details --print-summary --output
                             ${PROJECT_BINARY_DIR}/html/index.html
                     WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
                     DEPENDS all_unit_tests
                     COMMENT "Processing code coverage counters and 
generating HTML report."
                     COMMAND_EXPAND_LISTS)

add_custom_target (coverage_html
                    DEPENDS ${PROJECT_BINARY_DIR}/html/index.html
                    COMMENT "Generate coverage report.")

macro (pepr_test unit_test_cpp)
     file (RELATIVE_PATH unit_test "${CMAKE_SOURCE_DIR}/../unit" 
"${CMAKE_CURRENT_LIST_DIR}/${unit_test_cpp}")
     pepr_test_component (target "${unit_test}" TARGET_NAME)
     pepr_test_component (test_name "${unit_test}" TEST_NAME)

     add_executable (${target} ${unit_test_cpp})
     target_link_libraries (${target} pepr::test::coverage)
     add_test (NAME "${test_name}" COMMAND ${target})

     add_dependencies(all_unit_tests "${target}")

     unset (unit_test)
     unset (target)
     unset (test_name)
endmacro ()

Subsequently, the pepr_test macro is invoked a couple of times. The unit
tests are correctly recognised as dependencies of coverage_html, so
when I ninja coverage_html, the unit tests are rebuilt after source
code changes. However, the html is never updated.
What am I missing?

Thanks,
Hannes

This is not a file level dependency. What shall Ninja compare against to decide that index.html needs to be updated?

I don’t know? Why does it not just check all dependencies recursively?

Does this mean that the top-level target needs file-level dependencies on all lowest-level targets’ files? This is super inconvenient, or do you see a nice way to adapt my example code?

Assuming that the test output is stable, depending on the test binaries might be sufficient (they change when the source files changed)

You could also attach a post build command to each test case target that touches a common file that you can depend on (touch, so that the time stamp changes).

Yeah, I think that would be enough. How would I do that? I tried using a TARGET_FILE generator, but couldn’t make it work…

In particular, I tried adding

add_dependencies(coverage_html $<TARGET_FILE:${target}>)

below, add_dependencies(all_unit_tests "${target}").

But it says that the dependency target

CMake Error at CMakeLists.txt:104 (add_dependencies):
  The dependency target "$<TARGET_FILE:ConstexprFlatMap>" of target
  "coverage_html" does not exist.

You still try adding dependencies to the target but you need a proper file dependency for the custom command.

I still don’t understand why none of this is transitive. I thought that the build system would do exactly this for me :slightly_frowning_face:

In any case, how do I add “a proper file dependency for the custom command” after it’s been defined?

Could anyone help me with this? :pray:

Collect the executables in a property of your target. Use a GenEx to depend on the content of that property.

Something like:

...
  DEPENDS $<TARGET_PROPERTY:all_unit_tests,TEST_EXECUTABLES>
...

set_property(
  TARGET all_unit_tests
  APPEND
  PROPERTY TEST_EXECUTABLES "$<TARGET_FILE:${target}>"
)
1 Like

You may need to wrap that with $<GENEX_EVAL:...> since you’re allowing the TEST_EXECUTABLES target property to contain generator expressions too.

1 Like

Thank you! Combining these two things, solved the problem for me.