当前位置:网站首页>Makefile文件编写快速掌握
Makefile文件编写快速掌握
2022-06-12 05:43:00 【LEO-max】
本文有参考https://blog.csdn.net/wh_computers/article/details/97623394此篇博客。
目录
本问旨在从零学习Makefile编写。
引入Makefile文件是因为工程项目中有很多文件,并且它们相互依赖,一个一个编译会花很多时间,并且一旦某一文件发生修改后就需要重新编译,那么所有相关的文件都需要重新编译。Makefile文件是去判断哪个文件被修改了,然后会重新生成修改后的文件,而且只需要一个make命令,极大简化了编译过程。
一、make及其用法
Makefile文件是一类工程管理工具的工程描述符文件的默认名称,名称不一定是Makefile,也可以是makefile或GNUmakefile。
make命令会在执行路径中搜索Makefile文件,如果同时存在以上三个文件,执行顺序是GNUmakefile > makefile > Makefile,如果选择执行一个,其他的就不会再执行了。
如果想执行某个文件,只需要make -f 文件名就可以指定执行文件,-f也可以用–file=FILE或–makefile=FILE。
make命令详细参数通过make -h 或者 make --helo来获取。
二、Makefile文件编写规则
首先给出测试代码,测试代码有两个C文件构成,a.p和b.c,其中a.c包含主函数且调用b.c的函数,b.c为加法函数add(int a,int b)。
a.c
#include <stdio.h>
#include "b.c"
int main()
{
int a=1;
int b=2;
printf("%d\n",add(a,b));
return 0;
}
b.c
#include <stdio.h>
int add(int a,int b)
{
return a+b;
}
Makefile的核心——规则:
目标 : 依赖1 依赖2 ...
[TAB]命令
Makefile基础版本:
all: test #最后的可执行程序test,无论书写顺序是怎样,最后是生成test
test: a.o #test是结果,a.o是来源
#命令必须开头是tab键 -o后面生成目标
gcc -o test a.o
a.o: a.c #a.o是结果,a.c是来源
#-c表示只编译不链接,生成.o文件
gcc -c -o a.o a.c
在命令行中输入 make 指令:
[email protected]_Learn:~/makefile$ make
gcc -o test a.o
[email protected]_Learn:~/makefile$ ls
a.c a.o b.c Makefile test
[email protected]_Learn:~/makefile$ ./test
3
Makefile进阶版本
问题引入,如果某个文件被多次引用,但是现在需要修改文件名,那么一个一个修改就会很麻烦,所以Makefile文件中允许定义变量,然后后面只需要修改变量的值就可以了,原理就是Makefile文件会展开变量,类似于宏定义。
变量定义类型规则:变量名 = 命令,使用变量是通过$(变量名)
Bin = test # 定义变量名Bin
all: $(Bin) # 生成可执行文件test
test: a.o
gcc -o $(Bin) a.o
a.o: a.c
gcc -c a.c -o a.o
clean: # clean需要使用命令make clean才会执行
rm -f *.o $(Bin) # 删除生成的.o文件和可执行文件
如果要修改文件名,只需要修改test就行了。
一般如果再次make会提示make无需做任何事,但是需要重新生成的话需要把原来的.o可执行文件删除,所以定义一个clean,俗称假目标。

Makefile终极版
如果有很多个.o文件需要引用,每次写就会感到很烦,Makefile提出了自动便令的概念,需注意的是自动变量只能用在命令里面。
下面给出常用的六个自动变量:
| 变量名 | 作用 |
|---|---|
| [email protected] | 目标的文件名 |
| $< | 第一个条件的文件名 |
| $? | 时间戳在目标之后的所有条件,并以空格隔开这些条件 |
| $^ | 所有条件的文件名,并以空格隔开,且排除了重复的条件 |
| $+ | 与$^类似,只是没有排除重复的条件 |
| $* | 目标的主文件名,不包含扩展名 |
Bin = test
all: $(Bin)
test: a.o
gcc -o $(Bin) $< #$<表示第一个条件名,也就是a.o
a.o: a.c
gcc -c $< -o [email protected] #$<表示a.c [email protected]表示目标文件名a.o
clean:
rm -f *.o $(Bin)

