¿Cómo copiar archivos DLL en la misma carpeta que el ejecutable usando CMake?

98

Usamos CMake para generar los archivos de Visual Studio de nuestras fuentes en nuestro SVN. Ahora mi herramienta requiere que algunos archivos DLL estén en la misma carpeta que el ejecutable. Los archivos DLL están en una carpeta junto a la fuente.

¿Cómo puedo cambiar mi de CMakeLists.txtmodo que el proyecto de Visual Studio generado ya tenga los archivos DLL particulares en las carpetas de liberación / depuración o los copie al compilarlos?

Estera
fuente

Respuestas:

122

Yo usaría add_custom_commandpara lograr esto junto con cmake -E copy_if_different.... Para obtener información completa, ejecute

cmake --help-command add_custom_command
cmake -E


Entonces, en su caso, si tiene la siguiente estructura de directorio:

/CMakeLists.txt
/src
/libs/test.dll

y su objetivo de CMake al que se aplica el comando MyTest, entonces puede agregar lo siguiente a su CMakeLists.txt:

add_custom_command(TARGET MyTest POST_BUILD        # Adds a post-build event to MyTest
    COMMAND ${CMAKE_COMMAND} -E copy_if_different  # which executes "cmake - E copy_if_different..."
        "${PROJECT_SOURCE_DIR}/libs/test.dll"      # <--this is in-file
        $<TARGET_FILE_DIR:MyTest>)                 # <--this is out-file path


Si solo desea /libs/copiar todo el contenido del directorio, use cmake -E copy_directory:

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs"
        $<TARGET_FILE_DIR:MyTest>)


Si necesita copiar diferentes dlls dependiendo de la configuración (Release, Debug, por ejemplo), entonces puede tenerlos en subdirectorios nombrados con la configuración correspondiente:, /libs/Releasey /libs/Debug. Luego, debe inyectar el tipo de configuración en la ruta a la dll en la add_custom_commandllamada, así:

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
        $<TARGET_FILE_DIR:MyTest>)
Fraser
fuente
3
Nota rápida para lo que funcionó en mi caso en caso de que ayude a alguien más en el futuro: tengo un proyecto de biblioteca estática con el que el ejecutable principal se vincula opcionalmente, y esa biblioteca requiere que se copie una DLL si se agrega. Entonces, en el archivo CMakeLists.txt de esa biblioteca que usé ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>para el destino de destino. De lo contrario, lo copiaría a la ruta de construcción de la biblioteca, lo cual era inútil.
AberrantWolf
¿No es el objetivo de las install()directivas cmake ensamblar los binarios? ¿O tal vez hacer LIBRARYcosas? Realmente no conozco la cadena de herramientas.
Sandburg
1
$<TARGET_FILE_DIR:MyTest>- ¿Qué es? Cómo imprimir información, qué significa exactamente
ilw
A menos que me perdí algo cuando estaba integrando el comando, este método no funciona para las bibliotecas agregadas IMPORTED_LIBRARIES. Se queja de no poder ejecutar un comando posterior a la compilación cuando no se ha compilado nada.
Tzalumen
2
Al probar y presionar mi cmake: si está usando IMPORTEDbibliotecas y necesita reubicar las DLL, debe usar un comando de variante. Si ha agregado su IMPORTEDbiblioteca como MyImportedLiblo usaría, tenga en COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>cuenta que para ejecutar varios comandos posteriores a la compilación los necesita todos enlazados en un comando personalizado, por ejemploadd_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
Tzalumen
24

Pongo estas líneas en mi archivo CMakeLists.txt de nivel superior. Todas las bibliotecas y ejecutables compilados por CMake se colocarán en el nivel superior del directorio de compilación para que los ejecutables puedan encontrar las bibliotecas y sea fácil ejecutar todo.

set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

Tenga en cuenta que esto no resuelve el problema del OP de copiar archivos binarios precompilados del directorio fuente del proyecto.

David Grayson
fuente
7

Hoy he tenido este problema cuando intenté hacer una compilación de Windows de mi programa. Y terminé investigando un poco, ya que todas estas respuestas no me satisfacían. Hubo tres problemas principales:

  • Quería que las compilaciones de depuración estuvieran vinculadas con las versiones de depuración de las bibliotecas y que las compilaciones de lanzamiento estuvieran vinculadas con las compilaciones de lanzamiento de las bibliotecas, respectivamente.

  • Además de eso, quería que las versiones correctas de los archivos DLL (Debug / Release) se copiaran en los directorios de salida.

  • Y quería lograr todo esto sin escribir guiones complejos y frágiles.

