usar que como cmake shared-libraries

que - CMake: ¿cómo crear una única biblioteca compartida de todas las bibliotecas estáticas de subproyectos?



como usar cmake linux (4)

Mi solución es simplemente agregar /WHOLEARCHIVE , -all_load o --whole-archive a los indicadores del vinculador, de modo que cuando su biblioteca principal esté vinculada, se incluyan todas las bibliotecas secundarias, incluidos todos sus símbolos (el comportamiento predeterminado es solo incluya los símbolos de las bibliotecas secundarias que utiliza la biblioteca principal. Por ejemplo:

Archivos fuente

$ echo "void Func1() { }" > source1.cpp $ echo "void Func2() { }" > source2.cpp $ echo "void Func3() { }" > source3.cpp $ echo "void Func4() { }" > source4.cpp

Naive CMakeLists.txt

cmake_minimum_required(VERSION 3.7) # The ''sub'' libraries, e.g. from an `add_subdirectory()` call. add_library(sublib_a STATIC source1.cpp source2.cpp) add_library(sublib_b STATIC source3.cpp source4.cpp) # The main library that contains all of the sub libraries. add_library(mainlib SHARED) target_link_libraries(mainlib sublib_a sublib_b)

Ejecutándolo (en OSX):

$ make VERBOSE=1 ... [100%] Linking CXX shared library libmainlib.dylib /usr/local/Cellar/cmake/3.7.1/bin/cmake -E cmake_link_script CMakeFiles/mainlib.dir/link.txt --verbose=1 /Library/Developer/CommandLineTools/usr/bin/c++ -dynamiclib -Wl,-headerpad_max_install_names -o libmainlib.dylib -install_name @rpath/libmainlib.dylib libsublib_a.a libsublib_b.a [100%] Built target mainlib $ nm libmainlib.dylib | grep Func $

Corregir CMakeLists.txt

Agregue esto:

# By default, symbols provided by the sublibs that are not used by mainlib (which is all of them in this case) # are not used. This changes that. if (WIN32) set_target_properties(mainlib PROPERTIES LINK_FLAGS "/WHOLEARCHIVE" ) elseif (APPLE) set_target_properties(mainlib PROPERTIES LINK_FLAGS "-Wl,-all_load" ) else () set_target_properties(mainlib PROPERTIES LINK_FLAGS "-Wl,--whole-archive" ) endif ()

-all_load (note el extra -all_load ):

$ make VERBOSE=1 [100%] Linking CXX shared library libmainlib.dylib /usr/local/Cellar/cmake/3.7.1/bin/cmake -E cmake_link_script CMakeFiles/mainlib.dir/link.txt --verbose=1 /Library/Developer/CommandLineTools/usr/bin/c++ -dynamiclib -Wl,-headerpad_max_install_names -Wl,-all_load -o libmainlib.dylib -install_name @rpath/libmainlib.dylib libsublib_a.a libsublib_b.a [100%] Built target mainlib $ nm libmainlib.dylib | grep Func 0000000000001da0 T __Z5Func1v 0000000000001db0 T __Z5Func2v 0000000000001dc0 T __Z5Func3v 0000000000001dd0 T __Z5Func4v

Tenga en cuenta que solo he probado -all_load hasta el momento, y /WHOLEARCHIVE es una opción de /WHOLEARCHIVE 2015.

Tengo el siguiente diseño:

top_project + subproject1 + subproject2

Cada uno de subproject1 y subproject2 crea una biblioteca estática. Me gustaría vincular estas bibliotecas estáticas en una sola biblioteca compartida en el nivel top_project .

La información que recogí hasta ahora es:

  • Compile usando -fPic (necesario en todo menos en Windows) para crear un código independiente de la posición que permita vincular las bibliotecas estáticas en una sola biblioteca compartida o descomprimir todas las bibliotecas estáticas (por ejemplo, usar ar ) y volver a vincularlas en una compartida biblioteca (que creo que es una solución poco elegante y no portátil)
  • Todos los archivos de origen deben add_library explícitamente al comando add_library : por alguna razón que no puedo comprender, simplemente escribiendo add_library(${PROJECT_NAME} SHARED subproject1 subproject2) no funciona como se esperaba (esencialmente crea una biblioteca vacía y no registra las dependencias correctamente)
  • Hay una función de biblioteca OBJECT en CMake pero no creo que su propósito sea realmente hacer lo que quiero.

¿Alguna idea?


Ok, lo descubrí: esto es mucho más doloroso de lo que debería ser. Hasta hace muy poco, la gente de Kitware no entendía por qué alguien querría crear una DLL desde librerías estáticas. Su argumento es que siempre debe haber archivos de origen en el directorio principal (por ejemplo, top_project en mi caso) porque efectivamente es un proyecto propio. Veo las cosas de manera diferente y necesito dividir top_project en subproyectos más pequeños que no deberían existir independientemente (es decir, no tiene sentido crear un proyecto completo para ellos y agregarlos usando ExternalProject_Add ). Además, cuando envío mi biblioteca compartida (para usar, por ejemplo, con una interfaz nativa de Java), no quiero enviar docenas de bibliotecas compartidas porque eso equivaldría a exponer el diseño interno de mi proyecto. De todos modos, habiendo creado un caso para crear una biblioteca compartida a partir de bibliotecas estáticas, procederé a los detalles técnicos.

En el CMakeLists.txt de subproject1 y subproject2 , debe crear su objetivo utilizando la función de biblioteca OBJECT (introducida en CMake 2.8.8):

add_library(${PROJECT_NAME} OBJECT ${SRC})

donde SRC designa la lista de archivos de origen (tenga en cuenta que estos deben configurarse explícitamente en el archivo CMakeLists.txt, ya que permite que se reinicie CMake cuando se detecta una modificación de CMakeLists.txt, por ejemplo, al agregar o eliminar un archivo)

En el proyecto top_project , agregue los subproyectos usando:

add_subdirectory(subproject1) add_subdirectory(subproject2)

Para ver los símbolos de la biblioteca estática, use:

set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--export-all-symbols")

A continuación, puede crear la biblioteca compartida utilizando:

add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:subproject1> $<TARGET_OBJECTS:subproject2>)

