c++ - ¿Por qué se desalienta estáticamente el enlace glibc?
linker static-linking (3)
La mayoría de las fuentes en línea afirman que puede vincular estáticamente glibc, pero desalientan hacerlo; Por ejemplo, centos paquete repo :
The glibc-static package contains the C library static libraries
for -static linking. You don''t need these, unless you link statically,
which is highly discouraged.
Estas fuentes rara vez (o nunca) dicen por qué sería una mala idea.
La interfaz programa /
glibc
está estandarizada y documentada por POSIX, los estándares C y C ++ y otros.
Por ejemplo, la función
fopen()
comporta según el estándar C y
pthread_mutex_lock()
por POSIX.
La interfaz
glibc
/ kernel
no
está estandarizada.
¿
fopen()
usa
open()
debajo del capó?
¿O usa
openat()
?
¿O algo mas?
¿Qué usará el próximo año?
Usted no sabe
Si la interfaz
glibc
/ kernel cambia, un programa que usa lo que haya cambiado pero está enlazado estáticamente
glibc
ya no funcionará.
Hace más de 15 años, Solaris eliminó todas las versiones estáticas de
libc
por esta misma razón.
Vinculación estática: ¿a dónde se fue?
Con Solaris 10 ya no puede construir un ejecutable estático. No es que ld (1) no permita la vinculación estática o el uso de archivos, es solo que libc.a, la versión de archivo de libc.so.1, ya no se proporciona. Esta biblioteca proporciona las interfaces entre la tierra del usuario y el núcleo, y sin esta biblioteca es bastante difícil crear cualquier forma de aplicación.
Hemos estado advirtiendo a los usuarios contra el enlace estático desde hace algún tiempo, y el enlace contra libc.a ha sido especialmente problemático. Cada lanzamiento o actualización de Solaris (incluso algunos parches) ha resultado en alguna aplicación que fue construida contra libc.a, fallando. El problema es que se supone que libc aísla una aplicación del límite de usuario / núcleo, un límite que puede sufrir cambios de una versión a otra.
Si una aplicación se compila contra libc.a, cualquier interfaz de kernel a la que haga referencia se extrae del archivo y se convierte en parte de la aplicación. Por lo tanto, esta aplicación solo puede ejecutarse en un kernel que esté sincronizado con las interfaces de kernel utilizadas. Si estas interfaces cambian, la aplicación está pisando terreno inestable.
...
Editar:
Parece haber una sobreestimación seria de la estabilidad de la interfaz del kernel de Linux. Vea los cambios / adiciones de la API del kernel de Linux para más detalles. Para resumir:
Las correcciones de errores en glibc no se incluyen en una aplicación vinculada estáticamente cuando actualiza glibc a menos que reconstruya la aplicación.
Además, NSS (Name Service Switch) no funciona a menos que use enlaces dinámicos.
Las razones dadas en otras respuestas son correctas, pero no son la razón más importante.
La razón más importante por la que glibc no debe estar estáticamente vinculado, es que hace un uso interno extenso de
dlopen
, para cargar módulos NSS (
Name Service Switch
) y conversiones
iconv
.
Los módulos se refieren a las funciones de la biblioteca C.
Si el programa principal está vinculado dinámicamente con la biblioteca C, no hay problema.
Pero si el programa principal está vinculado estáticamente con la biblioteca C,
dlopen
tiene que cargar una
segunda copia
de la biblioteca C para satisfacer los requisitos de carga de los módulos.
Esto significa que su programa "enlazado estáticamente" todavía necesita una copia de
libc.so.6
para estar presente en el sistema de archivos, más el NSS o
iconv
o cualquier módulo en sí, además de otras bibliotecas dinámicas que los módulos puedan necesitar, como
ld-linux.so.2
,
libresolv.so.2
, etc. Esto no es lo que la gente suele querer cuando vinculan programas estáticamente.
También significa que el programa enlazado estáticamente tiene dos copias de la biblioteca C en su espacio de direcciones, y podrían
sbrk
sobre
sbrk
búfer
stdout
se usará, quién llamará a
sbrk
con un argumento distinto de cero, ese tipo de cosas.
Hay un montón de lógica defensiva dentro de glibc para intentar que esto funcione, pero nunca se ha
garantizado
que funcione.
Puede pensar que su programa no necesita preocuparse por esto porque nunca llama a
getaddrinfo
o
iconv
, pero el soporte local usa
iconv
internamente, lo que significa que
cualquier función
stdio.h
podría activar una llamada a
dlopen
, y usted no controle esto, la configuración de la variable de entorno del usuario sí.