一、 待编译工程的目录结构
1.1 图示
bin
: 可执行文件目录,即 Makefile 最终产物
inc
: 头文件目录
lib
: 静态库 / 动态库文件目录
obj
: 源文件编译的目标文件目录
src
: 源文件目录
二、 Makefile 简要说明
2.1 示例
INC_DIR = ./inc
BIN_DIR = ./bin
SRC_DIR = ./src
OBJ_DIR = ./obj
LIB_DIR = ./lib
TARGET = main
LIB = libmyLib.a
srcAll = $(wildcard $(SRC_DIR)/*.c)
src = $(nodir $(srcAll))
obj = $(patsubst %.c, $(OBJ_DIR)/%.o, $(src))
lib = $(LIB_DIR)/$(LIB)
bin = $(BIN_DIR)/$(TARGET)
main:$(obj) $(lib)
gcc $(obj) -o $(bin) -L$(LIB_DIR) -lmyLib
mlib:$(filter-out $(OBJ_DIR)/main.o, $(obj))
ar rcs $(lib) $^
$(OBJ_DIR)/%.o:$(SRC_DIR)/%.c
gcc -I$(INC_DIR) -c $< -o S@
.PHONY:clean
clean:
@echo clean is start...
find $(OBJ_DIR) -name *.o -exec rm {} \;
-rm $(bin)
-rm $(lib)
2.2 说明
INC_DIR = ./inc
该语句定义了一个变量 INC_DIR ,其值为 ./inc ,后续可以通过 $(INC_DIR) 访问变量值
Makefile 中的变量类似于 c 语言中的宏,访问变量值就是宏展开
1. 若变量存在相互引用关系,则建议使用:=
定义变量,该符号表示当前定义的变量只能引用之前已经定义过的变量,避免递归定义。如y = $(x) bar
,若之前定义x = foo
,则y
的值为foo bar
,否则y
的值为bar
2. 为避免变量二次定义,可以使用?=
定义变量,该符号表示若变量之前未定义,则此处定义变量并赋值,否则该语句无效srcAll = $(wildcard $(SRC_DIR)/*.c)
该语句使用通配符关键字
wildcard
定义了变量srcAll
,表示srcAll
的值为SRC_DIR
变量值对应目录下所有.c
文件集合
若直接定义srcAll = *.c
,表示srcAll
的值就是*.c
,通配符*
在定义变量时并不会直接生效src = $(nodir $(srcAll))
该语句提取出
srcAll
变量值中的文件名部分,即删除了文件路径(后文需要使用$src
定义目标文件集合)obj = $(patsubst %.c, $(OBJ_DIR)/%.o, $(src))
该语句使用字符串处理函数
patsubst
对src
变量中的值进行格式替换,通配符%
表示任意长度的字符串
变量src
通过上文中的提取后,是所有.c
文件的文件名集合
执行完本条语句,变量obj
的值为所有.c
文件对应的.o
文件名,且带有路径$OBJ_DIR
【重要】Makefile 规则
Makefile 规则由依赖关系与目标生成方法两部分组成,语法通常为
targets : prerequisites
command
...
main:$(obj) $(lib)
该语句定义了一个目标
mian
与其依赖项$(obj)
、$(lib)
,表示目标生成时需要引用这些依赖项
【注】该目标是 Makefile 文件中的第一个目标,也是默认执行目标,即在终端执行 make 命令时,默认生成该目标。若要生成其他目标,则需要执行: make 目标名称gcc $(obj) -o $(bin) -L$(LIB_DIR) -lmyLib
该语句定义了目标
main
的生成方法,表示使用 gcc 编译器链接所有的obj
文件生成最终的可执行文件bin
,同时-L
指定了库文件路径,-l
指定了目标文件所引用的库文件,且库文件名为libmyLib.a
该语句与上一条语句共同构成一条规则mlib:$(filter-out $(OBJ_DIR)/main.o, $(obj))
该语句定义了一个目标
mlib
,其依赖项的定义中使用了filter-out
函数,表示在路径$(OBJ_DIR)
下除main.o
之外的其他.o
文件集合ar rcs $(lib) $^
该语句定义了目标
mlib
的生成方法,表示将所有的依赖项打包成一个库文件,库文件为$(lib)
,即 ./lib/libmyLib.a
其中$^
为自动化变量,表示去重后的依赖项集合,类似有$@
表示目标集合,$<
表示依赖项集合,$?
表示比目标新的依赖项集合$(OBJ_DIR)/%.o:$(SRC_DIR)/%.c
该语句定义的目标文件为
.o
文件集合,依赖项为与其同名的.c
文件,同名是通过通配符%
实现的gcc -I$(INC_DIR) -c $< -o S@
该语句定义了目标文件
.o
的生成方法,表示使用 gcc 编译器编译各.c
文件生成对应的.o
文件
$<
表示遍历依赖项,$@
表示遍历目标
2.3 其他
#
该符号在 Makefile 中表示后续内容为注释,和 c 语言中的
//
类似,但是#
建议顶格或者紧接着语句开始
dir = ./src #directory to put source file in
注意该语句定义的变量dir
,其值为./src
+ 四个空格,这样访问目录文件是有问题的