2012-04-04 21 views
6

Digamos que hay siguiente estructura de directorios:dependencias de solapamiento entre las bibliotecas de CMake

projects 
    | 
    +--lib1 
    | | 
    | +-CMakeFiles.txt 
    | 
    +--lib2 
    | | 
    | +-CMakeFiles.txt 
    | 
    +--test 
     | 
     +-CMakeFiles.txt 

LIB1/CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0) 

add_library(lib1 STATIC lib1.cpp) 

LIB2/CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0) 

add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1) 
add_library(lib2 STATIC lib2.cpp) 
target_link_libraries(lib2 lib1) 

prueba /CMakeFiles.txt:

cmake_minimum_required(VERSION 2.0) 
project(test) 

add_subdirectory(../lib1 ${CMAKE_CURRENT_BINARY_DIR}/lib1) 
add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2) 

add_executable(test main.cpp) 
target_link_libraries(test lib1 lib2) 

I.e. lib2 depende de lib1 y test depende de ambos. (Sé que las bibliotecas técnicamente estáticas no "vinculan", pero eso es solo un ejemplo).

El problema es que con la configuración actual lib1 compila dos veces: la primera vez en el directorio de compilación "prueba" y una segunda vez en "test/build_directory/lib2/build_directory". Me gustaría evitar eso.

Quiero poder agregar la dependencia en lib1, lib2 o ambos (usando add_subdirectory) a cualquier proyecto que se encuentre en otro lugar. Así que mover CMakeFiles no es una opción. También quiero evitar compilar cualquier biblioteca varias veces.

¿Cómo puedo hacer eso?

cmake-2.8.4 WinXP SP3

--EDIT-- cmakelists de nivel superior no es una opción, porque yo quiero seguir directorio de nivel superior limpia y ser capaz de incluir bibliotecas de otros proyectos que puede estar ubicado en otro lugar. Debido a que es Windows, no puedo "instalar el paquete en todo el sistema". No quiero perder la capacidad de cambiar el compilador sobre la marcha. Las bibliotecas de utilidades compiladas con diferentes compiladores utilizarán diferentes bibliotecas de tiempo de ejecución de C/ABI y, como resultado, serán incompatibles.

Respuesta

4

Con CMake, las dependencias de la biblioteca son transitivas, por lo que no debe llamar al add_subdirectory dos veces en test/CMakeFiles.txt (tampoco necesita enumerar lib1 como una dependencia de test ya que es una dependencia de lib2).

Para poder modificar los archivos de filtro de test.txt a:

cmake_minimum_required(VERSION 2.8.7) # Prefer the most current version possible 
project(test) 

add_subdirectory(../lib2 ${CMAKE_CURRENT_BINARY_DIR}/lib2) 

add_executable(test main.cpp) 
target_link_libraries(test lib2) 

También, probablemente debería eliminar los cmake_minimum_required llamadas de sus archivos CMakeFiles.txt no pertenecen al proyecto (los lib). Para más información, ejecute:

cmake --help-policy CMP0000 


Esta configuración todavía causar todas las librerías a volver a compilar si se agrega un subdirectorio test2 proyecto similar y que depende de lib1 y lib2. Si realmente no desea tener un CMakeFiles.txt de nivel superior en projects/, entonces está atascado con lo que está haciendo, o podría usar el comando export o install.

export crearía un archivo que podría ser include d por otros proyectos y que importa los objetivos al proyecto que llama al include.

install podría instalar las bibliotecas en otro subdirectorio común de projects/. Dependiendo de la estructura de su directorio de origen, esto podría tener la ventaja de hacer que los encabezados de API de biblioteca deseados estén disponibles para los proyectos dependientes.

Sin embargo, estas dos opciones requieren que los proyectos de biblioteca dependientes sean reconstruidos (e instalados) si se modifican, mientras que su configuración actual incluye todos los destinos dependientes en su proyecto, por lo que cualquier cambio a un archivo fuente en un dependiente la biblioteca hará que su objetivo test se desactualice.

