Makefile-->基础规范

基本书写规则

一般来说,Makefile只应该有一个最终目标,这个目标被放在第一条规则中。

1 targets:prerequisites
2     command #注意command必须以[TAB]开头

Makefile就是通过command作用于prerequisites,然后生成最新的targets。

其中:

1、targets一般是一个文件,多个文件用空格隔开

2、command如果太长可以用'\'续行,可以使用Shell所支持的任何命令,整个规则中,若想使用特殊符号作普通符号,也使用'\'转义

3、在默认情况下,make会把要执行的命令显示到屏幕上,可以使用"@"字符屏蔽显示某行命令(一般在echo类命令前加@,避免重复输出)。

也可以通过"make -n"只显示命令而不执行,来达到调试的目的。若全部不显示,则使用"make -s"

4、若需要上一条命令作用于下一条命令,需要把两个命令放在同一行并用分号分隔。

cd /home/kcmetercec ; ls
#这样ls才会在上条命令基础上执行

5、若命令出错则make会停止,可以使用以下方式继续运行

clean:
    -rm -f *.o #忽略此条命令出错

.IGNORE       #忽略此目标的命令错误
clean :
    rm -f *.o
    rm -f *.bin


#也可以使用make -i 忽略整个make的命令错误
#或者使用make -k ,当遇到错误时,不执行此规则而去继续执行其他规则

 

文件搜寻

当有多个文件分别位于不同文件夹时,可以用过特殊变量"VPATH"指定搜寻路径。以告知Makefile在当前目录找不到依赖文件时,去指定路径寻找。

VPATH = ../test : ../Make #路径由':'分隔

为了能够使搜索更加灵活,需要使用关键字"vpath"

vpath pattern directories
#满足pattern模式的文件指定directories目录,目录同样可以用冒号分隔
vpath pattern
#清除满足pattern模式的文件搜索目录
vpath
#清除所有已经设置好了的文件搜索目录

#例如
vpath %.c ../src
#指定在当前目录没有找到.c文件,在../src目录中寻找

伪目标

一般在Makefile最后会有一个clean目标来清除make过程的文件,为了避免clean目标与项目重名使用伪目标来显示说明。

.PHONY clean
clean:
    rm *.c

 引用/嵌套其他的Makefile

通过使用include关键字可以包含其他Makefile,在实际运行过程中,被包含的文件会在include位置展开

include a.mk b.mk 
#可以包含路径,通配符,变量等
#可以在include前加减号"-",表明没有找到文件也继续运行

和shell一样,Makefile可以嵌套执行其他的Makefile,将其他的Makefile作为一个子程序。

同理,父Makefile的变量可以使用"export"传递到下级,或使用"unexport"不传递,默认参数"SHELL"和"MAKEFLAGS"总是会传递的。

一般来说,使用"make -w"可以使make输出当时执行的Makefile所在目录。也可以使用"MAKELEVEL"得到嵌套深度。

subsystem:
    cd subdir && ${MAKE}
#代表先进入subdir目录然后执行make命令,其中MAKE变量是为了make加入参数比较好维#护

#等价于
subsystem:
    ${MAKE} -C subdir

变量

默认变量:

AR 
#函数库打包程序,默认"ar"
ARFLAGS
#AR参数,默认"rv"

AS
#汇编编译程序,默认"as"
ASFLAG
#AS参数,默认空

CC
#c编译程序,默认"cc"
CFLAGS
#CC参数,默认空

CXX
#c++编译程序,默认"g++"
CXXFLAGS
#CXX参数,默认空

CPP
#c程序预处理器,默认"${CC} -E"
CPPFLASG
#CPP参数,默认空

RM
#删除文件命令,默认"rm -f"

LDFLAGS
#连接器参数,默认空

自动化变量:

自动化变量出现在规则命令中,用以代替目标或依赖。

${@}
#表示所有目标
${%}
#当目标为函数库文件,代表库文件中的成员
${<}
#表示第一个依赖
${?}
#表示所有比目标新的依赖
${^}
#表示所有依赖,当依赖有重复,自动去掉重复
${+}
#表示所有依赖,不去除重复

库文件

库文件就是对源代码编译所生成的中间文件的打包文件。

生成库文件格式如下:

LibName(a.o):a.o
    ar cr LibName a.o
#上面代表使用ar命令打包生成文件名为LibName的库文件,其成员为a.o

定义变量:

变量定义与shell中变量定义略有不同,不能使用引号。但使用变量依然用${val}的方式。

与c/c++宏类似,变量在运行中是完全替换的方式。

变量定义有4中方式:

=   :最后决定的赋值。 在Makefile中会展开扫描其他定义,在其他定义完成后才会决定左侧真正的值。因此它可以使用后面定义的值。

foo = ${bar}
bar = ${ugh}
ugh = Huh?
#foo的值为"Huh?"

:=  :立即赋值。在Makefile中会立即给予其值,所以它不能使用后面定义的值。

bar = abc.c
foo := ${bar}
bar = def.c

#foo 的值为"abc.c"

?=  :选择赋值。Makefile会判断左侧是否被定义过,若没有被定义则使用右值。

bar = abc.c
foo ?= def.c

