Makefile 学习笔记
2018-01-23 16:31
197 查看
1、linux执行一个文件:./加上执行文件名
以上原因在于若直接执行文件下下的文件,系统会默认到PATH下寻找执行代码,即对于系统来说可执行文件都默认在PATH中寻找。因此用./相对地址来指示执行地址。或者在PATH中添加./路径
2、gcc编译器(GUNCompiler Collection)
1>gcc编译步骤包含4步:(针对a.c举例)
预处理器(cpp):对源程序进行预处理得到.i文件,gcc执行选项-E
gcc -E a.c -o a.i
编译器(ccl):进行编译得到汇编程序.s文件,gcc执行选项-S
gcc -S a.i -o a.s 或 gcc -S a.c -o a.s
汇编器(as):生成可重定位目标程序.o文件,gcc执行选项-c
gcc -c a.s -o a.o 或 gcc -c a.c -o a.o
链接器(ld):生成可执行目标程序.out文件,gcc默认执行生成.out文件(.ou是t系统可以直接执行的二进制文件)
gcc a.o -o a.out 或 gcc a.c -o a.out
#-o选项后面接生成的文件名,不加则会自动命名
#其中后缀名在linux中只是标识作用,即使不带,如a.out写成a则会生成没有后缀的文件a,a也能执行。
#编译多个文件方式为: gcc a.c b.c ... -o a.out
#或者生成.o文件后再链接 gcc -c a.c -o a.o ... gcc a.o b.o ... -o a.out
2>加上单独的-Wall选项,会在编译有问题的地方发出警告
3>库文件编译方式
库文件实际上是一些.o文件的打包,具体分为:
静态库(.a文件):程序在编译时直接将库和程序编译链接成一个可执行二进制代码,
相当于每一个程序都包含了一份静态库,因此相对更占用磁盘和内存。
生成方式:ar rcs liba.a a.o 需要通过a.a才能生成a.o
使用方式:gcc b.c liba.a -o b.out
或gcc b.c -o b.out-L. -la #-L选项为添加库的搜索地址,-L.表示当前文件夹
#-la为对-liba的引用(相当于l替换lib)
动态库/共享库(.so或.sa文件):程序直接编译成可执行代码,并在运行代码时才进行动态库
的链接,将库从硬盘加载到内存,因此相对减少了占用内存的体积
生成方式:gcc –shared -fPIC a.o –o a.so
使用方式:gcc b.c -o b.out -L. -la #与静态库一致,但是系统会优先使用动态库
#库文件一般存放地址:/usr/lib /usr/local/lib
3、Makefile
makefile基本规则:
1>makefile的包括五个部分
显示规则:需要显式的给出一个规则的目标、依赖、命令等
隐含规则:指根据目标文件名自动产生目标的依赖文件并使用隐含的命令来执行重建
变量定义:使用变量来代替重复使用的字符串
指示符:包含include、define..endef、ifeq..endif等
注释:用#来进行注释。同时若结尾出现\则下一行也为注释。注释建议为单独行
2>makefile文件的命名
若没有指定make执行的makefile文件,make会自动在执行目录下依次寻找“GNUmakefile”、“makefile”、“Makefile”这几个文件名想要执行特定的makefile文件,可以使用make -f filename来执行
3>include指示符
1.用于包含其他的makefile文件。用途主要在于可以将多个makefile文件需要共同使用的变量定义、模式规则、自动依赖关系等
存放在一个makefile文件中,以便别的makefile文件调用。
2.make会在遇到include时转而执行其包含的makefile文件,直到执行完了再返回原makefile文件
3.MAKEFILES环境变量中包含其他的makefile文件,make指令会在执行makefile文件时将这些文件包含进来,
相当于每一个make指令都会include这写文件,因此不建议这么做。
4.MAKEFILE_LIST环境会包含所有被执行的makefile文件列表,可以通过这个变量查看哪些makefile被执行。
5.重载另外一个makefile
问题在于include另外一个makefile会导致规则冲突,但又需要使用另外一个makefile中定义的一部分变量或者规则时。
4>条件判断指示符
1.判断a与b是否相等ifeq和ifneq。如下相等则执行命令行1,否则执行2
ifeq (a,b) 或ifeq "a" "b" 或 ifeq 'a''b'都可以
命令行1
else
命令行2
endif
2.判断变量是否存在ifdef和ifndef
ifdef var #此处不是$(var)
3.if else endif等为make的语法,前面不能有tab
4.ifeq后接判断式时,中间有一个空格!
5>makefile的重建
makefile也可以被规则建立,makefile可由RCS或SCCS文件生成,若makefile中有对makefile的重建规则,会先按规则重建在执行新的makefile
6>make的执行过程
第一步:读取所有的makefile文件(包含include、MAKEFILES、make指定的文件),内建所有变量和规则
第二步:根据依赖关系,巨鼎哪些目标需要更新,然后对目标进行重建。
规则与目标:
1>规则的语法
TARGETS:PREREQUISITES
COMMAND
或者
TARGETS : PREREQUISITES ; COMMAND #这个command前面没有tab没有问题,但是下面的command必须要tab开头
COMMAND
TARGETS:目标 PREREQUISITES:依赖 COMMAND:命令
一个规则可以多目标,多依赖,也可以无依赖,无命令,但是不能无目标。
2>规则的执行条件为:
目标文件不存在则执行命令
目标文件存在且修改时间比任何一个依赖更旧则执行命令
3>两种类型依赖
定义方式:TARGETS : NORMAL-PREREQUISITES |ORDER-ONLY-PREREQUISITES
包含常规依赖和order-only依赖
区别在与order-only依赖不会因为更新而导致目标被重建,只会在常规依赖更新或者目标不存在时参与重建。
4>终极目标
终极目标为最终要形成的文件,make在执行时若未指定终极目标时,会自动寻找终极目标,默认是makefile中的第一个规则,
但是会忽略以.开头(如伪目标规则)和模式规则的目标(包含%的目标)来寻找。
5>文件搜寻
主要用于make对目标或者依赖的文件的搜索,若不指定则只在当前目录中搜寻
1.环境变量VPATH
通过向VPATH中添加搜索路径,用:隔开,make会自动到这些文件夹下面搜索目标文件。
2.vpath pattern dir
可用于在特定文件夹下搜索特定类型的文件。
在目录dir中搜索符合模式pattern的文件,patten一般使用%进行字符匹配。
6>伪目标
伪目标通
4000
过特殊目标.PHONY来设置,如.PHONY:clean,clean即为伪目标
伪目标的特点是该目标的规则在执行时不需要创建该目标对应的文件,这样有利于只是将该目标作为一个执行其规则下命令的手段,
如clean是用来删除多余文件的伪目标,通过make clean即可执行其规则中的命令。
伪目标也可以放在最前面当做默认终极目标,有利于一次重建多个目标(如想一次建立三个目标时.PHONY:all all:a.o b.o c.o)
7>强制目标
当一个目标没有依赖和命令时,该目标会被看做最新,然后可以用作别的规则的依赖来强制执行规则。
定义方式: FORCE:
8>多规则目标
1.当一个目标出现在多个规则中时,会将所有该目标对应规则中的依赖合并一起,再对该目标进行重建。
若每一个规则对应不同的重建命令,则会执行最后一个规则的命令。
2.::来划分目标和依赖可以实现实现多规则目标只通过时间更新依赖对应的规则进行重建。
3.建议尽量使用单目标多依赖形式,尽量少出现多规则目标。
9>静态模式规则
targets: target-pattern: prereq-patterns
commands
target-pattern 目标模式 prereq-patterns 依赖模式
模式通过模式字符%来设置,可以更好的处理多目标的规则
例:a.o b.o:%.o:%.c
$(CC) -c $(CFLAGS) $< -o $@
10>隐含规则
隐含规则主要是利用make对规则进行推导来补全命令。
命令:
make会在找到规则后,会将所有以tab键开头的行交由shell处理。
这代表了命令必须tab开头,而makefile自己的语法不能tab开头。
1>make会在执行makefile文件里的命令时,将命令打印出来。在命令前添加@可以不让其显示。
若使用 make -n/--just-print则是只打印命令但是不执行
若使用 make -s/--silent 则是执行命令但不打印命令
2>执行命令时,只有通过";"将多个命令分隔并写在同一行上,才相当于执行连续的shell命令。
原因是直接的多行命令执行时,相当于是对每一个命令启动一个子shell进程来执行,因此相互没有联系。
3>make会在执行每一条命令时检查返回码,若执行错误则停止make的执行。
可以通过在命令前添加"-"来忽略命令的出错,-可以用在命令上也可以用在include这样的指示符上。
也可以通过make -i/--ignore-errors来忽略所有的错误继续执行
还可以将目标文件作为特殊目标".IGNORE"的依赖,使得该目标文件下的命令执行时会忽略错误
还可以通过make -k/--keep-going来跳过当前依赖中的错误,继续执行别的依赖关系里面的命令,直至完全不能执行
4>可以将目标文件作为特殊目标.PRECIOUS的依赖,使得该目标文件在make中断时,不会将重建的部分文件删除。(一般不建议使用)
5>make的递归执行
6>定义命令包
实质是通过变量定义的方式定义多行命令。
命令包是将需要使用的重复性的多条命令通过define来包装成一个整体
具体定义方式为 define var(变量名)
命令(通过$^、$@等来使用依赖中的目标文件如.o和前置文件如.c)
endef
使用方式:a.o:a.c
$(var) #注意一定要加上tab键
7>空命令行
定义方式: 目标文件:;
主要用于防止隐藏规则对目标文件的重建动作,即该目标文件希望不要被重建时使用
如%.o:%.c会在需要生成.o目标时寻找到该规则,该规则通过隐含规则执行gcc命令将.c文件转换为.o文件。
变量:
1>变量的定义与赋值(以var举例)
1.递归展开式变量(在使用时展开值中的变量和函数)
定义方式:
var=变量内容
或者:
define var
变量内容(可以是多行,同时多行命令是使用一个shell进程来执行,所以不需要使用;进行分割)
endef
这种定义方式的变量在使用时是字符串的直接替换,即类似宏定义
优点为由于其定义的内容相当于字符串,因此可以引用当前还未定义的变量(使用时才展开,因此定义时内容相当于只是字符串)
缺点在于,由于可以引用当前未定义变量,当嵌套定义时,如a=b b=a,会导致在$a使用变量时陷入无限递归。
同理在变量中定义的是函数内容时,由于每次使用变量时才会执行内容,因此导致函数被执行多次,降低效率
赋值方式还有条件赋值符(?=),如a?=...,表示若a未定义,则对a进行赋值。a相当于递归展开式变量。
变量在赋值时,若长度过长,可以使用\来进行换行
2.直接展开式变量(在定义时展开值中的变量和函数)
定义方式:var:=...
这种定义方式在变量定义的时候就完成对变量内容中对其他变量或函数的执行或者展开
这种方式的变量在使用时也是文本内容的替换。同时定义时后面若有空格也会被记录进变量内容中
(注释不会被记录,但最好别在变量定义后面添加注释,因为会导致空格)
2>变量的引用
1.引用方式有两种:$(var)或${var}(对于单字符变量和自动化变量如$@,可以不需要外面的括号)
2.变量的引用为字文本内容的严格替换,类似于c语言中的宏定义
3.在规则下的命令行中,由于存在对shell变量($var或${var}方式)和makefile变量两种的引用,注意区分开不同的变量
4.变量可以进行嵌套引用(在一个变量中引用其他的变量或者函数),但嵌套引用时,会在展开嵌套的变量之前检查函数,若展开的变量
展开后是函数,将不会被识别。
5.若引用一个未定义的变量,则得到的值为空。
3>追加变量值(+=)
1.若变量没有定义过,则使用+=时相当于使用=进行递归展开式变量定义赋值
2.使用方式如a+=b,表示在a的内容中添加“ b”,前面有个空格作为划分。
3.若追加变量a时,若a是递归展开式变量,则不会进行对a的展开。
若a是直接展开式变量,则会对嵌套引用进行展开
4>override指示符
make指令可以在执行时定义变量(如 make var=...),该变量会覆盖makefile中已经存在的变量,在变量前添加override可以防止这种覆盖
可用于给make指令增加固定选项参数(在makefile文件里通过+=添加命令选项,同时make指令也将选项传入变量,得到最终的选项值)
5>特殊变量
1.隐含变量
隐含变量为预定义变量,允许对其修改(可通过直接修改,命令行修改,环境变量设置等方式都可以)
隐含变量多用于隐含规则中,如$(CC) -c $(CFLAGS) $(CPPFLAGS)这个隐含规则中有3个隐含变量
常见隐含变量有:
代表命令的隐含变量:
AR:用于创建静态库.a文件
AS:用于创建汇编.s文件
CC:相当于c编译器,linux是gcc
CXX:相当于cpp编译器,默认g++
CPP:c语言预处理器,默认$(CC)-E
PC:pascal编译器,默认pc
RM:相当于rm -f指令
等等
代表参数的隐含变量:
ARFLAGS:AR命令行参数,默认rv
ASFLAGS:AS命令行参数
CFLAGS:CC命令行参数
CXXFLAGS:CXX命令行参数
CPPFLAGS:CPP命令行参数
等等
2.自动化变量
自动化变量主要运用于模式规则中,模式规则中没有具体的目标或者依赖名,因此需要使用自动化变量来代指目标和依赖
自动化变量有:
$@:代表规则中的目标名
$<:代表规则中的第一个依赖名
$%:只用于当目标为一个静态库文件时,其代表静态库文件的第一个成员名
$*:代表规则中通配符%所代表的内容。若规则中没有通配符%,则代表可识别后缀前面的内容,如a.o:a.c中,$*代表a
#以下三个代表列表
$?:代表规则中所有比目标文件时间戳更新的依赖的文件名列表。若目标是静态库,则为其所有成员的列表
$^:代表规则中所有的依赖组成的文件名列表。若目标是静态库,则为其所有成员的列表
$+:功能类似$^,但它会将重复的文件名也列出来
自动化变量可以通过在后面添加D(dir)和F(file)符号来取其中的路径或者文件部分
例:$(@D)取目标名中的路径部分但不包括最后一个/,即/bin/a.c取/bin
$(@F)取目标名中的文件名部分,即/bin/a.c取a.c
3.系统环境变量和make环境变量
两种环境变量对于makefile都是可见的,makefile的环境变量只在一次执行过程中有效。
环境变量和make定义的变量可以传递给子进程(普通变量需要export才行),因此环境变量不能随意修改。
常见makefile环境变量有:MAKEFILESMAKEFILE_LIST VPATH SHELL等
4.变量.VARIABLES
变量存放引用点之前所有定义的变量,包含普通变量,内嵌变量等等
6>目标指定变量
使用方式:例以a为目标 a:var=...
var的作用范围为所有以a为目标的规则范围中。
7>模式指定变量
使用方式:例以%.o为模式%.o:var=...
var的作用范围为所有以.o结尾的目标的规则范围中。
内嵌函数:
1>调用方式
方式与变量类似(函数func参数a b c为例)
$(func a,b,c) 或者${func a,b,c}
#空格或者,作为参数想传入时只能间接通过变量传入
#
2>文本处理函数
1.$(subst FROM,TO,STR) #替换字符
返回将字符串STR中的FROM字符串替换为TO字符串的字符串,不会修改str本身
2.$(patsubst PATTERN,REPLACEMENT,STR) #模式替换字符
将字符串STR中匹配模式PATTERN的字符串替换为模式REPLACEMENT中对应的字符串,
模式可以通过“%字符串”或者“字符串”来设置,若有%(如%.o),表示匹配以.o结尾的字符串即可,
若只是字符串(如字符串“a bc”),则匹配a、b、c这几个字符。
模式匹配时,以空格为间隔进行匹配
例 $(patsubst %.o,%.c,str)
对变量进行替换时还有一种简化的替换方式,如将var中.o字符串变成.c字符串:$(var:.o=.c)等价于$(patsubst %.o,%.c,$(var))
3.$(strip STR) #去掉首尾空白字符
返回去掉STR中的首尾空白符的字符串,包含空格和tab等
4.$(findstring FIND,STR) #查找子字符串
在STR中查找FIND字符串,若找到则返回FIND字符串,否则返回空字符串
5.$(filter PATTERN,STR) #过滤不符合模式的字符串
将STR中不符合符合模式PATTERN的字符串过滤掉,返回过滤后的字符串
例 $(filter %.c %.o,a.c a.o b.cb.h) 返回a.c a.ob.c,过滤掉b.h
6.$(filter-out PATTERN,STR) #过滤符合模式的字符串
同理,与filter功能正相反。
7.$(sort STR) #对字符串进行排序
对字符串STR中的单词以首字母进行排序,并删去重复单词
8.$(word N,STR) #取字符串中的单词
取字符串STR中第N个单词,若超出索引(大于总数)返回空字符,若为0则报错
9.$(wordlist N,M,STR) #取字符串
取字符串STR中从N到M的单词组成的字符串
10.$(words STR) #计算单词数
计算字符串STR中的单词数量
11.$(firstword STR) #取第一个单词
取字符串STR中第一个单词
3>文件名处理函数
1.$(dir NAMES)
取每一个文件路径中的路径部分(如 /bin/sh取/bin/,a.c取./)
2.$(notdir NAMES)
取每一个文件路径中的文件部分(如 /bin/sh取sh,a.c取a.c)
3.$(suffix NAMES)
取每一个文件的后缀名(如 a.c取.c)
4.$(basename NAMES)
取每一个文件的前缀,包含路径(如 /bin/a.c取/bin/a)
5.$(addsuffix SUFFIX,NAMES)
为每一个文件添加后缀SUFFIX
6.$(addprefix PREFIX,NAMES)
为每一个文件添加前缀PREFIX (如 /bin/添加到a.c b.c的前面)
7.$(join LIST1,LIST2)
将LIST1和LIST2中的单词对应相连接(如 join a b c,.c .o 得到a.c b.o c)
8.$(wildcard PATTERN)
返回当前文件夹符合PATTERN模式的文件名组成的字符串
c7a3
wildcard的PATTERN使用的通配符为*、?、[...]这三种!!(注意区别与之前的PATTERN都是使用%,因为wildcard针对的是具体的文件
而不是针对字符串)
4>foreach函数
$(foreach VAR,LIST,EXPRESSION)
遍历函数,遍历LIST中的单词,并传递给变量VAR,再执行一次EXPRESSION。
最后返回的是每一次EXPRESSION执行的返回值通过 空格 拼接后的字符串
例:dirs:=.c .o .h
files:=$(foreach dir,$(dirs),$(wildcard *$(dir)))
相当于
files:=$(wildcard *.c *.o *.h)
5>if函数
$(ifCONDITION,THEN,ELSE)
对CONDITIOND表达式进行展开,如果展开的值不为空,则执行THEN
若展开值为空则执行ELSE表达式
6>call函数
$(call VAR,PARAM,PARAM,...)
对VAR变量展开的表达式进行函数计算,参数通过$(1)、$(2)...在VAR中进行引用。
#VAR必须为变量,而且使用的是变量名VAR,不是其引用$(VAR)。(如果引用的返回值为一个变量名,也可以以$()形式)
#VAR必须是递归展开变量,即用=、+=、?=来创建的变量
#VAR也可以是 内嵌函数名,但使用时需要注意参数数量,否则会出现问题。
例:func=$(subst $(2),$(3),S(1))
a=$(call func,a.o b.o,.o,.c)
返回值a为a.c b.c
#若想定义多行函数,用define定义变量即可。
7>value函数
$(value VAR)
返回变量VAR的值,而且是 不进行展开 的值。但是对变量定义时就进行的展开无效
(直接展开变量:=在定义时就展开了,因此返回的是展开值)
VAR在这里同上,也是变量名而不是对其引用
8>eval函数
$(eval EXPRESSION)
eval是将表达式展开后再提供给make执行,EXPRESSION可以是define定义的程序段。
eval展开后就相当于makefile的一个部分(因为展开的可以是规则,变量,目标、依赖等)
EXPRESSION中的程序段如果有变量和函数需要由make执行的,需要在$(...)前再添加一个$
9>origin函数
$(value VAR)
查询一个变量名的出处,VAR同理必须是变量名。
返回值包括:
undefined 表示未定义
default 表示变量是一个内嵌变量(如CC MAKE)
environment 表示一个系统环境变量
file 表示变量在makefile中定义
command line 表示变量在命令行中定义
override 表示是override声明的变量
automatic 表示是自动化变量
10>shell函数
$(shell EXPRESSION)
可以在makefile中执行shell命令(开启子shell进程),EXPRESSION为执行的shell命令,返回该shell命令执行后的返回值。
最好使用:=直接展开变量来接收shell函数的返回值,因为会在定义时就展开,提升效率。
11>error函数
$(error TEXT)
当函数被展开执行时,退出make的执行,并返回错误提示TEXT
12>warning函数
$(warning TEXT)
当函数被展开执行时,产生TEXT警告文本,但不终止执行
make的执行:
1>make -f file/--file=file
1.以指定的文件file作为makefile文件来执行
2.若没有指定具体文件,make会在当前目录依次搜索命名为“GNUmakefile”、“makefile”和“Makefile”的文件来执行
2>make obj
1.以指定目标obj为终极目标来执行makefile。(终极目标表示make将会对以obj为目标的规则向下执行,
并执行所有由依赖关系关联到的相关规则。不相关的不执行)
2.若没有obj指定终极目标,则默认以除了.开头的特殊目标(如.PHONY)外,第一个遇到的目标的第一个目标(多目标情况)为终极目标。
3.一些伪目标和空目标由于一般不和默认终极目标存在依赖关系,因此常常使用这种方式来对其进行执行,比如make clean
常见的伪目标和空目标约定:
all 当需要产生多个目标的时候,将多个目标作为伪目标all的依赖,并把all放到makefile文件的开头作为默认终极目标,
(因此只需要使用make而没必要make all),这样就可以不用产生all文件的同时产生想要的多个目标
clean 功能是清除makefile产生的所有文件
mostlyclean 清除部分不需要的文件,类似还有distclean、realclean等
clobber 清除不止makefile产生的文件,还有编译前的其他文件,比如配置文件,链接文件等。
install 将make创建成的可执行二进制文件拷贝到系统环境变量PATH的目录下面。(即该文件可以直接像shell指令那样执行了)
print 打印所有被更改过的源文件
tar 创建一个tar包
shar 为源代码创建一个shell文档shar文件
dist 创建一个源文件发布用的压缩包
TAGS 创建源文件的符号信息文件
test 对生成的最后文件进行检查
3>make -n/--just-print
不执行makefile,只打印出需要被重建的目标所需要使用的命令
4>make -t/--touch
更新所有目标文件的时间戳
5>make obj -q/--question
检查目标obj是否是最新的(是否需要重建),是最新则返回0,不是最新返回1,若发生错误则返回2
若没有指定目标则检查默认终极目标是否最新。
6>make -W/--what-if obj
将目标obj文件的时间戳假设为最新再进行执行
1.-W与-n结合 可以只打印出假设修改时间后需要重建的目标的命令
2.-W与-t结合 只将把obj作为目标的依赖的文件时间戳进行更新
3.-W与-q结合 假设修改对应文件的时间戳以后,make执行的返回状态在没有错误发生时为 1,存在错误时为 2
7>make -o obj.h
可以用于防止依赖obj.h头文件的目标因为obj.h的修改而被重建(相当于将.h的时间戳假设变为旧的再执行,与-W相反)
-o后面必须接.h文件
8>make var=... 或make var=...
通过命令行来定义变量,这种方式定义的变量会覆盖直接在makefile中定义的同名变量。
可以在makefile中在变量前声明override来使得变量不被覆盖。
9>make -k/--keep-going
make在执行时,若遇到错误会停止执行并返回非零状态值。-K可以使make忽略错误,继续执行直到不能执行再退出。
make-S/--stop可以用于取消-k选项,用于make递归调用时取消子make默认继承的-k选项
例:在生成.o目标时若出现错误,忽略错误继续执行别的规则,直到链接时没有该.o文件不能执行再退出
10>make -i/--ignore-errors
make执行时忽略所有的错误,会将所有指令都执行(相比-k,-i会将即使依赖发生错误的目标也进行执行,即执行的更彻底)
10>make -s/--silent
make只是执行命令但不打印命令出来,默认会打印所有命令
11>make -B/--always-make
强制重建所有目标(即不根据时间戳来判断是否重建)
12>make -C dir/--directory=dir
在目录dir下执行make,递归执行make时常用
13>make -d/--debug=option
-d相当于--debug=a,输出所有类型的调试信息
option的选项有:
a 输出所有类型调试信息
b 输出基本调试信息,哪些目标过期,是否成功重建过期目标
v 在b之上多一些其他的重建信息
i 在b之上多了使用到的隐含规则描述
j 输出所有执行命令的子进程
m 与makefile相关的读取、更新、执行等信息
14>make -e/--environment-overrides
使环境变量能够覆盖make定义的和makefile里定义的同名变量(不使用-e时环境变量会被同名变量覆盖)
15>make -I dir/--include-dir=dir
在指定的dir目录下搜寻make执行的文件
16>make -r/--no-builtin-rules
执行makefile时禁止使用内嵌的隐含规则
17>make -R/--no-builtin-variables
执行makefile时禁止使用内嵌的隐含变量
隐含规则:
1>隐含规则的使用
指定明确的依赖并不会影响隐含规则的执行。如 a.o:a.p 隐含规则若是在目录下发现a.c文件,
则会对a.c文件进行编译成a.o,因为.c的隐含规则更优先
隐含规则不会对.开头的目标和空目标生效,不会用隐含规则自动重建目标
2>隐含规则链
当一个目标文件需要一系列隐含规则才能完成它的创建,则称其为隐含规则链(如a.o:若只存在a.y文件,则隐含规则链为a.y->a.c->a.o)
1.隐含规则链中的中间过程文件是在makeflie执行结束后默认删除的(即a.c文件)
makefile中明确提起过的文件都不会被删除
.INTERMEDIATE来声明一些文件名,会在make执行完后自动删除
.SECONDARY声明的文件名,会在执行完后保留
.PRECIOUS声明的文件名,也会全部保留,如.PRECIOUS:%.o 将保留所有生成的.o中间文件
2.若存在优化的隐含规则,会优先执行,如.c到.out文件,直接用gcc执行到.out,而不需要.o中间文件
3>待续。。。。
以上原因在于若直接执行文件下下的文件,系统会默认到PATH下寻找执行代码,即对于系统来说可执行文件都默认在PATH中寻找。因此用./相对地址来指示执行地址。或者在PATH中添加./路径
2、gcc编译器(GUNCompiler Collection)
1>gcc编译步骤包含4步:(针对a.c举例)
预处理器(cpp):对源程序进行预处理得到.i文件,gcc执行选项-E
gcc -E a.c -o a.i
编译器(ccl):进行编译得到汇编程序.s文件,gcc执行选项-S
gcc -S a.i -o a.s 或 gcc -S a.c -o a.s
汇编器(as):生成可重定位目标程序.o文件,gcc执行选项-c
gcc -c a.s -o a.o 或 gcc -c a.c -o a.o
链接器(ld):生成可执行目标程序.out文件,gcc默认执行生成.out文件(.ou是t系统可以直接执行的二进制文件)
gcc a.o -o a.out 或 gcc a.c -o a.out
#-o选项后面接生成的文件名,不加则会自动命名
#其中后缀名在linux中只是标识作用,即使不带,如a.out写成a则会生成没有后缀的文件a,a也能执行。
#编译多个文件方式为: gcc a.c b.c ... -o a.out
#或者生成.o文件后再链接 gcc -c a.c -o a.o ... gcc a.o b.o ... -o a.out
2>加上单独的-Wall选项,会在编译有问题的地方发出警告
3>库文件编译方式
库文件实际上是一些.o文件的打包,具体分为:
静态库(.a文件):程序在编译时直接将库和程序编译链接成一个可执行二进制代码,
相当于每一个程序都包含了一份静态库,因此相对更占用磁盘和内存。
生成方式:ar rcs liba.a a.o 需要通过a.a才能生成a.o
使用方式:gcc b.c liba.a -o b.out
或gcc b.c -o b.out-L. -la #-L选项为添加库的搜索地址,-L.表示当前文件夹
#-la为对-liba的引用(相当于l替换lib)
动态库/共享库(.so或.sa文件):程序直接编译成可执行代码,并在运行代码时才进行动态库
的链接,将库从硬盘加载到内存,因此相对减少了占用内存的体积
生成方式:gcc –shared -fPIC a.o –o a.so
使用方式:gcc b.c -o b.out -L. -la #与静态库一致,但是系统会优先使用动态库
#库文件一般存放地址:/usr/lib /usr/local/lib
3、Makefile
makefile基本规则:
1>makefile的包括五个部分
显示规则:需要显式的给出一个规则的目标、依赖、命令等
隐含规则:指根据目标文件名自动产生目标的依赖文件并使用隐含的命令来执行重建
变量定义:使用变量来代替重复使用的字符串
指示符:包含include、define..endef、ifeq..endif等
注释:用#来进行注释。同时若结尾出现\则下一行也为注释。注释建议为单独行
2>makefile文件的命名
若没有指定make执行的makefile文件,make会自动在执行目录下依次寻找“GNUmakefile”、“makefile”、“Makefile”这几个文件名想要执行特定的makefile文件,可以使用make -f filename来执行
3>include指示符
1.用于包含其他的makefile文件。用途主要在于可以将多个makefile文件需要共同使用的变量定义、模式规则、自动依赖关系等
存放在一个makefile文件中,以便别的makefile文件调用。
2.make会在遇到include时转而执行其包含的makefile文件,直到执行完了再返回原makefile文件
3.MAKEFILES环境变量中包含其他的makefile文件,make指令会在执行makefile文件时将这些文件包含进来,
相当于每一个make指令都会include这写文件,因此不建议这么做。
4.MAKEFILE_LIST环境会包含所有被执行的makefile文件列表,可以通过这个变量查看哪些makefile被执行。
5.重载另外一个makefile
问题在于include另外一个makefile会导致规则冲突,但又需要使用另外一个makefile中定义的一部分变量或者规则时。
4>条件判断指示符
1.判断a与b是否相等ifeq和ifneq。如下相等则执行命令行1,否则执行2
ifeq (a,b) 或ifeq "a" "b" 或 ifeq 'a''b'都可以
命令行1
else
命令行2
endif
2.判断变量是否存在ifdef和ifndef
ifdef var #此处不是$(var)
3.if else endif等为make的语法,前面不能有tab
4.ifeq后接判断式时,中间有一个空格!
5>makefile的重建
makefile也可以被规则建立,makefile可由RCS或SCCS文件生成,若makefile中有对makefile的重建规则,会先按规则重建在执行新的makefile
6>make的执行过程
第一步:读取所有的makefile文件(包含include、MAKEFILES、make指定的文件),内建所有变量和规则
第二步:根据依赖关系,巨鼎哪些目标需要更新,然后对目标进行重建。
规则与目标:
1>规则的语法
TARGETS:PREREQUISITES
COMMAND
或者
TARGETS : PREREQUISITES ; COMMAND #这个command前面没有tab没有问题,但是下面的command必须要tab开头
COMMAND
TARGETS:目标 PREREQUISITES:依赖 COMMAND:命令
一个规则可以多目标,多依赖,也可以无依赖,无命令,但是不能无目标。
2>规则的执行条件为:
目标文件不存在则执行命令
目标文件存在且修改时间比任何一个依赖更旧则执行命令
3>两种类型依赖
定义方式:TARGETS : NORMAL-PREREQUISITES |ORDER-ONLY-PREREQUISITES
包含常规依赖和order-only依赖
区别在与order-only依赖不会因为更新而导致目标被重建,只会在常规依赖更新或者目标不存在时参与重建。
4>终极目标
终极目标为最终要形成的文件,make在执行时若未指定终极目标时,会自动寻找终极目标,默认是makefile中的第一个规则,
但是会忽略以.开头(如伪目标规则)和模式规则的目标(包含%的目标)来寻找。
5>文件搜寻
主要用于make对目标或者依赖的文件的搜索,若不指定则只在当前目录中搜寻
1.环境变量VPATH
通过向VPATH中添加搜索路径,用:隔开,make会自动到这些文件夹下面搜索目标文件。
2.vpath pattern dir
可用于在特定文件夹下搜索特定类型的文件。
在目录dir中搜索符合模式pattern的文件,patten一般使用%进行字符匹配。
6>伪目标
伪目标通
4000
过特殊目标.PHONY来设置,如.PHONY:clean,clean即为伪目标
伪目标的特点是该目标的规则在执行时不需要创建该目标对应的文件,这样有利于只是将该目标作为一个执行其规则下命令的手段,
如clean是用来删除多余文件的伪目标,通过make clean即可执行其规则中的命令。
伪目标也可以放在最前面当做默认终极目标,有利于一次重建多个目标(如想一次建立三个目标时.PHONY:all all:a.o b.o c.o)
7>强制目标
当一个目标没有依赖和命令时,该目标会被看做最新,然后可以用作别的规则的依赖来强制执行规则。
定义方式: FORCE:
8>多规则目标
1.当一个目标出现在多个规则中时,会将所有该目标对应规则中的依赖合并一起,再对该目标进行重建。
若每一个规则对应不同的重建命令,则会执行最后一个规则的命令。
2.::来划分目标和依赖可以实现实现多规则目标只通过时间更新依赖对应的规则进行重建。
3.建议尽量使用单目标多依赖形式,尽量少出现多规则目标。
9>静态模式规则
targets: target-pattern: prereq-patterns
commands
target-pattern 目标模式 prereq-patterns 依赖模式
模式通过模式字符%来设置,可以更好的处理多目标的规则
例:a.o b.o:%.o:%.c
$(CC) -c $(CFLAGS) $< -o $@
10>隐含规则
隐含规则主要是利用make对规则进行推导来补全命令。
命令:
make会在找到规则后,会将所有以tab键开头的行交由shell处理。
这代表了命令必须tab开头,而makefile自己的语法不能tab开头。
1>make会在执行makefile文件里的命令时,将命令打印出来。在命令前添加@可以不让其显示。
若使用 make -n/--just-print则是只打印命令但是不执行
若使用 make -s/--silent 则是执行命令但不打印命令
2>执行命令时,只有通过";"将多个命令分隔并写在同一行上,才相当于执行连续的shell命令。
原因是直接的多行命令执行时,相当于是对每一个命令启动一个子shell进程来执行,因此相互没有联系。
3>make会在执行每一条命令时检查返回码,若执行错误则停止make的执行。
可以通过在命令前添加"-"来忽略命令的出错,-可以用在命令上也可以用在include这样的指示符上。
也可以通过make -i/--ignore-errors来忽略所有的错误继续执行
还可以将目标文件作为特殊目标".IGNORE"的依赖,使得该目标文件下的命令执行时会忽略错误
还可以通过make -k/--keep-going来跳过当前依赖中的错误,继续执行别的依赖关系里面的命令,直至完全不能执行
4>可以将目标文件作为特殊目标.PRECIOUS的依赖,使得该目标文件在make中断时,不会将重建的部分文件删除。(一般不建议使用)
5>make的递归执行
6>定义命令包
实质是通过变量定义的方式定义多行命令。
命令包是将需要使用的重复性的多条命令通过define来包装成一个整体
具体定义方式为 define var(变量名)
命令(通过$^、$@等来使用依赖中的目标文件如.o和前置文件如.c)
endef
使用方式:a.o:a.c
$(var) #注意一定要加上tab键
7>空命令行
定义方式: 目标文件:;
主要用于防止隐藏规则对目标文件的重建动作,即该目标文件希望不要被重建时使用
如%.o:%.c会在需要生成.o目标时寻找到该规则,该规则通过隐含规则执行gcc命令将.c文件转换为.o文件。
变量:
1>变量的定义与赋值(以var举例)
1.递归展开式变量(在使用时展开值中的变量和函数)
定义方式:
var=变量内容
或者:
define var
变量内容(可以是多行,同时多行命令是使用一个shell进程来执行,所以不需要使用;进行分割)
endef
这种定义方式的变量在使用时是字符串的直接替换,即类似宏定义
优点为由于其定义的内容相当于字符串,因此可以引用当前还未定义的变量(使用时才展开,因此定义时内容相当于只是字符串)
缺点在于,由于可以引用当前未定义变量,当嵌套定义时,如a=b b=a,会导致在$a使用变量时陷入无限递归。
同理在变量中定义的是函数内容时,由于每次使用变量时才会执行内容,因此导致函数被执行多次,降低效率
赋值方式还有条件赋值符(?=),如a?=...,表示若a未定义,则对a进行赋值。a相当于递归展开式变量。
变量在赋值时,若长度过长,可以使用\来进行换行
2.直接展开式变量(在定义时展开值中的变量和函数)
定义方式:var:=...
这种定义方式在变量定义的时候就完成对变量内容中对其他变量或函数的执行或者展开
这种方式的变量在使用时也是文本内容的替换。同时定义时后面若有空格也会被记录进变量内容中
(注释不会被记录,但最好别在变量定义后面添加注释,因为会导致空格)
2>变量的引用
1.引用方式有两种:$(var)或${var}(对于单字符变量和自动化变量如$@,可以不需要外面的括号)
2.变量的引用为字文本内容的严格替换,类似于c语言中的宏定义
3.在规则下的命令行中,由于存在对shell变量($var或${var}方式)和makefile变量两种的引用,注意区分开不同的变量
4.变量可以进行嵌套引用(在一个变量中引用其他的变量或者函数),但嵌套引用时,会在展开嵌套的变量之前检查函数,若展开的变量
展开后是函数,将不会被识别。
5.若引用一个未定义的变量,则得到的值为空。
3>追加变量值(+=)
1.若变量没有定义过,则使用+=时相当于使用=进行递归展开式变量定义赋值
2.使用方式如a+=b,表示在a的内容中添加“ b”,前面有个空格作为划分。
3.若追加变量a时,若a是递归展开式变量,则不会进行对a的展开。
若a是直接展开式变量,则会对嵌套引用进行展开
4>override指示符
make指令可以在执行时定义变量(如 make var=...),该变量会覆盖makefile中已经存在的变量,在变量前添加override可以防止这种覆盖
可用于给make指令增加固定选项参数(在makefile文件里通过+=添加命令选项,同时make指令也将选项传入变量,得到最终的选项值)
5>特殊变量
1.隐含变量
隐含变量为预定义变量,允许对其修改(可通过直接修改,命令行修改,环境变量设置等方式都可以)
隐含变量多用于隐含规则中,如$(CC) -c $(CFLAGS) $(CPPFLAGS)这个隐含规则中有3个隐含变量
常见隐含变量有:
代表命令的隐含变量:
AR:用于创建静态库.a文件
AS:用于创建汇编.s文件
CC:相当于c编译器,linux是gcc
CXX:相当于cpp编译器,默认g++
CPP:c语言预处理器,默认$(CC)-E
PC:pascal编译器,默认pc
RM:相当于rm -f指令
等等
代表参数的隐含变量:
ARFLAGS:AR命令行参数,默认rv
ASFLAGS:AS命令行参数
CFLAGS:CC命令行参数
CXXFLAGS:CXX命令行参数
CPPFLAGS:CPP命令行参数
等等
2.自动化变量
自动化变量主要运用于模式规则中,模式规则中没有具体的目标或者依赖名,因此需要使用自动化变量来代指目标和依赖
自动化变量有:
$@:代表规则中的目标名
$<:代表规则中的第一个依赖名
$%:只用于当目标为一个静态库文件时,其代表静态库文件的第一个成员名
$*:代表规则中通配符%所代表的内容。若规则中没有通配符%,则代表可识别后缀前面的内容,如a.o:a.c中,$*代表a
#以下三个代表列表
$?:代表规则中所有比目标文件时间戳更新的依赖的文件名列表。若目标是静态库,则为其所有成员的列表
$^:代表规则中所有的依赖组成的文件名列表。若目标是静态库,则为其所有成员的列表
$+:功能类似$^,但它会将重复的文件名也列出来
自动化变量可以通过在后面添加D(dir)和F(file)符号来取其中的路径或者文件部分
例:$(@D)取目标名中的路径部分但不包括最后一个/,即/bin/a.c取/bin
$(@F)取目标名中的文件名部分,即/bin/a.c取a.c
3.系统环境变量和make环境变量
两种环境变量对于makefile都是可见的,makefile的环境变量只在一次执行过程中有效。
环境变量和make定义的变量可以传递给子进程(普通变量需要export才行),因此环境变量不能随意修改。
常见makefile环境变量有:MAKEFILESMAKEFILE_LIST VPATH SHELL等
4.变量.VARIABLES
变量存放引用点之前所有定义的变量,包含普通变量,内嵌变量等等
6>目标指定变量
使用方式:例以a为目标 a:var=...
var的作用范围为所有以a为目标的规则范围中。
7>模式指定变量
使用方式:例以%.o为模式%.o:var=...
var的作用范围为所有以.o结尾的目标的规则范围中。
内嵌函数:
1>调用方式
方式与变量类似(函数func参数a b c为例)
$(func a,b,c) 或者${func a,b,c}
#空格或者,作为参数想传入时只能间接通过变量传入
#
2>文本处理函数
1.$(subst FROM,TO,STR) #替换字符
返回将字符串STR中的FROM字符串替换为TO字符串的字符串,不会修改str本身
2.$(patsubst PATTERN,REPLACEMENT,STR) #模式替换字符
将字符串STR中匹配模式PATTERN的字符串替换为模式REPLACEMENT中对应的字符串,
模式可以通过“%字符串”或者“字符串”来设置,若有%(如%.o),表示匹配以.o结尾的字符串即可,
若只是字符串(如字符串“a bc”),则匹配a、b、c这几个字符。
模式匹配时,以空格为间隔进行匹配
例 $(patsubst %.o,%.c,str)
对变量进行替换时还有一种简化的替换方式,如将var中.o字符串变成.c字符串:$(var:.o=.c)等价于$(patsubst %.o,%.c,$(var))
3.$(strip STR) #去掉首尾空白字符
返回去掉STR中的首尾空白符的字符串,包含空格和tab等
4.$(findstring FIND,STR) #查找子字符串
在STR中查找FIND字符串,若找到则返回FIND字符串,否则返回空字符串
5.$(filter PATTERN,STR) #过滤不符合模式的字符串
将STR中不符合符合模式PATTERN的字符串过滤掉,返回过滤后的字符串
例 $(filter %.c %.o,a.c a.o b.cb.h) 返回a.c a.ob.c,过滤掉b.h
6.$(filter-out PATTERN,STR) #过滤符合模式的字符串
同理,与filter功能正相反。
7.$(sort STR) #对字符串进行排序
对字符串STR中的单词以首字母进行排序,并删去重复单词
8.$(word N,STR) #取字符串中的单词
取字符串STR中第N个单词,若超出索引(大于总数)返回空字符,若为0则报错
9.$(wordlist N,M,STR) #取字符串
取字符串STR中从N到M的单词组成的字符串
10.$(words STR) #计算单词数
计算字符串STR中的单词数量
11.$(firstword STR) #取第一个单词
取字符串STR中第一个单词
3>文件名处理函数
1.$(dir NAMES)
取每一个文件路径中的路径部分(如 /bin/sh取/bin/,a.c取./)
2.$(notdir NAMES)
取每一个文件路径中的文件部分(如 /bin/sh取sh,a.c取a.c)
3.$(suffix NAMES)
取每一个文件的后缀名(如 a.c取.c)
4.$(basename NAMES)
取每一个文件的前缀,包含路径(如 /bin/a.c取/bin/a)
5.$(addsuffix SUFFIX,NAMES)
为每一个文件添加后缀SUFFIX
6.$(addprefix PREFIX,NAMES)
为每一个文件添加前缀PREFIX (如 /bin/添加到a.c b.c的前面)
7.$(join LIST1,LIST2)
将LIST1和LIST2中的单词对应相连接(如 join a b c,.c .o 得到a.c b.o c)
8.$(wildcard PATTERN)
返回当前文件夹符合PATTERN模式的文件名组成的字符串
c7a3
wildcard的PATTERN使用的通配符为*、?、[...]这三种!!(注意区别与之前的PATTERN都是使用%,因为wildcard针对的是具体的文件
而不是针对字符串)
4>foreach函数
$(foreach VAR,LIST,EXPRESSION)
遍历函数,遍历LIST中的单词,并传递给变量VAR,再执行一次EXPRESSION。
最后返回的是每一次EXPRESSION执行的返回值通过 空格 拼接后的字符串
例:dirs:=.c .o .h
files:=$(foreach dir,$(dirs),$(wildcard *$(dir)))
相当于
files:=$(wildcard *.c *.o *.h)
5>if函数
$(ifCONDITION,THEN,ELSE)
对CONDITIOND表达式进行展开,如果展开的值不为空,则执行THEN
若展开值为空则执行ELSE表达式
6>call函数
$(call VAR,PARAM,PARAM,...)
对VAR变量展开的表达式进行函数计算,参数通过$(1)、$(2)...在VAR中进行引用。
#VAR必须为变量,而且使用的是变量名VAR,不是其引用$(VAR)。(如果引用的返回值为一个变量名,也可以以$()形式)
#VAR必须是递归展开变量,即用=、+=、?=来创建的变量
#VAR也可以是 内嵌函数名,但使用时需要注意参数数量,否则会出现问题。
例:func=$(subst $(2),$(3),S(1))
a=$(call func,a.o b.o,.o,.c)
返回值a为a.c b.c
#若想定义多行函数,用define定义变量即可。
7>value函数
$(value VAR)
返回变量VAR的值,而且是 不进行展开 的值。但是对变量定义时就进行的展开无效
(直接展开变量:=在定义时就展开了,因此返回的是展开值)
VAR在这里同上,也是变量名而不是对其引用
8>eval函数
$(eval EXPRESSION)
eval是将表达式展开后再提供给make执行,EXPRESSION可以是define定义的程序段。
eval展开后就相当于makefile的一个部分(因为展开的可以是规则,变量,目标、依赖等)
EXPRESSION中的程序段如果有变量和函数需要由make执行的,需要在$(...)前再添加一个$
9>origin函数
$(value VAR)
查询一个变量名的出处,VAR同理必须是变量名。
返回值包括:
undefined 表示未定义
default 表示变量是一个内嵌变量(如CC MAKE)
environment 表示一个系统环境变量
file 表示变量在makefile中定义
command line 表示变量在命令行中定义
override 表示是override声明的变量
automatic 表示是自动化变量
10>shell函数
$(shell EXPRESSION)
可以在makefile中执行shell命令(开启子shell进程),EXPRESSION为执行的shell命令,返回该shell命令执行后的返回值。
最好使用:=直接展开变量来接收shell函数的返回值,因为会在定义时就展开,提升效率。
11>error函数
$(error TEXT)
当函数被展开执行时,退出make的执行,并返回错误提示TEXT
12>warning函数
$(warning TEXT)
当函数被展开执行时,产生TEXT警告文本,但不终止执行
make的执行:
1>make -f file/--file=file
1.以指定的文件file作为makefile文件来执行
2.若没有指定具体文件,make会在当前目录依次搜索命名为“GNUmakefile”、“makefile”和“Makefile”的文件来执行
2>make obj
1.以指定目标obj为终极目标来执行makefile。(终极目标表示make将会对以obj为目标的规则向下执行,
并执行所有由依赖关系关联到的相关规则。不相关的不执行)
2.若没有obj指定终极目标,则默认以除了.开头的特殊目标(如.PHONY)外,第一个遇到的目标的第一个目标(多目标情况)为终极目标。
3.一些伪目标和空目标由于一般不和默认终极目标存在依赖关系,因此常常使用这种方式来对其进行执行,比如make clean
常见的伪目标和空目标约定:
all 当需要产生多个目标的时候,将多个目标作为伪目标all的依赖,并把all放到makefile文件的开头作为默认终极目标,
(因此只需要使用make而没必要make all),这样就可以不用产生all文件的同时产生想要的多个目标
clean 功能是清除makefile产生的所有文件
mostlyclean 清除部分不需要的文件,类似还有distclean、realclean等
clobber 清除不止makefile产生的文件,还有编译前的其他文件,比如配置文件,链接文件等。
install 将make创建成的可执行二进制文件拷贝到系统环境变量PATH的目录下面。(即该文件可以直接像shell指令那样执行了)
print 打印所有被更改过的源文件
tar 创建一个tar包
shar 为源代码创建一个shell文档shar文件
dist 创建一个源文件发布用的压缩包
TAGS 创建源文件的符号信息文件
test 对生成的最后文件进行检查
3>make -n/--just-print
不执行makefile,只打印出需要被重建的目标所需要使用的命令
4>make -t/--touch
更新所有目标文件的时间戳
5>make obj -q/--question
检查目标obj是否是最新的(是否需要重建),是最新则返回0,不是最新返回1,若发生错误则返回2
若没有指定目标则检查默认终极目标是否最新。
6>make -W/--what-if obj
将目标obj文件的时间戳假设为最新再进行执行
1.-W与-n结合 可以只打印出假设修改时间后需要重建的目标的命令
2.-W与-t结合 只将把obj作为目标的依赖的文件时间戳进行更新
3.-W与-q结合 假设修改对应文件的时间戳以后,make执行的返回状态在没有错误发生时为 1,存在错误时为 2
7>make -o obj.h
可以用于防止依赖obj.h头文件的目标因为obj.h的修改而被重建(相当于将.h的时间戳假设变为旧的再执行,与-W相反)
-o后面必须接.h文件
8>make var=... 或make var=...
通过命令行来定义变量,这种方式定义的变量会覆盖直接在makefile中定义的同名变量。
可以在makefile中在变量前声明override来使得变量不被覆盖。
9>make -k/--keep-going
make在执行时,若遇到错误会停止执行并返回非零状态值。-K可以使make忽略错误,继续执行直到不能执行再退出。
make-S/--stop可以用于取消-k选项,用于make递归调用时取消子make默认继承的-k选项
例:在生成.o目标时若出现错误,忽略错误继续执行别的规则,直到链接时没有该.o文件不能执行再退出
10>make -i/--ignore-errors
make执行时忽略所有的错误,会将所有指令都执行(相比-k,-i会将即使依赖发生错误的目标也进行执行,即执行的更彻底)
10>make -s/--silent
make只是执行命令但不打印命令出来,默认会打印所有命令
11>make -B/--always-make
强制重建所有目标(即不根据时间戳来判断是否重建)
12>make -C dir/--directory=dir
在目录dir下执行make,递归执行make时常用
13>make -d/--debug=option
-d相当于--debug=a,输出所有类型的调试信息
option的选项有:
a 输出所有类型调试信息
b 输出基本调试信息,哪些目标过期,是否成功重建过期目标
v 在b之上多一些其他的重建信息
i 在b之上多了使用到的隐含规则描述
j 输出所有执行命令的子进程
m 与makefile相关的读取、更新、执行等信息
14>make -e/--environment-overrides
使环境变量能够覆盖make定义的和makefile里定义的同名变量(不使用-e时环境变量会被同名变量覆盖)
15>make -I dir/--include-dir=dir
在指定的dir目录下搜寻make执行的文件
16>make -r/--no-builtin-rules
执行makefile时禁止使用内嵌的隐含规则
17>make -R/--no-builtin-variables
执行makefile时禁止使用内嵌的隐含变量
隐含规则:
1>隐含规则的使用
指定明确的依赖并不会影响隐含规则的执行。如 a.o:a.p 隐含规则若是在目录下发现a.c文件,
则会对a.c文件进行编译成a.o,因为.c的隐含规则更优先
隐含规则不会对.开头的目标和空目标生效,不会用隐含规则自动重建目标
2>隐含规则链
当一个目标文件需要一系列隐含规则才能完成它的创建,则称其为隐含规则链(如a.o:若只存在a.y文件,则隐含规则链为a.y->a.c->a.o)
1.隐含规则链中的中间过程文件是在makeflie执行结束后默认删除的(即a.c文件)
makefile中明确提起过的文件都不会被删除
.INTERMEDIATE来声明一些文件名,会在make执行完后自动删除
.SECONDARY声明的文件名,会在执行完后保留
.PRECIOUS声明的文件名,也会全部保留,如.PRECIOUS:%.o 将保留所有生成的.o中间文件
2.若存在优化的隐含规则,会优先执行,如.c到.out文件,直接用gcc执行到.out,而不需要.o中间文件
3>待续。。。。
相关文章推荐
- 【Linux 学习笔记】关于Makefile
- Makefile学习笔记
- 学习笔记之Makefile
- Linux学习笔记——例说makefile 增加系统共享库
- gcc、makefile、gdb学习笔记
- 操作系统学习笔记(11)--makefile的$@
- makefile学习笔记(二)
- Windows平台下Makefile学习笔记
- Makefile学习笔记
- 跟我一起写Makefile学习笔记1——文件搜寻&伪目标&静态模式
- makefile 学习笔记
- makefile学习笔记(三)
- Makefile学习笔记1
- Makefile学习笔记1:Linux平台Makefile文件的编写基础篇(zz)
- Linux下编译环境及Makefile的学习笔记
- Linux学习笔记——例说makefile 增加自定义共享库
- Makefile学习笔记
- [转]Linux学习笔记——例说makefile 头文件查找路径
- Makefile学习笔记4
- makefile学习笔记1