How to make CMake 'FILE' command dependent on TARGET or OUTPUT?

Viewed 3845

I've got some add_custom_command() stuff in a CMake build to do some things after building an elf file target: convert it to srec, fill various areas with 0xFF and create a binary image, generate a CRC and get the size of the image. add_custom_command() can have DEPENDS, making it run only when the elf file is regenerated, which is great.

What I also want to do is the create a new file using FILE() that contains the binary filename, crc, and size (maybe in simple JSON format), but the documentation implies that I can't do this file activity after the things I mention above have happened.

# This command creates the FF-filled binary file.  It uses objcopy to create the srec
# file to operate on.
add_custom_command(
    OUTPUT ThreadingApp.bin filled.srec
    MAIN_DEPENDENCY ThreadingApp.elf
    COMMAND ${CMAKE_OBJCOPY} ARGS -O srec ThreadingApp.elf ThreadingApp.srec
    COMMAND srec_cat.exe ThreadingApp.srec -offset - -minimum-addr ThreadingApp.srec
            −fill 0xFF -over ThreadingApp.srec -o filled.srec
    COMMAND srec_cat.exe filled.srec -o ThreadingApp.bin -binary
    )

# This command creates the CRC
add_custom_command(
    OUTPUT crc.out size.out
    MAIN_DEPENDENCY filled.srec
    COMMAND srec_cat.exe filled.srec -crc32-b-e 0x08100000 -crop 0x08100000 0x08100004 -o - -hex-dump > crc.out
    COMMAND srec_info.exe filled.srec > size.out
    )

file(
    WRITE ThreadingApp.json

    )

Looking at the synopsis of 'FILE', I don't see how I can make this happen only after my custom commands have already run. Any suggestions on how to achieve this within CMake? My alternative is to write a separate Python script to execute within an add_custom_command to create the json file.

Reading
  file(READ <filename> <out-var> [...])
  file(STRINGS <filename> <out-var> [...])
  file(<HASH> <filename> <out-var>)
  file(TIMESTAMP <filename> <out-var> [...])

Writing
  file({WRITE | APPEND} <filename> <content>...)
  file({TOUCH | TOUCH_NOCREATE} [<file>...])
  file(GENERATE OUTPUT <output-file> [...])

Filesystem
  file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])
  file(RENAME <oldname> <newname>)
  file({REMOVE | REMOVE_RECURSE } [<files>...])
  file(MAKE_DIRECTORY [<dir>...])
  file({COPY | INSTALL} <file>... DESTINATION <dir> [...])
  file(SIZE <filename> <out-var>)
  file(READ_SYMLINK <linkname> <out-var>)
  file(CREATE_LINK <original> <linkname> [...])

Path Conversion
  file(RELATIVE_PATH <out-var> <directory> <file>)
  file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>)

Transfer
  file(DOWNLOAD <url> <file> [...])
  file(UPLOAD <file> <url> [...])

Locking
  file(LOCK <path> [...])
1 Answers

Unlike to add_custom_command, which COMMAND is executed on build stage, FILE() is executed immediately, at configuration stage when CMakeLists.txt is processed.

You may however put FILE() invocation into separate CMake script, and run this script with add_custom_command. With that approach the script with FILE() will be executed at build stage of your project, and you may use OUTPUT or TARGET option:

# File: my_script.cmake
file(...)

# File: CMakeLists.txt:
add_custom_command(OUTPUT | TARGET ...
    COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_SOURCE_DIR}/my_script.cmake"
    )

Aside from demonstrated CMake scripting mode (cmake -P) there is a command line mode (cmake -E), which can perform basic operations without needing to write a script.

# File: CMakeLists.txt:
add_custom_command(OUTPUT | TARGET ...
    COMMAND ${CMAKE_COMMAND} -E echo "<content-of-the-file>" > "</path/to/file>"
    )

See also that question about redirecting output in add_custom_command: How to redirect the output of a CMake custom command to a file?.

Related