Copie el archivo del directorio de origen al directorio binario usando CMake


99

Estoy intentando crear un proyecto simple en CLion. Utiliza CMake (soy nuevo aquí) para generar Makefiles para construir un proyecto (o algún tipo de él)

Todo lo que necesito es transferir algún archivo que no sea del proyecto (algún tipo de archivo de recursos) al directorio binario cada vez que ejecuto my code.

Ese archivo contiene datos de prueba y la aplicación lo abre para leerlos. Intenté varias formas de hacerlo:

  • Vía file(COPY ...

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

    Se ve bien, pero funciona solo una vez y no vuelve a copiar el archivo después de la siguiente ejecución.

  • Vía add_custom_command

    • OUTPUT versión

      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 versión

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

    Pero ninguno de ellos funciona.

¿Qué estoy haciendo mal?

Respuestas:


127

Puede considerar usar configure_file con la COPYONLYopción:

configure_file(<input> <output> COPYONLY)

A diferencia de file(COPY ...)esto, crea una dependencia a nivel de archivo entre la entrada y la salida, es decir:

Si se modifica el archivo de entrada, el sistema de compilación volverá a ejecutar CMake para reconfigurar el archivo y generar el sistema de compilación nuevamente.


12
Tenga en cuenta que configure_fileno funcionará con subdirectorios, incluso si usa GLOB para crear una lista de archivos.
Tarántula

63

Ambas opciones son válidas y apuntan a dos pasos diferentes de su compilación:

  1. file(COPY ...copia el archivo en el paso de configuración y solo en este paso. Cuando reconstruya su proyecto sin haber cambiado su configuración de cmake, este comando no se ejecutará.
  2. add_custom_command es la opción preferida cuando desea copiar el archivo en cada paso de compilación.

La versión correcta para su tarea sería:

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

se puede elegir entre PRE_BUILD, PRE_LINK, POST_BUILD mejor es leer la documentación de add_custom_command

se puede encontrar un ejemplo sobre cómo usar la primera versión aquí: Use CMake add_custom_command para generar la fuente para otro objetivo


1
¿Es CMAKE_SOURCE_DIR o CMAKE_CURRENT_SOURCE_DIR?
Syaiful Nizam Yahya

1
@SyaifulNizamYahya use CMAKE_CURRENT_SOURCE_DIRsi el test/input.txtarchivo es relativo al CMakeLists.txtarchivo actual . Si es relativo a la raíz CMakeLists.txt, utilice CMAKE_SOURCE_DIR.
Mark Ingram

16

La primera de las opciones que probó no funciona por dos razones.

Primero, olvidó cerrar el paréntesis.

En segundo lugar, DESTINATIONdebe ser un directorio, no un nombre de archivo. Suponiendo que cerró el paréntesis, el archivo terminaría en una carpeta llamada input.txt.

Para que funcione, cámbialo a

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

4

Sugeriría TARGET_FILE_DIRsi desea que el archivo se copie en la misma carpeta que su archivo .exe.

$ Directorio del archivo 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}>)

En VS, este script cmake copiará input.txt al mismo archivo que su archivo ejecutable final, sin importar si es depurado o liberado.


3

Esto es lo que usé para copiar algunos archivos de recursos: los archivos de copia son un objetivo vacío para ignorar errores

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

También agregaría add_dependencies(MainTarget copy-files)para que se ejecute automáticamente cuando construyo MainTarget
Herrgott

Esta parece ser la mejor respuesta (+ comentario de Herrgott), ya que en realidad garantiza que la versión actual de la fuente esté siempre en la compilación de la publicación de destino. Para trabajos de copia pequeños, esto funciona bien, gracias. Poner add_dependencies(MainTarget copy-files)el CMakeLists.txtarchivo raíz significa que se puede utilizar durante todo el proyecto.
Satnhak

1

si desea copiar la carpeta del directorio currant a la carpeta binaria (carpeta de compilación)

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

entonces el syntexe es:

file(COPY pathSource DESTINATION pathDistination)

0

El configure_file sugerido es probablemente la solución más sencilla. Sin embargo, no volverá a ejecutar el comando de copia si eliminó manualmente el archivo del directorio de compilación. Para manejar también este caso, lo siguiente funciona para mí:

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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.