14

Using Cmake v3.8, I need my custom command to run only after my newly built .hex, .map, and .elf files are produced. However, the command is not truly running after all of the *.hex, *.map, and *.elf files are produced. Here is what I have:

    add_custom_command(
    POST_BUILD
    COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/performCrc32.py
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    OUTPUT  performCrc32.out
    COMMENT "Running CRC32 check..."
)
add_custom_target(
    performCrc32 ALL
    DEPENDS performCrc32.py
    performCrc32.out
) 

What am I missing, if anything?

S_Balb
  • 197
  • 1
  • 1
  • 7
  • Provide code which creates those `.hex`, `.map` and `.elf` files. – Tsyvarev May 27 '17 at 08:35
  • The .hex, .map, and .elf files are created after the build is complete. I need my custom command to run after the build is entirely complete. I thought adding the qualifier "POST_BUILD" would provide me the necessary timing requirements, however, that is not the case. performCrc32.py runs before the new .hex, .map, and .elf files are built. "execute_process()" runs during Cmake generation so it also doesn't provide me with what I need. – S_Balb May 28 '17 at 00:09

1 Answers1

18

There is no way for add commands to be executed "after the build is entirely complete".

  1. You may add commands to be executed after specific target is built:

    add_custom_command(TARGET <kernel-target> POST_BUILD
        COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/performCrc32.py
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        COMMENT "Running CRC32 check..."
    )
    

This would add command to be executed after <kernel-target> and all its dependencies will be built. Note on the absence of OUTPUT option in this case.

This is preferrable way for post-build checks, as a check will be performed every time target is actually (re)built.

  1. You may bind your custom command to your custom target (as usual), and add dependencies for the target:

    add_custom_command(
        COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/performCrc32.py
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        OUTPUT  performCrc32.out
        COMMENT "Running CRC32 check..."
    )
    add_custom_target(
        performCrc32 ALL
        DEPENDS performCrc32.py
        performCrc32.out
    ) 
    
    add_dependencies(performCrc32 <hex-targets...> <map-targets> <elf-target>)
    

    In this case command will be executed after all dependent targets are built. However, the command will be executed only first build: once OUTPUT file will be created, the command won't be executed again.


POST_BUILD option for add_custom_command is applicable only for TARGET flow of this command, as described above. I am curious why CMake doesn't emit error for your case, when you use POST_BUILD without TARGET.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • Option 1) which you described seems to be a viable option. Is "" merely a full path to the .hex/.map/.elfs? Here is the error I'm getting.... ** CMake Error at CMakeLists.txt:30 (add_custom_command): No TARGET '/Users/sami/dev/Github_repo/CalaTWO- NRF52832/build/bin/Release/Target/my_app.hex' has been created in this directory.** However, my_app.hex does exist. – S_Balb May 28 '17 at 20:06
  • `` is a **target**. In CMake *target* is no case a *file*. – Tsyvarev May 28 '17 at 22:15
  • I'm not sure I understood your last comment. ****, to me, seems to be a .hex file or a .bin file, etc. You said "In CMake target is no case a file" -- thus **target** is never a file? Can't **target** simply be a path to existing files? – S_Balb May 30 '17 at 01:34
  • `Can't target simply be a path to existing files?` Yes, it cannot. You may have a target named `app` and a file named `app` (in current binary directory), but whenever you use `app` as a *target*, CMake never checks the *file* `app.` In my answer I assume that you have **target** `` which is created like `add_custom_target( DEPENDS ...)`. In that case the *target* is assumed to be built when a *file* `` is built. That is why I asked you to provide CMake code, which creates those files - with that code my answer would be *more concrete*. – Tsyvarev May 30 '17 at 07:02
  • In the first suggestion, how do you make `add_custom_command(TARGET ..)` rerun each time the script `performCrc32.py` changes? – Maximilian Mordig Sep 09 '22 at 08:15
  • @MaximilianMordig: You need to add dependencies for the target with attached custom command. E.g., when create executable/library target, you could add `performCrc32.py` among its sources. Probably, `target_sources` could be used for the same purposes. Alternatively, you could specify dependency in [LINK_DEPENDS](https://cmake.org/cmake/help/latest/prop_tgt/LINK_DEPENDS.html) target's property. Note, that not only your `performCrc32.py` script will be rerun, but complete linking step will be rerun. A command added `add_custom_command(TARGET ..)` cannot be re-run separately from the target. – Tsyvarev Sep 09 '22 at 08:29