makefile举例说明


目录结构
在这里插入图片描述

makefile文件

include config.mk

导入config.mk的文件,通常包含项目的配置变量。

all:
	@for dir in $(BUILD_DIR); \
	do \
		make -C $$dir; \
	done

all是项目主目标,遍历BUILD_DIR变量每个子目录,并在每个子目录中运行make命令。

$$dir在Shell中被解释为$dir,因为Makefile中的Shell命令需要用 $$来转义$。

-C选项告诉make进入指定目录执行makefile。

clean:
	rm -rf app/link_obj app/dep nginx
	rm -rf signal/*.gch app/*.gch

clean目标用于清理文件。
rm -rf命令会强制删除列出的目录和文件,包括编译产生的目标文件、依赖文件、以及.gch预编译头文件。

如果子目录中的Makefile也有all和clean目标,它们应该被设计成可以被递归调用。

config.mk配置文件

定义环境变量,设置项目的编译环境和构建过程。

export BUILD_ROOT = $(shell pwd)

使用pwd命令动态获取当前工作目录,赋值给BUILD_ROOT变量。

通过export,这个变量将对所有被包含的Makefile文件可见,在子目录的Makefile中可以直接引用BUILD_ROOT

# 定义头文件的路径
export INCLUDE_PATH = $(BUILD_ROOT)/_include

INCLUDE_PATH变量指定项目中头文件的存放位置。
这对于编译器来说很重要,因为它需要知道去哪里查找.h等头文件。

# 定义编译目录
BUILD_DIR = $(BUILD_ROOT)/signal/ \
			$(BUILD_ROOT)/proc/   \
			$(BUILD_ROOT)/net/    \
			$(BUILD_ROOT)/misc/   \
			$(BUILD_ROOT)/logic/   \
			$(BUILD_ROOT)/app/

BUILD_DIR变量列出了需要编译的子目录。

# 编译时是否生成调试信息。GNU调试器可以利用该信息
# 很多调试工具,包括Valgrind工具集都会因为这个为true能够输出更多的调试信息;
export DEBUG = true

DEBUG变量设为true意味着编译时将包含调试信息。
这对于开发阶段非常有用,因为生成的可执行文件可以被调试器读取并提供详细的运行时信息。如果设置为false,则会生成优化过的二进制文件,但调试信息将不会包含在内。

export BUILD_ROOT = $(shell pwd)
export INCLUDE_PATH = $(BUILD_ROOT)/_include
BUILD_DIR = $(BUILD_ROOT)/signal/ \
			$(BUILD_ROOT)/proc/   \
			$(BUILD_ROOT)/net/    \
			$(BUILD_ROOT)/misc/   \
			$(BUILD_ROOT)/logic/   \
			$(BUILD_ROOT)/app/ 
export DEBUG = true

common.mk文件

这段Makefile代码定义了一个更复杂的构建流程,包括条件编译、源文件和目标文件的管理、依赖生成以及清理规则。

.PHONY: all clean

.PHONY指令确保allclean这两个目标不会被解释器误认为是文件,而是当作伪目标来处理。

ifeq ($(DEBUG),true)
CC = g++ -std=c++11 -g
VERSION = debug
else
CC = g++ -std=c++11
VERSION = release
endif

根据DEBUG变量的值选择编译器和编译选项。如果是true,则使用-g选项生成调试信息。

SRCS = $(wildcard *.cxx)
OBJS = $(SRCS:.cxx=.o)
DEPS = $(SRCS:.cxx=.d)

使用wildcard函数动态获取当前目录下的所有.cxx文件,并分别生成对应的.o.d文件列表。
.d文件是依赖关系文件,修改项目后能决定哪些文件需要重新编译。

LINK_OBJ_DIR = $(BUILD_ROOT)/app/link_obj
DEP_DIR = $(BUILD_ROOT)/app/dep

对象文件和依赖文件的输出目录。

OBJS := $(addprefix $(LINK_OBJ_DIR)/,$(OBJS))
DEPS := $(addprefix $(DEP_DIR)/,$(DEPS))

.o.d文件的路径前缀修改为相应的输出目录。

$(shell mkdir -p $(LINK_OBJ_DIR))
$(shell mkdir -p $(DEP_DIR))

创建目录,确保输出目录存在。

all: $(DEPS) $(OBJS) $(BIN)

主要构建目标all依赖于所有.d文件、.o文件和最终的二进制文件$(BIN)

ifneq ("$(wildcard $(DEPS))","")
include $(DEPS)
endif

如果.d文件存在,则包含它们,以便Makefile能够识别由.d文件定义的依赖关系。

$(BIN): $(LINK_OBJ)
	...
	$(CC) -o $@ $^ -lpthread

构建最终的可执行文件$(BIN),它依赖于所有.o文件,并链接线程库pthread

$(LINK_OBJ_DIR)/%.o: %.cxx
	$(CC) -I$(INCLUDE_PATH) -o $@ -c $(filter %.cxx,$^)

规则用于编译单个.cxx源文件到.o文件,使用-I选项指定头文件路径。

$(DEP_DIR)/%.d: %.cxx
	echo -n $(LINK_OBJ_DIR)/ > $@
	$(CC) -I$(INCLUDE_PATH) -MM $^ >> $@

生成依赖文件.d,它包含了每个.o文件对于.cxx.h文件的依赖。-MM选项生成Makemake风格的依赖文件。

clean:
	rm -f $(BIN) $(OBJS) $(DEPS) *.gch

清理规则用于删除构建产生的所有文件,包括二进制文件、对象文件、依赖文件和GCC优化文件。

整个Makefile设计了一套完整的自动化构建流程,包括源文件的编译、依赖文件的生成、最终可执行文件的链接以及清理操作。这种结构有助于大型项目的管理和维护。

.PHONY: all clean
ifeq ($(DEBUG),true)

CC = g++ -std=c++11 -g 
VERSION = debug
else
CC = g++ -std=c++11
VERSION = release
endif

SRCS = $(wildcard *.cxx)
OBJS = $(SRCS:.cxx=.o)
DEPS = $(SRCS:.cxx=.d)
BIN := $(addprefix $(BUILD_ROOT)/,$(BIN))
LINK_OBJ_DIR = $(BUILD_ROOT)/app/link_obj
DEP_DIR = $(BUILD_ROOT)/app/dep

$(shell mkdir -p $(LINK_OBJ_DIR))
$(shell mkdir -p $(DEP_DIR))

OBJS := $(addprefix $(LINK_OBJ_DIR)/,$(OBJS))
DEPS := $(addprefix $(DEP_DIR)/,$(DEPS))

LINK_OBJ = $(wildcard $(LINK_OBJ_DIR)/*.o)
LINK_OBJ += $(OBJS)

all:$(DEPS) $(OBJS) $(BIN)

ifneq ("$(wildcard $(DEPS))","")  
include $(DEPS)  
endif

$(BIN):$(LINK_OBJ)
	@echo "------------------------build $(VERSION) mode--------------------------------!!!"
	$(CC) -o $@ $^ -lpthread


$(LINK_OBJ_DIR)/%.o:%.cxx
	$(CC) -I$(INCLUDE_PATH) -o $@ -c $(filter %.cxx,$^)

$(DEP_DIR)/%.d:%.cxx
	echo -n $(LINK_OBJ_DIR)/ > $@
	$(CC) -I$(INCLUDE_PATH) -MM $^ >> $@
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值