Después de navegar por algunos manuales de CMake y algunos proyectos multiplataforma en github, encontré esta solución:

Declare su biblioteca como destino con el atributo "IMPORTADO", haga referencia a su depuración y libere los archivos .lib y .dll.

add_library(sdl2 SHARED IMPORTED GLOBAL)
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_RELEASE "${SDL_ROOT_PATH}/lib/SDL2.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_RELEASE "${SDL_ROOT_PATH}/bin/SDL2.dll")
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_DEBUG "${SDL_ROOT_PATH}/lib/SDL2d.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_DEBUG "${SDL_ROOT_PATH}/bin/SDL2d.dll")

Vincula este objetivo con tu proyecto como de costumbre

target_link_libraries(YourProg sdl2 ...)

Realice un paso de compilación personalizado para copiar el archivo dll a su destino si se ha modificado de alguna manera desde la compilación anterior

add_custom_command ( TARGET YourProg POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
Amenaza menor
fuente
5

Un apéndice a la respuesta aceptada, agregado como una respuesta separada para obtener el formato de código:

Si está compilando sus dlls en el mismo proyecto, normalmente estarán en los directorios Release, Debug, etc. Tendrá que usar las variables de entorno de Visual Studio para copiarlas correctamente. p.ej:

"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"

para la fuente y

"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"

para el destino. ¡Tenga en cuenta el escape!

No puede usar la variable CMake CMAKE_BUILD_TYPE para la configuración, ya que se resuelve en el momento de la generación del proyecto VS y siempre será el valor predeterminado.

Dana Robinson
fuente
8
La última parte de la respuesta aceptada aborda esto de la manera más limpia usando CMake$<CONFIGURATION>
Chuck Claunch
4

También puede usar el comando find_library:

find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")

Con un EXECUTABLE_PATH definido, por ejemplo:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

podría mover los archivos .dll que necesita su ejecutable, con

file(COPY ${<some_var>}
    DESTINATION ${EXECUTABLE_OUTPUT_PATH})
Felipe Espina
fuente
2

Esto es útil para uno de ellos.

SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
    ${PROJECT_SOURCE_DIR}/lib CACHE
    PATH "Directory where all the .lib files are dumped." FORCE)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY
    ${PROJECT_SOURCE_DIR}/bin CACHE
    PATH "Directory where .exe and .dll files are dumped." FORCE)
Sai Kiran Nadipilli
fuente
1

Probablemente necesite agregar un destino personalizado y hacer que dependa de uno de sus destinos ejecutables.

Para copiar un archivo usando la función anterior, use:

COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`
arrowd
fuente
0

Soy un principiante de CMake, pero aún así quería compartir mi experiencia. En mi caso, necesitaba una copia posterior a la instalación para que todos mis binarios estén en. En el caso de binarios de terceros que se pueden importar dentro de CMake, lo siguiente funciona para mí:

find_package( dependency REQUIRED )
if( MSVC ) 
    # If done properly and if the dependency has a correct config file, IMPORTED_LOCATION_RELEASE should be defined
    get_target_property( DEP_SHARED_LIB_PATH dependency IMPORTED_LOCATION_RELEASE )
    # Create a bin directory in the install folder
    add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory  ${CMAKE_INSTALL_PREFIX}/bin/)
    # Copy the shared lib file
    add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DEP_SHARED_LIB_PATH} ${CMAKE_INSTALL_PREFIX}/bin/)
endif()

Obviamente, IMPORTED_LOCATION_RELEASE puede tener variantes dependiendo de cómo se construyó / instaló la biblioteca compartida. Podría ser IMPORTED_LOCATION_DEBUG.

Quizás haya una mejor manera de obtener ese nombre de propiedad, no lo sé.

Pellet normando
fuente
0

Mover archivos durante la compilación usando install

Tuve este problema al intentar seguir el tutorial oficial de CMake en el Paso 9 . Esta era la ubicación del archivo que quería mover:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

Esta era la ubicación en la que quería que estuviera el archivo:

src
 |_build
    |_install
         |_bin
             - `MathFunctions.dll`

Dado que esta DLL se generó como una biblioteca compartida, todo lo que hice fue incluir esta línea CMakeLists.txten el subdirectorio que contenía el código fuente de la bibliotecasrc/Mathfunctions/CMakeLists.txt

install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)

Gracias a tus respuestas pude pensar en este. Es solo una línea, así que creo que está bien. El $<CONFIG>puede tener dos valores de depuración o la versión Dependiendo de cómo se construye el proyecto, ya que la pregunta original requiere.

David Martínez C.
fuente