Principio y uso del Makefile

archivo MAKE

make es una herramienta de comando, una herramienta de comando que interpreta las instrucciones en un archivo MAKE. La herramienta make necesita cargar un archivo llamado makefile al construir el proyecto, y el makefile está relacionado con las reglas de compilación de todo el proyecto.


1. Reglas

Cada regla consta de tres partes, respectivamente 目标(target), 依赖(depend) y 命令(command).
inserte la descripción de la imagen aquí
命令(command): La acción de la regla actual, en circunstancias normales, esta acción es un comando de shell
Por ejemplo: compilar un archivo, generar un archivo de biblioteca, ingresar a un directorio, etc. a través de un determinado comando. Puede haber varias acciones, y cada comando debe estar precedido por una sangría de tabulación y ocupar una línea exclusiva.
依赖(depend): Dependencias requeridas por la regla, que se pueden usar en los comandos de la regla.
Por ejemplo: el archivo de destino (*.o) que genera un archivo ejecutable se puede usar como una dependencia. Si no se requiere ninguna dependencia en el comando de la regla, entonces la dependencia de la regla puede estar vacía. La dependencia en el archivo actual regla puede ser un objetivo en otras reglas. De esta manera, las dependencias anidadas entre las reglas se pueden especificar de acuerdo con las necesidades reales de los comandos que se ejecutarán. : El objetivo
目标(target)en la regla, el objetivo y el comando en la regla son Al ejecutar el comando en la regla, puede generar Puede haber múltiples comandos en una regla de archivo con el mismo nombre que el objetivo, por lo que estos múltiples comandos se pueden usar para generar múltiples objetivos, y todos los objetivos también pueden tener muchos. Al ejecutar los comandos en la regla, solo se puede ejecutar una acción sin generar ningún archivo; estos objetivos se denominan pseudo-objetivos. Por ejemplo:

# 举例: 有源文件 a.c b.c c.c head.h, 需要生成可执行程序 app
################# 例1 #################
app:a.c b.c c.c
	gcc a.c b.c c.c -o app

################# 例2 #################
# 有多个目标, 多个依赖, 多个命令
app,app1:a.c b.c c.c d.c
	gcc a.c b.c -o app
	gcc c.c d.c -o app1
	
################# 例3 #################	
# 规则之间的嵌套
app:a.o b.o c.o
	gcc a.o b.o c.o -o app
# a.o 是第一条规则中的依赖
a.o:a.c
	gcc -c a.c
# b.o 是第一条规则中的依赖
b.o:b.c
	gcc -c b.c
# c.o 是第一条规则中的依赖
c.o:c.c
	gcc -c c.c

2. Principio de funcionamiento

Al llamar al comando make para compilar el programa, make primero encontrará la primera regla en el Makefile en el directorio actual, analizará y ejecutará acciones relacionadas (make no funcionará si no hay Makefile en el directorio actual). Sin embargo, cabe señalar que en muchos casos, las dependencias utilizadas en las acciones (comandos) a ejecutar no existen, si las dependencias utilizadas no existen, las acciones no se ejecutarán.

La solución correspondiente es generar primero las dependencias requeridas, luego podemos agregar una nueva regla en el archivo MAKE y usar las dependencias inexistentes como objetivos de la nueva regla. Cuando se ejecuta el comando correspondiente a la nueva regla, el correspondiente se genera el destino y existen las dependencias requeridas por la otra regla.

De esta manera, una determinada regla en el archivo MAKE será llamada por otras reglas cuando sea necesario, hasta que se generen todas las dependencias en la primera regla en el archivo MAKE, y los comandos en la primera regla se puedan basar en estas dependencias. Se genera el destino correspondiente , y la tarea de hacer se completa.

MAKEFILE
# makefile
# 规则之间的嵌套
# 规则1
app:a.o b.o c.o
	gcc a.o b.o c.o -o app
# 规则2
a.o:a.c
	gcc -c a.c
# 规则3
b.o:b.c
	gcc -c b.c
# 规则4
c.o:c.c
	gcc -c c.c

Expansión del conocimiento:
Si desea ejecutar el comando que no corresponde a la primera regla en el archivo MAKE, no puede hacer directamente, debe escribir el objetivo de esa regla después de hacer, por ejemplo, solo necesita ejecutar el comando en la regla 3, necesitas: hacer bo.

3. Derivación automática

make tiene la capacidad de deducir automáticamente y no dependerá completamente de makefile. Por ejemplo:
inserte la descripción de la imagen aquí

4. Variables

Cuando usamos Makefile para la definición de reglas, podemos usar variables en él para una escritura más flexible. Hay tres tipos de variables en makefile: 自定义变量, 预定义变量y 自动变量.

