一个简单的Makefile编译所有c代码文件为每个单独程序
笔者初学Makefile
用来方便编译项目,记录一下,若有问题欢迎指正,文件内容附在文末
本文目的
我在./src/
目录下有若干.c
文件,想对每个文件均进行编译,中间代码文件*.o
存放在./build/obj/
下,目标可执行文件放在./build/
下
Makefile的工作流程
- 没有指定输出项目时,Makefile会先在所有目标中找到第一个没有通配符的目标进行构造;例如本文中的
all
,即时它是个伪目标 - 根据构造
all
的规则,需要构造$(BUILD)
,而$(BUILD)
即是$(BUILD_DIR)
下无后缀的可执行文件 - 于是要构造的目标就变为了
$(OBJ_DIR)/%.o
,然后make在规则中继续寻找,找到了一个匹配的规则$(BUILD_DIR)/%: $(OBJ_DIR)/%.o
,但不幸的是该规则依赖OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
,于是继续寻找 - 下面又找到了
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
,现在不需要继续寻找了,即执行这个规则下的语句进行编译但不链接 - 完成后回到上层进行对
.o
文件的链接,然后继续回到上层,重复这个过程使得对于每一个$(BUILD)
中的目标都得到了生成
不删除中间文件
上述过程会在全部编译完成后使用rm
命令删除中间过程文件,仅保留目标文件,可以通过添加一条
.SECONDARY: $(OBJS)
让$(OBJS)
成为第二目标,从而不被清理掉
编写clean
方法
我们有时需要对项目进行清理,此时只需要将clean
写进伪目标,然后把它的实现放到最后一个就好了,实现很简单,即使用rm
对编译过程文件和结果文件进行清理即可
一个比较建议的项目树组织
.
├── build
│ ├── 若干可执行文件
│ └── obj
│ └── 若干.o中间代码文件
├── LICENSE
├── Makefile
├── README.md
└── src
└── 若干c源文件
附:Makefile全文
# File paths
SRC_DIR := ./src
BUILD_DIR := ./build
OBJ_DIR := $(BUILD_DIR)/obj
# Compilation flags
CC := gcc
LD := gcc
CFLAGS := -Wall
# Files to be compiled
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
BUILD := $(OBJS:$(OBJ_DIR)/%.o=$(BUILD_DIR)/%)
# Don't remove *.o files automatically
.SECONDARY: $(OBJS)
all: $(BUILD)
# Compile each *.c file as *.o files
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
@echo + CC $<
@mkdir -p $(OBJ_DIR)
@$(CC) $(CFLAGS) -c -o $@ $<
# Link each *.o file as executable files
$(BUILD_DIR)/%: $(OBJ_DIR)/%.o
@echo + LD $@
@mkdir -p $(BUILD_DIR)
@$(LD) $(CFLAGS) -o $@ $<
.PHONY: all clean
clean:
rm -rf $(BUILD_DIR)