博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
makefile learning
阅读量:6268 次
发布时间:2019-06-22

本文共 4624 字,大约阅读时间需要 15 分钟。

 

Copy:

本文给出万能Makefile的具体实现,以及对其中的关键点进行解析。所谓C++万能Makefile,即可编译链接所有的C++程序,而只需作很少的修改。

 

号称万能Makefile,一统江湖。我对原版的Makefile做了些修改。首先揭开它的庐山真面目:

 

##################################################### Generic makefile - 万能Makefile# for compiling and linking C++ projects on Linux # Author: George Foot  Modified:Jackie Lee####################################################### Customising## Adjust the following if necessary; EXECUTABLE is the target# executable's filename, and LIBS is a list of libraries to link in# (e.g. alleg, stdcx, iostr, etc). You can override these on make's# command line of course, if you prefer to do it that way.##EXECUTABLE := main    # 可执行文件名LIBDIR:=              # 静态库目录LIBS :=               # 静态库文件名INCLUDES:=.           # 头文件目录SRCDIR:=              # 除了当前目录外,其他的源代码文件目录## # Now alter any implicit rules' variables if you like, e.g.:CC:=g++CFLAGS := -g -Wall -O3CPPFLAGS := $(CFLAGS)CPPFLAGS += $(addprefix -I,$(INCLUDES))CPPFLAGS += -MMD## # The next bit checks to see whether rm is in your djgpp bin# # directory; if not it uses del instead, but this can cause (harmless)# # `File not found' error messages. If you are not using DOS at all,# # set the variable to something which will unquestioningly remove# # files.#RM-F := rm -f# # You shouldn't need to change anything below this point.#SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))OBJS := $(patsubst %.cpp,%.o,$(SRCS))DEPS := $(patsubst %.o,%.d,$(OBJS))MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS))).PHONY : all deps objs clean veryclean rebuild infoall: $(EXECUTABLE)deps : $(DEPS)objs : $(OBJS)clean :        @$(RM-F) *.o        @$(RM-F) *.dveryclean: clean        @$(RM-F) $(EXECUTABLE)rebuild: veryclean allifneq ($(MISSING_DEPS),)$(MISSING_DEPS) :        @$(RM-F) $(patsubst %.d,%.o,$@)endif-include $(DEPS)$(EXECUTABLE) : $(OBJS)        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))info:        @echo $(SRCS)        @echo $(OBJS)        @echo $(DEPS)        @echo $(MISSING_DEPS)        @echo $(MISSING_DEPS_SOURCES)

 

注:1)命令行前的空白符必须为一个制表符(Tab);如,@$(RM-F) *.o前不是空格,而是一个制表符;

 

内容解析

 

1.Makefile基本语法

 

target为要生成的目标文件;dependency为target的依赖文件;command为用于生成target的命令行;

 

:
...(tab)
(tab)
. . .

 

2.赋值符号 := 与 =

 

  :=与=的区别在于,符号:=表示立即展开变量值。例如:

 

A:=foo

 

B:=$(A)

 

A:=bar

 

这时,B的值仍为foo,因为它已被展开,不会再随A的值改变而改变。

 

3.符号#是Makefile的注释符号

 

4.wildcard函数

 

SRCS:=$(wildcard *.cpp) 表示列举当前目录中扩展名为.cpp的所有文件,然后赋值给变量SRCS。详细请google之。

 

5.patsubst函数

 

OBJS := $(patsubst %.cpp,%.o,$(SRCS))表示,将$(SRCS)中所有满足模式%.cpp的字符串替换为%.o。

 

6.filter-out函数

 

$(filter-out $(A),$(B))表示从B中过滤掉A中的内容,返回剩余内容;

 

7. “.PHONY”

 

用.PHONY修饰的target是“伪目标”,不需要生成真实的文件;make假定phony target是已经生成的,然后更新它后边的依赖文件和执行它下边的命令(command);

 

8.all deps objs clean veryclean rebuild info

 

这些都是“伪目标”。

 

all是第一个目标,所以输入make时它被默认执行;all生成或更新所有*.cpp文件对应的*.d文件和*.o文件,并链接所有*.o文件生成可执行文件$(EXECUTABLE)。

 

deps仅仅生成*.d文件;.d文件是什么文件?它包含了代码文件的依赖信息。

 

objs仅仅生成*.o文件;.o文件是C++代码编译后的中间结果文件,废话!

 

clean用于删除*.d文件和*.o文件。

 

veryclean删除*.d文件、*.o文件,还有名为$(EXECUTABLE)的可执行文件。

 