Para más detalles sobre export y install, ejecute:

cmake --help-command export 
cmake --help-command install 
+1

Puede haber casos en los que pueda asignar de forma única la dependencia lib1 a lib2 o viceversa. Pero también hay casos comunes en los que tiene módulos acoplados de forma flexible que desea construir (piense en diferentes complementos) que comparten dependencias. Entonces, por ejemplo, tiene prog1 que tiene la dependencia lib1 y lib2 y tiene prog2 que tiene la dependencia lib2 y lib3. Y ahora, si quiere tener combinaciones diferentes (por ejemplo, no necesita prog2 en este caso, por lo que no lo incluye), puede ser un problema si lib2 es una dependencia de prog2 porque ya no está disponible . – user518450

+1

user518450 tiene un punto válido; en mi caso, tengo una situación donde tanto la aplicación (llamada test en el ejemplo) como lib2 contienen código usando lib1, pero la dependencia de lib2 a lib1 es condicional, ya que depende de las características habilitadas en lib2. Entonces lib2 puede o no tener una dependencia en lib1. Huelga decir que me encantaría encontrar una solución a esto. – psyill

+1

@psyill compruebe mi respuesta a continuación con encabezados-guardias. funciona como un encanto para este tipo de situaciones. – user518450

0

Quizás agregue un CMakeLists.txt de nivel superior en su directorio de proyectos. Algo así como:

project(YourProjects) 

add_subdirectory(lib1) 
add_subdirectory(lib2) 
add_subdirectory(test) 

Esto debería ser suficiente y le dará una solución de archivo o archivo MAKE en su más alto nivel acumulación dir. A continuación, elimine el add_subdirectory(../lib1 ... de sus proyectos lib1 y lib2, pero en su lugar simplemente enlace a ellos. CMake sabrá cómo encontrar lib1 y lib2 al compilar la prueba.

I.e. en LIB2:

project(lib2) 
add_library(lib2 STATIC lib2.cpp) 
target_link_libraries(lib2 lib1) 

y en la prueba:

project(test) 
add_executable(test main.cpp) 
target_link_libraries(test lib1 lib2) 

ventaja añadida: obtendrá archivos make/solutionfiles para la construcción de LIB2 (con LIB1 dependiente) en el directorio LIB2 ...

+0

cmakelists de nivel superior no es una opción. Ahora, si pudieras decir cómo hacerle saber a cmake que hay otro proyecto en otra parte ... – SigTerm

+0

Por supuesto, no sabía sobre el requisito adicional que prohibía cmakelists de alto nivel ... Sabes que aún puedes "instalar" paquetes en Windows, por ejemplo especificando el CMAKE_INSTALL_PREFIX cuando ejecuta CMake? Si es necesario, también puede cambiar el prefijo de instalación cuando todavía está en el 'C: \ Archivos de programa' predeterminado. –

+0

¿Consideró separar todas sus bibliotecas y aplicaciones y escribir los archivos "BuildConfig.cmake" correctos y luego usar find_package en cada proyecto? –

11

Otra solución es añadir un guardia en la parte superior del subdirectorio-CMakeLists.txt:

if(TARGET targetname) 
    return() 
endif(TARGET targetname) 

lo que provocará Haga clic en no hacer nada la segunda vez que se agrega el subdirectorio (si el nombre del destino se está definiendo en ese archivo, por supuesto).

Esto dará lugar a la creación de lib en un lugar de tipo arbitrario (dependiendo de qué módulo se haya agregado primero) en la compilación/árbol, pero se compilará solo una vez y se vinculará a todas partes.

En su ejemplo, debe agregar

if(TARGET lib1) 
    return() 
endif(TARGET lib1) 

en la parte superior de lib1/CMakeFiles.txt

Cuestiones relacionadas