万能makefile的剖析与示例第一弹

来源:互联网 发布:如何做淘宝联盟 编辑:程序博客网 时间:2024/06/01 07:22

1. 本示例演示的是最简单的,即只需编译源文件,不需链接库的makefile的编写方式

2. 目的是帮助那些新接触makefile的新手如何快速写出可用的makefile,下载本例后完全可以稍作修改就可以满足自己的需要

3. 本篇博客逐条语句分析了万能makefile的实现,尽可能多的添加了注释,也在一些地方进行了修改,以用于不同情况下makefile的编写

4. 所有示例都在centos上亲测编译,运行通过的,附上完整示例下载链接:http://download.csdn.net/download/yzf279533105/9744371,下载解压后,根目录中有介绍文档,请按照里面的步骤操作,保证可以运行成功

5. 如有任何疑问,可联系本人QQ:279533105

以下是makefile的内容,如发现错误,欢迎拍砖

# 工程根目录," PROJECT_ROOT = ./ "表当前目录PROJECT_ROOT = ./# 最终生成的目标文件(可执行程序)的名字EXECUTABLE := hello_exe# 库文件所在的目录,没有的话不写内容即可LIBDIR:= # 库文件所在目录的扩展,不需扩展时不写内容即可LIBDIR+= # 所需库文件的名字(包括静态库和动态库),没有的话不写内容即可# 注意名字:比如需要链接 libmysql.a 时只需写 mysql 即可LIBS := # 本工程所有的头文件所在的目录,没有的话不写内容即可INCLUDES:= # 所有的头文件所在目录的扩展,不需扩展时不写内容即可INCLUDES += # 本工程所有源文件所在的目录,没有的话不写内容即可,现在所有的源文件都在当前目录下,# 下面的语句 " SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR))) "的前面部分指的就是当前目录中所有的.cpp文件,所以在此处不可重复包含SRCDIR:=# 所有的源文件所在目录的扩展,不需扩展时不写内容即可SRCDIR +=# 生成的最终目标文件所在的目录,会作为伪目标,如果该路径不存在,则新建该目录EXECUTEDIR := $(PROJECT_ROOT)# 生成的最终目标文件的全名(带全路径的)EXECUTABLE := $(EXECUTEDIR)/$(EXECUTABLE)# 指定编译器,编译c++时,必须使用 g++CC:=g++# 编译参数,-g 表带上调试信息,这样可以调试程序  -Wall 表输出警告信息  -O1表示优化级别为1级CFLAGS := -g -Wall -O1CPPFLAGS := $(CFLAGS)# 在所有的头文件目录前面加上 -I ,这是make包含头文件目录的语法要求CPPFLAGS += $(addprefix -I,$(INCLUDES))# 可以自动推导生成源文件对头文件的依赖关系CPPFLAGS += -MMD# 删除操作RM-F := rm -f# 函数介绍# 函数 wildcard :扩展通配符,比如下面的*符号在变量和函数中会失效,有了 wildcard 时,通配符就不会失效,比如可以使用 $(wildcard *.c) 来获取当前目录下的所有的.c文件名字列表# 函数 addsuffix:加后缀函数,示例:$(addsuffix .c,foo bar)返回值是“foo.c bar.c”# 函数 addprefix:加前缀函数,示例:$(addprefix lib, mysql.a ACE.so)返回值是 "libmysql.a libACE.so"# 函数 patsubst 模式字符串替换函数,$(patsubst %.c,%.o,x.c.c bar.c) 把字符串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”# 函数 filter-out:反过滤函数,即过滤掉模式符合的文件后剩下的文件名字,示例 objects=main1.o foo.o main2.o bar.o #                :mains=main1.o main2.o #                :则$(filter-out $(mains),$(objects)) 返回值是“foo.o bar.o”# 以下内容不需修改SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))      # 表当前目录的所有.cpp文件名字列表和SRCDIR所有目录下的所有.cpp文件名字列表,即本工程的所有.cpp文件OBJS := $(patsubst %.cpp,%.o,$(SRCS))                                     # 表上面所有.cpp编译产生的.o文件DEPS := $(patsubst %.o,%.d,$(OBJS))                                       # 表上面所有.cpp编译产生的中间文件.d文件MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))                 # 不清楚,打印结果是所有的.d文件MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS))) # 不清楚,打印结果是所有的.cpp文件# 所有的伪目标.PHONY : all deps objs clean veryclean rebuild info# 最终的要生成的目标文件all: $(EXECUTABLE)# 生成所有的.d中间文件deps : $(DEPS)# 生成所有的.o中间文件# 注意:所有的.o文件并没有指明依赖于谁,也没有指明哪条命令生成它们# 这里是make的隐含规则,对于每个.o文件,make会自动调用: $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@,来生成.o文件# 之所以生成.d文件,是因为$(CPPFLAGS)含有-MMD,编译器会自动推导依赖信息,放在.d文件中# 一个.cpp文件一定会生成一个.d文件和.o文件objs : $(OBJS)# 一般清空操作,删除所有的.o 和 .d文件clean :        @$(RM-F) $(OBJS)        @$(RM-F) $(DEPS)# 彻底清空操作,注意其依赖于伪目标 clean,所以必定会先执行clean操作,再执行下面的命令(删除最终的目标文件)veryclean: clean        @$(RM-F) $(EXECUTABLE)# 重新生成,其依赖于伪目标veryclean 和 all ,即先执行veryclean操作,再执行all操作rebuild: veryclean all# 若MISSING_DEPS为空,则产生一个伪目标,删除所有的.o文件ifneq ($(MISSING_DEPS),)$(MISSING_DEPS) :        @$(RM-F) $(patsubst %.d,%.o,$@)endif# 将DEPS中的文件包含进来,"-"表示忽略文件不存在的错误-include $(DEPS)# 打印出所有的源文件,.o文件,.d文件,info:        @echo $(SRCS)        @echo $(OBJS)        @echo $(DEPS)        @echo $(MISSING_DEPS)        @echo $(MISSING_DEPS_SOURCES)# 下面是必定要执行的目标,依赖于所有的.o文件和伪目标EXECUTEDIR(生成存放最终目标的目录)# 下面操作表示把所有的.o文件链接成可执行文件,-L指定链接库的路径,-l指定链接库的名字$(EXECUTABLE) : $(OBJS) $(EXECUTEDIR)        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))# 伪目标,用于生成存放最终目标的文件目录,-p 参数用于允许一次性创建多层次的目录$(EXECUTEDIR) :        mkdir -p $(EXECUTEDIR)
0 0
原创粉丝点击