Makefile简明模板和介绍
来源:互联网 发布:手机报纸排版软件 编辑:程序博客网 时间:2024/05/20 16:44
1:Makefile的作用
Makefile是UNIX下make工具的配置文件,其目的是实现项目的管理,主要包括编译、链接、打包、发布、清除等。Makefile中需要指定make的目标以及完成这些目标需要的规则和依赖关系。关于Makefile的更详细的介绍,可以参考http://blog.csdn.net/ruglcc/article/details/7814546 以及GNU Make 手册。
1.1 GNU make的工作方式
1. 读入所有的Makefile。
2. 读入被include的其它Makefile。
3. 初始化文件中的变量。
4. 推导隐晦规则,并分析所有规则。
5. 为所有的目标文件创建依赖关系链。
6. 执行生成命令。根据依赖关系,决定哪些目标要重新生成。
1.2 Makefile的书写规则
makefile中的规则描述如何生成特定的文件,即规则的目标。规则列出了目标的依赖文件,指定生成或更新目标的命令。规则的次序是不重要的,除非是确定缺省目标:缺省目标是第一个makefile中的第一个规则;
如果第一个规则有多个目标,第一个目标是缺省的。有两个例外:以’.’开头的目标不是缺省目标;模式规则对缺省目标没有影响。通常我们所写的地一个规则是编译整个或makefile中指定的所有程序。基本语法如下:
Targets : prerequisites ...
command
其中第一行指明目标及其依赖关系,第二行是生成这个目标需要执行的命令,必须用Tab开头。也可以书写成 Targets : prerequisites;command ;其可读性较差,一般不推荐。
规则中可以使用通配符,主要包括 '*' '?' '[...]' '~'.同UNIX shell用法。还可以使用Makefile内置函数,以及自动化变量等。
1.2.1 Makefile内置函数
$(subst <from>,<to>,<text> ) 把字串<text>中的<from>字符串替换成<to> $(patsubst <pattern>,<replacement>,<text> ) 查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换 $(strip <string> ) 去掉<string>字串中开头和结尾的空字符 $(findstring <find>,<in> ) 在字串<in>中查找<find>字串 $(filter <pattern...>,<text> ) 以<pattern>模式过滤<text>字符串中的单词,保留符合模式<pattern>的单词 $(filter-out <pattern...>,<text> ) 以<pattern>模式过滤<text>字符串中的单词,去除符合模式<pattern>的单词 $(sort <list> ) 给字符串<list>中的单词排序(升序) $(dir <names...> ) 从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./” $(notdir <names...> ) 从文件名序列<names>中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分 $(suffix <names...> ) 从文件名序列<names>中取出各个文件名的后缀 $(basename <names...> ) 从文件名序列<names>中取出各个文件名的前缀部分 $(addsuffix <suffix>,<names...> ) 把后缀<suffix>加到<names>中的每个单词后面 $(addprefix <prefix>,<names...> ) 把前缀<prefix>加到<names>中的每个单词后面 $(join <list1>,<list2> ) 把<list2>中的单词对应地加到<list1>的单词后面。如果<list1>的单词个数要比<list2>的多,那么,<list1>中的多出来的单词将保持原样。 如果<list2>的单词个数要比<list1>多,那么,<list2>多出来的单词将被复制到<list2>中 $(foreach <var>,<list>,<text> ) <span style="white-space:pre"> </span>把参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式 $(if <condition>,<then-part> ) 和 $(if <condition>,<then-part>,<else-part> ) $(call <expression>,<parm1>,<parm2>,<parm3>...) 用来创建新的参数化的函数
1.2.2 Makefile自动化变量
$@ 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。$% 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$< 依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$? 所有比目标新的依赖目标的集合。以空格分隔。
$^ 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+ 这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$* 这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir /a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,
但是,如果目标文件的后缀是 make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以,"$*"的值就是"foo"。
这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$*"就是空值。
2:Makefile模板分块介绍
假定一个C项目在主目录下有一个sakura的子目录,该项目需要编译成库并且接口API位于主目录的头文件中。完整Makefile见附件,下面分段介绍该Makefile的作用。2.1 常用变量定义
Makefile中可以定义自定义变量,并在之后引用这些变量的值。如下所示,MARCH是指机器位数,根据操作系统选择-m32 或者 -m64。strip
#1 Compiler, tools and options CC = gcc CXX = g++ MARCH = -m32 CFLAGS = $(MARCH) -pipe -Wall -W -fPIC CXXFLAGS = $(MARCH) -pipe -Wall -W -fPIC DEL_FILE = rm -f DEL_R = rm -rf MKDIR = mkdir -p DEL_DIR = rmdir MOVE = mv -f COPY = cp -f COPY_FILE = cp -f COPY_DIR = cp -f -R INSTALL_FILE = install -m 644 -p INSTALL_PROGRAM = install -m 755 -p INSTALL_DIR = cp -f -R SYMLINK = ln -f -s TAR = tar -cf COMPRESS = gzip -9f LINK = gcc AR = ar cqs SED = sed STRIP = strip
2.2 项目相关的选项
如下所示,主要是编译开关,额外的编译选项,链接选项,以及项目的依赖库。
#2 Program specifical options DEFINES = -DSAKURA CFLAGS += -std=gnu99 -Wno-pointer-sign -Wno-unused-variable -Wno-unused-parameter $(DEFINES) LFLAGS = $(MARCH) -shared -Wl,-soname,libsakura.so.1 //指定soname,方便so版本管理。如果编译可执行程序,-shared及-Wl可不需要。 LIBS = -L/usr/local/lib -Xlinker -rpath=/usr/local/lib -lpthread
2.3 编译目标
如下所示,如果编译可执行程序,TARGETA,TARGET0,TARGET1,TARGET2均可去掉。
#3 Target TARGET = libsakura.so.1.0.0 //动态链接库 TARGETA = libsakura.a //静态链接库 TARGET0 = libsakura.so TARGET1 = libsakura.so.1 TARGET2 = libsakura.so.1.0
2.4 工程的头文件路径
如下所示,包括本项目的头文件路径以及第三方SDK的头文件路径。
#4 Header file path INCDIR = . //当前项目目录 INCDIR += ./sakura //当前项目子目录,依项目而定 INCDIR += /usr/local/include/sakura INCPATH = $(addprefix -I, $(INCDIR)) //用-I连接路径2.5 源代码文件路径
此处需指定包含源代码全部目录,目录之间用空格分离。也可通过shell命令遍历源代码主目录获得,或者通过分级Makefile实现,有兴趣者可以自己实现。
#5 Source file path VPATH = . ./sakura //源代码目录及其子目录,用空格分离 SRC_PATH = $(foreach dir,$(VPATH),$(wildcard $(dir)/*.c)) //遍历源代码目录,获取其中的.c文件
2.6 中间文件及其目录
obj文件以及.d文件(存储obj目标的依赖关系)的生成目录
<pre name="code" class="html">#6 Output dir and filesOBJ_DIR = ./objsOBJS = $(addprefix $(OBJ_DIR)/,$(subst .c,.o, $(SRC_PATH)))//为每个源代码文件指定一个.o文件OBJ_PATH = $(addprefix $(OBJ_DIR)/,$(VPATH))MAKE_OBJECT_DIR := $(shell mkdir -p $(OBJ_DIR) $(OBJ_PATH))//创建./objs目录,并且和项目保持相同的目录结构</pre><pre></pre><br><span style="white-space:pre"></span>2.7 编译目标<br><span style="white-space:pre"></span>make的默认目标<br><pre name="code" class="html">#7 Default targetfirst: all</pre><br><span style="white-space:pre"></span>2.8<span style="white-space:pre"> </span>obj文件依赖关系的自动生成<br><span style="white-space:pre"></span>使用gcc -MM 自动推导依赖关系并输出到相应的.d文件。<br><pre name="code" class="html">#8 Obj dependenceDEPS = $(OBJS:.o=.d)include $(DEPS)$(OBJ_DIR)/%.d : %.c$(CC) -MM $(INCPATH) $< > $@//使用gcc -MM 自动推导依赖关系并输出到相应的.d文件</pre><br><span style="white-space:pre"></span>2.9 obj文件的编译规则<br><span style="white-space:pre"></span>由于2.8中生成的.d文件中有对应.o文件的依赖关系,因此此处无需指定依赖关系。<br><pre name="code" class="html">#9 Compile rules$(OBJ_DIR)/%.o :$(CC) -o $@ -c $< $(INCPATH) $(CFLAGS)</pre><span style="white-space:pre"> </span><br><span style="white-space:pre"></span>2.10 编译规则<br><span style="white-space:pre"></span>编译目标库并生成符号链接。<br><pre name="code" class="html">#10 Build rules$(TARGET): $(OBJS)-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)$(LINK) $(LFLAGS) -o $(TARGET) $(OBJS) $(LIBS)-ln -s $(TARGET) $(TARGET0)-ln -s $(TARGET) $(TARGET1)-ln -s $(TARGET) $(TARGET2)$(TARGETA): $(OBJS)-$(DEL_FILE) $(TARGETA)$(AR) $(TARGETA) $(OBJS)</pre><span style="white-space:pre"> </span><br><span style="white-space:pre"></span>2.11 常用目标<br><span style="white-space:pre"></span>顾名思义。<br><pre name="code" class="html">all: $(TARGET)static: $(TARGETA)clean:-$(DEL_R) $(OBJ_DIR)distclean:-$(DEL_R) $(OBJ_DIR)-$(DEL_FILE) $(TARGET)-$(DEL_FILE) $(TARGETA)-$(DEL_FILE) $(TARGET0)-$(DEL_FILE) $(TARGET1)-$(DEL_FILE) $(TARGET2)</pre><br><span style="white-space:pre"></span>2.12 安装和卸载<br><span style="white-space:pre"></span>此处变量一般可通过configure生成,不过自用的私有库,直接指定安装目录即可。<br><pre name="code" class="html"># Install header filesINSTALL_INC_FILE = $(wildcard *.h)INSTALL_INC_PATH = /usr/local/include/libsakurainstall_inc:@test -d $(INSTALL_INC_PATH) || mkdir -p $(INSTALL_INC_PATH)-$(INSTALL_FILE) $(INSTALL_INC_FILE) $(INSTALL_INC_PATH)uninstall_inc:-$(DEL_FILE) -r $(foreach file,$(INSTALL_INC_FILE),$(addprefix $(INSTALL_INC_PATH)/, $(file)))-$(DEL_DIR) $(INSTALL_INC_PATH)# Install libsINSTALL_LIB_PATH = /usr/local/lib/sakurainstall_lib: $(TARGET)@test -d $(INSTALL_LIB_PATH) || mkdir -p $(INSTALL_LIB_PATH)-$(INSTALL_PROGRAM) $(TARGET) $(INSTALL_LIB_PATH)/$(TARGET)-$(SYMLINK) $(INSTALL_LIB_PATH)/$(TARGET) $(INSTALL_LIB_PATH)/$(TARGET0)-$(SYMLINK) $(INSTALL_LIB_PATH)/$(TARGET) $(INSTALL_LIB_PATH)/$(TARGET1)-$(SYMLINK) $(INSTALL_LIB_PATH)/$(TARGET) $(INSTALL_LIB_PATH)/$(TARGET2)uninstall_lib:-$(DEL_FILE) $(INSTALL_LIB_PATH)/$(TARGET)-$(DEL_FILE) $(INSTALL_LIB_PATH)/$(TARGET0)-$(DEL_FILE) $(INSTALL_LIB_PATH)/$(TARGET1)-$(DEL_FILE) $(INSTALL_LIB_PATH)/$(TARGET2)install: install_inc install_libuninstall: uninstall_inc uninstall_lib</pre><br><br>
0 0
- Makefile简明模板和介绍
- Makefile简明模板和介绍
- make和makefile介绍
- MAKEFILE简明指南(一)
- MAKEFILE简明指南(二)
- makefile简明指南
- MAKEFILE简明指南(一)
- MAKEFILE简明指南(一)
- MAKEFILE简明指南(二)
- Makefile 简明手册 .
- MAKEFILE简明指南
- Makefile 简明手册
- Makefile 简明手册 .
- Makefile简明教程
- makefile模板
- makefile模板
- makefile模板
- makefile 模板
- kafka的Consumer均衡算法
- hadoop2.7.3 搭建QA
- E
- redis命令详解与使用场景举例——Set(集合)
- Mr.BG Hates Palindrome (SPOJ
- Makefile简明模板和介绍
- typeahead模糊搜索查询-结合bootstrap和jquery
- Android Studio Day02-2
- A Bug's Life(代权并查集(裸))
- mysql数据库知识点5
- eclipse字体、背景颜色设置
- Navicat日期时间格式
- 微信自媒体
- Codeforces 472D Design Tutorial: Inverse the Problem【MST+SPFA+思维】