4.1 Variables personalizadas

Al utilizar Makefile para definir reglas, los usuarios pueden definir sus propias variables, que se denominan variables definidas por el usuario. Las variables en el archivo MAKE no tienen tipo, simplemente cree la variable y asígnele un valor.

# 错误, 只创建了变量名, 没有赋值
变量名 
# 正确, 创建一个变量名并且给其赋值
变量名=变量值

在给 makefile 中的变量赋值之后,如何在需要的时候将变量值取出来呢?

# 如果将变量的值取出?
$(变量的名字)

# 举例 add.o  div.o  main.o  mult.o  sub.o
# 定义变量并赋值
obj=add.o  div.o  main.o  mult.o  sub.o
# 取变量的值
$(obj)

Ejemplo de uso de variables personalizadas:

# 这是一个规则,普通写法
calc:add.o  div.o  main.o  mult.o  sub.o
        gcc  add.o  div.o  main.o  mult.o  sub.o -o calc
        
# 这是一个规则,里边使用了自定义变量
obj=add.o  div.o  main.o  mult.o  sub.o
target=calc
$(target):$(obj)
        gcc  $(obj) -o $(target)

4.2 Variables predefinidas

Hay algunas variables ya definidas en Makefile, los usuarios pueden usar directamente estas variables sin definirlas. Al compilar, el Makefile utilizará los valores de estas variables predefinidas para la compilación bajo ciertas condiciones. Los nombres de estas variables predefinidas generalmente se escriben con mayúscula y las variables predefinidas de uso común se muestran en la siguiente tabla:
inserte la descripción de la imagen aquí
Ejemplo:

# 这是一个规则,普通写法
calc:add.o  div.o  main.o  mult.o  sub.o
        gcc  add.o  div.o  main.o  mult.o  sub.o -o calc
        
# 这是一个规则,里边使用了自定义变量和预定义变量
obj=add.o  div.o  main.o  mult.o  sub.o
target=calc
CFLAGS=-O3 # 代码优化
$(target):$(obj)
        $(CC)  $(obj) -o $(target) $(CFLAGS)

4.3 Variables automáticas

Además de las variables definidas por el usuario y las variables predefinidas, las variables en Makefile también tienen un tipo de variables automáticas. Los archivos de objetos y los archivos dependientes a menudo aparecen en declaraciones de reglas en Makefile, y las variables automáticas se usan para representar archivos de objetos y archivos dependientes en estas reglas, y solo se pueden usar en comandos de reglas.

En la siguiente tabla se muestran algunas variables automáticas comunes.
inserte la descripción de la imagen aquí
Ejemplo:

# 这是一个规则,普通写法
calc:add.o  div.o  main.o  mult.o  sub.o
        gcc  add.o  div.o  main.o  mult.o  sub.o -o calc
        
# 这是一个规则,里边使用了自定义变量
# 使用自动变量, 替换相关的内容
calc:add.o  div.o  main.o  mult.o  sub.o
	gcc $^ -o $@ 			# 自动变量只能在规则的命令中使用

5. Coincidencia de patrones

Antes de introducir el concepto, lea el siguiente archivo MAKE:

calc:add.o  div.o  main.o  mult.o  sub.o
        gcc  add.o  div.o  main.o  mult.o  sub.o -o calc
# 语法格式重复的规则, 将 .c -> .o, 使用的命令都是一样的 gcc *.c -c
add.o:add.c
        gcc add.c -c

div.o:div.c
        gcc div.c -c

main.o:main.c
        gcc main.c -c

sub.o:sub.c
        gcc sub.c -c

mult.o:mult.c
        gcc mult.c -c

Durante el proceso de lectura, se puede encontrar que la segunda regla a la sexta regla hacen lo mismo, pero debido a los diferentes nombres de archivo, se deben escribir varias reglas en el archivo, lo que hace que el archivo MAKE parezca muy redundante, podemos organice esta serie de las mismas operaciones en una plantilla, y todas las operaciones similares se agilizarán mucho al hacer coincidir el archivo MAKE con la plantilla, pero se reducirá la legibilidad.

# 模式匹配 -> 通过一个公式, 代表若干个满足条件的规则
# 依赖有一个, 后缀为.c, 生成的目标是一个 .o 的文件, % 是一个通配符, 匹配的是文件名
%.o:%.c
	gcc $< -c

inserte la descripción de la imagen aquí

6. Función

Hay muchas funciones en el archivo MAKE y todas las funciones devuelven valores. El formato de la función en el archivo MAKE también es diferente al de C/C++, está escrito así: $(函数名 参数1, 参数2, 参数3, ...), el propósito principal es permitirnos obtener el valor de retorno de la función de manera rápida y conveniente.
Aquí hay dos funciones de uso frecuente en makefile: comodín y patsubst.

