David McCabe
David McCabe

Reputation: 127

add_custom_command apparently fails silently after moving target declaration

I've been caught out by an add_custom_command w/target declaration problem and present it here. Below are two CMake source trees, the first one runs the custom command while the second version does not.

QQ. I expected the two trees to be (roughly equivalent) - why would the latter skip running the custom command?


V1: Building generates myFile.txt

# ~/CMakeLists.txt
project(myProj)
cmake_minimum_required(VERSION 3.16)

add_subdirectory(myDir)
# ~/myDir/CMakeLists.txt
add_executable(myExe)    # ***Declare target here***

add_custom_command(
  OUTPUT myFile.txt
  COMMAND touch myFile.txt
  DEPENDS myFile.txt
)

target_sources(myExe PRIVATE myFile.txt)

V2: Building doesn't generate a myFile.txt

# ~/myDir/CMakeLists.txt
project(myProj)
cmake_minimum_required(VERSION 3.16)

add_executable(myExe)    # ***Declare target here***
add_subdirectory(myDir)
# ~/myDir/CMakeLists.txt
add_custom_command(
  OUTPUT myFile.txt
  COMMAND touch myFile.txt
  DEPENDS myFile.txt
)

target_sources(myExe PRIVATE myFile.txt)

I've been tearing my hair out and didn't turn up much after skimming the reference. Cheers

Upvotes: 1

Views: 612

Answers (1)

Alex Reinking
Alex Reinking

Reputation: 19946

This is an unfortunate limitation of CMake, but it is documented. You can only attach generated source files to targets created in the same directory:

This defines a command to generate specified OUTPUT file(s). A target created in the same directory (CMakeLists.txt file) that specifies any output of the custom command as a source file is given a rule to generate the file using the command at build time.

Emphasis mine. See the original documentation here: https://cmake.org/cmake/help/latest/command/add_custom_command.html

You can work around this by using OBJECT libraries, like so:

# ./myDir/CMakeLists.txt
add_custom_command(
  OUTPUT myFile.cpp
  COMMAND touch myFile.cpp
  # The command doesn't depend on itself.
)

add_library(myExeObj OBJECT myFile.cpp)
target_link_libraries(myExe PRIVATE myExeObj)

Upvotes: 1

Related Questions