Biblioteca estática ou dinâmica?

138 views
Skip to first unread message

nan...@gmail.com

unread,
Nov 11, 2021, 2:09:27 PM11/11/21
to ccppb...@googlegroups.com

Boa tarde amigos. Estou muito em dúvida pra tomar uma decisão de design e queria ajuda de vocês nisso.

 

Um colega na empresa criou um algoritmo de similaridade chamado TLSH [1]. É uma biblioteca em C++. Ele fez wrappers para Python também (pip install tlsh) aí é só importar e usar.

 

Com este algoritmo disponível, eu criei um outro que chamei de Telfhash [2], mas fiz em Python (usando os wrappers dele). Para atingir meu objetivo, no meu código em Python também uso uma lib chamada Capstone (para disassemblar) e uma outra chamada pyelftools (para parsear binários ELF). Como resultado, minha lib em Python depende de 3 libs (TLSH, Capstone e pyelftools).

 

Isso não tá muito portável e recebi um pedido do time de reescrever minha lib (Telfhash) em C/C++. Comecei a desenhar a API, mas fiquei com algumas dúvidas:

 

  1. Eu importo a TLSH na minha lib, o que gera uma dependência. Não é estranho uma lib depender de outra? Na verdade nem cheguei na parte do disassembly e do parsing do ELF, o que resultaria em depender de três libs no total. Como vocês fariam isso? Uma lib dinâmica? Ou estática?
  2. Como a TLSH está em C++, vou precisar de um compilador de C++ ao importá-la. Então não faz sentido eu escrever minha lib em C, certo? Fica mais elegante/correto ser C++ mesmo?
  3. Vou precisar de um programa de linha de comando que use a minha lib. Vocês acham que eu deveria linká-lo estaticamente com a minha lib (que já vai estar linkada estaticamente com as outras três) ou faço um binário dependente da minha lib, ou ainda, um binário que depende de quatro libs (telfhash – a minha, TLSH, a de disassembly – que ainda não escolhi, e a de parsing de ELF)?
  4. Ainda vai entrar regex na minha lib, o que para mim (programador em C), significa mais uma lib. Talvez mais um motive para criar a lib em C++?
  5. Similar à dúvida 4), o programa cliente da minha lib vai precisar imprimir a saída em JSON. Mais uma dependência e talvez mais um motivo para usar C++ nele – e em tudo?

 

Perdão pelo excesso de perguntas. É que pra mim tá muito confuso ainda, mas espero ter sido claro pelo menos nas dúvidas.

 

Obrigado desde já!

 

Fernando

 

[1] https://github.com/trendmicro/tlsh

[2] https://github.com/trendmicro/telfhash

 

adb

unread,
Nov 12, 2021, 2:45:33 PM11/12/21
to ccppbrasil
Boa tarde Fernando.

Eu confesso que acho muito confuso misturar linguagens neste nível...
(não sou das ciências da computação, sou engenheiro).

Me parece que o programador começa a gastar muito tempo com a gestão de todos estes processos e sistemas.
São camadas em cima de camadas; migrações em cima de migrações....

Tem de ser muito nerd e acompanhar muito de perto todas estas informações e detalhes (o diabo esta nos detalhes, situações em que ocorrem problemas).

Eu sugiro pensar em usar C++ em tudo o que for possível;

Lembro que C++ já tem a biblioteca regex;

PS;
Uso GNU/Linux a uns 30 anos.
Tenho visto cada vez mais sistemas dependendo de Python, ao mesmo tempo nunca ví tantas falhas no sistema...será coincidência?
Acho que não!

Fabiano Furtado

unread,
Nov 12, 2021, 3:30:39 PM11/12/21
to ccppbrasil
Fernando, tudo bem?

Eu não sei se entendi direito a sua dúvida. Desculpe-se se estiver falando bobagem! :)

Se o seu projeto precisa de dependências, melhor optar por usar as libs de forma dinâmica, não? Desta forma, não importa muito em qual linguagem o ".so" foi feito e você terá a liberdade de escolher a linguagem de programação que lhe atenderá melhor para fazer o seu sistema. No seu caso, eu faria tudo em C mesmo e usaria essas libs de forma dinâmica. Acho essa abordagem mais interessante. Em relação ao uso de memória e velocidade, acredito que dê quase na mesma usar linkagem estática ou dinâmica.

