Compile varios archivos de programa C en un entorno Linux

¡Continúe creando, acelere el crecimiento! Este es el 7º día de mi participación en el "Nuggets Daily New Plan · June Update Challenge", haz clic para ver los detalles del evento

El proyecto utilizado en este artículo es el  proyecto del universo  , el significado del universo, el código de extracción: mku9. Por favor, descárguelo y colóquelo en el directorio de documentos. La estructura del proyecto es la siguiente:

linux-c-multiple-1-1

Este proyecto es así, zeus significa Zeus, puede controlar 3 planetas, el sol, la luna, la tierra gira.


La mayoría de los proyectos de código abierto de C/C++ tienen cientos o incluso decenas de miles de archivos de programa, pero no se deje intimidar por varios archivos. Cuando se compila gcc, en realidad es una compilación de un solo archivo , y luego la etapa de vinculación es un archivo múltiple. El diagrama de flujo completo es el siguiente:

Linux-c-múltiple-1-2

El comando de compilación para este proyecto es el siguiente:

gcc -c -o zeus.o zeus.c
gcc -c -o sun.o sun.c
gcc -c -o moon.o moon.c
gcc -c -o earth.o earth.c
复制代码

Sugerencia: el comando anterior puede agregar  -v o  -### mostrar más información de compilación.

Para el comando anterior, primero compilé el archivo zeus.c. Aunque este archivo zeus.c depende de tres archivos, sun.c, moon.c y earth.c, la etapa de compilación no necesita saber la existencia de estos tres Archivos C. Simplemente incluya sus archivos de encabezado en el código y conozca la definición de la función.

La etapa de compilación no necesita conocer la implementación específica de la función dependiente.

Después de compilar, ejecute el siguiente comando para comenzar a vincular:

gcc -o zeus zeus.o sun.o moon.o earth.o
复制代码

El funcionamiento es el siguiente:

Linux-c-múltiple-1-3

En este punto, se ha compilado un proyecto C de varios archivos.

Sin embargo, el ejemplo actual es demasiado simple, y muchos archivos C de proyectos usarán funciones anidadas.Por ejemplo, ahora hay un nuevo requisito de que la luna debe seguir cuando el sol gira. Entonces,  sun.c cambiemos el código interno y agreguemos el siguiente código:

linux-c-multiple-1-4

Debido a que sun.c llama a la función moon_rotate(),  moon.h es necesario importar el archivo de encabezado, pero no se confunda con la operación de importar el archivo de encabezado.Durante la fase de compilación, sun.c y moon.c aún no están relacionados. en absoluto, y todavía se compilan de forma independiente.

在编译阶段,sun.c 里面的 moon_rotate() 会被替换成 call 00 00 00 00 ,占下位置。

在链接阶段,链接器 就会去 扫描 moon.o 文件,找到 moon_rotate() 函数的真正地址,然后进行替换,因为 moon_rotate() 函数被调用了两次,第一次是在 zeus.c 里面调用,第二次是 在 sun.c 里面调用,所以链接器需要替换两个地方的地址。

再执行之前的编译命令,运行效果如下,月亮旋转了两次。

linux-c-multiple-1-5


上面的例子还是偏简单,在实际项目中,你可能会遇到一些 Makefile ,gcc 接受多个输入文件的情况,之前说过,gcc 可以接受多个输入文件。

现在 sun.c 依赖 moon.c 的函数,我们试着把这两个文件一起编译,看看会怎样?

gcc -c -o sun-moon.o sun.c moon.c
复制代码

linux-c-multiple-1-6

从上图可以看到,这条命令立即报错了,因为编译多文件的时候,不能使用 -c 参数,-c 参数是让 gcc 不要进行链接操作。

咱们 把 -c 去掉,再跑一次。

linux-c-multiple-1-7

依旧报错,这是因为,如果 gcc 进入 链接阶段 就会去找 main 函数的具体地址,而 main 函数的地址在 zeus.o 里面,zeus.o 没传递给 gcc 命令行参数,所以就报错了。

因此,无论是多庞大的C/C++ 项目,编译阶段,都是单个文件编译的,单个文件里面引用了外部的变量,函数。编译阶段只会把这些引用 替换成一些占位符号,例如 00 00 。

只有在链接阶段,gcc 才可以接受多个 文件作为输入。然后 扫描这些输入文件,找到各个 函数符号地址,然后进行替换。链接器通常会扫两次输入文件,第一次找到所有符号,第二次才开始替换占位符号。


通常大型 C/C++ 项目编译问题,主要有以下几种:

1,找不到头文件,错误信息如下:

linux-c-multiple-1-8

上面的报错,是因为我把 moon.h 头文件删了。

Cómo resolver el error de compilación de que no se puede encontrar el archivo de encabezado, generalmente no hay moon.h relacionado en la ruta de búsqueda del archivo de encabezado. En este momento, debe ver en qué directorios buscará el comando gcc los archivos de encabezado.

Simplemente agregue el parámetro -v, el comando es el siguiente:

gcc -v -c -o sun.o sun.c
复制代码

linux-c-múltiple-1-9

Conocimiento extendido: El uso de la mayoría del software en el entorno Linux está en --help Es muy importante aprender a leer --help y logs . La mayor parte del software de Windows también tiene --help, pero la documentación de Microsoft es más completa y la versión china de la documentación de Microsoft es más completa.

El registro en la figura anterior significa que buscará moon.h en el directorio actual  /usr/include y /usr/local/includeasí sucesivamente Como no hay ningún archivo moon.h en estos directorios, el compilador informará un error.

Por lo tanto, si el compilador no puede encontrar el archivo de encabezado cuando se compila su proyecto, pero tiene el archivo de encabezado, es decir, el directorio del archivo de encabezado no está en la ruta de búsqueda del compilador, puede agregarlo, puede agregarlo a través de la ruta de búsqueda del parámetro -I.

gcc -v -c -o sun.o sun.c -I/home/ubuntu/
复制代码

El comando anterior se puede compilar con éxito, porque puse moon.h en el directorio /home/ubuntu/.


#include Hay dos formas de escribir archivos de encabezado.

#include "moon.h"
#include <moon.h>
复制代码

<moon.h> Solo se busca en el directorio del sistema, no en el directorio actual, y se informará de un error si no se encuentra el archivo de encabezado. "moon.h" Buscará en el directorio actual y también en el directorio del sistema.


2, referencia indefinida, el mensaje de error es el siguiente:

linux-c-multiple-1-10

El error anterior se debe a que omití moon.o, solo agrégalo.


3. Todavía hay muchos problemas comunes de compilar bibliotecas estáticas y bibliotecas dinámicas en proyectos C/C++ a gran escala, que se explicarán en el próximo artículo.

Otras lecturas:

1, "Imprimir ruta de búsqueda del archivo de encabezado"


Debido al nivel limitado del autor, inevitablemente habrá algunos errores o inexactitudes en el texto. Insto a los lectores a criticarme y corregirme. Si los lectores tienen comentarios valiosos, pueden agregarme en WeChat Loken1.

Supongo que te gusta

Origin juejin.im/post/7103755248660906020
Recomendado
Clasificación