0

This is a follow-up to How can I get a target's output-file's name during CMake's configuration phase (not the generation phase)?

I want to achieve something similar to the below:

add_custom_command(
  OUTPUT ${CMAKE_BINARY_DIR}/to_zip/$<TARGET_FILE_NAME:Foo>
  DEPENDS Foo
  COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:Foo>
          ${CMAKE_BINARY_DIR}/to_zip/$<TARGET_FILE_NAME:Foo>)
list(APPEND ALL_FILES_IN_TO_ZIP
     ${CMAKE_BINARY_DIR}/to_zip/$<TARGET_FILE_NAME:Foo>)
add_custom_command(
  OUTPUT ${CMAKE_BINARY_DIR}/myzip.zip
  DEPENDS ${ALL_FILES_IN_TO_ZIP}
  COMMAND <zip everything up in ${CMAKE_BINARY_DIR}/to_zip>)
add_custom_target(create-zip DEPENDS ${CMAKE_BINARY_DIR}/to_zip/myzip.zip)

Basically, when I invoke the create-zip target, I want to copy a lot of files to ${CMAKE_BINARY_DIR}/to_zip, and then zip up everything in it. The issue with the above code is that I am not allowed to use target based generator expression for OUTPUT in add_custom_command, so the above code doesn't work. From the CMake docs:

New in version 3.20: Arguments to OUTPUT may use a restricted set of generator expressions. Target-dependent expressions are not permitted.

Is there a way to workaround this problem to make it work?

starball
  • 20,030
  • 7
  • 43
  • 238
user3667089
  • 2,996
  • 5
  • 30
  • 56
  • Just to make sure for this specific case: Adding install instructions, setting package vars and using `cpack -G ZIP` is not an option for you? – fabian Feb 11 '23 at 12:33

1 Answers1

1

I'm pretty sure you don't need to use the name of the target's output file as the OUTPUT of your custom command which does the copy. All you're really using the OUTPUT field for is CMake's dependency mechanisms (where it tracks what things have changed and does things again if anything in DEPENDS has changed (modification time in the filesystem)). You can just create a dummy file that you touch (update the modification time for in the filesystem) whenever the target has changed and once its copy has been made.

set(targets target_foo target_bar target_baz)
foreach(target "${targets}")
  set(indicator "${CMAKE_BINARY_DIR}/to_zip/rezip_indicators/${target}")
  add_custom_command(
    OUTPUT "${rezip_indicator_file}"
    DEPENDS "${target}"
    COMMAND "${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${target}>
      "${CMAKE_BINARY_DIR}/to_zip/$<TARGET_FILE_NAME:${target}>"
    COMMAND "${CMAKE_COMMAND}" -E touch "${rezip_indicator_file}"
  )
  list(APPEND NEEDS_REZIP_INDICATOR_FILES "${rezip_indicator_file}")
endforeach()

add_custom_command(
  OUTPUT "${CMAKE_BINARY_DIR}/myzip.zip"
  DEPENDS "${NEEDS_REZIP_INDICATOR_FILES}"
  COMMAND <zip everything up in ${CMAKE_BINARY_DIR}/to_zip>
)
add_custom_target(create-zip DEPENDS "${CMAKE_BINARY_DIR}/to_zip/myzip.zip")

Or something to that effect.

The indicator file will get its timestamp updated by the touch command in the custom command when the target file has changed. The target file and the needs-rezip indicator file get "synced" when the custom command runs, which will be whenever you run the buildsystem after the target has gotten rebuilt. At least- I'm pretty sure that's how things work.

starball
  • 20,030
  • 7
  • 43
  • 238