Makefile学习笔记——4.规则的命令

1 前言

在前篇Makefile规则中,描述了Makefile是为了生成一个文件,该文件称为目标,而用什么命令生成这个目标,就是规则

1.1 shell命令

所以在Makefile中,规则一般都由一些shell命令行组成。规则中除了第一条命令可以紧着着依赖列表之后(使用分隔符隔开),其他的都是一行一条命令,以[Tab]字符开头,多行命令之间可以添加空行和注释

1.2 注释

执行所使用的shell决定了规则中命令和语法的处理机制,使用默认的”/bin/sh“命令行中出现的”#“是注释

2 命令回显

在make执行命令行之前,会把执行的命令行输出到标准输出设备上,即"回显",但是如果规则的命令以"@"符号开始,则make在执行命令时不会回显此命令,常见用法是使用"echo"命令

@echo 输出日志信息......
  1. 如果没有"@",那么输出的信息是
echo编译XXX模块...... 
编译XXX模块......

由于使用了"@",所以只会输出"编译XXX模块......"

  1. 如果使用参数"-n"或"-just print",那么执行时只会回显,而不执行命令(包括使用"@"开头的命令)
  2. 使用参数"-s"或"--slient"则会禁止所有执行命令的显示(等于所有命令使用"@")开头

3 命令的执行

在Makefile中,当目标需要重建时,对应规则所定义的命令将会被执行,如果是多行命令,那么每一行都在一个独立的子shell进程中执行,即多行命令相互独立,相互不存在依赖

  1. 由于每一行shell独立,所以命令行"cd"不会影响后面的命令执行,所以如果需要使用"cd"功能,那么命令就不能分行写,需要写在一行,用分号隔开,例如
foo : bar/lose
    cd bar; gobble lose > ../foo
  1. 如果实在要分行,那么用反斜线连接,例如
foo : bar/lose cd bar; \
    gobble lose > ../foo
  1. make对所有的规则命令解析使用环境变量"shell"所指定的那个程序,默认程序是"/bin/sh"

4 并发执行命令

make支持同时多命令的执行,但是通常同一时刻只有一条命令执行,不过可以通过"-j"或者"-job"来实现多命令同时执行。如果"-j"之后存在一个整数,那么表示同一时刻允许执行的命令数目(即"job slots"),如果没有数字,那么表示使用默认的"job slots",默认值为1(即串行)

并行的缺点

  1. 多命令同时执行和输出信息,错误不好定位
  2. 对应标准输入设备,同一时刻只能有一个进程访问,所以其他进程的标准输入流将无效,这话导致错误
  3. 导致make的递归调用出现问题(见7.递归执行)

在make执行过程中,如果某条命令执行失败且产生的错误不可忽略,那么其他重建同一目标的命令将终止。如果make没有使用"-k"或"--keep-going",make将停止执行且退出

make在执行时,如果由于某原因被中止,如果它的子进程正在运行,那么make将等所有子进程结束之后才退出

4.1 负荷限制

在执行make时,如果系统处于重负荷状态下,则需要减轻执行make时的负荷。通过使用"-l"可以限制make当前任务的数量。"-l"或"--max-load"选项一般跟一个浮点数
例如

-l 2.5

是指系统平均负荷高于2.5时,不再启动任何执行命令的子任务,不带浮点的"-l"用于取消前面"-l"给定的负荷限制

在每次make执行一项任务之前,make会检查当前系统的负荷,如果当前系统的负荷高于"-l"设定的值,那么make就不会在其他任务完成前启动任务

5 命令执行的错误

通常命令执行结束后,make会检查命令执行的返回状态,如果返回成功,就启动另外一个子shell来执行命令。如果某一个规则命令出错(返回非0),make会放弃当前规则的后续执行,也可能终止所有规则执行

一般情况,某一个命令的失败不代表规则执行错误,对于一些失败并不影响的命令,可以通过在命令前加"-"减号告诉make忽略执行失败的情况。

减号会在shell解析并执行之前被去掉,它是有make处理的,例如常见的

clean:
    -rm *.o

即使执行"rm"失败,也需要后续执行

当使用"-"来忽略命令执行的错误时,make会始终当做命令成功,但是会给出错误提示。使用"-k"或者"--keep-going"时,make错误不会立刻退出,这一般用在编译时确定被修改后的文件都是否能被编译通过

6 中断make的执行

