Makefile文件编写
写在前面:本文只是作者在学习过程中的一些记录,多数为自己的理解,如果和您意见不一致,建议以您的为主,谢谢。
本文参考B站UP主《韦东山》相关课程,详情见右侧链接:点我直达韦东山老师课程
感谢韦东山老师提供的课程供大家学习和参考。
什么是Makefile
Makefile是一个用于组织和自动化编译和链接项目的文本文件。
在编写 Makefile 时,可以定义一系列规则,来说明哪些源文件需要先编译,哪些需要后编译,哪些需要重新编译等。Makefile 类似于一个 Shell 脚本,可以执行操作系统命令。Makefile 结合使用 GNU Make 这个工具,可以自动地根据源代码文件是否更新来编译项目,减少重复工作,提高编程效率。
组成内容
有五个组成部分:
- 显示规则:生成一个或多个目标文件的方法和步骤。
- 隐式规则:make工具具有自动推导的功能,所以在编写makefile文件时可以利用该规则,简写makefile。
- 变量的定义:支持变量定义,变量一般都是字符串。
- 文件指示:可以在一个makefile文件中引用另一个makefile;根据某些情况指定makefile中的有效部分,类似C语言中的编译宏#if;可以定义一个多行命令。
- 注释:‘#’用来注释。
文件包含:include <filename>
规则
格式:
目标文件:依赖文件
(有一个Tab) 命令
例子:
test:a.o b.o
gcc -o test a.o b.o
a.o:a.c
gcc -c a.o a.c
b.o:b.c
gcc -c b.o b.c
语法
通配符:%.o,全部后缀名为.o的文件
优化一下上面的例子:
test:a.o b.o
gcc -o test a.o b.o
%.o:%.c
gcc -c -o $@ $<
上面例子中:$@为目标文件,即为a.o和b.o;$<为第一个依赖文件,此处为对应的.c文件;$^为所有依赖文件。
所以上面的例子可以进一步优化为:
test:a.o b.o
gcc -o test $^
%.o:%.c
gcc -c -o $@ $<
假想目标:
通过关键字.PHONY声明的为假想目标
test:a.o b.o
gcc -o test $^
%.o:%.c
gcc -c -o $@ $<
clean:
rm *.o test
.PHONY:clean
假想目标:不代表实际存在的文件名,通常用于调用一系列命令而不用担心有同名文件存在。比如目录中存在与clean目标同名的文件或目录,当执行make clean时可能会提示没有对应的规则去生成目标。就出现了不能够删除文件的情况,所以将clean定义为假想目标,则在执行时就直接进行清理了。
变量
变量可以分为两类:即时变量和延时变量
即时变量:在变量定义时就确定好了值。A := 123
延时变量:若变量是第一次定义,才有效;若之前已经定义,则本语句无效。
例子:
A := $(C)
B = $(C)
C = abc
D = ask
D ?= jeffrey
all:
@echo A=$(A)
@echo B=$(B)
@echo C=$(C)
@echo D=$(D)
输出:
A=
B=abc
C=abc
D=ask
函数:
-
foreach函数
使用:$(foreach var,list,text)
功能:对list中每一个变量var执行text操作
例子:A = a b c B = $(foreach f,$(A),$(f).o) all: @echo B=$(B) 输出: B=a.o b.o c.o -
filter函数
使用:$(filter pattern...,text)
功能:在text中取出符合pattern格式的值 -
filter-out函数
使用:$(filter-out pattern...,text)
功能:在text中取出不符合pattern格式的值
例子A = a b c d/ B = $(filter %/, $(A)) C = $(filter-out %/, $(A)) all: @echo B=$(B) @echo C=$(C) 输出: B=d/ C=a b c -
wildcard函数
使用:$(wildcard pattern)
功能:用于获取符合特定模式(pattern)的文件名列表。
例子://假设当前目录中有文件:a.c b.c a.h b.h Makefile files = $(wildcard *.c) all: @echo files=$(files) 输出: files=a.c b.c files1 = a.c b.c c.c d.c files2 = $(wildcard $(files1)) all: @echo files2=$(files2) 输出: files2=a.c b.c 类似与筛选出在files1中真实在当前目录下存在的文件 -
patsubst函数
使用:$(patsubst pattern, replacement, $(var))
功能:将$(var)中满足pattern格式的值替换为replacement
例子:files = a.c b.c c.c file1 = $(patsubst %.c,%.o,$(files)) all: @echo file1=$(file1) 输出: file1=a.o b.o c.o
完整例子讲解
# 指定编译器
CC = gcc
# 指定头文件目录
INCLUDE = -I ./
# 指定源文件
SRCS = main.c func1.c func2.c
#指定编译选项
CFLAGS = -g -O0
# 指定目标文件
OBJS = $(SRCS:.c=.o)
# 链接库
LDFLAGS = -lpthread
# 链接库路径
LDPATH = -L ./
# 自己的库
LDFLAGS += -lmylib
# 指定最终执行文件
TARGET = myprogram
# 编译规则
$(TARGET): $(OBJS)
$(CC) -o $@ $(OBJS) $(CFLAGS) $(LDPATH) $(LDFLAGS) $(INCLUDE)
# 对每一个.c文件生成对应的.o文件
.c.o:
$(CC) -o $@ -c $<
# 清理规则
clean:
rm -f $(TARGET) $(OBJS)