Um exemplo, o NGINX usa a lib PCRE para fazer os regex e o openssl para fazer a parte de criptografia, ou seja, ele depende dessas duas libs. Talvez ele seja um dos web servers mais rápidos e estável do mercado. Se é publicada uma nova versão do openssl corrigindo uma falha grave de criptografia, o NGINX já automaticamente fica protegido, desde que aconteça um upgrade do openssl (e um reload no daemon do NGINX).

Eu usaria a estática para casos especiais onde precisa-se entregar para um cliente um sistema monolítico, com tudo dentro e sem dependências.

É isso. Espero ter mais te ajudado que te atrapalhado.

Abraços...
Fabiano Furtado

Derfel Cadarn

unread,
Nov 12, 2021, 4:43:35 PM11/12/21
to ccppb...@googlegroups.com
Apenas minha opiniao em cada ponto abaixo. Nao creio que haja
respostas absolutamente certas aqui...

> Eu importo a TLSH na minha lib, o que gera uma dependência. Não é estranho uma lib depender de outra?

Nao. Ao contrário, é extremamente comum.

> Na verdade nem cheguei na parte do disassembly e do parsing do ELF, o que resultaria em depender de três libs no total. Como vocês fariam isso? Uma lib dinâmica? Ou estática?

Dinâmica, sem dúvida. Linkagem estática só é interessante quando você
precisa gerar um executável auto-contido. Pela sua descrição (que foi
suscinta, devo dizer :-)) não é o seu caso.

> Como a TLSH está em C++, vou precisar de um compilador de C++ ao importá-la. Então não faz sentido eu escrever minha lib em C, certo? Fica mais elegante/correto ser C++ mesmo?

Na verdade não faria diferença, mas por outro lado não vejo motivos
para você fazer em C.

> Vou precisar de um programa de linha de comando que use a minha lib. Vocês acham que eu deveria linká-lo estaticamente com a minha lib (que já vai estar linkada estaticamente com as outras três) ou faço um binário dependente da minha lib, ou ainda, um binário que depende de quatro libs (telfhash – a minha, TLSH, a de disassembly – que ainda não escolhi, e a de parsing de ELF)?

Sem dúvida um binário que depende dinamicamente de todas as outras
libs. Isso é mais "padrão". Sair do padrão sem ter um motivo concreto
raramente é uma boa idéia.

> Ainda vai entrar regex na minha lib, o que para mim (programador em C), significa mais uma lib. Talvez mais um motive para criar a lib em C++?

Sim. Sem dúvida.

> Similar à dúvida 4), o programa cliente da minha lib vai precisar imprimir a saída em JSON. Mais uma dependência e talvez mais um motivo para usar C++ nele – e em tudo?

Sim. Sem dúvida.

Não compartilho da opinião do colega a respeito de Python, mas neste
caso eu nao tenho dúvida de que o melhor é fazer tudo em C++.

Boa sorte ai!

de...@roo.com.br

unread,
Nov 13, 2021, 5:46:51 PM11/13/21
to ccppbrasil
só de forma complementar aos comentários anteriores.

isso é muito natural (uma aplicação fazer uso de N bibliotecas).

um ponto que pode vir a ser considerado é :
- quando falamos de linkar com biblioteca estática ela será incorporada ao ELF/exe o que irá aumentar o tamanho final do arquivo, porém, garante a versão da lib.
- quando falamos de linkar com biblioteca dinâmica irá "confiar" no conteúdo que vem bem como a possível indisponibilidade* de versão
- pra quem normalmente usa c++ usar boost e a stl é meio que base pra qualquer projeto
- NORMALMENTE c e c++ tem interoperabilidade*

são muitos pontos a considerar.

PS:

veja só o htop e php7.2
@ip:/usr/bin$ ldd htop
        linux-vdso.so.1 (0x00007ffc4271e000)
        libncursesw.so.5 => /lib/x86_64-linux-gnu/libncursesw.so.5 (0x00007f0492e8c000)
        libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f0492c62000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f04928c4000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f04924d3000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f04922cf000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f04932e9000)

