El proceso de compilación de gcc y el combate de proyectos simple
1. El proceso de compilación de gcc
De hecho, cuando usamos cpp, usamos muchas bibliotecas, que están escritas por otros para que las usemos directamente, lo que nos facilita enormemente, pero cuando hacemos proyectos, a menudo necesitamos separar las funciones nosotros mismos, y luego Main Reference en la función, es necesario utilizar el proceso de compilación.
Como se muestra en la figura: en la
figura anterior, nuestro archivo principal y los archivos de entrada y calcu son una carpeta. Los archivos de entrada y calcu se implementan por separado. Uno es de entrada y el otro es de cálculo. Main implementa el cálculo de adición digital, pero para la función Claramente los separaremos, para que sea un rendimiento de bajo acoplamiento en proyectos de gran escala.
Código fuente del proyecto: https://github.com/yjc-123/gcc-compile-process
En primer lugar, debemos comprender el proceso de compilación de gcc:
Hay cuatro procesos:
precompilación -> compilación -> ensamblaje -> vinculación.
Aquí hablo principalmente del proceso de vinculación
. La
razón por la que la biblioteca estática se convierte en [biblioteca estática] (.a) es porque en la fase de vinculación, la Se generará el ensamblaje El archivo objeto .o y la biblioteca referenciada están vinculados y empaquetados en un archivo ejecutable. Por lo tanto, el método de enlace correspondiente se denomina enlace estático.
- La vinculación de la biblioteca estática a la biblioteca de funciones se realiza en tiempo de compilación.
- El programa no tiene nada que ver con la biblioteca de funciones cuando se está ejecutando y es fácil de trasplantar.
- Se desperdician espacio y recursos, porque todos los archivos de objetos relacionados y las bibliotecas de funciones involucradas están vinculadas a un archivo ejecutable.
Reglas de nomenclatura de bibliotecas estáticas de Linux:
debe ser "lib [your_library_name] .a": lib es el prefijo, el medio es el nombre de la biblioteca estática y la extensión es .a
Biblioteca dinámica
Debido a que el espacio de la biblioteca estática se desperdicia más seriamente, la biblioteca dinámica no se vinculará al código de destino cuando se compile el programa, sino que se cargará cuando el programa se esté ejecutando. Si diferentes aplicaciones llaman a la misma biblioteca, solo se necesita una instancia de la biblioteca compartida en la memoria, evitando el problema del desperdicio de espacio. La biblioteca dinámica se carga cuando el programa se está ejecutando, lo que también resuelve el problema causado por la página de actualización, implementación y lanzamiento del programa por parte de la biblioteca estática. Los usuarios solo necesitan actualizar la biblioteca dinámica. A continuación, veamos la biblioteca dinámica.
Estas son las dos formas de vincular, y finalmente vemos lo que está sucediendo en el combate real.
2. Combate real
Toma mi ejemplo:
Primero escribimos la función principal.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "input.h" //导入库
#include "calcu.h"
extern int input(); //引入input.h中的函数
extern int calcu(int a,int b); //引入calcu中的函数
int main(int argc, char ** argv){
int input_num_1 = input();
int input_num_2 = input();
printf("input over\n");
int sum;
sum = calcu(input_num_1, input_num_2);
printf("calcu successful ,the sum is :%d\n",sum);
return 0;
}
input.c
#include <stdio.h>
#include <stdlib.h>
int input(){
int a;
printf("input num:");
scanf("%d",&a);
return a;
}
calcu.c
#include <stdio.h>
#include <stdlib.h>
int calcu(int a, int b){
int sum;
sum = a+b;
return sum;
}
El anterior es el archivo c que implementa principalmente la función, pero el archivo principal no se refiere al archivo c cuando se cita, sino que usa el archivo de encabezado escrito por ellos.
calcu.h
#ifndef _CALCU_H
#define _CALCU_H
int calcu(int a, int b);
#endif
input.h
#ifndef _INPUT_H
#define _INPUT_H
int input();
#endif
Estos dos archivos de encabezado son responsables de declarar la función de la función, porque estos dos archivos de encabezado se introducen en main.c, pero la implementación está en input.cy calcu.c.
El siguiente paso es el Makefile para cada precio de venta.
Makefile_input
CC = gcc
libinput.so:
$(CC) -fPIC -shared input.c -o libinput.so
sudo cp libinput.so /usr/lib
sudo cp libinput.so /usr/bin
clean:
rm -rf libinput.so
Makefile_calcu
CC = gcc
libcalcu.so:
$(CC) -fPIC -shared calcu.c -o libcalcu.so
sudo cp libcalcu.so /usr/lib
sudo cp libcalcu.so /usr/bin
clean:
rm -rf libcalcu.so
La función de los dos archivos MAKE anteriores es generar una biblioteca dinámica y copiar la biblioteca dinámica a la biblioteca del sistema.
A continuación, mire el archivo que genera el Makefile final:
CC = gcc
main:
$(CC) main.c \
-I ./input -L ./input -linput \
-I ./calcu -L ./calcu -lcalcu \
-o main
clean:
rm -rf main
Aquí debe utilizar los tres parámetros de gcc -I, -L y -l, que son la ubicación del archivo conjunto, la carpeta de la biblioteca dinámica y la biblioteca dinámica, respectivamente.
Por qué debería enfatizar que sudo cp libcalcu.so /usr/lib
con esta declaración, porque por defecto cuando ejecutamos, el programa usr/lib
irá a buscar este archivo de biblioteca dinámica, si el error no existirá, por qué también necesitamos especificar el tiempo de ejecución debido a la necesidad de usar.