c++ - online - descarga cmake
cmake: incluye las dependencias de la biblioteca en lib estático (2)
Estoy creando una biblioteca estática en cmake, que depende de muchas otras bibliotecas estáticas. Me gustaría que todos se incluyeran en el archivo de salida .lib / .a, para poder enviar un gran archivo lib a los clientes. En VS2010 hay una opción "Vincular dependencias de biblioteca" que hace exactamente esto.
Pero no puedo encontrar cómo hacerlo en cmake. ¿Puedes establecer esta bandera a través de cmake, u obtener el mismo resultado de otra manera? He intentado target_link_libraries (...) y también add_dependencies (...) pero cmake parece simplemente ignorar esta línea para las librerías estáticas
Me gustaría mejorar las otras soluciones al proporcionar mi archivo CMakeLists.txt
que también funciona en términos de dependencias de construcción.
Solución mal uso de CMake
cmake_minimum_required(VERSION 2.8)
add_library(lib1 test1.cpp)
add_library(lib2 test2.cpp)
include_directories(${CMAKE_CURRENT_DIR})
add_executable(mainexec main.cpp)
target_link_libraries(mainexec combinedLib) # Important to place before add_custom_target
set(LIBNAME "combinedLib.lib")
add_custom_command(
OUTPUT ${LIBNAME}
COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
DEPENDS lib1 lib2
COMMENT "Combining libs..."
)
add_custom_target(combinedLib
DEPENDS ${LIBNAME}
)
Tenga en cuenta que esta solución funciona hasta ahora con Visual Studio, pero creo que puede ser compatible con múltiples plataformas. Puedo imaginar que la siguiente versión podría funcionar para plataformas basadas en Unix:
set(LIBNAME "libCombinedLib.a")
add_custom_command(
OUTPUT ${LIBNAME}
COMMAND ar -rcT ${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
DEPENDS lib1 lib2
COMMENT "Combining libs..."
)
Tenga en cuenta que estas soluciones de alguna manera hacen un mal uso de CMake, ya que se quejaría de un objetivo de tipo UTILITY (en lugar de STATIC o SHARED) si coloca la llamada target_link_libraries
después de la declaración add_custom_target
.
Solución compatible con la declaración de objetivos de CMake
Para hacerlo compatible, puede reemplazar la llamada `target_link_libraries ''por
target_link_libraries(mainexec ${LIBNAME})
add_dependencies(mainexec combinedLib)
En mi caso, no es del todo satisfactorio porque mainexec
tiene que saber sobre combinedLib
aunque espera que todas las dependencias sean manejadas por la llamada target_link_libraries
.
Solución alternativa con menos acoplamiento.
Mirando un poco más hacia objetivos importados, encontré una solución que resuelve mi último problema:
cmake_minimum_required(VERSION 2.8)
add_library(lib1 test1.cpp)
add_library(lib2 test2.cpp)
include_directories(${CMAKE_CURRENT_DIR})
add_executable(mainexec main.cpp)
set(LIBNAME "combinedLib.lib")
add_custom_command(
OUTPUT ${LIBNAME}
COMMAND lib.exe /OUT:${LIBNAME} $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>
DEPENDS lib1 lib2
COMMENT "Combining libs..."
)
add_custom_target(combinedLibGenerator
DEPENDS ${LIBNAME}
)
add_library(combinedLib STATIC IMPORTED)
set_property(TARGET combinedLib PROPERTY IMPORTED_LOCATION ${LIBNAME})
add_dependencies(combinedLib combinedLibGenerator)
target_link_libraries(mainexec combinedLib)
Si tiene la intención de modularizar todo, añada GLOBAL
después de STATIC IMPORTED
para que el destino importado sea visible globalmente.
Solución CMake portátil
Con las versiones actuales de CMake, CMake proporciona soporte completo para dependencias transitivas y bibliotecas de interfaz. Una biblioteca de interfaz puede entonces "vincularse" con otras bibliotecas y esta biblioteca de interfaz puede, a su vez, "vincularse" con. ¿Por qué comillas? Si bien esto funciona bien, en realidad no crea una biblioteca física combinada, sino que crea una especie de alias para el conjunto de "sub-libs". Aún así, esta era la solución que eventualmente necesitábamos, por lo que quería agregarla aquí.
add_library(combinedLib INTERFACE)
target_link_libraries(combinedLib INTERFACE lib1 lib2)
target_link_libraries(mainexec combinedLib)
¡Eso es!
Está bien, así que tengo una solución. Primero, es importante reconocer que las bibliotecas estáticas no vinculan otras bibliotecas estáticas en el código. Se debe crear una biblioteca combinada, que en linux se puede hacer con ar
. Consulte Vincular bibliotecas estáticas a otras bibliotecas estáticas para obtener más información allí.
Considere dos archivos de origen:
test1.c:
int hi()
{
return 0;
}
test2.c:
int bye()
{
return 1;
}
El CMakeLists.txt
para crear dos bibliotecas y luego crear una biblioteca combinada se ve así:
proyecto (test)
add_library(lib1 STATIC test1.c)
add_library(lib2 STATIC test2.c)
add_custom_target(combined ALL
COMMAND ${CMAKE_AR} rc libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>)
Las opciones para el comando ar
dependen de la plataforma en este caso, aunque la variable CMAKE_AR
es independiente de la plataforma. Hojearé para ver si hay una forma más general de hacer esto, pero este enfoque funcionará en sistemas que usan ar
.
Editar:
Basado en Cómo configurar las opciones para CMAKE_AR , parece que la mejor manera de hacerlo sería:
add_custom_target(combined ALL
COMMAND ${CMAKE_CXX_ARCHIVE_CREATE} libcombined.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2>)
Esto debería ser independiente de la plataforma porque esta es la estructura de comando utilizada para crear archivos internamente por CMake. Por supuesto, las únicas opciones que desea pasar a su comando de archivo son rc
ya que están incorporadas en CMake para el comando ar
.