GNU make规则的命令④书写命令

命令回显

  通常, make 在执行命令行之前会把要执行的命令行输出到标准输出设备。我们称之为“回显”,就好像我们在 shell 环境下输入命令执行时一样。

  如果规则的命令行以字符“ @”开始,则 make 在执行这个命令时就不会回显这个将要被执行的命令。

  如果使用make的命令行参数“ -n”或“ --just-print”,那么make执行时只显示所要执行的命令,但不会真正的去执行这些命令。其中也包括了使用“ @”字符开始的命令。

  make参数“ -s”或“ --slient”则是禁止所有执行命令的显示,就好像所有的命令行均使用“ @”开始一样。在Makefile中使用没有依赖的特殊目标“ .SILENT”也可以禁止命令的回显,但是它不如使用“ @”来的灵活。因此在书写Makefile时,我们推荐使用“ @”来控制命令的回显。

命令的执行

  规则中,当目标需要被重建时。此规则所定义的命令将会被执行,如果是多行命令,那么每一行命令将在一个独立的子 shell 进程中被执行(就是说,每一行命令的执行是在一个独立的 shell 进城中完成)。因此,多行命令之间的执行是相互独立的,相互之间不存在依赖(多条命令行的执行为多个相互独立的进程)。

  在 Makefile 中书写在同一行中的多个命令属于一个完整的 shell 命令行,书写在独立行的一条命令是一个独立的 shell 命令行。因此:在一个规则的命令中,命令行“ cd”改变目录不会对其后的命令的执行产生影响。就是说其后的命令执行的工作目录不会是之前使用“ cd”进入的那个目录。如果要实现这个目的, 就不能把“ cd”和其后的命令放在两行来书写。而应该把这两条命令写在一行上,用分号分隔。这样它们才是一个完整的 shell 命令行。如:

  foo : bar/lose

    cd bar; gobble lose > ../foo

  如果希望把一个完整的 shell 命令行书写在多行上,需要使用反斜杠( \)来对处于多行的命令进行连接,表示他们是一个完整的 shell 命令行。

并发执行命令

  GNU make 支持同时执行多条命令。通常情况下,同一时刻只有一个命令在执行,下一个命令只有在当前命令执行完成之后才能够开始执行。不过可以通过 make 的命令行选项“ -j”或者“ --job”来告诉 make 在同一时刻可以允许多条命令同时被执行(注意,在 MS-DOS 中此选项无效,因为它是单任务操作系统)。

命令执行的错误

  一些情况下,规则中一个命令的执行失败并不代表规则执行的错误。例如我们使用“ mkdir”命令来确保存在一个目录。当此目录不存在使我们就建立这个目录,当目录存在时那么“ mkdir”就会执行失败。其实我们并不希望 mkdir 在执行失败后终止规则的执行。为了忽略一些无关命令执行失败的情况,我们可以在命令之前加一个减号“ -”(在[Tab]字符之后),来告诉 make 忽略此命令的执行失败。命令中的“ -”号会在 shell解析并执行此命令之前被去掉, shell 所解释的只是纯粹的命令,“ -”字符是由 make来处理的。

中断make的执行

  make 在执行命令时如果收到一个致命信号(终止 make),那么 make 将会删除此过程中已经重建的那些规则的目标文件。其依据是此目标文件的当前时间戳和 make 开始执行时此文件的时间戳是否相同。删除这个目标文件的目的是为了确保下一次 make 时目标文件能够被正确重建。假设正在编译时键入“ Ctrl-c”,此时编译器已经开始写文件“ foo.o”,但是“ Ctrl-c”产生的信号关闭了编译器。这种情况下文件“ foo.o”可能是不完整的,但这个内容不完整的“ foo.o”文件的时间戳比源程序‘ foo.c’的时间戳新。如果在 make 收到终止信号后不删除文件“ foo.o”而直接退出,那么下次执行make 时此文件被认为已是最新的而不会去重建它。最后在链接生成终极目标时由于某一个.o 文件的不完整,可能出现一堆令人难以理解的错误信息,或者产生了一个不正确的终极目标。

