JvO
JvO

Reputation: 3106

CMake: how to build additional files for an existing target?

I need to generate extra files for an existing CMake target that is already defined with an add_executable(); I don't know how many files there are in advance, and in addition those files are not compiled/part of the executable itself. These files should be build or updated whenever I build that target, but only if their dependent files have been updated.

These extra files are generated and/or updated from an existing file with a Python script. So the natural choices are add_custom_target() and add_custom_command(), but I run into two issues with these:

So what does not work:

function(register_translation_files)

    ## determine TARGET and INPUT_FILES ...
 
    foreach (LANG IN LISTS TRANSLATION_LANGUAGES)
        message ("Add translation '${LANG}' for target ${TARGET}")
        set (XLF_FILE "${TARGET}_${LANG}.xlf")
        add_custom_command (
            OUTPUT ${XLF_FILE}
            COMMAND scripts/cet2xlf.py --language ${LANG} ${XLF_FILE} ${INPUT_FILES}
            DEPENDS ${INPUT_FILES}
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        )
    
        add_dependencies (${TARGET} ${XLF_FILE})   <<--- fails with '('the dependency target of TARGET does not exist')
    endforeach()
endfunction()

(....)

add_executable (MainTarget foo.cpp bla.cpp)
register_translation_files (TARGET MainTarget INPUT file1 file2)

add_custom_target works but is always executed (as CMake considers it always outdated):

function(register_translation_files)

    ## determine TARGET and INPUT_FILES ...
 
    foreach (LANG IN LISTS TRANSLATION_LANGUAGES)
        message ("Add translation '${LANG}' for target ${TARGET}")
        set (XLF_FILE "${TARGET}_${LANG}.xlf")
        add_custom_target (
            ${XLF_FILE}
            COMMAND scripts/cet2xlf.py --language ${LANG} ${XLF_FILE} ${INPUT_FILES}
            DEPENDS ${INPUT_FILES}
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        )
    
        add_dependencies (${TARGET} ${XLF_FILE})   <<--- builds, but script is executed every time!
    endforeach()
endfunction()

(....)

add_executable (MainTarget foo.cpp bla.cpp)
register_translation_files (TARGET MainTarget INPUT file1 file2)

I tried all kinds if variations, including a custom_target with dependencies on custom_command output, but I either end up with 'this dependency does not exist' or a script that is always executed.

Surely, one can add files with add_depencies()?

Upvotes: 2

Views: 730

Answers (1)

fabian
fabian

Reputation: 82491

You could combine both add_custom_target and add_custom_command to accomplish this:

List the files generated by add_custom_command in via the DEPENDS option of add_custom_target and then use add_dependencies.

I strongly recommend keeping the source directories free of any files generated during build/cmake configuration. Not doing this prevents projects you set up based on the same source directory from working properly.

function(register_translation_files)

    ## determine TARGET and INPUT_FILES ...
 
    set(OUTPUT_DIR ${CMKAE_CURRENT_BINARY_DIR}/generated_translation_files)
    file(MAKE_DIRECTORY ${OUTPUT_DIR})

    set(GENERATED_FILES)

    foreach (LANG IN LISTS TRANSLATION_LANGUAGES)
        message ("Add translation '${LANG}' for target ${TARGET}")
        set (XLF_FILE "${OUTPUT_DIR}/${TARGET}_${LANG}.xlf")
        add_custom_command (
            OUTPUT ${XLF_FILE}
            COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/cet2xlf.py" --language ${LANG} ${XLF_FILE} ${INPUT_FILES}
            DEPENDS ${INPUT_FILES}
            WORKING_DIRECTORY ${OUTPUT_DIR}
        )
        list(APPEND GENERATED_FILES ${XLF_FILE})
    endforeach()
    add_custom_target("${TARGET}_generate_translations" DEPENDS ${GENERATED_FILES})
    add_dependencies(${TARGET} "${TARGET}_generate_translations")
endfunction()

Surely, one can add files with add_depencies()?

No, this is not possible. This is hinted at in the documentation of add_dependencies alongside hinting at the solution presented above:

add_dependencies( [<target-dependency>]...)

[...]

See the DEPENDS option of add_custom_target() and add_custom_command() commands for adding file-level dependencies in custom rules.

Upvotes: 2

Related Questions