@ip:/usr/bin$ ldd php7.2
        linux-vdso.so.1 (0x00007ffcfb715000)
        libargon2.so.0 => /usr/lib/x86_64-linux-gnu/libargon2.so.0 (0x00007f17b3380000)
        libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f17b3166000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f17b2f49000)
        libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f17b2cd7000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f17b2939000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f17b2735000)
        libxml2.so.2 => /usr/lib/x86_64-linux-gnu/libxml2.so.2 (0x00007f17b2374000)
        libssl.so.1.1 => /usr/lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007f17b20e7000)
        libcrypto.so.1.1 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007f17b1c1c000)
        libsodium.so.23 => /usr/lib/x86_64-linux-gnu/libsodium.so.23 (0x00007f17b19cb000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f17b15da000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f17b13bb000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f17b3c53000)
        libicuuc.so.60 => /usr/lib/x86_64-linux-gnu/libicuuc.so.60 (0x00007f17b1003000)
        liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f17b0ddd000)
        libicudata.so.60 => /usr/lib/x86_64-linux-gnu/libicudata.so.60 (0x00007f17af234000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f17aeeab000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f17aec93000)

Rodrigo Avancini

unread,
Nov 15, 2021, 5:00:43 AM11/15/21
to ccppb...@googlegroups.com
Olá!

Vejo muitas dúvidas misturando projeto e construção.

a) Não vejo um motivo claro de não fazer em Python.
b) Sugiro você procurar alguém para te ajudar na parte de análise e fazer seu sistema|arquitetura Orientado a Objetos.
c) As libs não devem "poluir" seu código, use sempre fachadas para elas, crie interfaces|adaptadores e implemente com as libs.
d) Linha de comando é uma View, ou seja, faça seu sistema desacoplado para suportar diferentes Views.
e) O cliente json não faz parte da sua arquitetura, ele que deveria criar o adaptador usando os recursos que seu sistema vai disponibilizar, nada impede que você forneça a saída já em json, mas nesse caso seria algo genérico e talvez seu cliente precise de algo customizado.
f) Entre C++ ou C sempre escolha C++, a não ser que tenha alguma restrição que o impessa.

Dois livros bons de arquitetura:

[]'s

 Rodrigo Avancini 


--
http://ccppbrasil.github.io/
https://twitter.com/ccppbrasil
 
[&] C & C++ Brasil - http://www.ccppbrasil.org/
Para sair dessa lista, envie um e-mail para ccppbrasil-...@googlegroups.com
---
Você recebeu essa mensagem porque está inscrito no grupo "ccppbrasil" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para ccppbrasil+...@googlegroups.com.
Para ver essa discussão na Web, acesse https://groups.google.com/d/msgid/ccppbrasil/77587778-8dfa-43c6-a6b4-33f79ca343ebn%40googlegroups.com.

Fernando Mercês

unread,
Nov 16, 2021, 8:44:29 AM11/16/21
to ccppb...@googlegroups.com

Todas as considerações são muito valiosas, gente. Obrigado!

 

Alguns pontos:

 

Por que não deixar em Python?

Tem dois motivos: eu preciso integrar esse código em outros sistemas, que não são em Python. E tem um “cliente” que quer um binário estático. Esse último ponto até resolveria com algo tipo https://github.com/py2exe/py2exe, mas não sei quão confiável é esse projeto para produção.

 

Aplicação dependente de bibliotecas

Na verdade, eu me referia à minha biblioteca ser dependente de outras bibliotecas. Não a aplicação. Mas também entendi que é tão comum quanto.

 

Li atentamente todas as respostas aqui e creio que o melhor caminho seja então:

 

  1. Escrever minha lib em C++. Ela vai depender de pelo menos quatro outras libs. OK.
  2. Escrever um cliente CLI em C++, que vai depender da minha lib e, indiretamente, das quatro outra libs.
  3. Linkar um binário estático do meu cliente em C++ pra entregar pra esse cliente que quer algo monolítico.

 

Muito obrigado, gente. Eu tenho uma linha para seguir agora. Além disso, vou precisar estudar C++, o que é bom. Sempre quis ter um motivo para tal. hehe

 

Abraços,

Fernando

Thiago Adams

unread,
Nov 17, 2021, 2:33:01 PM11/17/21
to ccppbrasil


"Biblioteca estática ou dinâmica?"

Eu tento não usar nenhuma destas opções, partindo da experiência no Windows. 
(Acredito que linux seja mais  organizado)

A minha atual exceção é a openssl que é a biblioteca mais mala de todos os tempos
para se compilar, e estou usando como lib estática.

Ao invés de libs ou dll eu procuro por "single file" libs ou amalgamated version e compilo
direto do fonte. Muitas libs boas usam este formato em C. Quando gero libs eu distribuo 
desta forma também.


