为什么写这个呢,其实我有系统学过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++ -ldl all:$(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),用于执行清理操作