Descubrí que cualquier biblioteca "normal" (es decir, no un objeto) debe agregarse en un comando add_library separado, de lo contrario, simplemente se ignora.

Para los ejecutables, puede utilizar:

add_executable(name_of_executable $<TARGET_OBJECTS:subproject1> $<TARGET_OBJECTS:subproject2>) set(LINK_FLAGS ${LINK_FLAGS} "-Wl,-whole-archive") target_link_libraries(name_of_executable ${PROJECT_NAME}

Repito que esto solo funciona a partir de la versión 2.8.8 de CMake. Igualmente, CMake gestiona las dependencias extremadamente bien y es multiplataforma porque no es mucho menos doloroso que los Makefiles antiguos y, desde luego, menos flexible.


Otra forma de hacerlo es proporcionar la ruta de acceso de los archivos de origen y los archivos de encabezado de todos sus proyectos, y compilarlos juntos para producir el .so. Esta suele ser la forma recomendada, en lugar de crear las bibliotecas estáticas y luego una biblioteca compartida fuera de ellas.

Básicamente debes hacer lo siguiente:

FILE(GLOB subproject1_sources <sub_project1_lib_sources_dir>/file1.c <sub_project1_lib_sources_dir>/file2.c //... etc ) FILE(GLOB subproject2_sources <sub_project2_lib_sources_dir>/file1.c <sub_project2_lib_sources_dir>/file2.c //... etc ) FILE(GLOB topProject_sources <top_project_lib_sources_dir>/file1.c <top_project_lib_sources_dir>/file2.c //... etc ) include_directories("<sub_project1_lib_sources_dir>") include_directories("<sub_project2_lib_sources_dir>") include_directories("<top_project_lib_sources_dir>") //should be "." if you''re building from here add_library(topProject SHARED ${topProject_sources} ${subproject1_sources} ${subproject2_sources})


Otra forma de hacerlo.

De esta manera parece más simple, pero no estoy seguro de cuán perfecto es:

https://.com/a/14347487/602340