Dlls irão aumentar o seu trabalho na hora de gerar instaladores e manutenção. 
Existir algo a mais é um multiplicador de problemas.  Lembre-se do KISS.
Elas também deixam o inicio mais lento.

Libs estáticas aumentam o problema de gerar versões compatíveis, x86, x64 no Windows modo
multithread dll, multithread dll debug ,etc etc etc. Se você tiver ARM ou outro pior ainda.










nan...@gmail.com

unread,
Nov 19, 2021, 8:54:42 AM11/19/21
to ccppb...@googlegroups.com

Bom ponto também, Thiago. Só pra confirmer, tua sugestão é separar no código (tipo mylib.h, mylib.cpp e myapp.cpp) e simplesmente compilar, certo? É isso que chama de “single file” lib? “Amalgamated version” é sinônimo disso? Só curiosidade pra eu entender melhor hehe.

 

Abraço,

Fernando

--

http://ccppbrasil.github.io/
https://twitter.com/ccppbrasil
 
[&] C & C++ Brasil - http://www.ccppbrasil.org/
Para sair dessa lista, envie um e-mail para ccppbrasil-...@googlegroups.com
---
Você recebeu essa mensagem porque está inscrito no grupo "ccppbrasil" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para ccppbrasil+...@googlegroups.com.

Thiago Adams

unread,
Nov 19, 2021, 2:43:15 PM11/19/21
to ccppbrasil
On Friday, November 19, 2021 at 10:54:42 AM UTC-3 nan...@gmail.com wrote:

Bom ponto também, Thiago. Só pra confirmer, tua sugestão é separar no código (tipo mylib.h, mylib.cpp e myapp.cpp) e simplesmente compilar, certo?

É isso que chama de “single file” lib? “Amalgamated version” é sinônimo disso? Só curiosidade pra eu entender melhor hehe.

 
Não existe uma padronização destes nomes, mas é mais ou menos isso.

As vezes em C++ as pessoas costumam usar o nome header-only lib também.

No caso do C++ , código template nunca é compilado.
Por exemplo, se você fizer um container estilo vector você pode distribuir
a sua lib como header only. Também pode misturar com partes compiladas mas
a parte template sempre no header.
 
Single file lib pode ser usado para significar que você tem um header e um .c ou .cpp
que pode ter sido feito na mão ou não.
(Assim como você disse)

O termo "Amalgamate" é uma single file lib mas também entende-se que ele foi produzido
juntando outros c/cpp.

Aqui na documentação do sqlite se fala um pouco sobre isso 

Então se você faz uma lib usando vários arquivos você pode criar uma versão amalgameted 
de forma mecânica da  seguinte forma:

Se você tem uma lib com o seguintes arquivos

lib1_file1.c / lib1_file1.h
lib1_file2.c / lib1_file2.h
lib1_file3.c / lib1_file2.h

Para criar a versão amalgamated mecanicamente você junta todos os arquivos .c
expandindo o seus headers somente uma vez, ao encontrar o primeiro #include.
Os headers que são externos você não expande.

 Exemplo lib1_file1.c 
--------
#include <stdlib.h>
#include "lib1_file1.h"
/*código*/
--------

O #include <stdlib.h> fica como esta. 

Mas o #include "lib1_file1.h" é substituído pelo conteúdo do   lib1_file1.h.
Nas próximas vezes #include "lib1_file1.h" é apenas removido.

O header pode ser feito na mão. Você coloca nele a parte pública/exportada da lib.

Eu tenho implementado esta geração mecânica.

Ela é bem simples, mas também é interessante entender como seria a versão "ideal" e como
é mais difícil fazer ela mecanicamente.

No mecânico se eu tiver duas funções com linkagem estática de mesmo nome vai dar conflito.
Então uma limitação é que não pode colocar funções de linkagem estática com mesmo nome.
Alguma combinação de macros poderia falhar ou dar conflito também.

Idealmente toda função de linkagem externa não pública deveria ter sua linkagem transformada
em interna.


--------
/*lib1_file1.c*/
void F(void) {}
--------

Imagine que esta função F tem linkagem externa, ou seja, ela pode ser chamada
do arquivo lib1_file2.c.
Porém ela nunca é exportada para fora da lib. Neste caso ela poderia/deveria ser 
transformada em linkagem interna na versão almagameted. (acho que sqllite até faz isso 
com macros)

A continuação deste assunto entra em módulos do C++ 20.










Reply all
Reply to author
Forward
0 new messages