Wie kopiere ich DLL-Dateien mit CMake in denselben Ordner wie die ausführbare Datei?

98

Wir verwenden CMake zum Generieren der Visual Studio-Dateien unserer Quellen in unserem SVN. Jetzt erfordert mein Tool, dass sich einige DLL-Dateien im selben Ordner wie die ausführbare Datei befinden. Die DLL-Dateien befinden sich in einem Ordner neben der Quelle.

Wie kann ich meine CMakeLists.txtso ändern , dass das generierte Visual Studio-Projekt entweder bereits die bestimmten DLL-Dateien in den Release- / Debug-Ordnern enthält oder diese beim Kompilieren kopiert?

Matte
quelle

Antworten:

122

Ich würde add_custom_commanddies zusammen mit erreichen cmake -E copy_if_different.... Für vollständige Informationen laufen

cmake --help-command add_custom_command
cmake -E


Also in Ihrem Fall, wenn Sie die folgende Verzeichnisstruktur haben:

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

MyTestWenn Ihr CMake-Ziel, für das der Befehl gilt, lautet , können Sie Ihrer CMakeLists.txt Folgendes hinzufügen:

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


Wenn Sie nur den gesamten Inhalt des /libs/Verzeichnisses kopieren möchten , verwenden Sie 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>)


Wenn Sie je nach Konfiguration unterschiedliche DLLs kopieren müssen (Release, Debug, z. B.), können Sie diese in Unterverzeichnissen mit der entsprechenden Konfiguration haben:, /libs/Releaseund /libs/Debug. Anschließend müssen Sie den Konfigurationstyp add_custom_commandwie folgt in den Pfad zur DLL des Aufrufs einfügen :

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
        $<TARGET_FILE_DIR:MyTest>)
Fraser
quelle
3
Kurzer Hinweis zu dem, was in meinem Fall funktioniert hat, falls es in Zukunft jemand anderem hilft: Ich habe ein statisches Bibliotheksprojekt, mit dem die ausführbare Hauptdatei optional verknüpft ist, und für diese Bibliothek muss beim Hinzufügen eine DLL kopiert werden. Also in der CMakeLists.txt-Datei dieser Bibliothek, die ich ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>für das Ziel verwendet habe. Andernfalls würde es in den Bibliothekserstellungspfad kopiert, was nutzlos war.
AberrantWolf
Ist es nicht das Ziel der cmake- install()Direktiven, die Binärdateien zusammenzustellen? Oder vielleicht LIBRARYDinge machen? Ich kenne die Toolchain nicht wirklich.
Sandburg
1
$<TARGET_FILE_DIR:MyTest>- Was ist es? Wie man Infos druckt, was genau das bedeutet
ilw
Sofern ich bei der Integration des Befehls nichts verpasst habe, funktioniert diese Methode nicht für Bibliotheken, die mit hinzugefügt wurden IMPORTED_LIBRARIES. Es wird beanstandet, dass ein Post-Build-Befehl nicht ausgeführt werden kann, wenn nichts erstellt wurde.
Tzalumen
2
Beim Testen und Stoßen meines cmake: Wenn Sie IMPORTEDBibliotheken verwenden und die DLLs verschieben müssen, müssen Sie einen varianten Befehl verwenden. Wenn Sie Ihre IMPORTEDBibliothek so hinzugefügt haben, wie MyImportedLibSie es verwenden würden COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>Beachten Sie, dass Sie zum Ausführen mehrerer Post-Build-Befehle alle in einen benutzerdefinierten Befehl add_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
eingebunden haben müssen,
24

Ich habe diese Zeilen in meine CMakeLists.txt-Datei der obersten Ebene eingefügt. Alle von CMake kompilierten Bibliotheken und ausführbaren Dateien werden in der obersten Ebene des Build-Verzeichnisses abgelegt, damit die ausführbaren Dateien die Bibliotheken finden können und es einfach ist, alles auszuführen.

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

Beachten Sie, dass dies das Problem des OP beim Kopieren vorkompilierter Binärdateien aus dem Quellverzeichnis des Projekts nicht löst.

David Grayson
quelle
7

