Vinculando bibliotecas estáticas a outras bibliotecas estáticas

138

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.

Criei um programa de amostra simples que usa uma função do X, mas quando tento vinculá-lo ao X, recebo muitos erros sobre a falta de símbolos nas 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 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 para despejar tudo com ar e criar uma mega-lib, no entanto, que acaba incluindo muitos símbolos que não são necessários (todos os arquivos .o têm cerca de 700 MB, no entanto, um executável vinculado estaticamente é 7). MB). Existe uma boa maneira de incluir apenas o que é realmente necessário?


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

Jason Sundram
fonte

Respostas:

76

Bibliotecas estáticas não vinculam-se 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 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 conheço nenhuma ferramenta para ajudar a fazer isso (para não dizer que não existe), mas seria um projeto interessante produzi-lo.


fonte
Olá Neil, atualizei a pergunta - você conhece alguma maneira de incluir apenas os arquivos .o necessários?
precisa saber é o seguinte
Atualização - Se você deseja fazer isso, dê um passo atrás e prossiga com outra coisa (a menos que, como John Knoeller ressalte, esteja usando o Visual Studio). Eu dediquei muito tempo a essa abordagem e não obtive nada de útil.
Jason Sundram
A ferramenta GNU ld fornece uma opção -rcom a qual a saída pode ser usada como uma entrada para ld. Se você vincular uma vez que você deve obter um reposicionável, pode substituir suas bibliotecas. (tentei thogh).
Harper
49

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

A ferramenta de criação de bibliotecas que acompanha o Visual Studio permite associar 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
John Knoeller
fonte
5
No VS2008, nas propriedades do projeto do compositelib em Librarian / General, se você marcar [x] Link Library Dependencies, ele fará isso por você se lib1 e lib2 forem dependências do compositelib. Parece um pouco complicado, eu definiria a caixa de seleção separadamente em cada configuração de compilação, não uma vez em 'Todas as configurações'.
Spike0xff
2
IDE VS2015 - você não usa "Dependências adicionais" em Bibliotecário / Geral para obter bibliotecas adicionais vinculadas diretamente à biblioteca que seu projeto está construindo?
Davidbak
@davidbak Estou tentando descobrir isso nos últimos dias e, aparentemente, essa opção é obsoleta e não faz nada?
Montaldo
20

No Linux ou MingW, com a cadeia de ferramentas GNU:

ar -M <<EOM
    CREATE libab.a
    ADDLIB liba.a
    ADDLIB libb.a
    SAVE
    END
EOM
ranlib libab.a

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

ar crsT libab.a liba.a libb.a

No Windows, com a cadeia de ferramentas MSVC:

lib.exe /OUT:libab.lib liba.lib libb.lib
Star Brilliant
fonte
É bom saber, mas realmente não resolve o problema do OP, pois você inclui tudo, desde libb.a na lib conjunta, que pode se tornar muito grande se você precisar de apenas alguns módulos da libb.
Elmar Zander
1
@ElmarZander Mas você pode usar ar crsT, que faz algo como "ligação simbólica" em vez de copiar, então você só precisa enviar uma cópia dos dados.
Star Brilliant
Os arquivos thin são usados ​​notavelmente no kernel Linux v4.19: unix.stackexchange.com/questions/5518/…
Ciro Santilli
10

Uma biblioteca estática é apenas um arquivo morto de arquivos de .oobjetos. Extraia-os com ar(assumindo o Unix) e empacote-os novamente em uma grande biblioteca.

Nikolai Fetissov
fonte
6

Como alternativa às Link Library Dependenciespropriedades 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 o X (clique com o botão direito do mouse Add Existing Item...).
  3. Ir para as suas propriedades e certifique- Item TypeseLibrary

Isso incluirá as outras bibliotecas no X como se você executasse

lib /out:X.lib X.lib other1.lib other2.lib
evpo
fonte
Oi, estou usando o Intel IPP e criei minhas próprias funções, que quero que sejam agrupadas em uma única (estática) lib. No entanto, quando crio a lib e, em seguida, envio o projeto para outro computador, que desejo compilar o projeto usando apenas a lib que criei, recebo um erro ao dizer que é necessário um arquivo .h da Intel IPP Library. Qualquer ideia?
Royi 23/02
arquivo lib geralmente não é suficiente. Se você quiser usá-lo, também precisará incluir arquivos de cabeçalho. Mas está fora de tópico aqui, pois este tópico fala sobre vinculação e seu problema está na fase de compilação.
evpo 27/02
Está bem. Para ajudá-lo, precisarei de mais informações. Observe a saída ou o log da compilação e veja o que está reclamando no arquivo .h ausente. Eu acho que é cl.exe. Se for esse o caso, ele fornecerá o nome do arquivo .cpp / .cc / .c compilado que usa o cabeçalho. Qual é o nome desse arquivo .cpp e a qual projeto ele pertence?
evpo
Estou tão confuso. Antes de ler isso, parecia que nunca funcionou (é assim que meus projetos já estão configurados). Mas agora que li e redefini meus projetos, aparentemente está funcionando. Vai saber! :(
Mordachai
1
@Mordachai este haiku abaixo descreve a sua experiência perfeitamente: Ontem ele trabalhou Hoje ele não está funcionando Windows é como aquele
evpo
5

Observe antes de ler o restante: O script de shell mostrado aqui certamente não é seguro 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 que você precise incluir alguns símbolos é lib2. O script agora roda em um loop, onde primeiro verifica quais símbolos indefinidos da lib1 podem ser encontrados na lib2. Em seguida, extrai os arquivos de objeto correspondentes da lib2 com ar, renomeia-os um pouco e os coloca na lib1. Agora pode haver mais símbolos ausentes, porque as coisas que você incluiu na lib2 precisam de outras coisas da lib2, que ainda não incluímos, portanto o loop precisa ser executado novamente. Se após algumas passagens do loop não houver mais alterações, ou seja, nenhum arquivo de objeto da lib2 adicionado à lib1, o loop poderá parar.

Observe que os símbolos incluídos ainda são relatados como indefinidos nm, por isso estou acompanhando os arquivos de objetos que foram adicionados à lib1, eles mesmos, para 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 esse script libcomp, para que você possa chamá-lo, por exemplo, com

./libcomp libmylib.a libwhatever.a

onde libwhatever é de onde você deseja incluir símbolos. No entanto, acho mais seguro copiar tudo para um diretório separado primeiro. Eu não confiava tanto no meu script (no entanto, funcionou para mim; eu poderia incluir a libgsl.a na minha biblioteca de números com isso e deixar de fora essa opção do compilador -lgsl).

Elmar Zander
fonte