菜鸟笔记
提升您的技术认知

makefile文件管理基本操作

1. makefile基础规则

makefile: 管理项目。

    命名:makefile    Makefile  --- make 命令

    1 个规则:

       目标:依赖条件

      (一个tab缩进)命令

       1. 目标的时间必须晚于依赖条件的时间,否则,更新目标

       2. 依赖条件如果不存在,找寻新的规则去产生依赖条件。

        ALL:指定 makefile 的终极目标。

    2 个函数:

    src = $(wildcard ./*.c): 匹配当前工作目录下的所有.c 文件。将文件名组成列表,赋值给变量 src。  src = add.c sub.c div1.c

    obj = $(patsubst %.c, %.o, $(src)): 将参数3中,包含参数1的部分,替换为参数2。 obj = add.o sub.o div1.o

    clean: (没有依赖)

-rm -rf $(obj) a.out “-”:作用是,删除不存在文件时,不报错。顺序执行结束。

    3 个自动变量:

       $@: 在规则的命令中,表示规则中的目标。

       $^: 在规则的命令中,表示所有依赖条件。

       $<: 在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。

   模式规则:

       %.o:%.c

          gcc -c $< -o %@

    静态模式规则:

       $(obj):%.o:%.c

          gcc -c $< -o %@  

   伪目标:

       .PHONY: clean ALL

    参数:

       -n:模拟执行make clean 命令。

       -f:指定文件执行 make 命令。          

下面来一步一步升级makefile

第一个版本的Makefile:

                makefile的依赖是从上至下的,换句话说就是目标文件是第一句里的目标,如果不满足执行依赖,就会继续向下执行。如果满足了生成目标的依赖,就不会再继续向下执行了。

        make会自动寻找规则里需要的材料文件,执行规则下面的行为生成规则中的目标。

执行make指令

运行hello,没有问题

2. makefile的一个规则

第二个版本的Makefile:

test.c如下:

此时要进行编译,则需要多文件联合编译:

gcc test.c add.c sub.c div1.c -o a.out

对这个新的代码,写出下面的makefile

执行:

此时,修改add.c为下图

此时,再使用make,发现了问题

可以看到,只修改add.c,但是编译的时候,其他.c文件也重新编译了,这不太科学。

明明只改了一个,全部都重新编译了

于是将makefile改写如下:

执行make指令, 执行程序输出如下:

此时修改sub为下图:

再次make

可以看到,只重新编译了修改过的sub.c和最终目标

执行程序:

makefile检测原理:

        修改文件后,文件的修改时间发生变化,会出现目标文件的时间早于作为依赖材料的时间,出现这种情况的文件会重新编译。

        修改sub.c后,sub.o的时间就早于sub.c ,a.out的时间也早于sub.o的时间了,于是重新编译这俩文件了。

关于makefile指定目标问题,先修改makefile如下:

只是将a.out放在了文件末尾

执行make,如下:

这是因为,makefile默认第一个目标文件为终极目标,生成就跑路,这时候可以用ALL来指定终极目标

指定目标的makefile

执行:

3. makefile两个函数和clean

src = $(wildcard *.c)

匹配当前工作目录下的所有.c 文件。将文件名组成列表

赋值给变量 src:src = add.c sub.c div1.c

obj = $(patsubset %.c,%.o, $(src))

把src变量里所有后缀为.c的文件替换成.o

将参数3中,包含参数1的部分,替换为参数2。 obj = add.o sub.o div1.o

clean: (没有依赖)

-rm -rf $(obj) a.out

“-”:作用是,删除不存在文件时,不报错。顺序执行结束。

用这两个函数修改makefile如下:

执行,make指令,如下所示:

每次要删除.o文件,很恶心,于是改写makefile如下:

加了clean部分

        rm前面的-,代表出错依然执行。比如,待删除文件集合是5个,已经手动删除了1个,就只剩下4个,然而删除命令里面还是5个的集合,就会有删除不存在文件的问题,不加这-,就会报错,告诉你有一个文件找不到。加了-就不会因为这个报错。

执行make:

由于没有文件变动,a.out的时间戳晚于所有依赖文件,这里make就没干活

于是,执行时加新指令,先模拟执行clean部分:

可以看到模拟执行后,会删除哪些文件。

确定没有问题,执行

4. makefile3个自动变量和模式规则

3个自动变量

$@ :在规则命令中,表示规则中的目标。

$< :在规则命令中,表示规则中的第一个依赖条件,如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则。

$^ :在规则命令中,表示规则中的所有依赖条件,组成一个列表,以空格隔开,如果这个列表中有重复项,则去重。

用自动变量修改makefile,如下:

sub,add这些指令中使用$<和$^都能达到效果,但是为了模式规则,所以使用的 $<

执行make,如下:

        上面这个makefile,可扩展性不行。比如,要添加一个乘法函数,就需要在makefile里面增加乘法函数的部分。不科学,所以,模式规则

%.o:%.c        

    gcc -c $< -o $@

修改makefile,如下:

这时,增加一个mul函数,并添加mul.c文件如下:

执行make:

增加函数的时候,不用改makefile,只需要增加.c文件,改一下源码,就行。很强势。

        继续优化makefile,使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给obj用,以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则

$(obj):%.o:%.c

gcc -c $< -o $@

修改后makefile如下:

扩展

当前文件夹下有ALL文件或者clean文件时,会导致makefile瘫痪,如下所示,make clean没有工作        

用伪目标来解决,添加一行   .PHONY: clean ALL

makefile如下所示:

再来执行make clean,就不会受到干扰了

还有一个扩展就是,编译时的参数,-g,-Wall这些,可以放在makefile里面

修改后makefile如下:

执行makefile,如下:

练习一

源码add.c,sub.c这些在src目录下,.o文件要放在obj目录下,头文件head.h在inc目录下。

如下所示:

首先,将hello.c中的头文件单独拿出来

如下:

修改makefile如下,主要是注意%的匹配理解,只匹配文件名,目录位置要手动添加

执行一波,如下:

可以说是非常强势了

调用clean删除文件,直接用就行

如果makefile的名字变化一下,比如,叫m6

用m6执行makefile,     make -f m6

用m6执行clean          make -f m6 clean

练习二

编写一个 makefile 可以将其所在目录下的所有独立 .c 文件编译生成同名可执行文件。

将当前目录下所有.c文件编译为可执行程序

测试程序:

测试: