Come copiare i file DLL nella stessa cartella dell'eseguibile utilizzando CMake?


98

Usiamo CMake per generare i file di Visual Studio dei nostri sorgenti nel nostro SVN. Ora il mio strumento richiede che alcuni file DLL si trovino nella stessa cartella dell'eseguibile. I file DLL si trovano in una cartella accanto alla sorgente.

Come posso modificare il mio in modo CMakeLists.txttale che il progetto di Visual Studio generato abbia già i file DLL particolari nelle cartelle di rilascio / debug o li copierà al momento della compilazione?

Risposte:


122

Userei add_custom_commandper raggiungere questo obiettivo insieme a cmake -E copy_if_different.... Per informazioni complete corri

cmake --help-command add_custom_command
cmake -E


Quindi nel tuo caso, se hai la seguente struttura di directory:

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

e il tuo obiettivo CMake a cui si applica il comando è MyTest, quindi potresti aggiungere quanto segue al tuo 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


Se vuoi solo /libs/copiare l'intero contenuto della directory, usa 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>)


Se è necessario copiare diverse DLL a seconda della configurazione (Release, Debug, ad esempio), è possibile averle in sottodirectory denominate con la configurazione corrispondente:, /libs/Releasee /libs/Debug. È quindi necessario inserire il tipo di configurazione nel percorso della dll nella add_custom_commandchiamata, in questo modo:

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

3
Nota rapida per ciò che ha funzionato nel mio caso nel caso in cui aiuti qualcun altro in futuro: ho un progetto di libreria statica a cui si collega facoltativamente l'eseguibile principale e quella libreria richiede una DLL da copiare se aggiunta. Quindi nel file CMakeLists.txt di quella libreria ho usato ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>per la destinazione di destinazione. Altrimenti lo copierebbe nel percorso di creazione della libreria, che era inutile.
AberrantWolf

non è l'obiettivo delle install()direttive cmake assemblare i binari? O forse fare LIBRARYcose? Non conosco veramente la toolchain.
Sandburg

1
$<TARGET_FILE_DIR:MyTest>- che cos'è? Come stampare le informazioni, cosa significa esattamente
ilw

A meno che non mi sia perso qualcosa durante l'integrazione del comando, questo metodo non funziona per le librerie aggiunte con IMPORTED_LIBRARIES. Si lamenta di non essere in grado di eseguire un comando post-build quando non è stato creato nulla.
Tzalumen

2
Dopo aver testato e sollecitato il mio cmake: se stai usando IMPORTEDlibrerie e devi riposizionare le DLL, devi usare un comando variante. Se hai aggiunto la tua IMPORTEDlibreria come MyImportedLibfaresti, COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>Nota che per eseguire più comandi di post-compilazione, devi add_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
combinarli

24

Ho inserito queste righe nel mio file CMakeLists.txt di primo livello. Tutte le librerie e gli eseguibili compilati da CMake verranno posizionati nel livello superiore della directory di build in modo che gli eseguibili possano trovare le librerie ed è facile eseguire tutto.

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

Si noti che questo non risolve il problema dell'OP di copiare i binari precompilati dalla directory dei sorgenti del progetto.


7

Ho avuto questo problema oggi quando ho provato a creare una build per Windows del mio programma. E ho finito per fare qualche ricerca io stesso poiché tutte queste risposte non mi soddisfacevano. C'erano tre problemi principali:

  • Volevo che le build di debug fossero collegate alle versioni di debug delle librerie e le build di rilascio da collegare rispettivamente alle build di rilascio delle librerie.

  • In aggiunta a ciò, volevo che le versioni corrette dei file DLL (Debug / Release) venissero copiate nelle directory di output.

  • E volevo ottenere tutto questo senza scrivere sceneggiature complesse e fragili.

Dopo aver sfogliato alcuni manuali CMake e alcuni progetti multipiattaforma su github ho trovato questa soluzione:

Dichiara la tua libreria come destinazione con l'attributo "IMPORTED", fai riferimento al suo debug e rilascia i file .lib e .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")

Collega questo obiettivo al tuo progetto come al solito

target_link_libraries(YourProg sdl2 ...)

Effettua un passaggio di build personalizzato per copiare il file dll nella sua destinazione se è stato modificato in qualche modo dalla build precedente

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

5

Un addendum alla risposta accettata, aggiunto come risposta separata in modo da ottenere la formattazione del codice:

Se stai costruendo le tue dll nello stesso progetto, di solito saranno nelle directory di rilascio, debug, ecc. Dovrai utilizzare le variabili di ambiente di Visual Studio per copiarle correttamente. per esempio:

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

per la fonte e

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

per la destinazione. Nota la fuga!

Non è possibile utilizzare la variabile CMake CMAKE_BUILD_TYPE per la configurazione poiché è risolta al momento della generazione del progetto VS e sarà sempre qualunque sia l'impostazione predefinita.


8
L'ultima parte della risposta accettata affronta questo problema nel modo più pulito di CMake usando$<CONFIGURATION>
Chuck Claunch

4

Puoi anche usare il comando find_library:

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

Con un EXECUTABLE_PATH definito, ad esempio:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

potresti spostare i file .dll di cui il tuo eseguibile ha bisogno, con

file(COPY ${<some_var>}
    DESTINATION ${EXECUTABLE_OUTPUT_PATH})

2

Questo è utile per uno di loro

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)

1

Probabilmente è necessario aggiungere un target personalizzato e farlo dipendere da uno dei target eseguibili.

Per copiare il file utilizzando la funzione sopra, utilizzare:

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

0

Sono un principiante di CMake, ma volevo comunque condividere la mia esperienza. Nel mio caso avevo bisogno di una copia post-installazione in modo che tutti i miei binari siano in. Nel caso di binari di terze parti che possono essere importati all'interno di CMake, per me funziona quanto segue:

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

Ovviamente IMPORTED_LOCATION_RELEASE può avere varianti a seconda di come è stata costruita / installata la libreria condivisa. Potrebbe essere IMPORTED_LOCATION_DEBUG.

Forse c'è un modo migliore per ottenere quel nome di proprietà, non lo so.


0

Spostamento di file durante la compilazione utilizzando install

Ho riscontrato questo problema cercando di seguire il tutorial ufficiale di CMake al passaggio 9 . Questa era la posizione del file che volevo spostare:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

Questa era la posizione in cui volevo che si trovasse il file:

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

Dal momento che questa DLL è stata generata da una libreria condivisa, tutto quello che ho fatto è stato di inserire questa riga nel CMakeLists.txtnella sottodirectory che conteneva il codice sorgente per la libreriasrc/Mathfunctions/CMakeLists.txt

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

Grazie alle tue risposte ho potuto pensare a questo. È solo una riga, quindi penso che sia ok. L' $<CONFIG>può avere due valori di debug o di uscita A seconda di come il progetto è costruito, come la domanda iniziale richiesto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.