make的递归执行

  make 的递归过程指的是:在 Makefile 中使用“ make”作为一个命令来执行本身或者其它 makefile 文件的过程。递归调用在一个存在有多级子目录的项目中非常有用。例如,当前目录下存在一个“ subdir”子目录,在这个子目录中有描述此目录编译规则的 makefile 文件,在执行 make 时需要从上层目录(当前目录)开始并完成它所有子目录的编译。那么在当前目录下可以使用这样一个规则来实现对这个子目录的编译:

  subsystem:

    cd subdir && $(MAKE)

  其等价于规则:

  subsystem:

    $(MAKE) -C subdir

  第一个规则命令的意思是:进入子目录,然后在子目录下执行make。第二个规则使用了make的“ -C”选项,同样是首先进入子目录而后再执行make。

变量与递归

  在 make 的递归执行过程中,上层 make 可以明确指定将一些变量的定义通过环境变量的方式传递给子 make 过程。没有明确指定需要传递的变量,上层 make 不会将其所执行的 Makefile 中定义的变量传递给子 make 过程。使用环境变量传递上层所定义的变量时,上层所传递给子 make 过程的变量定义不会覆盖子 make 过程所执行makefile 文件中的同名变量定义。

  如果子make过程所执行Makefile中存在同名变量定义,则上层传递的变量定义不会覆盖子Makefile中定义的值。就是说如果上层make传递的变量和子make所执行的Makefile中存在重复的变量定义,则以子Makefile中的变量定义为准。除非使用make的“ -e”选项。

  上层 make 过程要将所执行的 Makefile 中的变量传递给子 make 过程,需要明确地指出。在 GNU make 中,实现此功能的指示符是“ export”。当一个变量使用“ export”进行声明后,变量和它的值将被加入到当前工作的环境变量中,以后在 make 执行的所有规则的命令都可以使用这个变量。而当没有使用指示符“ export”对任何变量进行声明的情况下,上层 make 只将那些已经初始化的环境变量(在执行 make 之前已经存在的环境变量)和使用命令行指定的变量(如命令“ makeCFLAGS +=-g”或者“ make –e CFLAGS +=-g”)传递给子 make 程序,通常这些变量由字符、数字和下划线组成。需要注意的是:有些 shell 不能处理那些名字中包含除字母、数字、下划线以外的其他字符的变量。

定义命令包

  书写Makefile时,可能有多个规则会使用相同的一组命令。就像c语言程序中需要经常使用到函数“ printf”。这时我们就会想能不能将这样一组命令进行类似c语言函数一样的封装,以后在我们需要用到的地方可以通过它的名字( c语言中的函数名)来对这一组命令进行引用。这样就可减少重复工作,提高了效率。在GNU make中,可以使用指示符“ define”来完成这个功能(关于指示符“ define”可参考 6.8 多行定义 一节)。通过“ define”来定义这样一组命令,同时用一个变量(作为一个变量,不能和Makefile中其它常规的变量命名出现冲突)来代表这一组命令。通常我们把使用“ define”定义的一组命令称为一个命令包。定义一个命令包的语法以“ define”开始,以“ endef”结束,例如:

  define run-yacc

  yacc $(firstword $^)

  mv y.tab.c [email protected]

  endef

  这里,“ run-yacc”是这个命令包的名字。在“ define”和“ endef”之间的命令就是命令包的主体。需要说明的是:使用“ define”定义的命令包中,命令体中变量和函数的引用不会展开。命令体中所有的内容包括“ $”、“(”、“)”等都是变量“ run-yacc”的定义。

空命令

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

《完》

时间: 2024-10-07 17:20:49

GNU make规则的命令④书写命令的相关文章

很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序

很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用make更新函数库文件 后序 近期在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出来,方便学习. 后记,看完发现这篇文章和<Linux环境下的C编程指南>

Linux makefile教程之书写命令四[转]

