【Linux开发】一个小规模工程的Makefile模板

本Makefile适用于小规模软件工程。修改SOURCE_PATH变量设置源码路径,修改BINARY_PATH变量设置输出文件的路径,OBJECT_PATH变量为中间.o文件的存放目录,INCLUDE_PATH变量为头文件包含路径,TARGET变量为输出文件名。Makefile会输出依赖关系文件“xxx.o.d”,以便根据依赖关系只进行必要的编译工作。

# GNU的make工作时的执行步骤如下:
# 1.读入所有的Makefile。
# 2.读入被include的其它Makefile。
# 3.初始化文件中的变量。
# 4.推导隐晦规则,并分析所有规则。
# 5.为所有的目标文件创建依赖关系链。
# 6.根据依赖关系,决定哪些目标要重新生成。
# 7.执行生成命令。
 
# Makefile最基础语法格式(依赖关系):
# targets : prerequisites
# <tab>commands
# 上面的示例中目标名为targets,其依赖于prerequisites表示的文件,
# 其可能是源码文件、头文件、库文件、其它依赖目标等,如果依赖文件中有
# 任何一个文件的更新时间新于targets表示的文件,那么依赖生效,则会
# 执行依赖下面的commands指令。
 
# Makefile中的变量其实相当于C语言里面的宏,会在使用变量的地方做替换
 
# Makefile通配符:* , ? 和 ~
# ~ 表示当前用户的HOME目录
# * 表示全能匹配
# ? 表示
 
# Makefile有三个非常有用的变量。分别是$@,$^,$<代表的意义分别是:
# $@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件。
 
 
CC := g++
LD := g++
 
# 这是编译阶段使用的参数选项,一般是一些选项设置和头文件路径
CFLAGS  += -std=c++11 
 
# 这是链接阶段使用的参数选项,一般是链接库和链接库路径
LDFLAGS += -L./lib \
			-lpthread \
			-ldl
 
SOURCE_PATH ?= src src/a src/b src/c
BINARY_PATH ?= 
OBJECT_PATH ?= objs
INCLUDE_PATH := -I./include $(foreach tmp,$(SOURCE_PATH),-I$(tmp))
TARGET ?= target
 
# wildcard 通配符,将所有的源文件的文件名都赋值给SOURCES变量
# SOURCES := $(wildcard *.c *.cpp src/*.cpp src/*/*.cpp src/*/*/*.cpp)
# SOURCES :=  
SOURCES := $(foreach tmp,$(SOURCE_PATH),$(wildcard $(tmp)/*.c $(tmp)/*.cpp))
 
# notdir 过滤掉所有文件的路径信息,例如src/main.c变为main.c
# basename 去除文件的文件类型后缀,例如main.c变为main
# addprefix 添加一个前缀,为objects文件的存放目录,例如main变为objs/main
# addsuffix 添加一个后缀,为存放的中间文件的文件名,例如objs/main变为objs/main.o
OBJECTS := $(addsuffix .o,$(addprefix $(OBJECT_PATH)/,$(basename $(notdir $(SOURCES)))))
# OBJECTS := main.o display.o gpio.o video.o spi.o
 
# addsuffix 添加一个后缀,为存放的依赖文件的文件名
DEPENDS := $(addsuffix .d,$(OBJECTS))
 
# 第一个依赖,也是默认依赖,Makefile会根据这个依赖关系展开所有依赖
# 如果依赖的内容是其它的依赖目标,就会依次展开所有依赖目标的依赖关系,
# 例如这里就会展开$(TARGET)、test1、test2这三个依赖目标的依赖关系。
all : $(TARGET) test1 test2
# all : test1 test2
 
$(TARGET) : $(OBJECTS)
	$(info LD $@)
	$(LD) -o $@ $(OBJECTS) $(LDFLAGS)
 
# 可以将依赖关系和执行的命令分开描述,例如下面的两个依赖关系中没有直接
# 说明test1和test2两个依赖的命令部分,而是在后面定义了命令部分。
test1:
test2:
 
test1:
	$(info SOURCES:$(SOURCES))
	$(info OBJECTS:$(OBJECTS))
	$(info DEPENDS:$(DEPENDS))
# $(foreach tmp,$(SOURCES),\
# 	$(info $(addprefix $(OBJECT_PATH)/,$(addsuffix .o,$(basename $(notdir $(tmp)))))))
test2:
	$(info $@)
 
# 包含所有源文件的依赖关系,举其中一个依赖文件为例:
# objs/audio_test.o: src/audio_test.cpp include/TCloudRealtimeASR.h \
#  include/TCloudRealtimeASRDefines.h include/TCloudRequestBuilder.h \
#  include/TCloudHTTPSender.h include/TSpeex.h include/speex/speex.h \
#  include/speex/speex_types.h include/speex/speex_config_types.h \
#  include/speex/speex_bits.h
# 这是一个典型的依赖关系,‘.o’文件作为一个目标,其依赖于后面的所有源码文件和头文件,
# 如果后面的任何源文件发生修改都会导致依赖关系生效。但是没有描述依赖关系的命令,
# 这和上面的 test 依赖结构是一样的,在后面定义了依赖关系的命令。
-include $(DEPENDS)
 
# # eval函数用于动态添加makefile脚本,类似js中的eval。
# $(foreach tmp,$(OBJECTS),\
# 	$(eval $(tmp):;${CC} ${CFLAGS} -MMD -MF $(tmp).d -c -o  $(tmp) $(addprefix $(SOURCE_PATH)/,$(addsuffix .cpp,$(basename $(notdir $(tmp)))))))
$(foreach tmp,$(SOURCES),\
	$(eval $(addprefix $(OBJECT_PATH)/,$(addsuffix .o,$(basename $(notdir $(tmp))))):; \
				${CC} ${CFLAGS} $(INCLUDE_PATH) \
				-MMD -MF $(OBJECT_PATH)/$(basename $(notdir $(tmp))).o.d \
				-c -o $(OBJECT_PATH)/$(basename $(notdir $(tmp))).o $(tmp)))
	
.PHONY : clean setenv
clean:
	rm objs/*.o objs/*.d ${TARGET}

测试用例:

猜你喜欢

转载自blog.csdn.net/tq384998430/article/details/100087283
今日推荐