写在前面
从大三做学编译开始,第一次接触makefile,觉得超级方便,基本语法样例中老师给好了,都是基础性makefile
到了自己源码编译什么东西时,看人家的makefile,根本摸不到头脑,只知道make modules,make, make install…
又是之前绕过的拦路虎,现在再一次避不过去了。近期目标是看懂,远期目标是会写。
Makefile基础
由这里 二次整理而来
- 一些不明所以的符号: $@, $^, $<
# hello由hello.o生成,所以hello依赖于hello.o及多个hellox.o文件;
# 依赖关系用冒号(:)隔开
# 冒号左边的叫做目标(target);
# 冒号右边称为依赖(prerequisites)
# `$@`是指所有的编译目标;
# `$<`是指第一个依赖文件;
# `$^`是指多个依赖文件;
SRC_DIR := .
SUB_SRC_DIR := ./sub
# patsubst 模式匹配文本并替换。第一个参数,匹配模式;第二个参数,替换字符串;第三个参数,要替换的文本字符串
# wildcard 列举符合通配符表达式的所有源文件,输出以空格为分隔符的列表
OBJS += $(patsubst %.c,%.o, $(wildcard $(SRC_DIR)/*.c $(SUB_SRC_DIR)/*.c))
hello: $(OBJS)
gcc -o $@ $^
# $@即hello,$^即$(OBJS)中,所有的.o目标文件
# 如果此处只有一个依赖文件,比如hello.o,也可以用$<替代$^
# 伪目标的意义就是,无论如何都执行下面的命令
# 防止Makefile中定义的目标和工作目录的实际文件出现名字冲突,导致命令无法执行
# 伪目标,只是一个标签,不会生成文件,当然就不会有冲突啦
.PHONY: clean
clean:
rm -f hello $(OBJS)
- 如何指定编译目录
可以通过BUILD_DIR指定build目录,作为编译过程中间文件的存放位置
makefile文件变成了这样
SRC_DIR := .
SUB_SRC_DIR := ./sub
BUILD_DIR := ./build
# 目标文件
SRCS := $(wildcard $(SRC_DIR)/*.c $(SUB_SRC_DIR)/*.c)
OBJS += $(addprefix $(BUILD_DIR)/,$(patsubst %.c,%.o,$(notdir $(wildcard $(SRC_DIR)/*.c $(SUB_SRC_DIR)/*.c))))
hello: $(OBJS)
gcc -o $@ $^
# 这时候因为目标文件已经脱离了源文件的环境,
# 用makefile隐含规则自动编译已经不可行了。
# 需要显式执行编译
$(BUILD_DIR)/%.o:$(SRC_DIR)/%.c
gcc -c -o $@ $^
$(BUILD_DIR)/%.o:$(SUB_SRC_DIR)/%.c
gcc -c -o $@ $^
.PHONY: clean
clean:
rm -f hello $(OBJS)
Makefile手册
Makefile概述
- 在makefile中可以使用变量 (类似于C语言中的宏)
- 然后可以以 $(objects) 的方式来使用它
- 显式规则
- 隐式规则:makefile的自动推导功能
- 变量定义
- 文件指示:可以引用其他makefile(include <filename>);可以实现#if
- 注释
- 命令要以 tab 键开始(绝对不能是空格),与之对应的include这些关键字前边一定不能有Tab键
- 两条命令:在同一行时可用分号(;)分隔,或者是放在两行。以此保证前后依赖关系
- 另外,Makefile以/bin/sh执行命令
关于语法
- 支持通配符 *,?, ~
- vpath 关键字
- vpath <pattern> <directories> 为符合pattern的文件指定搜索目录
- vpath <pattern> 清除符合pattern的文件的搜索目录
- vpath 清除所有设置好的文件搜索目录
- ps, 这里的pattern用%匹配符,举个例子,vpath %.h …/headers
- 自动化变量 $@
- $@表示 目标的集合
- 静态模式
- 基本语法,为啥叫这个名字我还没弄明白
<targets ...> : <target-pattern> : <prereq-patterns ...>
<commands>
- 看个栗子就明白了这个语法了
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
关于Makefile的书写和调试
怎么知道自己写的Makefile对不对呢,插装哈哈哈哈哈
- @echo something_to_tell
- make -n 或 make --just-print
- 与之相对的就是 make -s 或 make --silent 或 make --quiet
- 看到这里突然有了新的想法,鸽了暂时