¿Diferencia entre objetos compartidos (.so), bibliotecas estáticas (.a) y DLL (.so)?
He estado involucrado en algún debate con respecto a las bibliotecas en Linux y me gustaría confirmar algunas cosas.
Según tengo entendido (corríjame si me equivoco y editaré mi publicación más adelante), hay dos formas de usar bibliotecas al crear una aplicación:
- Bibliotecas estáticas (archivos .a): en el momento del enlace, se coloca una copia de toda la biblioteca en la aplicación final para que las funciones dentro de la biblioteca estén siempre disponibles para la aplicación que realiza la llamada.
- Objetos compartidos (archivos .so): en el momento del enlace, el objeto simplemente se verifica con su API a través del archivo de encabezado correspondiente (.h). En realidad, la biblioteca no se utiliza hasta el tiempo de ejecución, cuando es necesaria.
La ventaja obvia de las bibliotecas estáticas es que permiten que toda la aplicación sea autónoma, mientras que el beneficio de las bibliotecas dinámicas es que el archivo ".so" se puede reemplazar (es decir, en caso de que sea necesario actualizarlo debido a un problema de seguridad). error) sin necesidad de volver a compilar la aplicación base.
He escuchado a algunas personas hacer una distinción entre objetos compartidos y bibliotecas de vínculos dinámicos (DLL), aunque ambos son archivos ".so". ¿Existe alguna distinción entre objetos compartidos y DLL cuando se trata de desarrollo C/C++ en Linux o cualquier otro sistema operativo compatible con POSIX (es decir, MINIX, UNIX, QNX, etc.)? Me han dicho que una diferencia clave (hasta ahora) es que los objetos compartidos solo se usan en tiempo de ejecución, mientras que las DLL deben abrirse primero usando la llamada dlopen() dentro de la aplicación.
Finalmente, también escuché a algunos desarrolladores mencionar "archivos compartidos", que, según tengo entendido, también son bibliotecas estáticas, pero que una aplicación nunca usa directamente. En cambio, otras bibliotecas estáticas se vincularán con los "archivos compartidos" para extraer algunas (pero no todas) funciones/recursos del archivo compartido a la biblioteca estática que se está creando.
Actualizar
En el contexto en el que me proporcionaron estos términos, se trataba de términos efectivamente erróneos utilizados por un equipo de desarrolladores de Windows que tuvieron que aprender Linux. Intenté corregirlos, pero las normas lingüísticas (incorrectas) se mantuvieron.
- Objeto compartido: una biblioteca que se vincula automáticamente a un programa cuando este se inicia y existe como un archivo independiente. La biblioteca se incluye en la lista de enlaces en el momento de la compilación (es decir,
LDOPTS+=-lmylib
para un archivo de biblioteca denominadomylib.so
). La biblioteca debe estar presente en el momento de la compilación y cuando se inicia la aplicación. - Biblioteca estática: una biblioteca que se fusiona con el programa real en el momento de la compilación para una única aplicación (más grande) que contiene el código de la aplicación y el código de la biblioteca que se vincula automáticamente a un programa cuando se compila el programa, y el binario final que contiene ambos. el programa principal y la biblioteca misma existen como un único archivo binario independiente. La biblioteca se incluye en la lista de enlaces en el momento de la compilación (es decir,
LDOPTS+=-lmylib
para un archivo de biblioteca denominadomylib.a
). La biblioteca debe estar presente en el momento de la compilación. - DLL: Esencialmente lo mismo que un objeto compartido, pero en lugar de incluirse en la lista de enlaces en el momento de la compilación, la biblioteca se carga mediante comandos
dlopen()
/dlsym()
para que no sea necesario que la biblioteca esté presente en el momento de la compilación para que el programa se compile. Además, no es necesario que la biblioteca esté presente (necesariamente) en el inicio de la aplicación o en el momento de la compilación , ya que solo es necesaria en el momento en que se realizan las llamadasdlopen
/ .dlsym
- Archivo compartido: Esencialmente lo mismo que una biblioteca estática, pero se compila con los indicadores "exportar compartido" y "
-fPIC
". La biblioteca se incluye en la lista de enlaces en el momento de la compilación (es decir,LDOPTS+=-lmylibS
para un archivo de biblioteca denominadomylibS.a
). La distinción entre los dos es que este indicador adicional es necesario si un objeto compartido o DLL desea vincular estáticamente el archivo compartido a su propio código Y poder hacer que las funciones del objeto compartido estén disponibles para otros programas, en lugar de simplemente usarlas. interno de la DLL. Esto es útil en el caso de que alguien le proporcione una biblioteca estática y desee volver a empaquetarla como SO. La biblioteca debe estar presente en el momento de la compilación.
Actualización adicional
La distinción entre " DLL
" y " shared library
" era simplemente un coloquialismo (vago, inexacto) en la empresa en la que trabajaba en ese momento (los desarrolladores de Windows se vieron obligados a cambiar al desarrollo de Linux y el término se quedó), adhiriéndose a las descripciones mencionadas anteriormente.
Además, el S
literal " " al final del nombre de la biblioteca, en el caso de "archivos compartidos", era solo una convención utilizada en esa empresa, y no en la industria en general.
Una biblioteca estática (.a) es una biblioteca que se puede vincular directamente al ejecutable final producido por el vinculador; está contenido en él y no es necesario tener la biblioteca en el sistema donde se implementará el ejecutable.
Una biblioteca compartida (.so) es una biblioteca que está vinculada pero no integrada en el ejecutable final, por lo que se cargará cuando se inicie el ejecutable y debe estar presente en el sistema donde se implementa el ejecutable.
Una biblioteca de enlaces dinámicos en Windows (.dll) es como una biblioteca compartida (.so) en Linux, pero existen algunas diferencias entre las dos implementaciones relacionadas con el sistema operativo (Windows frente a Linux):
Una DLL puede definir dos tipos de funciones: exportadas e internas. Las funciones exportadas están destinadas a ser llamadas por otros módulos, así como desde la DLL donde están definidas. Por lo general, las funciones internas están diseñadas para llamarse solo desde la DLL donde están definidas.
Una biblioteca SO en Linux no necesita una declaración de exportación especial para indicar los símbolos exportables, ya que todos los símbolos están disponibles para un proceso de interrogación.
Siempre he pensado que las DLL y los objetos compartidos son simplemente términos diferentes para la misma cosa: Windows los llama DLL, mientras que en los sistemas UNIX son objetos compartidos, y el término general (biblioteca vinculada dinámicamente) cubre ambos (incluso la función para abrir un .so en UNIX se llama dlopen()
después de 'biblioteca dinámica').
De hecho, solo están vinculados al inicio de la aplicación; sin embargo, su noción de verificación con el archivo de encabezado es incorrecta. El archivo de encabezado define los prototipos que se requieren para compilar el código que utiliza la biblioteca, pero en el momento del enlace, el enlazador mira dentro de la biblioteca para asegurarse de que las funciones que necesita estén realmente allí. El vinculador tiene que encontrar los cuerpos de la función en algún lugar en el momento del vínculo o generará un error. TAMBIÉN lo hace en tiempo de ejecución, porque, como bien señala, la biblioteca en sí podría haber cambiado desde que se compiló el programa. Esta es la razón por la que la estabilidad de ABI es tan importante en las bibliotecas de plataforma, ya que el cambio de ABI es lo que rompe los programas existentes compilados con versiones anteriores.
Las bibliotecas estáticas son simplemente paquetes de archivos objeto sacados directamente del compilador, como los que usted mismo está creando como parte de la compilación de su proyecto, por lo que se extraen y se envían al vinculador exactamente de la misma manera, y los bits no utilizados se cayó exactamente de la misma manera.