web-dev-qa-db-fra.com

CMake - lien vers la bibliothèque téléchargée depuis ExternalProject_add ()

J'essaie d'utiliser ExternalProject_add () pour télécharger/installer les dépendances. Il s'installe correctement, mais je ne sais pas comment lier réellement les bibliothèques après leur téléchargement.

Je veux appeler target_link_libraries () sur la bibliothèque qui vient d'être téléchargée, mais le chemin d'accès à la bibliothèque variera selon le système.

S'il s'agissait d'une dépendance système, je pourrais simplement appeler find_package () - mais les packages n'étaient pas installés sur le chemin de recherche par défaut. Je ne pense pas que vous puissiez spécifier un chemin de recherche pour find_package en mode module.

Voici un extrait de mon CMakeLists.txt qui ne fonctionne pas:

ExternalProject_Add(
protobuf
URL http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.gz
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR>
PREFIX ${MYPROJ_SOURCE_DIR}/dependencies
)
find_package(protobuf REQUIRED)
set(LIBS ${LIBS} ${PROTOBUF_LIBRARIES})
target_link_libraries (mybinary ${LIBS})
48
Brett Thomas

Lorsque vous utilisez ExternalProject_Add, vous ne pouvez pas utiliser find_package, car il n'y a rien à trouver lorsque CMake s'exécute pour configurer le projet externe.

Donc, si l'emplacement des bibliothèques varie selon la plateforme, vous aurez besoin d'une logique conditionnelle basée sur votre plateforme. (Je ne connais pas les bibliothèques ou la structure de protobuf ici, donc ce n'est qu'un exemple, mais cela devrait vous aider à aller dans la bonne direction ...) Quelque chose comme ça:

if(WIN32)
  set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/win"
  set(prefix "")
  set(suffix ".lib")
elseif(Apple)
  set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/mac"
  set(prefix "lib")
  set(suffix ".a")
else()
  set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/linux"
  set(prefix "lib")
  set(suffix ".a")
endif()

set(PROTOBUF_LIBRARIES
  "${PROTOBUF_LIB_DIR}/${prefix}protobufLib1${suffix}"
  "${PROTOBUF_LIB_DIR}/${prefix}protobufLib2${suffix}")

Certes, c'est moins pratique que d'utiliser find_package. Si vous pouvez utiliser un package pré-construit/pré-installé, vous devriez, afin que vous puissiez utiliser find_package. Si vous devez créer l'autre package à partir du code source dans le cadre de votre projet, ExternalProject_Add est utile, même s'il n'est pas en mesure d'abstraire tous les détails pour vous.

19
DLRdave

Parce que vous téléchargez le projet externe, vous savez déjà où tout se trouve parce que vous venez de le télécharger, il n'a donc pas besoin d'être "trouvé".

Je l'ai fait fonctionner avec add_library. Ceci est mon code réel qui fonctionne:

ExternalProject_Add(ForexConnectDownload
    PREFIX 3rd_party
    #--Download step--------------
    URL http://fxcodebase.com/bin/forexconnect/1.3.1/ForexConnectAPI-1.3.1-Linux-x86_64.tar.gz
    URL_HASH SHA1=7fdb90a2d45085feb8b76167cae419ad4c211d6b
    #--Configure step-------------
    CONFIGURE_COMMAND ""
    #--Build step-----------------
    BUILD_COMMAND ""
    #--Install step---------------
    UPDATE_COMMAND "" # Skip annoying updates for every build
    INSTALL_COMMAND ""
)

SET(FXCM_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/3rd_party/src/ForexConnectDownload/include)
SET(FXCM_LIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/3rd_party/src/ForexConnectDownload/lib)

add_library(ForexConnect SHARED IMPORTED)
set_target_properties(ForexConnect PROPERTIES IMPORTED_LOCATION ${FXCM_LIB_DIR}/libForexConnect.so)

À partir de là, chaque programme qui en dépend a besoin d'un add_dependencies et bien sûr target_link_libraries. Par exemple:

include_directories(${FXCM_INCLUDE_DIR})
add_executable(syncDatabase syncDatabase.cpp trader/database.cpp trader/fxcm.cpp)
target_link_libraries(syncDatabase ForexConnect)
add_dependencies(syncDatabase ForexConnectDownload)
  • include_directories - lui dit de rechercher des répertoires là-bas
  • target_link_libraries - ajoutez simplement votre bibliothèque, comme vous l'avez nommée (pas une variable)

Les add_dependencies le font attendre avant d'essayer d'inclure les répertoires nécessaires.

Cela fait l'affaire pour moi. Fonctionne avec make -j4. Obtenez toutes les dépendances à droite.

22
matiu

Pour développer la réponse DLRdave ci-dessus, vous n'avez pas besoin de définir manuellement les préfixes et suffixes pour les bibliothèques statiques car CMAKE fournit des variables avec les bonnes pour chaque plate-forme.

Voir CMake Variables utiles pour plus d'informations.

Par exemple:

  • CMAKE_SHARED_LIBRARY_PREFIX
  • CMAKE_SHARED_LIBRARY_SUFFIX
  • CMAKE_STATIC_LIBRARY_PREFIX
  • CMAKE_STATIC_LIBRARY_SUFFIX
18
aled

Un autre idiome que vous pouvez utiliser pour résoudre ce problème:

  1. Rendez vos commandes find_package facultatives (supprimez 'REQUIS')
  2. Ajoutez du code de condition pour créer vos cibles uniquement si find_package réussit.
  3. find_package échouera et vos cibles ne seront pas construites la première fois, mais les projets externes seront construits.
  4. Exécutez à nouveau cmake/make, cette fois find_package réussira et vos cibles seront construites.

Vous pouvez voir cet idiome en action dans https://github.com/biometrics/l prévue .

4
jklontz

Vous pouvez utiliser la commande link_directories pour lier des bibliothèques dans un répertoire spécifique. Dans votre cas, le répertoire où votre projet externe est construit.

ExternalProject_Add(MyExternalLibrary ...)

Ajoutez le répertoire de sortie au chemin de recherche:

link_directories(${CMAKE_BINARY_DIR}/lib/MyExternalLibrary-prefix/lib)

Assurez-vous d'ajouter l'exécutable après en spécifiant le répertoire de liens:

add_executable(MyProgram main.c)

Spécifiez les bibliothèques auxquelles votre projet doit être lié:

target_link_libraries(MyProgram ExternalLibraryName)

N'oubliez pas de dépendre du projet externe:

add_dependencies(MyProgram MyExternalLibrary)
4
joke