Necesito implementar una aplicación C ++ construida en Ubuntu 12.10 con libstdc ++ de GCC 4.7 en sistemas que ejecutan Ubuntu 10.04, que viene con una versión considerablemente más antigua de libstdc ++.
Actualmente, estoy compilando con -static-libstdc++ -static-libgcc
, como sugiere esta publicación de blog: Vinculando libstdc ++ estáticamente . El autor advierte contra el uso de cualquier código C ++ cargado dinámicamente al compilar libstdc ++ estáticamente, que es algo que aún no he comprobado. Aún así, todo parece ir bien hasta ahora: puedo hacer uso de las funciones de C ++ 11 en Ubuntu 10.04, que es lo que buscaba.
Observo que este artículo es de 2005 y quizás mucho ha cambiado desde entonces. ¿Sigue vigente su consejo? ¿Hay algún problema oculto que deba tener en cuenta?
-static-libstdc++
opción no tendría sentido, simplemente usaría-static
kernel too old
error en algún sistema ubuntu 1404. El glibc.so es comokernel32.dll
en la ventana, es parte de la interfaz del sistema operativo, no debemos incrustarlo en nuestro binario. Puede utilizarobjdump -T [binary path]
para verlo cargado dinámicamentelibstdc++.so
o no. Para el programador de golang, puede agregar#cgo linux LDFLAGS: -static-libstdc++ -static-libgcc
antes de importar "C"-static-libstdc++
no,-static
porlibc.so
lo que no estará vinculado estáticamente.Respuestas:
Esa publicación de blog es bastante inexacta.
No es verdad. Los únicos cambios de C ++ ABI introducidos desde GCC 3.4 han sido compatibles con versiones anteriores, lo que significa que C ++ ABI se ha mantenido estable durante casi nueve años.
Las diferencias entre las versiones parcheadas de GCC de las distribuciones son menores y no cambian la ABI, por ejemplo, la 4.6.3 20120306 de Fedora (Red Hat 4.6.3-2) es compatible con ABI con las versiones anteriores de FSF 4.6.xy casi con certeza con cualquier 4.6. x de cualquier otra distro.
En GNU / Linux, las bibliotecas en tiempo de ejecución de GCC usan el control de versiones de símbolos ELF, por lo que es fácil verificar las versiones de símbolos que necesitan los objetos y las bibliotecas, y si tiene una
libstdc++.so
que proporciona esos símbolos, funcionará, no importa si es una versión parcheada ligeramente diferente. de otra versión de tu distribución.Esto tampoco es cierto.
Dicho esto, vincular estáticamente a
libstdc++.a
es una opción para ti.La razón por la que podría no funcionar si carga dinámicamente una biblioteca (usando
dlopen
) es que los símbolos libstdc ++ de los que depende podrían no haber sido necesarios para su aplicación cuando la vinculó (estáticamente), por lo que esos símbolos no estarán presentes en su ejecutable. Eso se puede resolver vinculando dinámicamente la biblioteca compartida alibstdc++.so
(que es lo correcto de todos modos si depende de ello). La interposición de símbolos ELF significa que los símbolos que están presentes en su ejecutable serán utilizados por la biblioteca compartida, pero otros no presente en su ejecutable se encontrará en el quelibstdc++.so
se vincule. Si su aplicación no se usadlopen
, no necesita preocuparse por eso.Otra opción (y la que prefiero) es implementar la más nueva
libstdc++.so
junto con su aplicación y asegurarse de que se encuentre antes que el sistema predeterminadolibstdc++.so
, lo que se puede hacer obligando al vinculador dinámico a buscar en el lugar correcto, ya sea utilizando$LD_LIBRARY_PATH
la variable de entorno en la ejecución. time, o estableciendo unRPATH
en el ejecutable en link-time. Prefiero usarloRPATH
porque no depende de que el entorno esté configurado correctamente para que la aplicación funcione. Si vincula su aplicación con'-Wl,-rpath,$ORIGIN'
(tenga en cuenta las comillas simples para evitar que el shell intente expandirse$ORIGIN
), el ejecutable tendrá unaRPATH
de las$ORIGIN
cuales le indica al vinculador dinámico que busque bibliotecas compartidas en el mismo directorio que el ejecutable. Si pones lo nuevolibstdc++.so
en el mismo directorio que el ejecutable se encontrará en tiempo de ejecución, problema resuelto. (Otra opción es poner el ejecutable/some/path/bin/
y el libstdc ++ más nuevo. Así,/some/path/lib/
y vincularlo con'-Wl,-rpath,$ORIGIN/../lib'
o cualquier otra ubicación fija relativa al ejecutable, y establecer el RPATH relativo a$ORIGIN
)fuente
libstdc++.so.6
enlace simbólico que se establece en el momento de la instalación para apuntar a la biblioteca incluida o al sistema si es más nuevo. Hay modelos de vínculos mixtos más complicados, como los que usa Red Hat DTS, pero son difíciles de hacer por sí mismo.Una adición a la excelente respuesta de Jonathan Wakely, por qué dlopen () es problemático:
Debido al nuevo grupo de manejo de excepciones en GCC 5 (consulte PR 64535 y PR 65434 ), si abre y cierra una biblioteca que está vinculada estáticamente a libstdc ++, obtendrá una pérdida de memoria (del objeto del grupo) cada vez. Entonces, si hay alguna posibilidad de que alguna vez uses dlopen, parece una muy mala idea vincular estáticamente libstdc ++. Tenga en cuenta que se trata de una fuga real a diferencia de la benigna mencionada en PR 65434 .
fuente
__gnu_cxx::__freeres()
parece proporcionar al menos algo de ayuda con este problema, ya que libera el búfer interno del objeto del grupo. Pero para mí no está claro qué implicación tiene una llamada a esta función con respecto a las excepciones lanzadas accidentalmente después.Complemento a la respuesta de Jonathan Wakely con respecto al RPATH:
RPATH solo funcionará si el RPATH en cuestión es el RPATH de la aplicación en ejecución . Si tiene una biblioteca que se vincula dinámicamente a cualquier biblioteca a través de su propio RPATH, el RPATH de la biblioteca será sobrescrito por el RPATH de la aplicación que lo carga. Esto es un problema cuando no puede garantizar que el RPATH de la aplicación sea el mismo que el de su biblioteca, por ejemplo, si espera que sus dependencias estén en un directorio en particular, pero ese directorio no es parte del RPATH de la aplicación.
Por ejemplo, supongamos que tiene una aplicación App.exe que tiene una dependencia vinculada dinámicamente en libstdc ++. So.x para GCC 4.9. El App.exe tiene esta dependencia resuelta a través del RPATH, es decir
App.exe (RPATH=.:./gcc4_9/libstdc++.so.x)
Ahora digamos que hay otra biblioteca Dependency.so, que tiene una dependencia vinculada dinámicamente en libstdc ++. So.y para GCC 5.5. La dependencia aquí se resuelve a través del RPATH de la biblioteca, es decir
Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y)
Cuando App.exe carga Dependency.so, no agrega ni antepone el RPATH de la biblioteca . No lo consulta en absoluto. El único RPATH que se considerará será el de la aplicación en ejecución, o App.exe en este ejemplo. Eso significa que si la biblioteca se basa en símbolos que están en gcc5_5 / libstdc ++. So.y pero no en gcc4_9 / libstdc ++. So.x, la biblioteca no se cargará.
Esto es solo una advertencia, ya que me he encontrado con estos problemas en el pasado. RPATH es una herramienta muy útil pero su implementación aún tiene algunos inconvenientes.
fuente
También es posible que deba asegurarse de no depender del glibc dinámico. Ejecute
ldd
el ejecutable resultante y observe las dependencias dinámicas (libc / libm / libpthread son sospechosos habituales).Un ejercicio adicional sería construir un montón de ejemplos de C ++ 11 involucrados usando esta metodología y realmente probar los binarios resultantes en un sistema 10.04 real. En la mayoría de los casos, a menos que haga algo extraño con la carga dinámica, sabrá de inmediato si el programa funciona o falla.
fuente
printf
) pero siempre que glibc en Ubuntu 10.04 proporcione todas las funciones que necesita la nueva libstdc ++, no hay problema con la dependencia de la glibc dinámica, de hecho, se recomienda encarecidamente no vincular nunca estáticamente a glibcMe gustaría agregar a la respuesta de Jonathan Wakely lo siguiente.
Jugando
-static-libstdc++
con Linux, me he enfrentado al problema condlclose()
. Supongamos que tenemos una aplicación 'A' vinculada estáticamentelibstdc++
y se carga dinámicamente vinculada allibstdc++
complemento 'P' en tiempo de ejecución. Esta bien. Pero cuando 'A' descarga 'P', se produce una falla de segmentación. Mi suposición es que después de descargarlibstdc++.so
, 'A' ya no puede usar símbolos relacionados conlibstdc++
. Tenga en cuenta que si tanto 'A' como 'P' están vinculados estáticamentelibstdc++
, o si 'A' está vinculado dinámicamente y 'P' estáticamente, el problema no ocurre.Resumen: si su aplicación carga / descarga complementos que pueden vincularse dinámicamente
libstdc++
, la aplicación también debe estar vinculada a ella de forma dinámica. Esta es solo mi observación y me gustaría recibir sus comentarios.fuente
sbrk
) hace ciertas suposiciones y espera estar solo dentro de un proceso ... no estoy seguro si esto se limita a un versión glibc particular o lo que sea.