Copie o arquivo do diretório de origem para o diretório binário usando CMake


100

Estou tentando criar um projeto simples no CLion. Ele usa CMake (sou novo aqui) para gerar Makefiles para construir o projeto (ou algum tipo dele)

Tudo que preciso é transferir algum arquivo que não seja do projeto (algum tipo de arquivo de recurso) para o diretório binário toda vez que executo o meu código.

Esse arquivo contém dados de teste e um aplicativo aberto para lê-los. Tentei várias maneiras de fazer isso:

  • Através da file(COPY ...

    file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
            DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/input.txt
    

    Parece bom, mas funciona apenas uma vez e não copia novamente o arquivo após a próxima execução.

  • Através da add_custom_command

    • OUTPUT versão

      add_custom_command(
              OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/input.txt
              COMMAND ${CMAKE_COMMAND} -E copy
                      ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
                      ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
      
    • TARGET versão

      add_custom_target(foo)
      add_custom_command(
              TARGET foo
              COMMAND ${CMAKE_COMMAND} copy
                      ${CMAKE_CURRENT_BINARY_DIR}/test/input.txt
                      ${CMAKE_SOURCE_DIR})
      

    Mas nada disso funciona.

O que estou fazendo de errado?

Respostas:


127

Você pode considerar usar configure_file com a COPYONLYopção:

configure_file(<input> <output> COPYONLY)

Ao contrário, file(COPY ...)ele cria uma dependência de nível de arquivo entre entrada e saída, que é:

Se o arquivo de entrada for modificado, o sistema de compilação executará novamente o CMake para reconfigurar o arquivo e gerar o sistema de compilação novamente.


12
Observe que isso configure_filenão funcionará com subdiretórios, mesmo que você use GLOB para criar uma lista de arquivos.
Tarantula

63

ambas as opções são válidas e visam duas etapas diferentes de sua construção:

  1. file(COPY ...copia o arquivo na etapa de configuração e somente nesta etapa. Quando você reconstrói seu projeto sem ter alterado a configuração do cmake, este comando não será executado.
  2. add_custom_command é a escolha preferida quando você deseja copiar o arquivo em cada etapa de construção.

A versão certa para sua tarefa seria:

add_custom_command(
        TARGET foo POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy
                ${CMAKE_SOURCE_DIR}/test/input.txt
                ${CMAKE_CURRENT_BINARY_DIR}/input.txt)

você pode escolher entre PRE_BUILD, PRE_LINK, POST_BUILD melhor é que você leia a documentação de add_custom_command

um exemplo de como usar a primeira versão pode ser encontrado aqui: Use CMake add_custom_command para gerar fonte para outro destino


1
É CMAKE_SOURCE_DIR ou CMAKE_CURRENT_SOURCE_DIR?
Syaiful Nizam Yahya

1
@SyaifulNizamYahya use CMAKE_CURRENT_SOURCE_DIRse o test/input.txtarquivo for relativo ao CMakeLists.txtarquivo atual . Se for relativo à raiz CMakeLists.txt, use CMAKE_SOURCE_DIR.
Mark Ingram de

16

A primeira opção que você tentou não funcionou por dois motivos.

Primeiro, você se esqueceu de fechar o parêntese.

Em segundo lugar, DESTINATIONdeve ser um diretório, não um nome de arquivo. Supondo que você fechou o parêntese, o arquivo iria parar em uma pasta chamada input.txt.

Para fazer funcionar, basta alterá-lo para

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
     DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

4

Eu sugeriria TARGET_FILE_DIRse você deseja que o arquivo seja copiado para a mesma pasta do seu arquivo .exe.

$ Diretório do arquivo principal (.exe, .so.1.2, .a).

add_custom_command(
  TARGET ${PROJECT_NAME} POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy 
    ${CMAKE_CURRENT_SOURCE_DIR}/input.txt 
    $<TARGET_FILE_DIR:${PROJECT_NAME}>)

No VS, este script cmake irá copiar input.txt para o mesmo arquivo que seu exe final, não importa se ele é depurado ou lançado.


3

Isso é o que eu usei para copiar alguns arquivos de recursos: os arquivos de cópia são um alvo vazio para ignorar erros

 add_custom_target(copy-files ALL
    COMMAND ${CMAKE_COMMAND} -E copy_directory
    ${CMAKE_BINARY_DIR}/SOURCEDIRECTORY
    ${CMAKE_BINARY_DIR}/DESTINATIONDIRECTORY
    )

Eu também adicionaria add_dependencies(MainTarget copy-files)para fazê-lo rodar automaticamente quando eu construir MainTarget
Herrgott,

Esta parece ser a melhor resposta (+ comentário de Herrgott), pois na verdade garante que a versão atual da origem esteja sempre no post build de destino. Para trabalhos de cópia pequenos, isso funciona bem, obrigado. Colocar add_dependencies(MainTarget copy-files)no CMakeLists.txtarquivo raiz significa que ele pode ser usado em todo o projeto.
satnhak

1

se você deseja copiar a pasta do diretório atual para a pasta binária (pasta de compilação)

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/yourFolder/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/yourFolder/)

então o syntexe é:

file(COPY pathSource DESTINATION pathDistination)

0

O configure_file sugerido é provavelmente a solução mais fácil. No entanto, ele não executará novamente o comando de cópia se você excluiu manualmente o arquivo do diretório de construção. Para lidar também com este caso, o seguinte funciona para mim:

add_custom_target(copy-test-makefile ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/input.txt)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/input.txt
                   COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
                                                    ${CMAKE_CURRENT_BINARY_DIR}/input.txt
                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.txt)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.