05 - Makefile 工程编译文件简要说明

一、 待编译工程的目录结构

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))

    该语句使用字符串处理函数 patsubstsrc 变量中的值进行格式替换,通配符 % 表示任意长度的字符串
    变量 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 + 四个空格,这样访问目录文件是有问题的

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值