0

Let's assume I have a script that generates a set of source files forming a target I want to link against in a CMakeLists.txt. If the file names are known to the latter then the usual add_custom_target() and add_custom_command() commands will make it possible to use the generated files as target sources.

Let's assume, though, that only the generator script knows the file names and locations. How can a target library be generated so that the parent CMakeLists.txt can link against it without its knowing the actual file names?

Note that the dependency topic isn't in this question's scope as the script knows itself when to regenerate or not. It's not the finest use of CMake, but it's sufficient in this use case.

Idea #1

The script also generates a generated.cmake file included by the parent one using include(generated.cmake). Problem: CMake doesn't find generated.cmake as it isn't existing at configuration time.

Idea #2

Similar to idea #1, but the script is called with the execute_process() so that generated.cmake is present at configuration time. Problem: The script is not called anymore at subsequent builds, thus ignoring possible changes to its input.

Idea #3

The script passes back a list of targets and files that is somehow considered by the parent CMakeLists.txt. So far I couldn't find a way to do so.

Roland Sarrazin
  • 1,203
  • 11
  • 29
  • https://stackoverflow.com/a/25482963/1945549 shows a way to retrigger the configuration step, i.e. the `execute_process()` command when a specific file changes. It gets me closer to what I'm aiming at, but I face the problem that I don't know all relevant input files (as the script parses the input files itself to derive other input files). – Roland Sarrazin Sep 28 '18 at 14:01
  • "Problem: The script is not called anymore at subsequent builds, thus ignoring possible changes to its input.". The problem is clearly about the dependency tracking, which **contradicts** to "Note that the dependency topic isn't in this question's scope". So whether dependency tracking is relevant or not? – Tsyvarev Sep 28 '18 at 19:50
  • @Tsyvarev: Thanks for pointing this contradiction out. I'm working currently on a solution that actually calls the script using `execute_process()` and has the script "publish" its identified input files so that the parent CMake file can add them to the directory's `CMAKE_CONFIGURE_DEPENDS` property. I'll describe it thoroughly as possible answer as soon as it is finalized. – Roland Sarrazin Oct 01 '18 at 06:41
  • Command `add_executable` requires all source files to be specified at *configuration step*. As you don't know source file, generated by your script, you have no other way than call that script at configuration stage, and collect the generated files using, e.g. `file(GLOB)`. So your "Idea #1" and "Idea #2" are just inevitable. This is described in that question: https://stackoverflow.com/questions/44076307/cmake-globbing-generated-files. And dependency tracking for the generating script is just **another** problem, which is described by the question referenced by you. – Tsyvarev Oct 01 '18 at 08:01
  • @Tsyvarev, I kind of used your suggestion but eventually replacing file(GLOB) by a CMake file generated by the script itself (see my answer). – Roland Sarrazin Oct 09 '18 at 06:52

1 Answers1

0

The solution I came with is eventually a mixture of all three ideas.

Solution to idea #1's problem

execute_process() actually ensures that generated_targets.cmake is present at configure time.

Solution to idea #2's and #3's problems

As stated in this answer to "Add dependency to the CMake-generated build-system itself", the CMAKE_CONFIGURE_DEPENDS directory property can be edited to add files whose touching re-triggers the configure step.

The key success factor is that this property can be set after the initial execute_process() call so that the script can identify and list its input dependencies (in an output file) that are then added to CMAKE_CONFIGURE_DEPENDS, hence also solving the input dependency problem.

Resulting pseudo code

# The script generates:
# - <output_dir>/cmake/input_files
# - <output_dir>/cmake/generated_targets.cmake
execute_process(
  COMMAND myScript
    --output-dir ${CMAKE_CURRENT_BINARY_DIR}/generated
)

# Mark the input files as configure step dependencies so that the execute_process
# commands are retriggered on input file change.
file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/generated/cmake/input_files _input_files)

set_property(
  DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
    ${_input_files}
)

# Add the generated CMake targets.
include(${CMAKE_CURRENT_BINARY_DIR}/generated/cmake/generated_targets.cmake)
Roland Sarrazin
  • 1,203
  • 11
  • 29