Eu preciso implantar um aplicativo C ++ construído no Ubuntu 12.10 com libstdc ++ do GCC 4.7 para sistemas que executam o Ubuntu 10.04, que vem com uma versão consideravelmente mais antiga do libstdc ++.
Atualmente, estou compilando com -static-libstdc++ -static-libgcc
, como sugerido por esta postagem do blog: Linking libstdc ++ estaticamente . O autor adverte contra o uso de qualquer código C ++ carregado dinamicamente ao compilar libstdc ++ estaticamente, que é algo que ainda não verifiquei. Mesmo assim, tudo parece estar indo bem até agora: posso usar os recursos do C ++ 11 no Ubuntu 10.04, que era o que eu procurava.
Observo que este artigo é de 2005 e talvez muita coisa tenha mudado desde então. Seu conselho ainda é atual? Há algum problema oculto que eu deva estar ciente?
-static-libstdc++
opção, você simplesmente usaria-static
kernel too old
erros em alguns sistemas ubuntu 1404. O glibc.so é comokernel32.dll
na janela, faz parte da interface do sistema operacional, não devemos embuti-lo em nosso binário. Você pode usarobjdump -T [binary path]
para vê-lo carregado dinamicamentelibstdc++.so
ou não. Para programador golang, você pode adicionar#cgo linux LDFLAGS: -static-libstdc++ -static-libgcc
antes de importar "C"-static-libstdc++
não-static
de modolibc.so
não será ligado estaticamente.Respostas:
Essa postagem do blog é muito imprecisa.
Não é verdade. As únicas alterações do C ++ ABI introduzidas desde o GCC 3.4 são compatíveis com versões anteriores, o que significa que o C ++ ABI está estável há quase nove anos.
As diferenças entre as versões corrigidas das distribuições do GCC são menores e não mudam o ABI, por exemplo, o 4.6.3 20120306 do Fedora (Red Hat 4.6.3-2) é ABI compatível com as versões upstream do FSF 4.6.x e quase certamente com qualquer 4.6. x de qualquer outra distro.
No GNU / Linux, as bibliotecas de tempo de execução do GCC usam a versão de símbolo ELF para que seja fácil verificar as versões de símbolo necessárias para objetos e bibliotecas, e se você tiver um
libstdc++.so
que fornece esses símbolos ele funcionará, não importa se é uma versão com patch ligeiramente diferente de outra versão da sua distro.Isto também não é verdade.
Dito isso, vincular estaticamente a
libstdc++.a
é uma opção para você.O motivo pelo qual pode não funcionar se você carregar dinamicamente uma biblioteca (usando
dlopen
) é que os símbolos libstdc ++ dos quais ela depende podem não ter sido necessários para seu aplicativo quando você o vinculou (estaticamente), portanto, esses símbolos não estarão presentes em seu executável. Isso pode ser resolvido vinculando dinamicamente a biblioteca compartilhada aolibstdc++.so
(o que é a coisa certa a se fazer de qualquer maneira se depender disso). A interposição de símbolo ELF significa que os símbolos que estão presentes em seu executável serão usados pela biblioteca compartilhada, mas outros não presente em seu executável será encontrado em qualquerlibstdc++.so
link para o qual ele esteja vinculado. Se seu aplicativo não usadlopen
você não precisa se preocupar com isso.Outra opção (e a que eu prefiro) é implantar o mais recente
libstdc++.so
junto com seu aplicativo e garantir que ele seja encontrado antes do sistema padrãolibstdc++.so
, o que pode ser feito forçando o vinculador dinâmico a procurar no lugar certo, usando$LD_LIBRARY_PATH
a variável de ambiente em run- tempo, ou definindo umRPATH
no executável no momento do link. Prefiro usarRPATH
, pois não depende do ambiente estar configurado corretamente para o aplicativo funcionar. Se você vincular seu aplicativo com'-Wl,-rpath,$ORIGIN'
(observe as aspas simples para evitar que o shell tente se expandir$ORIGIN
), o executável terá umRPATH
dos$ORIGIN
que informa ao vinculador dinâmico para procurar bibliotecas compartilhadas no mesmo diretório que o próprio executável. Se você colocar o mais recentelibstdc++.so
no mesmo diretório do executável ele será encontrado em tempo de execução, problema resolvido. (Outra opção é colocar o executável em/some/path/bin/
e o libstdc ++ mais recente. Assim, em/some/path/lib/
e vincular com'-Wl,-rpath,$ORIGIN/../lib'
ou qualquer outro local fixo em relação ao executável e definir o RPATH em relação a$ORIGIN
)fonte
libstdc++.so.6
link simbólico que é definido no momento da instalação para apontar para a lib empacotada ou para o sistema, se for mais recente. Existem modelos de ligação mista mais complicados, como os usados pelo Red Hat DTS, mas eles são difíceis de fazer você mesmo.Uma adição à excelente resposta de Jonathan Wakely, por que dlopen () é problemático:
Devido ao novo pool de tratamento de exceções no GCC 5 (consulte PR 64535 e PR 65434 ), se você abrir e fechar uma biblioteca que está estaticamente vinculada a libstdc ++, você obterá um vazamento de memória (do objeto pool) a cada vez. Portanto, se houver alguma chance de você usar dlopen, parece uma péssima ideia vincular estaticamente libstdc ++. Observe que este é um vazamento real, em oposição ao benigno mencionado no PR 65434 .
fonte
__gnu_cxx::__freeres()
parece fornecer pelo menos alguma ajuda com esse problema, uma vez que libera o buffer interno do objeto pool. Mas para mim não está claro qual implicação uma chamada para essa função tem com respeito às exceções acidentalmente lançadas posteriormente.Complemento à resposta de Jonathan Wakely sobre o RPATH:
RPATH só funcionará se o RPATH em questão for o RPATH do aplicativo em execução . Se você tiver uma biblioteca que se vincula dinamicamente a qualquer biblioteca por meio de seu próprio RPATH, o RPATH da biblioteca será sobrescrito pelo RPATH do aplicativo que o carrega. Este é um problema quando você não pode garantir que o RPATH do aplicativo é o mesmo que o de sua biblioteca, por exemplo, se você espera que suas dependências estejam em um diretório específico, mas esse diretório não faz parte do RPATH do aplicativo.
Por exemplo, digamos que você tenha um aplicativo App.exe que possui uma dependência vinculada dinamicamente em libstdc ++. So.x para GCC 4.9. O App.exe tem essa dependência resolvida por meio do RPATH, ou seja,
App.exe (RPATH=.:./gcc4_9/libstdc++.so.x)
Agora, digamos que haja outra biblioteca Dependency.so, que possui uma dependência vinculada dinamicamente em libstdc ++. So.y para GCC 5.5. A dependência aqui é resolvida através do RPATH da biblioteca, ou seja
Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y)
Quando App.exe carrega Dependency.so, ele não acrescenta nem acrescenta o RPATH da biblioteca . Não o consulta de forma alguma. O único RPATH considerado será o do aplicativo em execução ou App.exe neste exemplo. Isso significa que se a biblioteca depender de símbolos que estão em gcc5_5 / libstdc ++. So.y, mas não em gcc4_9 / libstdc ++. So.x, a biblioteca falhará ao carregar.
Esta é apenas uma palavra de advertência, uma vez que já me deparei com esses problemas no passado. RPATH é uma ferramenta muito útil, mas sua implementação ainda tem alguns problemas.
fonte
Você também pode precisar ter certeza de que não depende da glibc dinâmica. Execute
ldd
em seu executável resultante e observe todas as dependências dinâmicas (libc / libm / libpthread são normalmente suspeitas).O exercício adicional seria construir um monte de exemplos C ++ 11 envolvidos usando esta metodologia e realmente tentar os binários resultantes em um sistema 10.04 real. Na maioria dos casos, a menos que você faça algo estranho com o carregamento dinâmico, você saberá imediatamente se o programa funciona ou trava.
fonte
printf
), mas desde que a glibc no Ubuntu 10.04 forneça todos os recursos necessários para a libstdc ++ mais recente, não há problema em depender da glibc dinâmica, na verdade, é altamente recomendado nunca vincular estaticamente para glibcEu gostaria de acrescentar o seguinte à resposta de Jonathan Wakely.
Jogando
-static-libstdc++
no Linux, eu enfrentei o problema comdlclose()
. Suponha que tenhamos uma aplicação 'A' vinculada estaticamentelibstdc++
e carregue vinculada dinamicamente aolibstdc++
plugin 'P' em tempo de execução. Isso é bom. Mas quando 'A' descarrega 'P', ocorre falha de segmentação. Minha suposição é que após o descarregamentolibstdc++.so
, 'A' não pode mais usar símbolos relacionados alibstdc++
. Observe que se 'A' e 'P' estiverem estaticamente vinculados alibstdc++
, ou se 'A' estiver vinculado dinamicamente e 'P' estaticamente, o problema não ocorre.Resumo: se seu aplicativo carrega / descarrega plug-ins que podem
libstdc++
ser vinculados dinamicamente, o aplicativo também deve ser vinculado a ele dinamicamente. Esta é apenas uma observação minha e gostaria de receber seus comentários.fonte
sbrk
) faz certas suposições e espera estar sozinho dentro de um processo ... não tenho certeza se isso é limitado a um versão glibc particular ou qualquer outra coisa.