Vincular libstdc ++ estáticamente: ¿cualquier problema?

Necesito implementar una aplicación C ++ creada en Ubuntu 12.10 con libstdc ++ de GCC 4.7 para sistemas que ejecutan Ubuntu 10.04, que viene con una versión considerablemente más antigua de libstdc ++.

Actualmente, estoy comstackndo con -static-libstdc++ -static-libgcc , como lo sugiere esta publicación de blog: Vincular libstdc ++ estáticamente . El autor advierte contra el uso de cualquier código C ++ cargado dinámicamente al comstackr libstdc ++ estáticamente, que es algo que aún no he comprobado. Aún así, todo parece ir sin problemas hasta ahora: puedo usar las características de C ++ 11 en Ubuntu 10.04, que es lo que buscaba.

Observo que este artículo es de 2005, y tal vez haya cambiado mucho desde entonces. Es su consejo todavía actual? ¿Hay algún problema al acecho que deba tener en cuenta?

Esa publicación en el blog es bastante inexacta.

Por lo que yo sé, los cambios C ++ ABI se han introducido con cada versión principal de GCC (es decir, aquellos con diferentes componentes de número de versión primero o segundo).

No es verdad. Los únicos cambios de C ++ ABI introducidos desde GCC 3.4 han sido compatibles con versiones anteriores, lo que significa que el C ++ ABI se ha mantenido estable durante casi nueve años.

Para empeorar las cosas, la mayoría de las principales distribuciones de Linux usan instantáneas de GCC y / o parchean sus versiones de GCC, lo que hace que sea virtualmente imposible saber exactamente qué versiones de GCC puede tener cuando distribuya binarios.

Las diferencias entre las versiones parcheadas de GCC de las distribuciones son menores, y no el cambio de ABI, por ejemplo, 4.6.3 20120306 de Fedora (Red Hat 4.6.3-2) es ABI compatible con las versiones anteriores de FSF 4.6.x y casi con seguridad con cualquier 4.6. x de cualquier otra distribución.

En GNU / Linux, las bibliotecas de tiempo de ejecución de GCC usan 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 proporcione esos símbolos funcionará, no importa si es un poco versión parchada diferente de otra versión de su distribución.

pero no se puede vincular dinámicamente ningún código de C ++ (o cualquier código que utilice el soporte de tiempo de ejecución de C ++) para que funcione.

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 de libstdc ++ de los que depende podrían no haber sido necesitados por su aplicación cuando (estáticamente) lo vinculó, por lo que esos símbolos no estarán presentes en su ejecutable. Esto se puede resolver vinculando dinámicamente la biblioteca compartida a libstdc++.so (lo cual es lo correcto si de todos modos depende de ello). La interposición del símbolo ELF significa que los símbolos que están presentes en el ejecutable serán utilizados por la biblioteca compartida. pero otros no presentes en su ejecutable se encontrarán en cualquier libstdc++.so lo libstdc++.so se vincula a. Si su aplicación no utiliza dlopen , no necesita preocuparse por eso.

Otra opción (y la que prefiero) es desplegar la libstdc++.so más nueva, libstdc++.so junto con su aplicación y asegurarse de que se encuentra antes del sistema predeterminado libstdc++.so , libstdc++.so , lo que se puede hacer forzando al enlazador dynamic a buscar en el lugar correcto, ya sea utilizando la $LD_LIBRARY_PATH entorno $LD_LIBRARY_PATH en tiempo de ejecución o configurando un RPATH en el ejecutable en tiempo de enlace. Prefiero usar RPATH ya que no depende de que el entorno esté configurado correctamente para que la aplicación funcione. Si vincula su aplicación con '-Wl,-rpath,$ORIGIN' (observe las comillas simples para evitar que el shell intente expandir $ORIGIN ), el ejecutable tendrá un RPATH de $ORIGIN que le indica al enlazador dynamic que busque compartido bibliotecas en el mismo directorio que el ejecutable mismo. Si coloca la libstdc++.so más reciente, libstdc++.so en el mismo directorio que el ejecutable se encontrará en tiempo de ejecución, problema resuelto. (Otra opción es poner el ejecutable en /some/path/bin/ y el libstdc ++ más nuevo. Entonces en /some/path/lib/ y enlazar con '-Wl,-rpath,$ORIGIN/../lib' o cualquier otra ubicación fija relativa al ejecutable, y establecer el RPATH relativo a $ORIGIN )

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 (vea PR 64535 y PR 65434 ), si abre y cierra una biblioteca que está estáticamente vinculada a libstdc ++, obtendrá una pérdida de memoria (del objeto de grupo) cada vez. Entonces, si hay alguna posibilidad de que alguna vez use dlopen, parece una muy mala idea vincular estáticamente libstdc ++. Tenga en cuenta que esta es una fuga real en comparación con la benigna mencionada en la PR 65434 .

Es posible que también deba asegurarse de no depender del glibc dynamic. Ejecute ldd en su ejecutable resultante y observe cualquier dependencia dinámica (libc / libm / libpthread son sospechosos usales).

El ejercicio adicional consistiría en crear un grupo de ejemplos de C ++ 11 implicados utilizando esta metodología y, en realidad, probando los binarios resultantes en un sistema real 10.04. En la mayoría de los casos, a menos que haga algo extraño con la carga dinámica, sabrá de inmediato si el progtwig funciona o falla.