Vinculación de bibliotecas estáticas con otras bibliotecas estáticas

Tengo un pequeño fragmento de código que depende de muchas bibliotecas estáticas (a_1-a_n). Me gustaría empaquetar ese código en una biblioteca estática y ponerlo a disposición de otras personas.

Mi biblioteca estática, llamémosla X, comstack bien.

Creé un progtwig de ejemplo simple que usa una función de X, pero cuando trato de vincularlo con X, recibo muchos errores acerca de los símbolos faltantes de las bibliotecas a_1 – a_n.

¿Hay alguna manera de que pueda crear una nueva biblioteca estática, Y que contenga X y toda la funcionalidad necesaria para X (bits seleccionados de a_1 – a_n), de modo que pueda distribuir solo Y para que las personas vinculen sus progtwigs?


ACTUALIZAR:

Sin embargo, he visto simplemente volcar todo con ar y hacer un mega-lib, que termina incluyendo muchos símbolos que no son necesarios (todos los archivos .o son de unos 700 MB, sin embargo, un ejecutable estáticamente vinculado es 7 MEGABYTE). ¿Hay una buena manera de incluir solo lo que realmente se necesita?


Esto se ve estrechamente relacionado con Cómo combinar varias bibliotecas C / C ++ en una sola? .

Las bibliotecas estáticas no se vinculan con otras bibliotecas estáticas. La única forma de hacerlo es usar la herramienta bibliotecario / archivador (por ejemplo, ar en Linux) para crear una única biblioteca estática al concatenar las múltiples bibliotecas.

Editar: en respuesta a su actualización, la única manera que conozco de seleccionar solo los símbolos que se requieren es crear manualmente la biblioteca a partir del subconjunto de los archivos .o que los contienen. Esto es difícil, lento y propenso a errores. No conozco ninguna herramienta para ayudarme a hacer esto (por no decir que no existen), pero sería un proyecto bastante interesante producir una.

Si está usando Visual Studio, entonces sí, puede hacerlo.

La herramienta de creación de bibliotecas que viene con Visual Studio le permite unir bibliotecas en la línea de comandos. Sin embargo, no sé de ninguna manera de hacer esto en el editor visual.

 lib.exe /OUT:compositelib.lib lib1.lib lib2.lib 

En Linux o MingW, con la cadena de herramientas GNU:

 ar -M <  

De si no elimina liba.a y libb.a , puede hacer un "archivo delgado":

 ar crsT libab.a liba.a libb.a 

En Windows, con la cadena de herramientas de MSVC:

 lib.exe /OUT:libab.lib liba.lib libb.lib 

Una biblioteca estática es solo un archivo de .o archivos de objeto. Extraigalos con ar (suponiendo Unix) y empaquételos en una gran biblioteca.

Alternativamente a las Link Library Dependencies en las propiedades del proyecto hay otra manera de vincular las bibliotecas en Visual Studio.

  1. Abra el proyecto de la biblioteca (X) que desea combinar con otras bibliotecas.
  2. Agregue las otras bibliotecas que desee combinadas con X (clic derecho, Add Existing Item... ).
  3. Vaya a sus propiedades y asegúrese de que el Item Type sea Library

Esto incluirá las otras bibliotecas en X como si se ejecutara

 lib /out:X.lib X.lib other1.lib other2.lib 

Nota antes de leer el rest: El script de shell que se muestra aquí ciertamente no es seguro de usar y está bien probado. ¡Úselo bajo su propio riesgo!

Escribí un script bash para realizar esa tarea. Supongamos que su biblioteca es lib1 y la que necesita incluir algunos símbolos es lib2. El script ahora se ejecuta en un bucle, donde primero verifica qué símbolos indefinidos de lib1 se pueden encontrar en lib2. A continuación, extrae los archivos de objeto correspondientes de lib2 con ar , los renombra un poco y los coloca en lib1. Ahora puede haber más símbolos que faltan, porque las cosas que incluiste de lib2 necesitan otras cosas de lib2, que aún no hemos incluido, por lo que el ciclo debe ejecutarse nuevamente. Si después de algunos pases del ciclo ya no hay cambios, es decir, no hay archivos de objetos de lib2 agregados a lib1, el ciclo puede detenerse.

Tenga en cuenta que los símbolos incluidos aún se informan como no definidos por nm , por lo que estoy haciendo un seguimiento de los archivos de objeto, que se agregaron a lib1, a fin de determinar si el ciclo se puede detener.

 #! /bin/bash lib1="$1" lib2="$2" if [ ! -e $lib1.backup ]; then echo backing up cp $lib1 $lib1.backup fi remove_later="" new_tmp_file() { file=$(mktemp) remove_later="$remove_later $file" eval $1=$file } remove_tmp_files() { rm $remove_later } trap remove_tmp_files EXIT find_symbols() { nm $1 $2 | cut -c20- | sort | uniq } new_tmp_file lib2symbols new_tmp_file currsymbols nm $lib2 -s --defined-only > $lib2symbols prefix="xyz_import_" pass=0 while true; do ((pass++)) echo "Starting pass #$pass" curr=$lib1 find_symbols $curr "--undefined-only" > $currsymbols changed=0 for sym in $(cat $currsymbols); do for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do echo " Found $sym in $obj." if [ -e "$prefix$obj" ]; then continue; fi echo " -> Adding $obj to $lib1" ar x $lib2 $obj mv $obj "$prefix$obj" ar -r -s $lib1 "$prefix$obj" remove_later="$remove_later $prefix$obj" ((changed=changed+1)) done done echo "Found $changed changes in pass #$pass" if [[ $changed == 0 ]]; then break; fi done 

Llamé a ese script libcomp , por lo que puede llamarlo, por ejemplo, con

 ./libcomp libmylib.a libwhatever.a 

donde libwhatever es donde desea incluir símbolos. Sin embargo, creo que es más seguro copiar todo en un directorio separado primero. No confiaría tanto en mi script (sin embargo, funcionó para mí; podría incluir libgsl.a en mi biblioteca numérica con eso y dejar de lado el modificador de comstackción -lgsl).