为什么写这个呢,其实我有系统学过Makefile和CMake。但是因为用的不是很多或者说没有深入的使用场景,导致我不是很熟练,或者说没法优雅地使用。刚好最近对Linux的嵌入式编程比较感兴趣,借着demo来分析一下资深工程师写的Makefile,学习一下。由易到难吧,先来第一个,是一个GPIO的Makefile。
Makefile文件
BIN = test_gpio
CC = $(CROSS)gcc
CPP = $(CROSS)g++
LD = $(CROSS)ld
#
INCS =
LIBS =
SUBDIRS =
#
DEFINC = -I ./ \# LIBVAR =-shared -fPIE -L.
#
INCS += $(DEFINC)
LIBS +=$(LIBVAR)
#
CSRCS = $(wildcard *.c)
CPPSRCS = $(wildcard *.cpp)
#
COBJS := $(CSRCS:.c=.o)
CPPOBJS := $(CPPSRCS:.cpp=.o)
#
CFLAGS += $(INCS)
CFLAGS += -O2 -Wall -g -fPIE
CPPFLAGS += $(INCS)
CPPFLAGS += -O2 -Wall -g -fPIE
LDFLAGS += -lm -lrt -lstdc++ -ldlall:$(BIN)
$(COBJS) : %.o: %.c $(CC) $(CFLAGS) -c $< -o $@
$(CPPOBJS) : %.o: %.cpp $(CPP) $(CPPFLAGS) -c $< -o $@ $(BIN) : $(COBJS) $(CPPOBJS) $(CC) -o $(BIN) $(COBJS) $(CPPOBJS) $(LDFLAGS) $(LIBS) rm -rf $(COBJS) rm -rf $(CPPOBJS) .PHONY:clean cleanall clean: rm -rf $(BIN) $(COBJS) $(CPPOBJS)
#rm *.d
cleanall: rm $(BIN) $(COBJS) $(CPPOBJS)
拆解分析
BIN = gpio_red_blink
CC = $(CROSS)gcc
CPP = $(CROSS)g++
LD = $(CROSS)ld
- 定义了变量
BIN
,表示生成可执行文件名为gpio_red_blink
- 定义变量
CC
,表示使用的C编译器为$(CROSS)gcc
(其中$(CROSS)是一个可能存在的前缀 - 定义变量
CPP
,表示使用的C++编译器为$(CROSS)g++
- 定义变量
LD
,表示使用的链接器为$(CROSS)ld
INCS =
LIBS =
SUBDIRS =
- 定义空变量
INCE
,LIBS
,SUBDIRS
DEFINC = -I ./ \
- 定义变量
DEFINC
,指定编译过程中需要包含的头文件路径。这里设置为当前路径
INCS += $(DEFINC)
LIBS +=$(LIBVAR)
- 将
DEFINC
添加到INCS
中 - 将未定义变量
LIBVAR
添加到LIBS
中
CSRCS = $(wildcard *.c)
CPPSRCS = $(wildcard *.cpp)
- 使用通配符,将当前目录所有
.c
文件加入到CSRCS
变量中 - 使用通配符,将当前目录所有
.cpp
文件加入到CSRCS
变量中
COBJS := $(CSRCS:.c=.o)
CPPOBJS := $(CPPSRCS:.cpp=.o)
- 将
CSRCS
中所有.c
文件扩展名替换为.o
,并且赋值给COBJS
- 将
CPPSRCS
中所有,cpp
文件扩展名替换为.o
,并且赋值给CPPOBJS
CFLAGS += $(INCS)
CFLAGS += -O2 -Wall -g -fPIE
CPPFLAGS += $(INCS)
CPPFLAGS += -O2 -Wall -g -fPIE
LDFLAGS += -lm -lrt -lstdc++ -ldl -lpthread
- 将
INCS
分别添加到CFLAGS
和CPPFLAGS
,指定了编译包含头文件路径 - 将
-O2 -Wall -g -fPIE
添加到CFLAGS
和CPPFLAGS
,表示编译选项 - 将
-lm -lrt -lstdc++ -ldl -lpthread
,添加到LDFLAGS
中,表示链接选项
all:$(BIN)
- 定义了一个目标叫做
all
- 依赖于可执行文件
$(BIN)
$(COBJS) : %.o: %.c$(CC) $(CFLAGS) -c $< -o $@
- 定义了一个规则模式,将
.c
文件编译为.o
文件 %
表示通配符,任意字符$<
表示第一个依赖的文件,即.c
文件$@
表示目标文件,即.o
文件
$(CPPOBJS) : %.o: %.cpp$(CPP) $(CPPFLAGS) -c $< -o $@
- 定义了一个规则模式,将
.cpp
文件编译为.o
文件
$(BIN) : $(COBJS) $(CPPOBJS)$(CC) -o $(BIN) $(COBJS) $(CPPOBJS) $(LDFLAGS) $(LIBS)rm -rf $(COBJS)rm -rf $(CPPOBJS)
- 定义一个规则模式,用于链接目标文件生成可执行文件
$(BIN)
$(BIN)
依赖$(COBJS) $(CPPOBJS)
- 链接完成后删除中间文件
.PHONY:clean cleanall
clean:rm -rf $(BIN) $(COBJS) $(CPPOBJS)
cleanall:rm $(BIN) $(COBJS) $(CPPOBJS)
- 定义两个伪目标
(.PHONY)
,用于执行清理操作