Makefile简明模板和介绍
来源:互联网 发布:linux vi如何添加 编辑:程序博客网 时间:2024/05/20 17:28
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> )把参数<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。
#1 Compiler, tools and optionsCC = gccCXX = g++MARCH = -m32CFLAGS = $(MARCH) -pipe -Wall -W -fPICCXXFLAGS = $(MARCH) -pipe -Wall -W -fPICDEL_FILE = rm -fDEL_R = rm -rfMKDIR = mkdir -pDEL_DIR = rmdirMOVE = mv -fCOPY = cp -fCOPY_FILE = cp -fCOPY_DIR = cp -f -RINSTALL_FILE = install -m 644 -pINSTALL_PROGRAM = install -m 755 -pINSTALL_DIR = cp -f -RSYMLINK = ln -f -sTAR = tar -cfCOMPRESS = gzip -9fLINK = gccAR = ar cqsSED = sedSTRIP = strip
2.2 项目相关的选项
如下所示,主要是编译开关,额外的编译选项,链接选项,以及项目的依赖库。
#2 Program specifical optionsDEFINES = -DSAKURACFLAGS += -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 TargetTARGET = libsakura.so.1.0.0//动态链接库TARGETA = libsakura.a//静态链接库TARGET0 = libsakura.soTARGET1 = libsakura.so.1TARGET2 = libsakura.so.1.0
2.4 工程的头文件路径
如下所示,包括本项目的头文件路径以及第三方SDK的头文件路径。
#4 Header file pathINCDIR = .//当前项目目录INCDIR += ./sakura//当前项目子目录,依项目而定INCDIR += /usr/local/include/sakuraINCPATH = $(addprefix -I, $(INCDIR))//用-I连接路径
2.5 源代码文件路径
此处需指定包含源代码全部目录,目录之间用空格分离。也可通过shell命令遍历源代码主目录获得,或者通过分级Makefile实现,有兴趣者可以自己实现。
#5 Source file pathVPATH = . ./sakura//源代码目录及其子目录,用空格分离SRC_PATH = $(foreach dir,$(VPATH),$(wildcard $(dir)/*.c))//遍历源代码目录,获取其中的.c文件
2.6 中间文件及其目录
obj文件以及.d文件(存储obj目标的依赖关系)的生成目录
#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目录,并且和项目保持相同的目录结构
2.7 编译目标
make的默认目标#7 Default targetfirst: all
2.8 obj文件依赖关系的自动生成
使用gcc -MM 自动推导依赖关系并输出到相应的.d文件。#8 Obj dependenceDEPS = $(OBJS:.o=.d)include $(DEPS)$(OBJ_DIR)/%.d : %.c$(CC) -MM $(INCPATH) $< > $@//使用gcc -MM 自动推导依赖关系并输出到相应的.d文件
2.9 obj文件的编译规则
由于2.8中生成的.d文件中有对应.o文件的依赖关系,因此此处无需指定依赖关系。#9 Compile rules$(OBJ_DIR)/%.o :$(CC) -o $@ -c $< $(INCPATH) $(CFLAGS)
2.10 编译规则
编译目标库并生成符号链接。#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)
2.11 常用目标
顾名思义。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)
2.12 安装和卸载
此处变量一般可通过configure生成,不过自用的私有库,直接指定安装目录即可。# 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
0 0
- Makefile简明模板和介绍
- Makefile简明模板和介绍
- make和makefile介绍
- MAKEFILE简明指南(一)
- MAKEFILE简明指南(二)
- makefile简明指南
- MAKEFILE简明指南(一)
- MAKEFILE简明指南(一)
- MAKEFILE简明指南(二)
- Makefile 简明手册 .
- MAKEFILE简明指南
- Makefile 简明手册
- Makefile 简明手册 .
- Makefile简明教程
- makefile模板
- makefile模板
- makefile模板
- makefile 模板
- ir红外遥控
- MDNet(multi domain CNN用于视觉跟踪)--源代码详解--mdnet_features_fcX.m
- C#邮件发送
- 使用apache-jmeter工具发起大量并发请求测试服务器性能
- 设计模式之责任链模式
- Makefile简明模板和介绍
- 【转】从零开始React服务器渲染
- 如何对网站的文件和资源进行优化
- js变量声明
- 利用SCP传输文件
- 前端工程的三大阶段
- 红外遥控led灯及LCD屏幕
- log4net使用详解
- 使用wagtail搭建cms的安装流程