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 $@
endef
这里,“ run-yacc”是这个命令包的名字。在“ define”和“ endef”之间的命令就是命令包的主体。需要说明的是:使用“ define”定义的命令包中,命令体中变量和函数的引用不会展开。命令体中所有的内容包括“ $”、“(”、“)”等都是变量“ run-yacc”的定义。
空命令
空命令行可以防止make在执行时试图为重建这个目标去查找隐含命令(包括了使用隐含规则中的命令和“ .DEFAULT”指定的命令。
《完》
GNU make规则的命令④书写命令的更多相关文章
- 很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序
很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用m ...
- Linux makefile教程之书写命令四[转]
书写命令———— 每 条规则中的命令和操作系统Shell的命令行是一致的.make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟 在依赖规则后面的分号后的.在命令 ...
- [转] Makefile 基础 (4) —— Makefile 书写命令
该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...
- centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件、目录属性 shell数组简单用法 $( ) 和${ } 和$(( )) 与 sh -n sh -x sh -v 第三十五节课
centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件.目录属性 shell数组简单用法 $( ) 和$ ...
- linux管道命令grep命令参数及用法详解---附使用案例|grep
功能说明:查找文件里符合条件的字符串. 语 法:grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>] ...
- Linux常用命令学习2---(文件搜索命令locate find、命令搜索命令whereis which、字符串搜索命令grep、帮助命令man)
1.文件搜索命令:locate [文件名] 在后台数据库中按文件名搜索,搜索速度比find快,耗费资源更少 例子:locate test.txt,就会显示文件名包含 test.txt的所 ...
- 《The Linux Command Line》 读书笔记02 关于命令的命令
<The Linux Command Line> 读书笔记02 关于命令的命令 命令的四种类型 type type—Indicate how a command name is inter ...
- 菜鸟学Linux命令:tail命令 查看日志
tail 命令用于显示指定文件末尾内容,不指定文件时,作为输入信息进行处理. tail命令常用来查看日志文件.使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filenam ...
- 菜鸟学Linux命令:find命令 查找文件
find命令是Linux下最常用的命令之一,灵活的使用find命令,你会发现查找文件变得十分简单. 命令格式 find [指定查找目录] [查找规则(选项)] [查找完后执行的动作] 参数规则 - ...
随机推荐
- EWS API 2.0读取日历信息-读取内容注意事项
采用模拟账号的方式读取日历信息,注意下日历的内容读取(Body)读取.代码如下:(采用 EWS API 2.0版本) 1.读取内容前必须设置如下属性:否则会提示:You must load or as ...
- wydomain
目标系统信息收集组件,完全模块化,脚本均可拆可并.可合可分的使用! 运行流程 利用FOFA插件获取兄弟域名,并透视获取到的子域名相关二级域名.IP信息 检查域名和兄弟域名是否存在域传送漏洞,存在就遍历 ...
- 表达式语言EL
表达式语言EL 表达式语言 EL(Expression Language,表达式语言)主要是用在JSP页面中,用来辅助我们产生无脚本的JSP页面,此处的脚本指的是JSP中的Java代码. EL的语法是 ...
- 操作系统开发系列—13.g.操作系统的系统调用 ●
在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...
- Android studio 如何查看模拟器里面的文件
1.查看SD卡里面的内容 2.看数据库
- iOS 学习 - 10下载(4) NSURLSession 会话 篇
NSURLConnection通过全局状态来管理cookies.认证信息等公共资源,这样如果遇到两个连接需要使用不同的资源配置情况时就无法解决了,但是这个问题在NSURLSession中得到了解决.N ...
- DFX 安全测试-- 告诉你什么是XSS、sql注入?POST和GET的区别....
1.用户权限测试 (1) 用户权限控制 1) 用户权限控制主要是对一些有权限控制的功能进行验证 2) 用户A才能进行的操作,B是否能够进行操作(可通过窜session,将在下面介绍) 3)只能有A条件 ...
- 在【Xamarin+Prism开发详解三:Visual studio 2017 RC初体验】中分享了Visual studio 2017RC的大致情况,同时也发现大家对新的Visual Studio很是感兴趣。于是发时间深入研究了一下Visual Studio 2017RC 是不是和微软Connect()://2016上说得一样神。
总共列出了12点,耐心点慢慢看! 1,添加了不少[代码样式]的设置项目. 通过合理的设置每个人都能写出优美的代码,而且团队项目也可以达到统一代码风格. this首选项:可以设置[字段,属性,方法,事件 ...
- .net 读写记事本文件
这是读取文件的代码 StreamReader myreader = File.OpenText(_filepath);//读取记事本文件 string s = ""; s = my ...
- Java Gradle入门指南之gretty插件(安装、命令与核心特性)
Java Web应用开发时常使用Gradle来进行项目管理,可以十分便利地解决包依赖等问题.war插件的出现,让项目部署成为一个复制粘贴的过程,那有没有办法让Java web应用的部署,就像w ...