Makefile的简单使用

Posted Heavy sea

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Makefile的简单使用相关的知识,希望对你有一定的参考价值。

一、Makefile核心规则

目标文件(target)… : 依赖文件(prerequiries)…
tab键+ 命令(command)

如果依赖文件比目标文件更加新,那么执行命令来重新生成目标文件

举例:

a.c

#include <stdio.h>

int main()

        func_b();
        return 0;

b.c

#include <stdio.h>

void func_b()


        printf("this is A!\\n");


可用命令gcc -o test a.c b.c 进行编译,但现在需要用make命令,编写Makefile文件
我们知道可以用gcc -c 命令分别对a.c 和 b.c 文件进行编译不链接,形成a.o 和 b.o 文件,然后再对a.o 和 b.o 文件进行链接形成可执行文件test。基于这一点,可以编写以下Makefile文件(后续进行完善)

test: a.o b.o
        gcc -o test a.o b.o
a.o: a.c
        gcc -c -o a.o a.c
b.o: b.c
        gcc -c -o b.o b.c

二、 Makefile语法

1.通配符: %.o
表示目标 $@
表示第一个依赖文件 $<
表示所有依赖文件 $^

2.假相目标: .PHONY

根据以上语法可对之前的Makefile文件进行改进
若make 不指定目标,默认执行第一条命令,即生成可执行文件test;若指定目标clean则执行删除有关文件。

Makefile命令执行条件是:目标文件不存在或者依赖文件比目标文件新
若文件目录存在clean文件,而无依赖文件,则执行不了删除命令,则需要使用.PHONY

test: a.o b.o
        gcc -o $@ $^
%.o: %.c
        gcc -c -o $@ $<
clean:
        rm *.o test -f
.PHONY: clean

3.即时变量 延时变量

:= 即时变量
= 延时变量
?= 延时变量,如果是第一次定义才起效,如果在前面该变量已定义则忽略这句
+= 附加,它是即时变量还是延时变量取决于前面的定义

有以下Makefile文件
A为即时变量,在定义时就确定,此时变量C为空
B为延时变量 使用时才确定

A := $(C)
B = $(C)

C = ab

D = hello
D ?= heavysea

all:
        @echo A = $(A)
        @echo B = $(B)
        @echo D = $(D)

C += ee
~

执行make命令:

A =
B = ab ee
D = hello

三、Makefile部分常用函数

1. $(foreach var f,list,text)
把参数list中的单词逐一取出来放到var所指的变量中,然后再执行text所包含的表达式

2. $(filter pattern…,text)
在text中取出符合pattern格式的值

3. $(filter-out pattern…,text)
在text中取出不符合pattern格式的值

4. $(wildcard pattern)
pattern 定义了条件名的格式
wildcard 取出其中存在的文件

5. $(patsubst pattern,replacement, $(var))
从列表中取出每一个值,如果符合pattern,则替换为replacement

Makefile

A = a b c
B = $(foreach f,$(A),$(f).o)
C = a b c d e/

// 查找C中符合 .../的形式
D = $(filter %/,$(C))
// 查找C中不符合 .../的形式
E = $(filter-out %/,$(C))

//取出存在的.c文件
file = $(wildcard *.c)

file2 = a.c b.c c.c d.c e.c
// 取出file2中且存在的文件
file3 = $(wildcard $(file2))

// 从file2中取出的值若符合.c形式则替换为.d文件
dep_files = $(patsubst %.c,%.d,$(file2))

all:
        @echo B = $(B)
        @echo D = $(D)
        @echo E = $(E)
        @echo file = $(file)
        @echo file3 = $(file3)
        @echo dep_files = $(dep_files)

运行结果如下图

四、Makefile的实例(自动检测头文件)

文件目录下有a.c b.c 文件

objs = a.o b.o

// .a.o.d   .b.o.d
// 需要判断是否存在依赖文件
dep_files := $(patsubst %,.%.d,$(objs))
dep_files := $(wildcard $(dep_files))

// 警告作为错误提醒  指定头文件路径
CFLAGS = -Werror -I .

test: $(objs)
        gcc -o $@ $^

// 把依赖文件包含进来
ifneq ($(dep_files),)
include $(dep_files)
endif

%.o: %.c
        gcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d
clean:
        rm *.o test -f
 // 删除依赖文件
distclean:
        rm $(dep_files)
.PHONY: clean

有关依赖文件的常用命令

// 打印出依赖
gcc -M b.c    

// 把依赖写入文件b.d 
gcc -M -MF b.d b.c

// 编译b.o 把依赖写入文件b.d
gcc -c -o b.o b.c -MD -MF b.d

以上是关于Makefile的简单使用的主要内容,如果未能解决你的问题,请参考以下文章

如何在此高级 makefile 中链接两个 .c 文件?

重建后的Makefile重新编译代码需要很多时间

无法在内核模块 makefile 中使用通配符

VC++ makefile 项目永远不会更新

将perl脚本添加到makefile

CMake 的 FetchContent 与 Makefile 构建的依赖项