Vinculando bibliotecas estáticas a outras bibliotecas estáticas
Pergunta
Eu tenho um pequeno pedaço de código que depende de muitas bibliotecas estáticas (A_1-A_N). Eu gostaria de empacotar esse código em uma biblioteca estática e disponibilizá -lo para outras pessoas.
Minha biblioteca estática, vamos chamá -la de x, compila bem.
Criei um programa de amostra simples que usa uma função de X, mas quando tento vinculá -lo a X, recebo muitos erros sobre os símbolos ausentes das bibliotecas A_1 - A_N.
Existe uma maneira de criar uma nova biblioteca estática, y que contém X e toda a funcionalidade necessária por 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 de cerca de 700 MB, no entanto, um executável estaticamente vinculado é 7 MB). Existe uma boa maneira de incluir apenas o que é realmente necessário?
Isso parece intimamente relacionado a Como combinar várias bibliotecas C/C ++ em uma?.
Solução
As bibliotecas estáticas não se conectam a outras bibliotecas estáticas. A única maneira de fazer isso é usar sua ferramenta de bibliotecário/arquiver (por exemplo ar no Linux) para criar uma única nova biblioteca estática concatenando as várias bibliotecas.
Editar: Em resposta à sua atualização, a única maneira que sei 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 estou ciente de nenhuma ferramenta para ajudar a fazer isso (para não dizer que não existe), mas seria um projeto interessante para produzir um.
Outras dicas
Se você estiver usando o Visual Studio, então sim, você pode fazer isso.
A ferramenta Bibliotec Builder que vem com o Visual Studio permite unir bibliotecas na linha de comando. Eu não conheço nenhuma maneira de fazer isso no editor visual.
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
No Linux ou Mingw, com a Chain de ferramentas GNU:
ar -M <<EOM
CREATE libab.a
ADDLIB liba.a
ADDLIB libb.a
SAVE
END
EOM
ranlib libab.a
De se você não excluir liba.a
e libb.a
, você pode fazer um "arquivo fino":
ar crsT libab.a liba.a libb.a
No Windows, com MSVC Toolchain:
lib.exe /OUT:libab.lib liba.lib libb.lib
Uma biblioteca estática é apenas um arquivo de .o
arquivos de objeto. Extraí -los com ar
(assumindo o Unix) e leve -os de volta em uma grande biblioteca.
Alternativamente para Link Library Dependencies
Nas propriedades do projeto, há outra maneira de vincular bibliotecas no Visual Studio.
- Abra o projeto da biblioteca (x) que você deseja ser combinado com outras bibliotecas.
- Adicione as outras bibliotecas que você deseja combinadas com x (clique com o botão direito do mouse,
Add Existing Item...
). - Vá para suas propriedades e certifique -se de
Item Type
éLibrary
Isso incluirá as outras bibliotecas em X como se você corresse
lib /out:X.lib X.lib other1.lib other2.lib
Nota Antes de ler o resto: o script do shell mostrado aqui certamente não é seguro de usar e 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 incluir alguns símbolos é lib2. O script agora é executado em um loop, onde primeiro verifica quais símbolos indefinidos do LIB1 podem ser encontrados no LIB2. Em seguida, ele extrai os arquivos de objeto correspondentes de Lib2 com ar
, renomeie -os um pouco e os coloca no Lib1. Agora, pode haver mais símbolos ausentes, porque as coisas que você incluiu no Lib2 precisa de outras coisas do LIB2, que ainda não incluímos, então o loop precisa ser executado novamente. Se, depois de alguns passes do loop, não houver mais alterações, ou seja, nenhum arquivo de objeto do LIB2 adicionado ao LIB1, o loop poderá parar.
Observe que os símbolos incluídos ainda são relatados como indefinidos por nm
, por isso, estou acompanhando os arquivos de objeto, que foram adicionados ao LIB1, eles mesmos, a fim de determinar se o loop pode ser interrompido.
#! /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 nomeei aquele script libcomp
, então você pode chamá -lo então, por exemplo, com
./libcomp libmylib.a libwhatever.a
de onde é o que você deseja incluir símbolos. No entanto, acho 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 incluir libgsl.a na minha biblioteca numérica com isso e deixar de fora esse switch -lgsl compilador).