rebuild先调用veryclean清除结果文件,再调用all重新编译和链接。

 

info查看某些信息。

 

使用方法:

 

make deps即可执行deps;

 

9.ifneq...else...endif

 

条件语句,ifneq表示如果不想等,则...;

 

10.include <files>语句

 

include表示把<files>的内容包含进来;

 

$(DEPS)是包含依赖信息的文件,每个源文件对应一个.d文件;-include $(DEPS)表示把这些依赖信息包含进来;

 

11.链接*.o文件,生成可执行文件

 

主菜来了!

 

$(EXECUTABLE) : $(OBJS)        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS))

 

 

 

$(EXECUTABLE)为可执行文件名;$(OBJS)为所有.o文件名;$(CC)在这里是g++;$(addprefix -l,$(LIBS)添加引用库;

 

前面说好的*.d文件和*.o文件是怎么生成的呢?貌似没有命令指出要生成它们呀!请看隐含规则!

 

12. 隐含规则(Implicit rules)

 

$(EXECUTABLE)依赖于$(OBJS),但makefile中没有指明$(OBJS)依赖于谁,也没指明命令生成它们;

 

这时,make的隐含规则开始起作用;针对$(OBJS)中的每个目标,make自动调用:

 

$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ 

 

依次生成.o文件和.d文件;

 

$<表示依赖文件列表的第一个文件名;

 

$@表示目标文件名;

 

之所以会生成.d文件,是由于“-MMD”这一编译选项。为g++加上这一选项后,编译器会生成文件依赖信息,并存放至.d文件中。

 

每一个.cpp文件相应地生成一个.d文件和一个.o文件。

 

13.@符号

 

命令行前的@符号表示不回显命令行;

 

14.CFLAGS和CPPFLAGS

 

这两者包含编译选项,更详细内容请Google之。

 

-g 添加gdb调试信息;

 

-Wall 提示warning信息;

 

-O3 表示第3级优化;

 

 

makefile 里的函数跟它的变量很相似——使用的时候,你用一个 $ 符号跟开括号,函数名,空格后跟一列由逗号分隔的参数,最后用关括号结束。例如,在 GNU Make 里有一个叫 'wildcard' 的函 数,它有一个参数,功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。你可以像下面所示使用这个命令:

    
    SOURCES = $(wildcard *.c)
    
    这行会产生一个所有以 '.c' 结尾的文件的列表,然后存入变量 SOURCES 里。当然你不需要一定要把结果存入一个变量。
    另一个有用的函数是 patsubst ( patten substitude, 匹配替换的缩写)函数。它需要3个参数——第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的字列。例如,处理那个经过上面定义后的变量,
    
    OBJS = $(patsubst %.c,%.o,$(SOURCES))
    
    这行将处理所有在 SOURCES 字列中的字(一列文件名),如果它的 结尾是 '.c' ,就用 '.o' 把 '.c' 取代。注意这里的 % 符号将匹 配一个或多个字符,而它每次所匹配的字串叫做一个‘柄’(stem) 。 在第二个参数里, % 被解读成用第一参数所匹配的那个柄。

转载于:https://www.cnblogs.com/xiaotlili/p/3299157.html

你可能感兴趣的文章
rtf格式的一些说明,转载的
查看>>
REST Security with JWT using Java and Spring Security
查看>>
echarts学习总结(二):一个页面存在多个echarts图形,图形自适应窗口大小
查看>>
IIS7显示ASP的详细错误信息到浏览器
查看>>
使用fiddler对手机APP进行抓包
查看>>
exit和_exit的区别
查看>>
Javascript、Jquery获取浏览器和屏幕各种高度宽度(单位都为px)
查看>>
php不重新编译,安装未安装过的扩展,如curl扩展
查看>>
JavaScript编码encode和decode escape和unescape
查看>>
ppp点对点协议
查看>>
html5游戏开发-简单tiger机
查看>>
Codeforces 712C Memory and De-Evolution
查看>>
编写的windows程序,崩溃时产生crash dump文件的办法
查看>>
Ural2110 : Remove or Maximize
查看>>
Django REST framework 的TokenAuth认证及外键Serializer基本实现
查看>>
《ArcGIS Runtime SDK for Android开发笔记》——问题集:如何解决ArcGIS Runtime SDK for Android中文标注无法显示的问题(转载)...
查看>>
Spring Boot日志管理
查看>>
动态注册HttpModule管道,实现global.asax功能
查看>>
使用 ES2015 编写 Gulp 构建
查看>>
[转]Using NLog for ASP.NET Core to write custom information to the database
查看>>