CC++ - makefile(规则、伪目标、变量、内置函数)

    科技2023-09-24  79

    视频:https://www.bilibili.com/video/BV1dW411n7vk?from=search&seid=13869936161616988114

    可以试想一下,有一个上百个文件的代码构成的项目,如果其中只有一个或几个文件进行修改,需要从头到尾将每一个文件都重新编译是一个比较繁琐的过程。 为此,引入了Make工程管理器的概念,工程管理器指管理较多文件,自动根据文件时间自动发现更新过的文件而减少编译的工作量,同时通过读入Makefile文件来执行大量的编译工作。

    makefile规则

    规则:用于说明如何生成一个或多个目标文件

    makefile文件里面可以有很多规则,但是第一个规则是最终生成的文件规则。

    规则格式:

    target: dependency_files // 目标项:依赖项 <tab>command // 必须以tab开头,command编译命令

    规则就是为了生成某一个文件的。 目标项:这个就是你要生成的文件名 依赖项:要生成目标项需要的文件 编译命令:如果有依赖项生成目标项;必须以TAB开头

    在mekefile中,规则的顺序是很重要的。因为,Makefile中只应该有一个最终目标,其他的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标

    归结:

    目标文件不存在,执行命令文件已经更新了,执行命令Makefile的第一条规则为最终的目标。

    例1:单文件

    #include <stdio.h> int main(int argc, int **argv) { printf("hello world\n"); return 0; }

    写成makefile如下

    创建名称为makefile或者Makefile的文档在文档中输入相应的内容test:test.c gcc -o test test.c 运行makefile文件 命令行输入make

    如果马上再执行make命令 这是因为,make命令会对比源文件的修改时间,如果早于目标文件,说明源文件没有修改,就不会帮你再次编译了。

    例2:多文件

    test.c

    #include <stdio.h> extern void sort(int *arr, int len); extern void show(int *arr, int len); int main(int argc, int **argv) { int arr[] = {3, 2, 1, 5, 9, 8, 7}; int len = sizeof(arr) / sizeof(arr[0]); sort(arr, len); show(arr, len); return 0; } void show(int *arr, int len) { for (int i = 0; i < len; i++) { printf("%d ", arr[i]); } printf("\n"); }

    sequence.c

    void sort(int *arr, int len) { for (int i = 0; i < len; i++) { for (int j = i; j < len; j++) { if (arr[i] > arr[j]) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } }

    makefile

    test:test.o sequence.o gcc -o test test.o sequence.o test.o:test.c gcc -o test.o -c test.c sequence.o:sequence.c gcc -o sequence.o -c sequence.c

    Makefile中特殊处理与伪目标

    .PHONY是makefile文件中的关键字,表示它后面列表中的目标均为伪目标。

    如:

    .PHONY:b b: echo 'b' # 通常用@echo "hello"

    伪目标通常用在清理文件、强制重新编译等情况下。一般伪目标没有时间的检查,一旦指明了就会执行。 如:

    .PHONY:clean //".PHONY"将"clean"目标声明为伪目标 clean: rm -f hello main.c func1.o func2.o

    例3

    继续例子2

    修改Makefile文件

    test:test.o sequence.o gcc -o test test.o sequence.o test.o:test.c gcc -o test.o -c test.c sequence.o:sequence.c gcc -o sequence.o -c sequence.c .PHONY:clean rebuild clean: rm -f test.o sequence.o test rebuild:clean test

    注意文件创建时间

    Makefile的变量、规则与内置函数

    变量

    随着软件项目的变大、变复杂,源文件也越来越多,如果采用前面的方式写makefile文件,将会使makefile也变得复杂而难于维护。 通过make支持的变量定义、规则和内置函数,可以写出通用性较强的makefile文件,使得同一个makefile文件能够适应不同的项目。

    变量:用来代替一个文本字符串 定义变量的2种方法: 变量名=变量值 递归变量展开(几个变量共享一个值) // 不常用 变量名:=变量值 简单变量展开(类似与C++的赋值) // 通常采用这种形式 使用变量的一般方法: $(变量名)=??? // 赋值 ???=$(变量名) // 引用

    变量分为:用户自定义变量、自动变量、预定义变量、环境变量

    用户自定义变量

    如:

    OBJS:=test.o add.o EXE:=test.exe $(EXE):$(OBJS) gcc -o $(EXE) $(OBJS) test.o:test.c gccc -c test.c add.o:add.c gcc -c add.c .PHONY:rebuild clean rebuild:clean $(EXE) clean: rm -rf $(EXE) $(OBJS)

    上面的例子就是用户自定义变量。

    自动变量

    值在使用的时候,自动用特定的值替换。 如:

    OBJS:=test.o add.o EXE:=test.exe $(EXE):$(OBJS) gcc -o $@ $^ test.o:test.c gcc -c $^ add.o:add.c gcc -c $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: rm -rf $(EXE) $(OBJS)

    预定义变量、环境变量(查看环境变量export)

    内部事先定义好的变量,但是它的值是固定的,并且有些值是为空的。

    根据内部变量,可以将makefile改写为:TEST_file3文件夹。

    OBJS:=test.o add. EXE:=test.exe $(EXE):$(OBJS) $(CC) -o $@ $^ test.o:test.c $(CC) -c $^ add.o:add.c $(CC) -c $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: $(RM) $(EXE) $(OBJS)

    规则:普通规则,隐含规则,模式规则

    1、 普通规则

    普通规则即基本语法规则

    另外

    makefile里面的注释使用#命令如果不想显示到终端,加@

    2、隐含规则

    例如:*.o文件自动依赖*.c或*.cc文件,所以可以忽略main.o:main.c等

    OBJS:=test.o add.o EXE:=test.exe $(EXE):$(OBJS) $(CC) -o $@ $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: $(RM) $(EXE) $(OBJS)

    省略了

    3、模式规则

    通过匹配模式找字符串,%匹配1或多个任意字符串。 %.o:%.cpp表示任何目标文件的依赖文件是与目标文件同名的并且扩展名为.cpp的文件

    OBJS:=main.o fun.o main.exe:$(OBJS) gcc $^ -o $@ %.o:%.cpp gcc -o $@ -c $^

    另外还可以指定将*.o、*.exe、*.a、*.so等编译到指定目录中

    DIR:=./Debug/ EXE:=main.exe OBJS:=main.o $(DIR)$(EXE):$(DIR)$(OBJS) gcc -o $@ $< -L ./ -1func $(DIR)main.o:main.c gcc -o $@ -c $^ .PHONY:rebuild clean rebuild:clean $(DIR)$(EXE) clean: rm -rf $(DIR)*.0 $(DIR)*.exe

    注意: 当OBJS里面有多项的时候,此时$(DIR)$(OBJS)只能影响到OBJS第一个,后面的全部无效,因此需要全部列出来

    函数

    wildcard(搜索文件函数)

    搜索当前目录下文件名,展开成一列所有符合由其参数描述的文件名,文件间以空格隔开

    SOURCES=$(wildcard *.cpp) // 把当前目录下所有.cpp文件存入变量SOURCES里

    patsubst(字符替换函数)

    格式:$(patsubst 要查找的子串, 替换后的目标子串, 源字符串) 将源字符串(以空格分隔)中的所有要查找的子串替换成目标子串 如:

    OBJS=$(patsubst %.cvpp,%.o,$(SOURCES))

    把SOURCES中.cpp替换为.o然后把替换后的字符串存入变量OBJS中

    addprefix(加前缀函数)

    格式:$(addprefix 前缀, 源字符串) 该函数把第二个参数列表里的每一项前缀加上第一个参数值。

    make的命令行选项

    其他

    《GNU make 中文手册.pdf》

    DIR:=./build/ OBJS=tt.o ConfigFile.o DEPENDENCES:=$(addprefix $(DIR), $(OBJS)) EXE:=main RM:=rm -rf $(EXE):$(DEPENDENCES) gcc -o $(EXE) $(DEPENDENCES) $(DIR)%.o:%.c gcc -o $@ -g -c $^ .PHONY:rebuild clean rebuild:clean $(EXE) clean: $(RM) $(DIR)* $(EXE)
    Processed: 0.016, SQL: 8