如果在make执行命令时收到一个致命信号,那么make将会删除此过程中已经重建的那些规则目标。删除的原因是为了保证下一次make时目标文件能够被正确重建(因为那些已经重建的文件时间戳会更新,但是不能保证一定正确)

不过,如果目标文件是特殊目标“.PRECIOUS”的依赖,那么可以不被删除,不被删除的原因有

  1. 目标的重建动作是一个原子的不可被中断的过程;
  2. 目标文件的存在仅仅为了记录其重建时间(不关心其内容无)
  3. 这个目标文件必须一直存在来防止其它麻烦

7 递归执行

make的递归执行是:在Makefile中使用"make“命令执行本身或其他Makefile文件的过程,例如递归一个目录

subsystem:
    cd subdir && $(MAKE)

$(MAKE)是对变量"MAKE"的引用,改命令的意思是:进入子目录,然后执行make

7.1 CURDIR变量

在make递归调用时,变量"CURDIR"表示make的工作目录,当使用"-C"选项进入一个子目录后,此变量会被重新赋值,如果Makefile中没有对此变量显示赋值,那么它代表make的工作目录

7.2 MAKE变量

变量"make"的值是"make”,如果是"/bin/make",那么之前的递归命令等于"cd subdir&&/bin/make",如果使用其他版本的make程序,那么"MAKE"的值会改变

注意:当使用变量"MAKE"时,标志"-t","-n",-q"都不起作用

7.3 变量和递归

在make的递归过程中,上层make可以指明一些变量通过环境变量传递给子make,没有指明的变量将不会传递。使用环境变量传递上层定义的变量时,上层传递的变量不会覆盖子make过程中Makefile文件中的同名变量(同名变量以子Makefile变量为准)

  1. 传递使用的指示符是"export"
  2. 当一个变量用"export"声明后,变量和它的值都被加入当前工作的环境变量中,之后的make都可以使用这个变量
  3. 如果没有"export"声明,那么make只讲已经初始化的环境变量和使用命令行指定的变量传递给子make
  4. 这些变量由字符、数字和下划线组成(有些shell不能处理那些名字中包含除字母、数字、下划线以外的其他字符的变量)
  5. 特殊的变量“SHELL”和“MAKEFLAGS”,这两个变量除非使用指示符“unexport”对它们进行声明,否则默认会自动传递给所有的子make。变量“MAKEFILES”如果有值(不为空)也会被自动的传递给子make
  6. 如果"export"不带任何参数,那么此Makefile中定义的所有变量都传递给子make(新版本GNU make使用“.EXPORT_ALL_VARIABLES”代替)

8 定义命令包

在Makefile中,对于重复的命令,可以类似c语言函数一样封装,使用指示符"define"

8.1 定义

define run-yacc 
yacc $(firstword $^) 
mv y.tab.c $@ 
endef
  1. run-yacc就是命令包主体
  2. “define”和“endef”之间的命令就是命令包的主体
  3. “define”定义的命令包中,命令体中变量和函数的引用不会展开
  4. 命令体中所有的内容包括“$”、“(”、“)”等都是变量“run-yacc”的定义(类似c语言中的宏)

8.2 使用

命令包中所有命令中对其它变量的引用,在规则被执行时会被完全展开

foo.c : foo.y 
    $(run-yacc)

这里的具体含义在后续的变量相关章节中说明

9 空命令

对于只有目标文件,没有命令行的定义

target: ;

如果空命令使用独立命令行,那么必须使用[Tab]开始,所以一般不使用独立命令行

使用空命令的原因
空命令行可以防止make在执行时试图为重建这个目标去查找隐含命令(包括了使用隐含规则中的命令和“.DEFAULT”指定的命令

对于空命令最好不要指定依赖文件

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容

  • 来自陈浩的一片老文,但绝对营养。 示例工程:3 个头文件*.h,和 8 个 C 文件*.c。 初 编译过程,源文件...
    周筱鲁阅读 4,698评论 0 17
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,393评论 0 5
  • 1.前言 在Makefile中,规则描述了用什么命令生成一个文件,该文件被称为规则的目标,生成"目标"的方式就是规...
    tianyl阅读 3,603评论 0 1
  • Makefile学习笔记 学习Makefile的资料 《跟我一起写makefile》 《GUN make manu...
    crazybaoli阅读 2,959评论 0 4
  • 与人为善,与己有善。人之初始性为其善,可如今,人心难以找到它最初的样子,善良在灯红酒绿的繁华都市中更显得弥足珍贵。...
    穹涯阅读 476评论 2 2