1. Archivos de biblioteca
El llamado archivo de biblioteca, los lectores pueden ser equivalentes a un archivo de paquete comprimido, el archivo generalmente contiene más de un archivo de objeto (es decir, un archivo binario).
Vale la pena mencionar que el código almacenado en cada archivo objeto en el archivo de la biblioteca no es un programa completo, sino un módulo funcional práctico. Por ejemplo, una C
biblioteca de lenguaje proporciona una serie de funciones (tales como scanf()
, printf()
, strlen()
etc.), C++
funciones de biblioteca proporcionar no sólo tienen que utilizar, hay un gran número de clases de pre-diseñadas (tales como string
clase String).
La generación del archivo de biblioteca mejora en gran medida la eficiencia de desarrollo del programador, porque muchas funciones no necesitan ser desarrolladas desde 0 en absoluto, simplemente llame al archivo de biblioteca que contiene la función directamente. Además, llamar al método de la biblioteca también es muy simple para la función de salida del C
idioma printf()
, por ejemplo, el programa acaba de introducir <stdio.h>
el archivo de encabezado, puede llamar a la printf()
función.
¿Por qué está involucrado el archivo de encabezado cuando se llama al archivo de biblioteca? En primer lugar, los archivos de encabezado y los archivos de biblioteca no son lo mismo. La mayor diferencia entre ellos es:
- El archivo de encabezado solo almacena la parte de declaración de estos módulos funcionales como variables, funciones o clases;
- El archivo de la biblioteca es responsable de almacenar las partes de implementación específicas de cada módulo;
Los lectores pueden entender de esta manera: todos los archivos de la biblioteca se proporcionan con los archivos de encabezado correspondientes como interfaz para llamarlos. En otras palabras, los archivos de biblioteca no se pueden usar directamente y solo se pueden llamar indirectamente a través de archivos de encabezado.
La mayor ventaja del mecanismo de acceso combinado de archivos de encabezado y archivos de biblioteca es que a veces solo queremos que otros usen las funciones que hemos implementado y no queremos revelar el código fuente de las funciones. Podemos convertirlos en archivos de biblioteca, por lo que que los usuarios pueden obtener Es un archivo binario, y el archivo de encabezado solo contiene la parte de declaración, por lo que el propósito de "ocultar el código fuente" se realiza sin afectar el uso del usuario.
De hecho, los archivos de la biblioteca son solo un término general, que se refiere a un tipo de paquete comprimido, todos contienen archivos de objetos funcionales y prácticos. Debe saber que aunque el archivo de la biblioteca se utiliza en la fase de vinculación del programa, el compilador proporciona dos formas de lograr la vinculación, que se denominan vinculación estática y vinculación dinámica.
- Los archivos de biblioteca que utilizan enlaces estáticos para lograr operaciones de enlace se denominan bibliotecas de enlaces estáticos;
- Un archivo de biblioteca que utiliza vínculos dinámicos para lograr operaciones de vinculación se denomina biblioteca de vínculos dinámicos;
En C
, C++
el proceso de desarrollo real, además de utilizar los archivos de la biblioteca del sistema, podemos crear una biblioteca de vínculos estáticos o DLL de acuerdo a las necesidades reales, de forma manual.
2. Biblioteca de enlaces estáticos
La biblioteca de enlaces estáticos realiza la operación del enlace de una manera muy simple, es decir, cuando el módulo de función del archivo de la biblioteca se utiliza en el archivo del programa, el GCC
compilador copiará directamente el código de la plantilla en la ubicación adecuada del archivo del programa y finalmente generar un archivo ejecutable.
El uso de archivos de biblioteca estática para implementar operaciones de vinculación de programas tiene ventajas y desventajas:
- La ventaja es que el archivo ejecutable generado se puede ejecutar de forma independiente sin el soporte de ningún archivo de biblioteca estático (portabilidad fuerte);
- La desventaja es que si se llama varias veces al mismo módulo de función de la biblioteca en el archivo de programa, el código del módulo se copiará inevitablemente varias veces y el archivo ejecutable generado contendrá varias piezas de código idéntico, lo que provocará la redundancia del código.
En comparación con el archivo ejecutable generado por la biblioteca de vínculos dinámicos, el archivo ejecutable generado por la biblioteca de vínculos estáticos tiene un volumen mayor.
- En la
Linux
versión de lanzamiento del sistema, la extensión de los archivos de la biblioteca de enlaces estáticos generalmente.a
representan; - En el
Windows
sistema, el sufijo nombre de archivo de biblioteca de vínculos estáticos.lib
;
2.1 Crear una biblioteca de enlaces estáticos
Una biblioteca de enlaces estáticos es en realidad equivalente a un paquete comprimido, que puede contener varios archivos fuente. Pero debe tenerse en cuenta que no se puede procesar ningún archivo fuente en una biblioteca de enlaces estáticos, debe cumplir al menos las dos condiciones siguientes:
- Los archivos de origen solo proporcionan que el código se puede reutilizar, como funciones, etc. diseñadas, no pueden contener
main
la función principal; - Si bien el archivo fuente realiza la función del módulo, también proporciona una interfaz para acceder a él, es decir, el archivo de encabezado que contiene la parte de declaración de cada módulo de función;
Estructura de código de muestra:
wohu@ubuntu:~/cpp/src$ tree
.
├── function.h
├── greeting.cpp
├── main.cpp
└── name.cpp
0 directories, 4 files
wohu@ubuntu:~/cpp/src$
function.h
Código
void sayGreetings();
void sayName();
greeting.cpp
El código que lo contiene #include "function.h"
no necesita incluir el archivo de encabezado cuando no se crea la biblioteca estática.
#include <iostream>
#include "function.h"
void sayGreetings()
{
std::cout << "hello,world" << std::endl;
}
name.cpp
El código, que está incluido #include "function.h"
, no necesita incluir el archivo de encabezado cuando no se crea la biblioteca estática.
#include <iostream>
#include "function.h"
void sayName()
{
std::cout << "My name is wohu" << std::endl;
}
main.cpp
Código
#include <iostream>
#include "function.h"
int main()
{
sayGreetings();
sayName();
return 0;
}
Para name.cpp
y greeting.cpp
están en línea con las dos condiciones anteriores, se puede procesar en una biblioteca de enlaces estáticos. Y de acuerdo con las necesidades reales, podemos comprimirlos colectivamente en una biblioteca de enlaces estáticos, o cada uno puede comprimirse en una biblioteca de enlaces estáticos.
El proceso de empaquetar el archivo fuente como una biblioteca de enlaces estáticos es muy simple, solo siga los siguientes 2 pasos:
- Compile todos los archivos de origen especificados en los archivos de destino correspondientes
wohu@ubuntu:~/cpp/src$ g++ -c greeting.cpp name.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
- Luego, usando
ar
instrucciones comprimidas, los archivos de objetos generados en una biblioteca de enlaces estáticos, el formato básico es el siguiente:
ar rcs 静态链接库名称 目标文件1 目标文件2 ...
Acerca de ar
las instrucciones de empaquetado de compresión, así como rcs
el significado y la función de cada opción, consulte el comando ar de Linux
El punto importante es que la biblioteca de enlaces estáticos no se puede nombrar arbitrariamente y se deben seguir las siguientes reglas de nomenclatura:
libxxx.a
Linux
En el sistema, el sufijo de la biblioteca de enlaces estáticos es.a
;Windows
En el sistema, el sufijo de la biblioteca de enlaces estáticos es.lib
;
Entre ellos, xxx
en nombre de los que jugamos para el nombre de la biblioteca, tales como Linux
el sistema viene con algún nombre de la biblioteca de vínculos estáticos libc.a
,, libgcc.a
, libm.a
sus nombres son c
, gcc
y m
.
A continuación, empaque greeting.o
y name.o
empaque en una biblioteca de enlaces estáticos:
wohu@ubuntu:~/cpp/src$ ar rcs libmyfunction.a name.o greeting.o
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
Entre ellos, libmyfunction.a
es decir name.o
, greeting.o
empaquetados juntos generaron biblioteca de enlaces estáticos, myfunction
un nombre de biblioteca personalizado.
2.2 Usar biblioteca de enlaces estáticos
El uso de la biblioteca de vínculos estáticos es muy simple, es decir, en la etapa de vinculación del programa, la biblioteca de vínculos estáticos y otros archivos objeto se vinculan entre sí para generar un archivo ejecutable.
Usando el código anterior como ejemplo, primero el main.cpp
archivo se compilará en archivos de objeto:
wohu@ubuntu:~/cpp/src$ g++ -c main.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
wohu@ubuntu:~/cpp/src$
Sobre esta base, podemos ejecutar directamente los siguientes comandos para completar la operación del enlace:
wohu@ubuntu:~/cpp/src$ g++ -static main.o libmyfunction.a
wohu@ubuntu:~/cpp/src$ ls
a.out function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
wohu@ubuntu:~/cpp/src$
Entre ellos, -static
la opción de obligar GCC
al compilador a utilizar una biblioteca de enlaces estáticos.
Tenga en cuenta que si GCC
el compilador no puede encontrar los consejos libmyfunction.a
, también puede utilizar el siguiente enlace. Se realiza la operación:
wohu@ubuntu:~/cpp/src$ g++ -static main.o -L /home/wohu/cpp/src -lmyfunction
wohu@ubuntu:~/cpp/src$ ls
a.out function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
entre ellos,
-L
LaL
opción (mayúsculas ) se usa paraGCC
especificar la ubicación de almacenamiento de la biblioteca de enlaces del compilador estático (puede usar el comando pwd para ver la ubicación de almacenamiento específica);-l
(LowercaseL
opción) se utiliza para indicar el nombre de la biblioteca de enlace estática requerida, prestar atención a los nombres utilizados en esta memoria se refiere a laxxx
parte, y recomendará-l
yxxx
conjunción directa (es decir-lxxx
), sin espacios intermedios.
Como resultado, genera a.out
un archivo ejecutable:
wohu@ubuntu:~/cpp/src$ ./a.out
hello,world
My name is wohu
wohu@ubuntu:~/cpp/src$
3. Biblioteca de vínculos dinámicos
Biblioteca de vínculos dinámicos, también conocida como biblioteca de vínculos compartidos. A diferencia de la biblioteca de enlaces estáticos, cuando se utiliza la biblioteca de enlaces dinámicos para realizar la operación del enlace, donde se necesita el módulo de función del archivo de la biblioteca en el archivo de programa, el GCC
compilador no copiará directamente el código del módulo de función al archivo, pero la información de ubicación del módulo de función Grabe en el archivo y genere directamente el archivo ejecutable.
Obviamente, el archivo ejecutable generado de esta manera no puede ejecutarse de forma independiente. Cuando se ejecuta el archivo ejecutable generado por la biblioteca de vínculos dinámicos, el GCC
compilador cargará la biblioteca de vínculos dinámicos correspondiente en la memoria juntos. Dado que la información de posición del módulo de función requerido se registra en el archivo ejecutable de antemano, la biblioteca de vínculos dinámicos existente También se puede ejecutar con éxito con el apoyo de.
Las ventajas y desventajas de usar la biblioteca de enlaces dinámicos para realizar la operación de conexión del programa son exactamente opuestas a las de la biblioteca de enlaces estáticos:
- La ventaja es que debido a que el archivo ejecutable registra la dirección del módulo de función, el código de implementación real se cargará en la memoria cuando el programa se esté ejecutando, lo que significa que incluso si el módulo de función se llama varias veces, el mismo código de implementación es utilizado (Esta es también la razón por la que la biblioteca de vínculos dinámicos se denomina biblioteca de vínculos compartidos).
- La desventaja es que el archivo ejecutable generado por este método no se puede ejecutar de forma independiente y se debe utilizar el archivo de biblioteca correspondiente (poca portabilidad).
En comparación con el archivo ejecutable generado por la biblioteca de vínculos estáticos, el archivo ejecutable generado por la biblioteca de vínculos dinámicos tiene un volumen más pequeño, porque un montón de códigos redundantes no se copiarán en su interior.
- En la
Linux
versión de lanzamiento del sistema, la biblioteca de vínculos dinámicos de extensión suele estar.so
representada; - En el
Windows
sistema, la biblioteca de vínculos dinámicos de sufijos denominada.dll
;
GCC
Cuando el compilador genera un archivo ejecutable, dará prioridad al uso de la biblioteca de vínculos dinámicos para lograr la operación del vínculo de forma predeterminada. A menos que no exista una biblioteca de vínculos dinámicos requerida por el archivo de programa en el entorno del sistema actual, el GCC
compilador seleccionará la biblioteca de enlaces estáticos correspondiente. Si no se encuentran ambos (o GCC
no se encuentra el compilador), el enlace falla.
3.1 Crear una biblioteca de enlaces dinámicos
En general, hay dos formas de crear una biblioteca de vínculos dinámicos.
- La creación directa de archivos fuente de biblioteca de vínculos dinámicos, utilizando el
gcc
formato básico del comando, se implementa de la siguiente manera:
gcc -fpic -shared 源文件名... -o 动态链接库名
entre ellos,
-shared
La opción se utiliza para generar una biblioteca de enlaces dinámicos;-fpic
La-fPIC
opción (también escrita como función) es hacer queGCC
el compilador genere una biblioteca de vínculos dinámicos (archivar varios archivos de objeto), indica la dirección de cada función de archivo de objeto, las clases y otros módulos funcionales usan una dirección relativa, en lugar de una dirección absoluta. De esta manera, no importa dónde se cargue la biblioteca de enlaces en la memoria en el futuro, se puede usar normalmente.
Por ejemplo, al frente del proyecto greeting.cpp
, name.cpp
estos dos archivos fuente para generar una biblioteca de vínculos dinámicos, ejecute el comando de la siguiente manera:
wohu@ubuntu:~/cpp/src$ g++ -fPIC -shared name.cpp greeting.cpp -o libmyfunction.so
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp libmyfunction.a libmyfunction.so main.cpp name.cpp
wohu@ubuntu:~/cpp/src$
Tenga en cuenta que el nombre de las bibliotecas de vínculos dinámicos y las bibliotecas vinculadas estáticamente son idénticos, pero en el Linux
sistema de lanzamiento, su extensión con .so
representación; Windows
sufijo del sistema .dll
.
- Primero use las
gcc -c
instrucciones para especificar que los archivos de origen se compilan en archivos de objeto y luego cree un archivo de biblioteca de vínculos dinámicos desde el destino
Tenga en cuenta que cuando el seguimiento para generar una biblioteca de vínculos dinámicos y se puede utilizar normalmente, los archivos de origen se compilan en archivos de objeto, también es necesario utilizar la -fpic
opción.
wohu@ubuntu:~/cpp/src$ g++ -c -fPIC name.cpp greeting.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
Sobre esta base, utilice el archivo objeto generado en el paso anterior para generar una biblioteca de vínculos dinámicos:
wohu@ubuntu:~/cpp/src$ g++ -shared greeting.o name.o -o libmyfunction.so
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a libmyfunction.so main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
3.2 Usar biblioteca de enlaces dinámicos
A través del estudio de los capítulos anteriores, sabemos que el escenario de uso de la biblioteca de vínculos dinámicos es participar en la vinculación con otros archivos fuente o archivos de destino en el proyecto. Usando el ejemplo anterior, por ejemplo, estaremos al frente greeting.cpp
, name.cpp
empaquetados en una libmyfunction.so
biblioteca de enlaces dinámicos, en cuyo caso el proyecto quedó como main.cpp
archivos fuente, por lo que evolucionó hacia la implementación del proyecto de demostración main.cpp
y el libmyfunction.so
enlace, y luego generaremos un archivo ejecutable.
Tenga en cuenta que el archivo de encabezado function.h no participa directamente en la compilación, porque en la etapa de preprocesamiento del programa, se han procesado los archivos de encabezado que deben usarse en el proyecto.
Ejecute las siguientes instrucciones para generar con éxito un archivo ejecutable con la ayuda de la biblioteca de vínculos dinámicos:
wohu@ubuntu:~/cpp/src$ g++ main.cpp libmyfunction.so -o main
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a libmyfunction.so main main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
Tenga en cuenta que los archivos ejecutables generados main
generalmente no se pueden implementar directamente, como:
wohu@ubuntu:~/cpp/src$ ./main
./main: error while loading shared libraries: libmyfunction.so: cannot open shared object file: No such file or directory
wohu@ubuntu:~/cpp/src$
Podemos ver, el proceso de implementación no puede encontrar libmyfunction.so
la biblioteca de enlaces dinámicos. Al ejecutar la ldd main
instrucción, puede ver todo el archivo de biblioteca de vínculos dinámicos que se encuentra actualmente en la implementación que necesita usar, así como la ubicación de almacenamiento de cada archivo de biblioteca:
wohu@ubuntu:~/cpp/src$ ldd main
linux-vdso.so.1 => (0x00007fffb17ea000)
libmyfunction.so => not found
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f548673a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5486370000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5486067000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5486abc000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5485e51000)
wohu@ubuntu:~/cpp/src$
Como puede ver, main
el archivo ejecutable necesita el soporte de siete bibliotecas de vínculos dinámicos, incluida libmyfunction.so
, pero el archivo no se puede encontrar, por lo que main
la implementación fallará.
Al ejecutar el archivo ejecutable generado por la biblioteca de vínculos dinámicos, debe asegurarse de que el programa pueda encontrar la biblioteca de vínculos dinámicos cuando se esté ejecutando. Las soluciones más utilizadas son las siguientes:
- El archivo de biblioteca de vínculos con el directorio de la biblioteca estándar (por ejemplo
/usr/lib
,/usr/lib64
,/lib
,/lib64
); - Escribe la terminal
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
Donde xxx
la ruta absoluta almacenada en el archivo de biblioteca de enlace dinámico (en esta realización solo es válida en el terminal actual, el terminal no es válido después del cierre);
- Modificar
~/.bashrc
o~/.bash_profile
archivar, el archivo se agrega en la última línea
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
Que xxx
, después de una ruta absoluta al almacenamiento de archivos de la biblioteca de vínculos dinámicos, preservación, ejecute el source bashrc
comando (de esta manera solo el usuario registrado actual es válido).
En este ejemplo se utiliza la segunda opción, que es ingresar en la terminal
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/wohu/cpp/src
Para la main
implementación exitosa.
wohu@ubuntu:~/cpp/src$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/wohu/cpp/src
wohu@ubuntu:~/cpp/src$ ldd main
linux-vdso.so.1 => (0x00007ffddc5fa000)
libmyfunction.so (0x00007f017bec9000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f017bb47000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f017b77d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f017b474000)
/lib64/ld-linux-x86-64.so.2 (0x00007f017c0cb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f017b25e000)
wohu@ubuntu:~/cpp/src$ ./main
hello,world
My name is wohu
wohu@ubuntu:~/cpp/src$