命令回显

  通常, 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 $@

  endef

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

空命令

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

《完》

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

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

    很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用m ...

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

    书写命令———— 每 条规则中的命令和操作系统Shell的命令行是一致的.make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟 在依赖规则后面的分号后的.在命令 ...

  3. [转] Makefile 基础 (4) —— Makefile 书写命令

    该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...

  4. centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件、目录属性 shell数组简单用法 $( ) 和${ } 和$(( )) 与 sh -n sh -x sh -v 第三十五节课

    centos   shell脚本编程1 正则  shell脚本结构  read命令  date命令的用法  shell中的逻辑判断  if 判断文件.目录属性  shell数组简单用法 $( ) 和$ ...

  5. linux管道命令grep命令参数及用法详解---附使用案例|grep

    功能说明:查找文件里符合条件的字符串. 语 法:grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>] ...

  6. Linux常用命令学习2---(文件搜索命令locate find、命令搜索命令whereis which、字符串搜索命令grep、帮助命令man)

     1.文件搜索命令:locate [文件名]    在后台数据库中按文件名搜索,搜索速度比find快,耗费资源更少    例子:locate test.txt,就会显示文件名包含 test.txt的所 ...

  7. 《The Linux Command Line》 读书笔记02 关于命令的命令

    <The Linux Command Line> 读书笔记02 关于命令的命令 命令的四种类型 type type—Indicate how a command name is inter ...

  8. 菜鸟学Linux命令:tail命令 查看日志

    tail 命令用于显示指定文件末尾内容,不指定文件时,作为输入信息进行处理. tail命令常用来查看日志文件.使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filenam ...

  9. 菜鸟学Linux命令:find命令 查找文件

    find命令是Linux下最常用的命令之一,灵活的使用find命令,你会发现查找文件变得十分简单. 命令格式 find [指定查找目录]  [查找规则(选项)]  [查找完后执行的动作] 参数规则 - ...

随机推荐

  1. 微信 小程序 drawImage wx.canvasToTempFilePath wx.saveFile 获取设备宽高 尺寸问题

    以下问题测试环境为微信开发者0.10.102800,手机端iphone6,如有不对敬谢指出. 根据我的测试,context.drawImage,在开发者工具中并不能画出来,只有预览到手机中显示. wx ...

  2. ArcGIS中的WKID

    提到坐标系统,大家多少能明白一些,但在运用时,有些朋友搞得不是非常清楚,以后专门来总结.在实地生产项目中,使用较多的2000中国大地坐标系(CGCS2000).1980西安坐标系.1954北京坐标系统 ...

  3. Kafka主要参数详解(转)

    原文档地址:http://kafka.apache.org/documentation.html ############################# System ############## ...

  4. tomcat下运行多个项目

    1. tomact下修改端口解决端口冲突 http://jingyan.baidu.com/article/9f63fb91d0f1b8c8400f0e1d.html 打开 servers下面的ser ...

  5. 经典的Java基础面试题集锦

    经典的Java基础面试题集锦,欢迎收藏和分享. 问题:如果main方法被声明为private会怎样? 答案:能正常编译,但运行的时候会提示”main方法不是public的”. 问题:Java里的传引用 ...

  6. %1$s,%2$s等的用法

    String.format(String format, Object... args)方法中:   format:格式字符串. 如:%1$s,%1$d,%2$s...                 ...

  7. 【CoreData】表之间的关联

    这次是表之间怎么进行关联,要求如下: // 建立学生与班级表之间的联系 既然是表与表之间的关联,那肯定是要先创建表: // 1.创建模型文件 (相当于一个数据库里的表) // New File ——— ...

  8. android 最简单的自定义圆点view

    首先创建一个选择器,用来判断圆点状态,可以根本自己的需求改 <selector xmlns:android="http://schemas.android.com/apk/res/an ...

  9. UEditor无法复制的解决方法

    今天终于知道UEditor不能复制的真正原因啦,还是自己一直没有仔细研究. UEditor 粘贴 Excell 中的表格时报错导致无法粘贴的解决办法 在UEditor一些版本中,如果粘贴Excell中 ...

  10. go的环境变量设置

    GOROOT go的安装路劲 如:D:\Program Files\Go GOPATH go的工作路径 GOPATH可以设置多个.存放包文件.比如你引入 "xxx"包.那么go会去 ...