书写命令———— 每 条规则中的命令和操作系统Shell的命令行是一致的.make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟 在依赖规则后面的分号后的.在命令行之间中的空格或是空行会被忽略,但是如果该空格或空行是以Tab键开头的,那么make会认为其是一个空命令. 我们在UNIX下可能会使用不同的Shell,但是make的命令默认是被“/bin/sh”——UNIX的标准Shell解释执行的.除非你特别指定一个其它的Shell.Makefile中,“#”是

Makefile文件(四)_书写命令

变量说明: [email protected]       --->      目标文件 $^       --->       所有的依赖文件 $<       --->       第一个依赖文件 一.显示命令 @echo 正在编译xx模块...... 当make执行时,会输出"正在编译xx模块......",但不会输出命令 echo 正在编译xx模块...... make将输出:echo 正在编译xx模块......  正在编译xx模块...... 说明:

电源管理ACPI、及APM、GNU/Linux系统下的对应命令使用

/*********************************************************************  * Author  : Samson  * Date    : 05/19/2014  * Test platform:  *              Mint 15-3.8.13.13  *              GNU bash, version 4.2.45  * ***************************************

setfacl命令--Linux命令应用大词典729个命令解读

内容来源于人民邮电出版社<Linux命令应用大词典> 讲述729个命令,1935个例子 学习Linux系统的参考书.案头书,遇到不懂的命令或命令选项一查即可 争取每天都发布内容 本文出自 "airfish2000" 博客,更多命令查看博客: http://airfish2000.blog.51cto.com/10829608/1894364 setfacl命令 使用setfacl命令可以设置文件或目录的ACL. 命令语法: setfacl [选项] [目录|文件] 命令中各

命令管理命令(一)

命令管理命令:type,man,help,which,whereis,whatis,file,info 1.1.type 功能:显示指定命令的类型 命令类型有如下情形: alias 别名 keyword 关键字,Shell保留字 function 函数,Shell函数 builtin 内建命令,Shell内建命令 file 文件,磁盘文件,外部命令 unfound 没有找到 常用选项: -a:显示所有类型 -p:外部命令信息,相当于which -f:shell函数信息 -t:指定类型信息 [[e

man命令--Linux命令应用大词典729个命令解读

内容来源于人民邮电出版社<Linux命令应用大词典> 讲述729个命令,1935个例子 学习Linux系统的参考书.案头书,遇到不懂的命令或命令选项一查即可 争取每天都发布内容 本文出自 "airfish2000" 博客,更多命令查看博客: http://airfish2000.blog.51cto.com/10829608/1881635 man命令 使用man命令可以格式化并显示在线的手册页.man会列出一份完整的说明,其内容包括命令语法.各选项的意义以及相关命令等.

(001) Linux命令行命令之ls

十年运维系列之基础篇 - Linux 作者:曾林 联系:[email protected] 网站:www.jplatformx.com 版权:文章未经同意请勿转载 一.引言 一般情况下,Linux下的命令本身都不复杂,毕竟Linux沿袭地是Unix的哲学文化,所谓Less is more.Linux下命令真正难地是命令中的选项和参数.下面,让我们来大致了解一下Linux下大部分的命令是如何工作的.通常,命令后面都是跟一个或多个选项,带有不同选项的命令其功能也不一样.此外,命令后面还会跟一个或多个

Linux常用命令总结——命令基础

有人感觉Linux命令行操作是件非常神秘和高难度的事,其实并不然,只要我们静下心来了解一下Linux命令行下操作的相关基础知识,就会发现命令行操作并没有想象的那么难.命令行操作的特点可以用四个字概括"简单高效".在图形界面下需要点几十次鼠标的工作只需要一两条命令即可完成.我们在学习具体命令之前,先要掌握命令的基础知识,掌握了这些,学习命令就是件非常简单的事了. Linux命令使用格式: 命令  [选项]  [参数] 命令.选项.参数之间使用空格分隔. 选项:用于调节命令的具体功能. 短