2011-06-15 5 views
38

Estoy tratando de usar ExternalProject_add() para descargar/instalar dependencias. Se instala bien, pero no puedo encontrar la forma de vincular las bibliotecas una vez que se hayan descargado.CMake - enlace a la biblioteca descargada de ExternalProject_add()

Deseo llamar a target_link_libraries() en la biblioteca que acaba de descargar, pero la ruta a la biblioteca variará según el sistema.

Si esto fuera una dependencia del sistema, podría simplemente llamar a find_package() - pero los paquetes no se instalaron en la ruta de búsqueda predeterminada. No creo que pueda especificar una ruta de búsqueda para find_package en el modo de módulo.

He aquí un fragmento de mi CMakeLists.txt que no funciona:

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

Respuesta

15

Al utilizar ExternalProject_Add, no se puede utilizar find_package, ya que no hay nada que encontrar cuando se ejecuta CMake para configurar el proyecto exterior.

Por lo tanto, si las ubicaciones de las bibliotecas varían según la plataforma, necesitará una lógica condicional basada en su plataforma. (No sé bibliotecas o estructura de protobuf aquí, así que esto es sólo un ejemplo, pero debería conseguir que va en la dirección correcta ...) Algo como esto:

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

Por supuesto, esto es menos conveniente que usar find_package. Si puede usar un paquete precompilado/preinstalado, debe hacerlo, de modo que pueda usar find_package. Sin embargo, si debe compilar el otro paquete desde el código fuente como parte de su proyecto, ExternalProject_Add es útil, aunque no puede abstraer todos los detalles por usted.

+0

Gracias, eso es realmente útil. También para no causar confusión, protobuf no tiene ubicaciones de bibliotecas variables, pero R sí. –

+7

cmake proporciona las variables de prefijo y sufijo para su plataforma: '" $ {install_dir}/lib/$ {CMAKE_SHARED_MODULE_PREFIX} protobufLib1 $ {CMAKE_SHARED_LIBRARY_SUFFIX} "' –

+4

Mientras esto funciona, creo que es horrible. ¿De qué sirve usar cmake si tengo que escribir el código condicional de la plataforma? Además, esperaría que ExternalProject proporcionara una manera simple de importar los objetivos construidos, ¿por qué querría construir un proyecto externo si no puedo importarlos fácilmente después? ¿Cuál es el punto de? ¿Me estoy perdiendo de algo? – Jens

2

Puede usar el comando link_directories para vincular las bibliotecas dentro de un directorio específico. En su caso, el directorio donde se construyó su proyecto externo.

ExternalProject_Add(MyExternalLibrary ...) 

Añadir el directorio de salida a la ruta de búsqueda:

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

Asegúrese de añadir el ejecutable después especificando el directorio de enlaces:

add_executable(MyProgram main.c) 

Especificar las bibliotecas de su proyecto debería estar vinculado a:

target_link_libraries(MyProgram ExternalLibraryName) 

No se olvide que depender de los proyectos externos:

add_dependencies(MyProgram MyExternalLibrary) 
+0

Siento que la cadena 'link_directories' actual debería ser más larga, ya que veo algo como * MyExternalLibrary-build/lib * bajo * lib * en mi caso. – mlt

+0

Intenté esta técnica y no funciona en una nueva compilación. Obtiene el error (su biblioteca no pudo ser encontrada). – matiu

3

Otro lenguaje que puede utilizar para resolver este problema:

  1. Hacer comandos opcionales su find_package (quitar 'required')
  2. Agregue un código de condición para construir solo sus objetivos si find_package tiene éxito.
  3. find_package fallará y sus objetivos no se generarán la primera vez, pero se generarán los proyectos externos.
  4. Ejecute cmake/make nuevamente, esta vez find_package tendrá éxito y sus objetivos se construirán.

Puede ver este modismo en acción en https://github.com/biometrics/likely.

14

Para ampliar la respuesta anterior de DLRdave, no necesita establecer prefijos y sufijos manualmente para las bibliotecas estáticas porque CMAKE proporciona variables con las correctas para cada plataforma.

Consulte CMake Useful Variables para obtener más información.

Por ejemplo:

  • CMAKE_SHARED_LIBRARY_PREFIX
  • CMAKE_SHARED_LIBRARY_SUFFIX
  • CMAKE_STATIC_LIBRARY_PREFIX
  • CMAKE_STATIC_LIBRARY_SUFFIX
11

Debido a que está descargando el proyecto externo, ya sabe dónde está todo, ya que sólo lo descargué, por lo que no necesita 'fin timbre'.

Lo tengo trabajando con add_library. Este es mi código real que funciona:

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) 

A partir de ahí, cada programa que depende de él necesita un add_dependencies y por supuesto target_link_libraries. Por ejemplo:

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 - dice que la búsqueda de directorios allí
  • target_link_libraries - sólo tiene que añadir su biblioteca, como se la llamó (no una variable)

Los add_dependencies hace esperar antes de intentar incluir los directorios necesarios.

Eso hace el truco para mí. Funciona con make -j4. Obtenga todas las dependencias correctas.

+1

Desde cmake 3.2 puede usar UPDATE_DISCONNECTED para evitar actualizaciones automáticas.Puede actualizar agregando un objetivo personalizado si es necesario. – Jens

+0

¿cómo sabe 'ForexConnect'? ejemplo aquí 'add_library (ForexConnect SHARED IMPORTED)' – Lamda

+0

Solución realmente genial, que incluso va más allá de la simple diferenciación y gestiona las dependencias y los enlaces. –

Cuestiones relacionadas