Use a lista como dependências em add_custom_command

Aug 30 2020

Eu quero usar list ie., set(RESOURCES foo.txt bar.txt foo.bar bar.foo)Como dependências em vez de digitar manualmente na add_custom_commandparte DEPENDS.

O caso de uso da vida real real é para glib-compile-resourcesferramenta de utilitário onde um usuário pode deixá-lo gerar todas as dependências do arquivo xml usando o --generate-dependenciesparâmetro. Em nosso caso, a saída é armazenada em uma variável usando o CMake execute_process(). Dessa forma, não preciso atualizar manualmente o script CMake cada vez que um novo recurso é adicionado ou removido do arquivo xml.

cmake_minimum_required(VERSION 3.15)

project(dummy LANGUAGES C)

find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED)

set(GRESOURCE_C      dummy.gresource.c)
set(GRESOURCE_XML    dummy.gresource.xml)
set(GRESOURCE_XML_IN dummy.gresource.xml.in)
set(GRESOURCE_DEPENDENCIES)

set(OLD ${CMAKE_CURRENT_SOURCE_DIR}/${GRESOURCE_XML_IN})
set(NEW ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_XML})

if(NOT EXISTS ${OLD} OR (${OLD} IS_NEWER_THAN ${NEW})) configure_file(${GRESOURCE_XML_IN} ${GRESOURCE_XML}) execute_process( WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        COMMAND ${GLIB_COMPILE_RESOURCES} --generate-dependencies ${GRESOURCE_XML}
        OUTPUT_VARIABLE GRESOURCE_DEPENDENCIES
    )
endif()

add_custom_command(
    OUTPUT ${GRESOURCE_C} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMAND ${GLIB_COMPILE_RESOURCES} ARGS --generate-source --target=${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} {NEW} VERBATIM MAIN_DEPENDENCY ${GRESOURCE_XML}
    DEPENDS ${GRESOURCE_DEPENDENCIES} # <-- Here lies the problem ) add_custom_target( dummy-resource DEPENDS ${GRESOURCE_C}
)

add_executable(${PROJECT_NAME} dummy.c) add_dependencies(${PROJECT_NAME} dummy-resource)

dummy.gresource.xml.in

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
    <gresource>
        <!-- touch foo.glade && touch bar.glade -->
        <file>foo.glade</file>
        <file>bar.glade</file>
    </gresource>
</gresources>

O manequim pode ser apenas oi, mundo por enquanto.

A lista não está expandida na parte DEPENDS acima. Mas se eu digitar manualmente todas as dependências, funciona. Existe uma maneira de alcançar o comportamento que desejo?

Respostas

1 KeyikedalubeNdang Sep 01 2020 at 04:40

A fonte da causa é o valor de saída que GRESOURCE_DEPENDENCIESobtemos deexecute_process()

Tente imprimir seu comprimento real como uma lista. Vamos pegar o tamanho 1!

Mas a string impressa usando message(${GRESOURCE_DEPENDENCIES})é tão convincente:

foo.glade
bar.glade

Mas essa saída está errada! Só obteremos esse tipo de saída se o foreach()loop for usado em conjunto com message(). Sem loop, uma lista impressa usando apenas message(), a saída correta sai assim:

foo.gladebar.glade

O remédio para isso é simples:

  1. Use string(REPLACE "\n" ";" ...)para converter nosso valor de string em uma lista
  2. Destaque o último item porque é apenas um único \ncaractere de espaço em branco
  3. Graças aos comentários acima Definir GRESOURCE_DEPENDENCIEScomo uma variável persistente

Script corrigido

cmake_minimum_required(VERSION 3.15)

project(dummy LANGUAGES C)

find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED)

set(GRESOURCE_C      dummy.gresource.c)
set(GRESOURCE_XML    dummy.gresource.xml)
set(GRESOURCE_XML_IN dummy.gresource.xml.in)
set(GRESOURCE_DEPENDENCIES CACHE INTERNAL "GResource dependencies for dummy")

set(OLD ${CMAKE_CURRENT_SOURCE_DIR}/${GRESOURCE_XML_IN}) set(NEW ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_XML}) if(NOT EXISTS ${NEW} OR (${OLD} IS_NEWER_THAN ${NEW}))
    configure_file(${GRESOURCE_XML_IN} ${GRESOURCE_XML})

    execute_process(
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${GLIB_COMPILE_RESOURCES} --generate-dependencies ${GRESOURCE_XML} OUTPUT_VARIABLE GRESOURCE_DEPENDENCIES ) # OUTPUT_VARIABLE is not a list but a single string value with newlines # Convert it to a list and pop out the last newline character string(REPLACE "\n" ";" GRESOURCE_DEPENDENCIES ${GRESOURCE_DEPENDENCIES})
    list(POP_BACK GRESOURCE_DEPENDENCIES)
endif()

add_custom_command(
    OUTPUT ${GRESOURCE_C} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMAND ${GLIB_COMPILE_RESOURCES} ARGS --generate-source --target=${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} ${NEW}
    VERBATIM
    MAIN_DEPENDENCY ${GRESOURCE_XML} DEPENDS ${GRESOURCE_DEPENDENCIES}
)

add_custom_target(
    dummy-resource
    DEPENDS ${GRESOURCE_C} ) add_executable(${PROJECT_NAME} dummy.c)
add_dependencies(${PROJECT_NAME} dummy-resource)