Comment copier des fichiers DLL dans le même dossier que l'exécutable à l'aide de CMake?

98

Nous utilisons CMake pour générer les fichiers Visual Studio de nos sources dans notre SVN. Maintenant, mon outil nécessite que certains fichiers DLL se trouvent dans le même dossier que l'exécutable. Les fichiers DLL sont dans un dossier à côté de la source.

Comment puis-je changer mon CMakeLists.txtafin que le projet Visual Studio généré contienne déjà les fichiers DLL particuliers dans les dossiers release / debug ou les copie lors de la compilation?

Tapis
la source

Réponses:

122

J'utiliserais add_custom_commandpour y parvenir avec cmake -E copy_if_different.... Pour des informations complètes, exécutez

cmake --help-command add_custom_command
cmake -E


Donc, dans votre cas, si vous avez la structure de répertoires suivante:

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

et votre cible CMake à laquelle la commande s'applique est MyTest, alors vous pouvez ajouter ce qui suit à votre 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 vous souhaitez simplement /libs/copier l'intégralité du contenu du répertoire, utilisez 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 vous avez besoin de copier différentes DLL en fonction de la configuration (Release, Debug, par exemple), vous pouvez les avoir dans des sous-répertoires nommés avec la configuration correspondante:, /libs/Releaseet /libs/Debug. Vous devez ensuite injecter le type de configuration dans le chemin de la dll dans l' add_custom_commandappel, comme ceci:

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
        $<TARGET_FILE_DIR:MyTest>)
Fraser
la source
3
Note rapide pour ce qui a fonctionné dans mon cas au cas où cela aiderait quelqu'un d'autre à l'avenir: j'ai un projet de bibliothèque statique auquel l'exécutable principal est éventuellement lié, et cette bibliothèque nécessite une DLL à copier si elle est ajoutée. Donc, dans le fichier CMakeLists.txt de cette bibliothèque, j'ai utilisé ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>pour la destination cible. Sinon, il le copierait dans le chemin de construction de la bibliothèque, ce qui était inutile.
AberrantWolf le
n'est-ce pas le but des install()directives cmake d'assembler les binaires? Ou peut-être faire des LIBRARYchoses? Je ne connais pas vraiment la chaîne d'outils.
Sandburg
1
$<TARGET_FILE_DIR:MyTest>- qu'Est-ce que c'est? Comment imprimer des informations, que signifient exactement
ilw
Sauf si j'ai manqué quelque chose lors de l'intégration de la commande, cette méthode ne fonctionne pas pour les bibliothèques ajoutées avec IMPORTED_LIBRARIES. Il se plaint de ne pas pouvoir exécuter une commande post-build alors que rien n'a été construit.
Tzalumen
2
Après avoir testé et poussé mon cmake: si vous utilisez des IMPORTEDbibliothèques et que vous devez déplacer les DLL, vous devez utiliser une commande variant. Si vous avez ajouté votre IMPORTEDbibliothèque comme MyImportedLibvous le feriez, COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>notez que pour exécuter plusieurs commandes de post-construction, vous devez toutes les add_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
relier
24

J'ai mis ces lignes dans mon fichier CMakeLists.txt de niveau supérieur. Toutes les bibliothèques et exécutables compilés par CMake seront placés dans le niveau supérieur du répertoire de construction afin que les exécutables puissent trouver les bibliothèques et il est facile de tout exécuter.

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

Notez que cela ne résout pas le problème de l'OP de copier des binaires précompilés à partir du répertoire source du projet.

David Grayson
la source
7

J'ai eu ce problème aujourd'hui lorsque j'ai essayé de créer une version Windows de mon programme. Et j'ai fini par faire des recherches moi-même puisque toutes ces réponses ne me satisfaisaient pas. Il y avait trois problèmes principaux:

  • Je voulais que les versions de débogage soient liées aux versions de débogage des bibliothèques et que les versions de version soient liées aux versions de version des bibliothèques, respectivement.

  • En plus de cela, je voulais que les versions correctes des fichiers DLL (Debug / Release) soient copiées dans les répertoires de sortie.

  • Et je voulais réaliser tout cela sans écrire de scripts complexes et fragiles.

Après avoir parcouru certains manuels CMake et certains projets multiplateformes sur github, j'ai trouvé cette solution:

Déclarez votre bibliothèque comme cible avec l'attribut "IMPORTED", référencez son débogage et publiez les fichiers .lib et .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")

Associez cette cible à votre projet comme d'habitude

target_link_libraries(YourProg sdl2 ...)

Faites une étape de construction personnalisée pour copier le fichier dll vers sa destination s'il a été modifié d'une manière ou d'une autre depuis la construction précédente

add_custom_command ( TARGET YourProg POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
Menace mineure
la source
5

Un addendum à la réponse acceptée, ajouté en tant que réponse distincte afin d'obtenir le formatage du code:

Si vous construisez vos dll dans le même projet, elles seront généralement dans les répertoires Release, Debug, etc. Vous devrez utiliser les variables d'environnement Visual Studio pour les copier correctement. par exemple:

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

pour la source et

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

pour la destination. Notez la fuite!

Vous ne pouvez pas utiliser la variable CMake CMAKE_BUILD_TYPE pour la configuration car elle est résolue au moment de la génération du projet VS et sera toujours la valeur par défaut.

Dana Robinson
la source
8
La dernière partie de la réponse acceptée aborde cela de manière plus propre CMake en utilisant$<CONFIGURATION>
Chuck Claunch
4

Vous pouvez également utiliser la commande find_library:

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

Avec un EXECUTABLE_PATH défini, par exemple:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

vous pouvez déplacer les fichiers .dll dont votre exécutable a besoin, avec

file(COPY ${<some_var>}
    DESTINATION ${EXECUTABLE_OUTPUT_PATH})
Felipe Thorn
la source
2

Ceci est utile pour l'un d'eux

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
la source
1

Vous devez probablement ajouter une cible personnalisée et la rendre dépendante de l'une de vos cibles exécutables.

Pour copier un fichier en utilisant la fonction ci-dessus, utilisez:

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

Je suis un débutant CMake, mais je voulais quand même partager mon expérience. Dans mon cas, j'avais besoin d'une copie post-installation pour que tous mes binaires soient inclus. Dans le cas d'un binaire tiers pouvant être importé dans CMake, ce qui suit fonctionne pour moi:

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()

De toute évidence, IMPORTED_LOCATION_RELEASE peut avoir des variantes en fonction de la manière dont la bibliothèque partagée a été construite / installée. Peut-être IMPORTED_LOCATION_DEBUG.

Il y a peut-être une meilleure façon d'obtenir ce nom de propriété, je ne sais pas.

Norman Pellet
la source
0

Déplacement de fichiers pendant la construction à l'aide de install

J'ai eu ce problème en essayant de suivre le didacticiel officiel de CMake à l' étape 9 . C'était l'emplacement du fichier que je voulais déplacer:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

C'était l'emplacement dans lequel je voulais que le fichier se trouve:

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

Étant donné que cette DLL a été générée en tant que bibliothèque partagée, tout ce que j'ai fait était d'inclure cette ligne dans le CMakeLists.txtsous- répertoire contenant le code source de la bibliothèquesrc/Mathfunctions/CMakeLists.txt

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

Grâce à vos réponses, j'ai pu réfléchir à celle-ci. Est juste une ligne, donc je pense que ça va. Le $<CONFIG>peut avoir deux valeurs Debug ou Release Selon la façon dont le projet est construit, comme la question d'origine l'exige.

David Martinez C.
la source