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
原创粉丝点击