¿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.

A mi entender (corríjanme si me equivoco y editaré mi publicación más tarde), hay dos formas de usar las bibliotecas al crear una aplicación:

  1. Bibliotecas estáticas (archivos .a): en el momento del enlace, se coloca una copia de la biblioteca completa 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.
  2. Objetos compartidos (archivos .so): en el momento del enlace, el objeto simplemente se verifica contra su API a través del archivo de encabezado correspondiente (.h). La biblioteca no se usa realmente hasta el tiempo de ejecución, donde se necesita.

La ventaja obvia de las bibliotecas estáticas es que permiten que toda la aplicación sea independiente, mientras que el beneficio de las bibliotecas dinámicas es que el archivo “.so” puede ser reemplazado (es decir: en caso de que necesite ser actualizado debido a una seguridad). error) sin requerir que la aplicación base sea recomstackda.

He escuchado que algunas personas hacen una distinción entre objetos compartidos y bibliotecas vinculadas dinámicas (DLL), a pesar de que ambos son archivos “.so”. ¿Hay alguna distinción entre los objetos compartidos y las DLL cuando se trata del desarrollo de C / C ++ en Linux o cualquier otro sistema operativo compatible con POSIX (es decir: MINIX, UNIX, QNX, etc.)? Me dijeron que una diferencia clave (hasta ahora) es que los objetos compartidos solo se usan en tiempo de ejecución, mientras que los archivos DLL se deben abrir primero usando la llamada dlopen () dentro de la aplicación.

Finalmente, también he escuchado que algunos desarrolladores mencionan “archivos compartidos”, que, a mi entender, también son bibliotecas estáticas, pero nunca son utilizados por una aplicación directamente. En cambio, otras bibliotecas estáticas se vincularán con los “archivos compartidos” para extraer algunas (pero no todas) las funciones / recursos del archivo compartido en la biblioteca estática que se está creando.

Gracias de antemano por su ayuda.

Actualizar


