Vinculando bibliotecas estáticas a outras bibliotecas estáticas

Eu tenho um pequeno pedaço de código que depende de muitas bibliotecas estáticas (a_1-a_n). Gostaria de empacotar esse código em uma biblioteca estática e disponibilizá-lo para outras pessoas.

Minha biblioteca estática, vamos chamá-lo de X, compila bem.

Eu criei um programa de amostra simples que usa uma function do X, mas quando tento vinculá-lo ao X, recebo muitos erros sobre a falta de símbolos das bibliotecas a_1 – a_n.

Existe uma maneira que eu possa criar uma nova biblioteca estática, Y, que contém X e todas as funcionalidades necessárias para X (bits selecionados de a_1 – a_n), para que eu possa distribuir apenas Y para as pessoas vincularem seus programas?


ATUALIZAR:

Eu olhei apenas despejando tudo com ar e fazendo um mega-lib, no entanto, que acaba incluindo muitos símbolos que não são necessários (todos os arquivos .o são cerca de 700 MB, no entanto, um executável estaticamente ligado é 7 MB) Existe uma boa maneira de include apenas o que é realmente necessário?


Isso parece estreitamente relacionado a como combinar várias bibliotecas C / C ++ em uma? .

Bibliotecas estáticas não se vinculam a outras bibliotecas estáticas. A única maneira de fazer isso é usar sua ferramenta bibliotecária / arquivadora (por exemplo ar no Linux) para criar uma única nova biblioteca estática, concatenando as múltiplas bibliotecas.

Editar: Em resposta à sua atualização, a única maneira que sei de selecionar apenas os símbolos necessários é criar manualmente a biblioteca a partir do subconjunto dos arquivos .o que os contêm. Isso é difícil, demorado e propenso a erros. Não tenho conhecimento de nenhuma ferramenta para ajudar nisso (para não dizer que elas não existem), mas seria um projeto bastante interessante para produzir uma.

Se você estiver usando o Visual Studio, então sim, você pode fazer isso.

A ferramenta do construtor de bibliotecas que vem com o Visual Studio permite que você una bibliotecas juntas na linha de comando. Eu não sei de qualquer maneira de fazer isso no editor visual embora.

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

No Linux ou MingW, com o conjunto de ferramentas GNU:

 ar -M < 

Se você não excluir liba.a e libb.a , poderá criar um "arquivo thin":

 ar crsT libab.a liba.a libb.a 

No Windows, com o toolchain MSVC:

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

Uma biblioteca estática é apenas um arquivo de arquivos de object. Extraia-os com ar (assumindo o Unix) e coloque-os de volta em uma grande biblioteca.

Como alternativa às Link Library Dependencies nas propriedades do projeto, há outra maneira de vincular bibliotecas no Visual Studio.

  1. Abra o projeto da biblioteca (X) que você deseja combinar com outras bibliotecas.
  2. Adicione as outras bibliotecas que você deseja combinar com X (Clique com o botão direito, Add Existing Item... ).
  3. Vá para as propriedades deles e certifique-se de que o Item Type seja Library

Isso includeá as outras bibliotecas no X como se você tivesse executado

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

Observe antes de ler o resto: O script de shell mostrado aqui não é seguro de usar e está bem testado. Use por sua conta e risco!

Eu escrevi um script bash para realizar essa tarefa. Suponha que sua biblioteca seja lib1 e a que você precisa include alguns símbolos seja lib2. O script agora é executado em um loop, onde ele primeiro verifica quais símbolos indefinidos da lib1 podem ser encontrados na lib2. Em seguida, ele extrai os arquivos de object correspondentes da lib2 com ar , renomeia-os um pouco e os coloca na lib1. Agora pode haver mais símbolos ausentes, porque o material que você incluiu da lib2 precisa de outras coisas da lib2, que ainda não incluímos, então o loop precisa ser executado novamente. Se após algumas passagens do loop não houver mais mudanças, ou seja, nenhum arquivo object da lib2 adicionado à lib1, o loop pode parar.

Note que os símbolos incluídos ainda são reportados como indefinidos por nm , então eu estou acompanhando os arquivos de object, que foram adicionados à lib1, para determinar se o loop pode ser parado.

 #! /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 

Eu libcomp esse script de libcomp , então você pode chamá-lo então por exemplo com

 ./libcomp libmylib.a libwhatever.a 

onde libwhatever é de onde você deseja include símbolos. No entanto, acho que é mais seguro copiar tudo em um diretório separado primeiro. Eu não confiaria tanto no meu script (no entanto, funcionou para mim; eu poderia include libgsl.a em minha biblioteca numérica com isso e deixar de fora o switch do compilador -lgsl).