#此时foo依然为 "abc.c"

+=  :追加赋值。Makefile会将右侧字符串追加到左侧

注意:定义变量后面不要加注释!因为这样会将空格也算入字符串中!

dir := /foo/bar    #在bar后的空格也会存入dir变量中!

目标变量:

目标变量的作用范围仅仅在当前目标规则中,类似于c/c++中的局部变量一样。

规则是在定义一般变量的基础上加上目标头即可。

prog : CFLAGS := -g
prog : prog.o foo.o bar.o
    ${CC} ${CFLAGS} prog.o foo.o bar.o

#无论外部CFLAGS值为什么,在目标prog中一直是"-g"

同理,我们可以一次定义很多模式相同的目标变量

%.o : CFLAGS := -g
#所有以".o"结尾的目标其局部变量CFLAGS的值都为"-g"

 

多行变量:

当有些命令序列多次出现时,可以将他们打包便于以后管理

define make_a #以define 变量名做开头,命令依然要以[TAB]开头!
  gcc -c *.c
  mv *.o ../
endef #以endef做结尾

#调用方式和变量一样${make_a}

替换变量:

替换变量一部分字符使用格式:${var:a=b}(代表将var变量中"a"结尾替换为"b")

foo := a.o b.o c.o
bar :=${foo:.o=.c}
#此时bar就为"a.c b.c c.c"

foo := a.o b.o c.o
bar :=${foo:%.o=%.c}
#仅将foo中满足格式%.o替换为.c结尾
#此时bar就为"a.c b.c c.c"

 条件判断

条件判断可以比较变量之间以及变量和常量之间的逻辑关系

需要注意的是:条件判断参数不要用自动化变量,因为make在读取Makefile时就会得出判断真假,而自动化变量是运行时才有的。如同c/c++宏条件判断一样

 1 ifeq(arg1,arg2)#比较arg1和arg2是否相同
 2 ......
 3 else
 4 .......
 5 endif
 6 
 7 ifneq(arg1,arg2)#比较arg1和arg2是否不同
 8 ......
 9 else
10 .......
11 endif
12 
13 ifdef arg #判断变量arg是否非空,也就是是否有值
14 ......
15 else
16 .....
17 endif
18 
19 ifndef arg #判断变量arg是否为空,也就是是否无值
20 ......
21 else
22 .....
23 endif

函数

关于Makefile自带函数参考文档:http://blog.csdn.net/haoel/article/details/2894

$(function arg1,arg2,...)
#函数名与参数用空格分离,参数间用逗号分隔

make命令

默认目标名

在make中有一些默认大家都遵守的目标命名方式:

all:这是所有目标的目标,其他目标都是它的依赖,这样可以编译所有目标。

clean:清理被make创建的文件

install:安装已经编译好的程序,就是把可执行文件拷贝到指定目录下。对于Linux而言,站在用户角度,拷贝到:/usr/local/bin

print:列出改变过的源文件

tar:打包源代码

dist:创建一个源代码的压缩文件

TAGS:更新所有目标,以备完全编译

check/test:测试Makefile

检查规则:

#只打印命令不执行
-n
--just-print
--dry-run
--recon

#更新目标文件时间但不更改目标文件内容
-t
--touch

#寻找目标
-q
--question

#指定编译依赖于文件File的目标,配合-n来查看相关目标
-W File
--what-if=File
--assume-new=File
--new-file=File

常用命令:

#完全编译
-B
--always-make

#输出调试信息
--debug
-d#输出所有调试信息

#输出环境变量值覆盖Makefile中变量值
-e
--environment-overrides

#执行时忽略所有错误
-i
--ignore-errors

#制定运行Makefile目录Dir
-I Dir
--include-dir=Dir

#如果某个规则出错,则跳出此规则继续运行其他规则
-k
--keep-going

#运行时不输出命令
-s
--silent
--quiet

隐含规则

对汇编和汇编预处理的隐含规则:

对于"*.o"的目标,若没有明确说明其依赖和命令,自动推导其依赖文件为"*.s",默认编译器为"as",命令为"${AS} -c ${ASFLAGS}"

对于"*.s"的目标,若没有明确说明其依赖和命令,自动推导其依赖文件为"*.S",默认编译器为"cpp",命令为"${AS} -c ${ASFLAGS}"

对C程序的隐含规则:

对于"*.o"的目标,若没有明确说明其依赖和命令,自动推导其依赖文件为"*.c",命令为"${CC} -c ${CPPFLAGS} ${CFLAGS}"

对C++程序的隐含规则:

对于"*.o"的目标,若没有明确说明其依赖和命令,自动推导其依赖文件为"*.cc"或"*.C",命令为"${CXX} -c ${CPPFLAGS} ${CFLAGS}"

模式规则

模式规则中使用"%"来达到规范模式的目的,"%"代表至少有一个字符。

通过与目标一同使用,便可得出整个规则列表,例如:

%.o:%.c
#说明了将.c结尾的依赖文件编译为.o结尾的目标文件
#当依赖文件为a.c 时,目标文件就必然为a.o

 

转载于:https://www.cnblogs.com/KcMeterCEC/p/5380619.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值