Ich hatte heute dieses Problem, als ich versuchte, ein Windows-Build meines Programms zu erstellen. Und am Ende habe ich selbst recherchiert, da mich all diese Antworten nicht zufriedenstellten. Es gab drei Hauptprobleme:

  • Ich wollte, dass Debug-Builds mit Debug-Versionen von Bibliotheken verknüpft werden und Release-Builds mit Release-Builds von Bibliotheken verknüpft werden.

  • Außerdem wollte ich, dass korrekte Versionen von DLL-Dateien (Debug / Release) in Ausgabeverzeichnisse kopiert werden.

  • Und ich wollte all dies erreichen, ohne komplexe und fragile Skripte zu schreiben.

Nach dem Durchsuchen einiger CMake-Handbücher und einiger Multiplattform-Projekte bei github habe ich folgende Lösung gefunden:

Deklarieren Sie Ihre Bibliothek als Ziel mit dem Attribut "IMPORTED", verweisen Sie auf das Debugging und geben Sie die .lib- und .dll-Dateien frei.

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

Verknüpfen Sie dieses Ziel wie gewohnt mit Ihrem Projekt

target_link_libraries(YourProg sdl2 ...)

Führen Sie einen benutzerdefinierten Build-Schritt aus, um die DLL-Datei an ihr Ziel zu kopieren, wenn sie seit dem vorherigen Build irgendwie geändert wurde

add_custom_command ( TARGET YourProg POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
Kleine Bedrohung
quelle
5

Ein Nachtrag zur akzeptierten Antwort, der als separate Antwort hinzugefügt wurde, damit ich die Code-Formatierung erhalte:

Wenn Sie Ihre DLLs im selben Projekt erstellen, befinden sie sich normalerweise in den Verzeichnissen Release, Debug usw. Sie müssen die Visual Studio-Umgebungsvariablen verwenden, um sie korrekt zu kopieren. z.B:

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

für die Quelle und

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

für das Ziel. Beachten Sie die Flucht!

Sie können die Variable CMake CMAKE_BUILD_TYPE nicht für die Konfiguration verwenden, da sie zur Zeit der VS-Projektgenerierung aufgelöst wird und immer die Standardeinstellung ist.

Dana Robinson
quelle
8
Der letzte Teil der akzeptierten Antwort spricht dies auf sauberere CMake-Weise mit$<CONFIGURATION>
Chuck Claunch
4

Sie können auch den Befehl find_library verwenden:

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

Mit einem definierten EXECUTABLE_PATH zum Beispiel:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

Sie können die DLL-Dateien, die Ihre ausführbare Datei benötigt, mit verschieben

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

Dies ist für einen von ihnen nützlich

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
quelle
1

Sie müssen wahrscheinlich ein benutzerdefiniertes Ziel hinzufügen und es von einem Ihrer ausführbaren Ziele abhängig machen.

Um eine Datei mit der obigen Funktion zu kopieren, verwenden Sie:

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

Ich bin ein CMake-Anfänger, aber ich wollte trotzdem meine Erfahrungen teilen. In meinem Fall benötigte ich eine Kopie nach der Installation, damit alle meine Binärdateien gespeichert sind. Im Fall von Binärdateien von Drittanbietern, die in CMake importiert werden können, funktioniert Folgendes für mich:

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

Offensichtlich kann IMPORTED_LOCATION_RELEASE Varianten haben, abhängig davon, wie die gemeinsam genutzte Bibliothek erstellt / installiert wurde. Könnte IMPORTED_LOCATION_DEBUG sein.

Vielleicht gibt es einen besseren Weg, um diesen Eigenschaftsnamen zu erhalten, ich weiß es nicht.

Norman Pellet
quelle
0

Verschieben von Dateien während der Erstellung mit install

Ich hatte dieses Problem beim Versuch, dem offiziellen CMake-Tutorial zu Schritt 9 zu folgen . Dies war der Speicherort der Datei, die ich verschieben wollte:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

Dies war der Speicherort, an dem sich die Datei befinden sollte:

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

Da diese DLL als gemeinsam genutzte Bibliothek generiert wurde, habe ich diese Zeile nur CMakeLists.txtin das Unterverzeichnis aufgenommen , das den Quellcode für die Bibliothek enthieltsrc/Mathfunctions/CMakeLists.txt

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

Dank Ihrer Antworten konnte ich darüber nachdenken. Ist nur eine Zeile, also denke ich ist ok. Das $<CONFIG>kann zwei Werte haben: Debuggen oder Freigeben Je nachdem, wie das Projekt erstellt wurde, ist die ursprüngliche Frage erforderlich.

David Martinez C.
quelle