Makefile的语法扩展
有三个文件,分别为:a.c 、b.c、 c.c
a.c
#include <stdio.h>
int main()
{
func_b();
func_c();
return 0;
}
b.c
#include <stdio.h>
void func_b()
{
printf("This is B\n");
}
c.c
#include <stdio.h>
void func_c()
{
printf("This is C\n");
}
通配符%
利用Makefile的通配符: %.o进行编写
test: a.o b.o c.o
gcc -o test $^
%.o: %.c
gcc -c -o [email protected] $<
clean:
rm *.o test
效果如下:
clean操作+假想目标.PHONY
根据以上的操作,我们可以知道Makefile里面定义了clean,并且通过make clean进行删除操作,但是如果我们在文件中已经有了clean这个文件然后再次进行make clean操作会怎么样呢?其实会出现“最新”的告警信息。
因为Makefile的规则是:
当"目标文件"不存在,
或
某个依赖文件比目标文件"新",
则: 执行"命令"
为了避免出现make clean无法删除指定文件,我们可以引入Makefile的假想目标.PHONY进行操作
Makefile:
test: a.o b.o c.o
gcc -o test $^
%.o: %.c
gcc -c -o [email protected] $<
clean:
rm *.o test
.PHONY: clean
效果如下:
即使变量、延迟变量、export
| A := XXX | 即时变量,A的值即刻确定,在定义时即确定 |
|---|---|
| B = XXX | 延时变量,B的值在使用到时才确定 |
| C ?= XXX | 延时变量,如果是第一次定义,这语句才起效,但如果在前面语句中该变量已被定义则忽略这句 |
| D += XXX | 附加,它是即时变量还是延时变量取决于前面的定义 |
先看一个小例子:
Makefile:
A := abc
B = 123
all:
echo $(A)
echo $(B)
效果:
如果不希望打印出echo的话可以在echo语句前面加@
A := abc
B = 123
all:
@echo $(A)
@echo $(B)

修改:
Makeifle:
A := $(C)
B = $(C)
C = abc
all:
@echo $(A)
@echo $(B)
可以看出效果如下:
A为空,B成功打印出C的值,可以看出即使变量:=与延迟变量=的区别
修改二:
A := $(C)
B = $(C)
# C = abc
all:
@echo $(A)
@echo $(B)
C = 123
效果:
从结果看出,变量C放在前面还是后面对变量B是没有影响的,当执行make的时候,程序会整个读进去的,所以变量C放在前后都一样。
修改二pro:
A := $(C)
B = $(C)
C = abc
all:
@echo $(A)
@echo $(B)
C = 123
其实结果还是和上面的一样,C的前一个值abc被后面的123覆盖了,所以B的值还是123,
修改三:
A := $(C)
B = $(C)
C = abc
all:
@echo $(A)
@echo $(B)
C += 123
效果如下:
+= 为附加,它是即时变量还是延时变量取决于前面的定义
修改四:
D = leo
D ?= LEOmax
all:
@echo $(D)
效果:
打印出的值为第一次定义的值,所以说?=如果是第一次定义,这语句才起效,但如果在前面语句中该变量已被定义则忽略这句.
修改四pro:通过命令行存入变量D:
D ?= LEOmax
all:
@echo $(D)