6.1 comodín

La función principal de esta función es obtener el nombre de archivo del tipo especificado en el directorio especificado, y su valor de retorno es una lista separada por espacios de todos los nombres de archivo elegibles en el directorio especificado. El prototipo de la función es el siguiente:

# 该函数的参数只有一个, 但是这个参数可以分成若干个部分, 通过空格间隔
$(wildcard PATTERN...)
	参数:	指定某个目录, 搜索这个路径下指定类型的文件,比如: *.c
  • Función de parámetro:
    • PATRÓN se refiere a cierto tipo de archivo en uno o más directorios, por ejemplo, un archivo .c en el directorio actual se puede escribir como *.c
    • Se pueden especificar varios directorios, con espacios entre cada ruta
  • valor de retorno:
    • Obtenga una lista de archivos de varios archivos, use espacios entre los nombres de los archivos
    • Ejemplo: $(comodín .c ./sub/ .c)
      • Formato del valor devuelto: ac bc cc dc ec fc ./sub/aa.c ./sub/bb.c
        Ejemplo:
# 使用举例: 分别搜索三个不同目录下的 .c 格式的源文件
src = $(wildcard /home/robin/a/*.c /home/robin/b/*.c *.c)  # *.c == ./*.c
# 返回值: 得到一个大的字符串, 里边有若干个满足条件的文件名, 文件名之间使用空格间隔
/home/robin/a/a.c /home/robin/a/b.c /home/robin/b/c.c /home/robin/b/d.c e.c f.c

6.2 patsubst

La función de esta función es reemplazar el sufijo del nombre de archivo especificado de acuerdo con el patrón especificado. El prototipo de función es el siguiente:

# 有三个参数, 参数之间使用 逗号间隔
$(patsubst <pattern>,<replacement>,<text>)
  • Función de parámetro:
    • patrón: esta es una cadena de patrón que necesita especificar cuál es el sufijo en el nombre del archivo que se reemplazará
      • El nombre del archivo y la ruta no necesitan preocuparse, así que use % para expresar [el comodín es %]
      • Especifique el sufijo que se reemplazará después del comodín, por ejemplo: %.c, lo que significa que se reemplazará el sufijo de .c
    • reemplazo: esta es una cadena de patrón que especifica con qué se reemplazará eventualmente el sufijo en el patrón de parámetro
      • Todavía use% para representar la ruta y el nombre del archivo en el patrón de parámetros
      • Especifique un nuevo sufijo después del comodín %, por ejemplo: %.o Esto significa que el sufijo original se reemplaza por .o
    • texto: Este parámetro almacena los datos originales a ser reemplazados
    • valor de retorno:
      • La función devuelve la cadena reemplazada.
        Ejemplo:
src = a.cpp b.cpp c.cpp e.cpp
# 把变量 src 中的所有文件名的后缀从 .cpp 替换为 .o
obj = $(patsubst %.cpp, %.o, $(src)) 
# obj 的值为: a.o b.o c.o e.o

Ejemplo de archivo MAKE:

# 添加自定义变量 -> makefile中注释前 使用 # 
# 使用函数搜索当前目录下的源文件 .c
src=$(wildcard *.c)
# 将源文件的后缀替换为 .o
obj=$(patsubst %.c, %.o, $(src))
target=calc

$(target):$(obj)
        gcc $(obj)  -o $(target)

%.o:%.c
        gcc $< -c

# 添加规则, 删除生成文件 *.o 可执行程序
# 声明clean为伪文件
.PHONY:clean
clean:
        # shell命令前的 - 表示强制这个指令执行, 如果执行失败也不会终止
        -rm $(obj) $(target) 
        echo "hello, 我是测试字符串"

Aviso:clean es un pseudoobjetivo que no corresponde a ningún archivo físico.Como dije antes sobre la actualización de la marca de tiempo del archivo, si el objetivo no existe, se ejecutará el comando de la regla.Si el archivo objetivo existe, el objetivo el archivo en la regla necesita ser comparado.Y la marca de tiempo del archivo dependiente, el comando de la regla se ejecuta solo cuando se cumple la condición, de lo contrario no se ejecuta.

Para resolver este problema, debe declarar clean como un pseudoobjetivo en el archivo MAKE, de modo que make no verifique la marca de tiempo del archivo y los comandos de la regla se ejecuten siempre.

Declarar un pseudoobjetivo en el archivo MAKE requiere el uso de la palabra clave .PHONY. La declaración es: .PHONY: nombre del pseudoarchivo

Supongo que te gusta

Origin blog.csdn.net/qq_39030233/article/details/129099312
Recomendado
Clasificación