在復雜的項目中,通常會將項目劃分為多個模塊或子項目,每個模塊都有自己的?Makefile
。上層?Makefile
?的作用是協調和控制這些下層?Makefile
?的構建過程。下面是幾種常見的示例,實現上層?Makefile
?對下層?Makefile
?的控制。
-
直接調用:通過?
$(MAKE)
?或?make
?命令直接調用下層?Makefile
。 -
傳遞變量:通過環境變量或命令行參數將變量傳遞給下層?
Makefile
。 -
遞歸構建:通過遞歸調用?
make
?命令構建所有模塊。 -
導入規則:通過?
include
?指令導入下層?Makefile
?的規則和變量。
目錄
一個實際例子
1.工程目錄結構
2.主目錄Makefile內容
3.Service目錄的Makefile
4.Client目錄的Makefile?
方法 1:直接調用下層?Makefile
示例項目結構
上層?Makefile?示例
下層?Makefile?示例(module1/Makefile)
使用說明
方法 2:傳遞變量給下層?Makefile
上層?Makefile?示例
下層?Makefile?示例(module1/Makefile)
使用說明
方法 3:使用遞歸構建
上層?Makefile?示例
下層?Makefile?示例(module1/Makefile)
使用說明
方法 4:使用?include?導入下層?Makefile
上層?Makefile?示例
下層?Makefile?示例(module1/Makefile)
使用說明
總結
一個實際例子
1.工程目錄結構
├── ChatRoom
│?? ├── Client
│?? │?? ├── Client.c
│?? │?? ├── Makefile
│?? │?? ├── Tcp_Sock.c
│?? │?? ├── Tcp_Sock.h
│?? │?? ├── main
│?? │?? └── obj
│?? └── Service
│?? ├── Makefile
│?? ├── Service.c
│?? ├── Tcp_Sock.c
│?? ├── Tcp_Sock.h
│?? ├── main
│?? └── obj
├── Makefile
2.主目錄Makefile內容
簡單版本:
SUBDIR1 = ChatRoom/Service
SUBDIR2 = ChatRoom/Client
SUBDIRS = $(SUBDIR1) $(SUBDIR2).PHONY: all clean $(SUBDIRS)all: $(SUBDIRS)$(SUBDIRS):$(MAKE) -C $@clean:for dir in $(SUBDIRS); \do \$(MAKE) -C $$dir clean; \done
# 定義模塊路徑
##################################
########用戶配置區#################
MODULE1 = ChatRoom/Client
MODULE2 = ChatRoom/ServiceMODULE1_TARGET = $(MODULE1)/main
MODULE2_TARGET = $(MODULE2)/mainMODULES = $(MODULE1) $(MODULE2)
MODULES_TARGET = $(MODULE1_TARGET) $(MODULE2_TARGET)
##################################
# 默認目標
all: $(MODULES_TARGET)# 構建模塊
$(MODULE1_TARGET): $(MODULE1)@echo "正在編譯模塊:$(MODULE1)"$(MAKE) -C $(MODULE1) all$(MODULE2_TARGET): $(MODULE2)@echo "正在編譯模塊:$(MODULE2)"$(MAKE) -C $(MODULE2) all# 清理所有模塊
clean:$(MAKE) -C $(MODULE1) clean$(MAKE) -C $(MODULE2) cleanrm -f $(MODULE1_TARGET) $(MODULE2_TARGET)# 幫助信息
help:@echo "可用命令:"@echo " make 編譯所有模塊"@echo " make clean 清理所有模塊"@echo " make help 查看幫助信息"
3.Service目錄的Makefile
CC = gcc
SCRC = $(wildcard *.c)
OBJS_DIR = ./obj
OBJ = $(SCRC:%.c=$(OBJS_DIR)/%.o)
CFLAGS = -Wall -O2
LDFLAGS = -lpthread
TARGET = main# 默認目標
all: $(TARGET)$(TARGET):$(OBJ)$(CC) $^ -o $@ $(LDFLAGS)
$(OBJS_DIR)/%o:%c@mkdir -p $(OBJS_DIR)$(CC) $< -o $@ $(CFLAGS) -c echo:@echo $(OBJ)clean:rm -rf ./obj.PHONY:clean
.PHONY:echo
4.Client目錄的Makefile?
CC = gcc
SCRC = $(wildcard *.c)
OBJS_DIR = ./obj
OBJ = $(SCRC:%.c=$(OBJS_DIR)/%.o)
CFLAGS = -Wall -O2
LDFLAGS = -lpthread
TARGET = main# 默認目標
all: $(TARGET)$(TARGET):$(OBJ)$(CC) $^ -o $@ $(LDFLAGS)
$(OBJS_DIR)/%o:%c@mkdir -p $(OBJS_DIR)$(CC) $< -o $@ $(CFLAGS) -c echo:@echo $(OBJ)clean:rm -rf ./obj.PHONY:clean
.PHONY:echo
方法 1:直接調用下層?Makefile
上層?Makefile
?可以通過?$(MAKE)
?或?make
?命令直接調用下層?Makefile
。這種方法簡單且靈活。
示例項目結構
project/
├── Makefile # 上層 Makefile
├── module1/
│ ├── Makefile # 下層 Makefile
│ └── *.c
├── module2/
│ ├── Makefile # 下層 Makefile
│ └── *.c
└── main.c
上層?Makefile
?示例
# 定義下層模塊的路徑
MODULE1 = module1
MODULE2 = module2# 定義所有模塊
MODULES = $(MODULE1) $(MODULE2)# 默認目標
all: $(MODULES)# 構建模塊
$(MODULES):$(MAKE) -C $@# 清理所有模塊
clean:$(MAKE) -C $(MODULE1) clean$(MAKE) -C $(MODULE2) cleanrm -f main# 幫助信息
help:@echo "可用命令:"@echo " make 編譯所有模塊"@echo " make clean 清理所有模塊"@echo " make help 查看幫助信息"
下層?Makefile
?示例(module1/Makefile
)
# 定義編譯器
CC = gcc# 定義目標文件
TARGET = module1.o# 定義源文件
SRC = module1.c# 編譯選項
CFLAGS = -g -Wall# 默認目標
all: $(TARGET)# 生成目標文件
$(TARGET):$(CC) $(CFLAGS) -c $(SRC) -o $(TARGET)# 清理
clean:rm -f $(TARGET)
使用說明
-
編譯所有模塊
????????????????上層?Makefile
?會依次調用?module1/Makefile
?和?module2/Makefile
?進行編譯。
make
-
清理所有模塊
make clean
上層?
Makefile
?會調用每個模塊的?clean
?目標,并清理上層生成的文件。 -
查看幫助
make help
方法 2:傳遞變量給下層?Makefile
上層?Makefile
?可以通過環境變量或命令行參數將變量傳遞給下層?Makefile
。
上層?Makefile
?示例
# 定義構建類型
BUILD_TYPE ?= Debug# 定義下層模塊的路徑
MODULE1 = module1
MODULE2 = module2# 定義所有模塊
MODULES = $(MODULE1) $(MODULE2)# 默認目標
all: $(MODULES)# 構建模塊
$(MODULES):$(MAKE) -C $@ BUILD_TYPE=$(BUILD_TYPE)# 清理所有模塊
clean:$(MAKE) -C $(MODULE1) clean$(MAKE) -C $(MODULE2) cleanrm -f main# 幫助信息
help:@echo "可用命令:"@echo " make 編譯所有模塊"@echo " make clean 清理所有模塊"@echo " make help 查看幫助信息"
下層?Makefile
?示例(module1/Makefile
)
# 定義編譯器
CC = gcc# 定義目標文件
TARGET = module1.o# 定義源文件
SRC = module1.c# 從環境變量中獲取構建類型
ifeq ($(BUILD_TYPE), Debug)CFLAGS = -g -Wall
elseCFLAGS = -O2
endif# 默認目標
all: $(TARGET)# 生成目標文件
$(TARGET):$(CC) $(CFLAGS) -c $(SRC) -o $(TARGET)# 清理
clean:rm -f $(TARGET)
使用說明
-
編譯所有模塊(Debug 模式)
make
-
編譯所有模塊(Release 模式)
make BUILD_TYPE=Release
-
清理所有模塊
make clean
方法 3:使用遞歸構建
上層?Makefile
?可以通過遞歸調用?make
?命令來構建所有下層模塊。
上層?Makefile
?示例
# 定義模塊路徑
MODULES = module1 module2# 默認目標
all: $(MODULES)# 構建模塊
$(MODULES):@echo "構建模塊: $@"$(MAKE) -C $@# 清理
clean:@echo "清理模塊..."$(MAKE) -C module1 clean$(MAKE) -C module2 cleanrm -f main# 幫助信息
help:@echo "可用命令:"@echo " make 編譯所有模塊"@echo " make clean 清理所有模塊"@echo " make help 查看幫助信息"
下層?Makefile
?示例(module1/Makefile
)
# 定義編譯器
CC = gcc# 定義目標文件
TARGET = module1.o# 定義源文件
SRC = module1.c# 編譯選項
CFLAGS = -g -Wall# 默認目標
all: $(TARGET)# 生成目標文件
$(TARGET):$(CC) $(CFLAGS) -c $(SRC) -o $(TARGET)# 清理
clean:rm -f $(TARGET)
使用說明
-
編譯所有模塊
make
-
清理所有模塊
make clean
方法 4:使用?include
?導入下層?Makefile
上層?Makefile
?可以通過?include
?指令導入下層?Makefile
?的規則和變量。
上層?Makefile
?示例
# 定義模塊路徑
MODULES = module1 module2# 導入下層 Makefile 的變量和規則
include $(MODULES:%=%.mk)# 默認目標
all: $(MODULES:%=build_%)# 構建模塊
build_%:$(MAKE) -C $* all# 清理
clean:$(MAKE) -C module1 clean$(MAKE) -C module2 cleanrm -f main# 幫助信息
help:@echo "可用命令:"@echo " make 編譯所有模塊"@echo " make clean 清理所有模塊"@echo " make help 查看幫助信息"
下層?Makefile
?示例(module1/Makefile
)
# 定義編譯器
CC = gcc# 定義目標文件
TARGET = module1.o# 定義源文件
SRC = module1.c# 編譯選項
CFLAGS = -g -Wall# 默認目標
all: $(TARGET)# 生成目標文件
$(TARGET):$(CC) $(CFLAGS) -c $(SRC) -o $(TARGET)# 清理
clean:rm -f $(TARGET)
使用說明
-
編譯所有模塊
make
-
清理所有模塊
make clean
總結
通過上述方法,上層?Makefile
?可以靈活地控制下層?Makefile
?的構建過程。以下是關鍵點的總結:
- 直接調用:通過?
$(MAKE)
?或?make
?命令直接調用下層?Makefile
。 - 傳遞變量:通過環境變量或命令行參數將變量傳遞給下層?
Makefile
。 - 遞歸構建:通過遞歸調用?
make
?命令構建所有模塊。 - 導入規則:通過?
include
?指令導入下層?Makefile
?的規則和變量。