通过命令行make D=123456赋值D为123456覆盖了在Makefile里面leo。
Makefile函数
$(foreach var, list, text)
对于list的每一个(var)变量执行test的操作
实例如下:
A = a b c
B = $(foreach f, $(A), $(f).o)
all:
@echo B = $(B)
make后:
$(filter pattern…, text)与 $(filter-out pattern…, text)
$(filter pattern…, text):在text中取出符合 pattern格式的值
$(filter-out pattern…, text):在text中取出不符合pattern格式的值
实例:
A = a b c
B = $(foreach f, $(A), $(f).o)
C = a b c d/
D = $(filter %/,$(C))
E = $(filter-out %/,$(C))
all:
@echo B = $(B)
@echo D = $(D)
@echo E = $(E)
make结果如下 :
$(wildcard pattern)
pattern定义了文件名的格式
wildcard取出其中存在的文件
wildcard函数会会寻找pattern格式的文件并赋给某个值,最后利用echo打印出符合条件格式的文件。
如图目录下存在a.c b.c c.c 的文件
Makefile代码示例:
A = a b c
B = $(foreach f, $(A), $(f).o)
C = a b c d/
D = $(filter %/,$(C))
E = $(filter-out %/,$(C))
files = $(wildcard *.c)
all:
@echo B = $(B)
@echo D = $(D)
@echo E = $(E)
@echo files = $(files)
结果如下:
扩展:判断哪些文件真实存在:
根据代码中写出的几个格式的文件,判断目录有存在哪些符合的文件。
代码如下:
A = a b c
B = $(foreach f, $(A), $(f).o)
C = a b c d/
D = $(filter %/,$(C))
E = $(filter-out %/,$(C))
files = $(wildcard *.c)
files2 = a.c b.c c.c d.c e.c
files3 = $(wildcard $(files2))
all:
@echo B = $(B)
@echo D = $(D)
@echo E = $(E)
@echo files = $(files)
@echo files2 = $(files3)
结果如下:
$(patsubst pattern,replacement, $(var))
从列表中取出每一个值,如果符合pattern则替换为replacement
代码实例如下:将.c文件替换成.d文件
A = a b c
B = $(foreach f, $(A), $(f).o)
C = a b c d/
D = $(filter %/,$(C))
E = $(filter-out %/,$(C))
files = $(wildcard *.c)
files2 = a.c b.c c.c d.c e.c
files3 = $(wildcard $(files2))
dep_files = $(patsubst %.c, %.d, $(files2))
all:
@echo B = $(B)
@echo D = $(D)
@echo E = $(E)
@echo files = $(files)
@echo files2 = $(files3)
@echo dep_file2 = $(dep_files)
结果如下:
注意:如果不符合格式的值则不进行替换
边栏推荐
- IO stream introduction
- Go 接口实现原理【高阶篇】
- Special materials | household appliances, white electricity, kitchen electricity
- Stack and queue classic interview questions
- [go] Viper reads the configuration file in the go project
- TCP and UDP introduction
- FPGA语法的细节
- Halcon 3D 深度图转换为3D图像
- CCF noi2022 quota allocation scheme
- PHP实现图片登录验证码的解决方案
猜你喜欢
随机推荐
C WMI query remote Win32_ Operatingsystem class
March 4, 2021
A solution for PHP to implement image login verification code
SIM卡信号的驱动电流是多少mA,是否是可调节的?
Redis cache data consistency and problems
Identification of campus green plants based on tensorflow
第五讲:数据仓库搭建(三)
16. sum of the nearest three numbers
XML参数架构,同一MTK SW版本兼容两套不同的音频参数
CCF noi2022 quota allocation scheme
Towards End-to-End Lane Detection: an Instance SegmentationApproach
[fastapi] use pycharm to configure and use environment variables for fastapi projects
Is the individual industrial and commercial door a legal person enterprise
Redis persistence
[daily question on niuke.com] two point search
Filter的注解配置
Kubernetes certificate online update
Greenplum【问题 05】Greenplum Streaming Server自定义客户端问题处理(不断增加ing)
What is the difference between ArrayList and LinkedList?
CODIS stress test (PHP)
![【长时间序列预测】Aotoformer 代码详解之[4]自相关机制](/img/12/27531fc791b3f49306385831309c5e.png)