En el contexto en el que se me proporcionaron estos términos, descubrí las pequeñas diferencias en estos términos, que pueden ser solo coloquialismos en mi industria:

  1. Objeto compartido: una biblioteca que se vincula automáticamente a un progtwig cuando se inicia el progtwig, y ​​existe como un archivo independiente. La biblioteca está incluida en la lista de enlaces en tiempo de comstackción (es decir: LDOPTS+=-lmylib para un archivo de biblioteca denominado mylib.so ). La biblioteca debe estar presente en tiempo de comstackción y cuando se inicia la aplicación.
  2. Biblioteca estática: una biblioteca que se fusiona en el progtwig real en el momento de comstackción para una aplicación única (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 progtwig cuando se crea el progtwig, y ​​el binario final que contiene ambos el progtwig principal y la biblioteca en sí existe como un único archivo binario independiente. La biblioteca está incluida en la lista de enlaces en tiempo de comstackción (es decir: LDOPTS+=-lmylib para un archivo de biblioteca denominado mylib.a). La biblioteca debe estar presente en el momento de la comstackción.
  3. DLL: Esencialmente el mismo que un objeto compartido, pero en lugar de incluirse en la lista de enlaces en tiempo de comstackción, la biblioteca se carga mediante dlopen() / dlsym() para que la biblioteca no tenga que estar presente en el momento de la comstackción para el progtwig para comstackr. Además, la biblioteca no necesita estar presente (necesariamente) al momento de iniciar o comstackr la aplicación , ya que solo es necesaria en el momento en que se dlsym llamadas dlopen / dlsym .
  4. Archivo compartido: Esencialmente el mismo que una biblioteca estática, pero se comstack con los indicadores “export-shared” y “-fPIC”. La biblioteca está incluida en la lista de enlaces en tiempo de comstackción (es decir: LDOPTS + = – lmylib S para un archivo de biblioteca denominado mylib S .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 en su propio código Y poder hacer que las funciones del objeto compartido estén disponibles para otros progtwigs, en lugar de simplemente usarlas interno a la DLL. Esto es útil en el caso cuando alguien le proporciona una biblioteca estática, y desea volver a empaquetarlo como un SO. La biblioteca debe estar presente en el momento de la comstackción.

Actualización adicional

La distinción entre ” DLL ” y ” shared library ” era simplemente un coloquio (vago, impreciso) 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 estancó), adhiriéndose a las descripciones indicado arriba.

Además, el final ” S ” literal después del nombre de la biblioteca, en el caso de “archivos compartidos” era simplemente una convención utilizada en esa empresa, y no en la industria en general.

Siempre he pensado que las DLL y los objetos compartidos son solo términos diferentes para la misma cosa: Windows los llama DLLs, mientras que en sistemas UNIX son objetos compartidos, con el término general biblioteca dinámicamente enlazada que cubre ambos (incluso la función de abrir .so en UNIX se llama dlopen() después de ‘dynamic library’).

De hecho, solo están vinculados al inicio de la aplicación, sin embargo, su noción de verificación en el archivo de encabezado es incorrecta. El archivo de encabezado define los prototipos que se requieren para comstackr el código que usa la biblioteca, pero en el momento del enlace, el vinculador se ve dentro de la biblioteca para asegurarse de que las funciones que necesita estén realmente allí. El enlazador tiene que encontrar los cuerpos de la función en alguna parte en el momento del enlace o generará un error. TAMBIÉN lo hace en tiempo de ejecución, porque, como bien indica, la biblioteca en sí podría haber cambiado desde la comstackción del progtwig. 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 progtwigs existentes comstackdos contra versiones anteriores.

Las bibliotecas estáticas son solo paquetes de archivos de objetos directamente del comstackdor, al igual que los que usted está creando usted mismo como parte de la comstackción de su proyecto, por lo que se introducen y alimentan al enlazador exactamente de la misma manera, y los bits no utilizados son cayó exactamente de la misma manera.

Una biblioteca estática (.a) es una biblioteca que se puede vincular directamente en el 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 está incorporada en el ejecutable final, por lo que se cargará cuando se ejecute el ejecutable y debe estar presente en el sistema donde se implementa el ejecutable.

Una biblioteca de enlaces dynamics en Windows (.dll) es como una biblioteca compartida (.so) en Linux, pero existen algunas diferencias entre las dos implementaciones que están relacionadas con el sistema operativo (Windows vs Linux):

Una DLL puede definir dos tipos de funciones: exportada e interna. Las funciones exportadas están destinadas a ser llamadas por otros módulos, así como también desde el DLL donde están definidas. Por lo general, se pretende que las funciones internas sean llamadas solo desde el DLL donde están definidas.

Una biblioteca SO en Linux no necesita una statement de exportación especial para indicar símbolos exportables, ya que todos los símbolos están disponibles para un proceso de interrogación.

Puedo profundizar en los detalles de las DLL en Windows para ayudar a aclarar esos misterios a mis amigos aquí en * NIX-land …

Una DLL es como un archivo de Objeto Compartido. Ambas son imágenes, listas para cargar en memoria mediante el cargador de progtwigs del sistema operativo respectivo. Las imágenes van acompañadas de varios bits de metadatos para ayudar a los vinculadores y cargadores a realizar las asociaciones necesarias y utilizar la biblioteca de códigos.

Las DLL de Windows tienen una tabla de exportación. Las exportaciones pueden ser por nombre o por posición de tabla (numérica). El último método se considera “old school” y es mucho más frágil: reconstruir el DLL y cambiar la posición de una función en la tabla terminará en desastre, mientras que no existe un problema real si el enlace de los puntos de entrada es por nombre. Por lo tanto, olvídate de eso como un problema, pero ten en cuenta que está ahí si trabajas con código “dinosaurio”, como libs de proveedores externos.

Las DLL de Windows se comstackn comstackndo y enlazando, tal como lo haría con un EXE (aplicación ejecutable), pero el DLL no está solo, al igual que un SO está destinado a ser utilizado por una aplicación, ya sea mediante carga dinámica, o mediante el enlace en tiempo de enlace (la referencia al SO está integrada en los metadatos del binario de la aplicación, y el cargador del progtwig del SO cargará automáticamente las SO referenciadas). Las DLL pueden hacer referencia a otras DLL, al igual que las SO pueden hacer referencia a otras SO.

En Windows, las DLL pondrán a disposición solo puntos de entrada específicos. Estos se llaman “exportaciones”. El desarrollador puede usar una palabra clave del comstackdor especial para hacer que un símbolo sea visible externamente (para otros vinculadores y el cargador dynamic), o las exportaciones se pueden enumerar en un archivo de definición de módulo que se usa en tiempo de enlace cuando la DLL es siendo creado. La práctica moderna es decorar la definición de la función con la palabra clave para exportar el nombre del símbolo. También es posible crear archivos de encabezado con palabras clave que declararán ese símbolo como uno que se importará desde una DLL fuera de la unidad de comstackción actual. Busque las palabras clave __declspec (dllexport) y __declspec (dllimport) para obtener más información.

Una de las características interesantes de las DLL es que pueden declarar una función de controlador estándar “al cargar / descargar”. Cada vez que se carga o descarga la DLL, la DLL puede realizar alguna inicialización o limpieza, según sea el caso. Esto se relaciona perfectamente con tener una DLL como un administrador de recursos orientado a objetos, como un controlador de dispositivo o una interfaz de objeto compartido.

Cuando un desarrollador desea usar un archivo DLL ya creado, debe hacer referencia a una “biblioteca de exportación” (* .LIB) creada por el desarrollador de DLL cuando creó el archivo DLL, o debe cargar explícitamente el archivo DLL en tiempo de ejecución y solicitar el dirección del punto de entrada por nombre mediante los mecanismos LoadLibrary () y GetProcAddress (). La mayoría de las veces, la vinculación con un archivo LIB (que simplemente contiene los metadatos del vinculador para los puntos de entrada exportados de la DLL) es la forma en que se utilizan los archivos DLL. La carga dinámica se reserva típicamente para implementar “polymorphism” o “configurabilidad de tiempo de ejecución” en comportamientos de progtwig (accediendo a complementos o funcionalidades definidas posteriormente, también conocidas como “complementos”).

La forma en que Windows hace las cosas puede causar cierta confusión a veces; el sistema usa la extensión .LIB para referirse tanto a bibliotecas estáticas normales (archivos, como archivos POSIX * .a) como a las bibliotecas “export stub” necesarias para vincular una aplicación a una DLL en el momento del enlace. Por lo tanto, uno siempre debe ver si un archivo * .LIB tiene un archivo * .DLL del mismo nombre; de lo contrario, es probable que el archivo * .LIB sea un archivo de biblioteca estática y no exporte metadatos vinculantes para una DLL.

Tiene razón en que los archivos estáticos se copian a la aplicación en tiempo de enlace, y que los archivos compartidos solo se verifican en el momento del enlace y se cargan en el tiempo de ejecución.

La llamada dlopen no es solo para objetos compartidos, si la aplicación lo desea en tiempo de ejecución en su nombre, de lo contrario, los objetos compartidos se cargan automáticamente cuando se inicia la aplicación. DLLS y .so son lo mismo. el dlopen existe para agregar aún más habilidades de carga dinámica de grano fino para los procesos. No tiene que usar dlopen para abrir / usar las DLL, eso también ocurre al inicio de la aplicación.