单源文件目录makefile
目录结构
由于只是用来编译简单的小型程序,所以目录尽量简洁:
.
├── build
│ ├── bin
│ ├── .dep
│ └── obj
├── makefile
└── src
这里用户需要创建的就只有makefile和src目录(里面放入项目.h
和.cpp
文件)。
build目录下用于存放编译中间文件和最终的可执行程序,其中.dep
用于记录.cpp
文件的头文件依赖关系。
自动生成头文件依赖
利用g++命令中推导头文件依赖的功能生成每个.cpp
文件对应的.d
依赖文件,再将.d
依赖文件include
到makefile文件中,实现对依赖头文件的检测。
具体原理见:Auto-Dependency Generation
makefile
# 目录结构
# .
# ├── build
# │ ├── bin
# │ ├── .dep
# │ └── obj
# ├── makefile
# └── src
# 获取当前的makefile所在的目录绝对路径
# MAKEFILE_LIST是make工具定义的环境变量,最后一个值就是当前的makefile的启动路径(可以是相对路径)
TOP_DIR:=$(patsubst %/, %, $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
# 各项目录
BIN_DIR:=$(TOP_DIR)/build/bin
DEP_DIR:=$(TOP_DIR)/build/.dep
OBJ_DIR:=$(TOP_DIR)/build/obj
SRC_DIR:=$(TOP_DIR)/src
# 编译器,链接器
CXX:=g++
LD:=g++
# 生成依赖文件选项
DEPFLAGS=-MT $@ -MMD -MP -MF $(DEP_DIR)/$*.d
# 编译选项
CXXFLAGS:=-std=c++11 -Wall -Wextra -Og -g
# 宏定义
MACROS:=
# 链接选项
LDFLAGS:=
# 包含的头文件和库文件
INCS:=
LIBS:=
# 源文件以及中间目标文件和依赖文件
SRCS:=$(notdir $(wildcard $(SRC_DIR)/*.cpp))
OBJS:=$(addprefix $(OBJ_DIR)/, $(patsubst %.cpp, %.o, $(SRCS)))
DEPS:=$(addprefix $(DEP_DIR)/, $(patsubst %.cpp, %.d, $(SRCS)))
# 最终目标文件
TARGET:=$(BIN_DIR)/hello
# 默认最终目标
.PHONY:all
all:$(TARGET)
# 生成最终目标
$(TARGET):$(OBJS) | $(BIN_DIR)
@echo -e "\e[32m""Linking executable $(TARGET)""\e[0m"
@$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
# 若没有bin目录则自动生成
$(BIN_DIR):
@mkdir -p $@
# 生成中间目标文件
$(OBJ_DIR)/%.o:$(SRC_DIR)/%.cpp $(DEP_DIR)/%.d | $(OBJ_DIR) $(DEP_DIR)
@echo -e "\e[33m""Building object $@""\e[0m"
@$(CXX) -c $(DEPFLAGS) $(CXXFLAGS) $(INCS) $(MACROS) -o $@ $<
# 若没有obj目录则自动生成
$(OBJ_DIR):
@mkdir -p $@
# 若没有.dep目录则自动生成
$(DEP_DIR):
@mkdir -p $@
# 依赖文件会在生成中间文件的时候自动生成,这里只是为了防止报错
$(DEPS):
# 引入中间目标文件头文件依赖关系
include $(wildcard $(DEPS))
# 删除build目录
.PHONY:clean
clean:
@rm -rf $(TOP_DIR)/build