首页 > Autools学习总结(一)

Autools学习总结(一)

一、Makefile

简介

    在编写C/C++程序的时候,我们经常需要编译并运行代码。在程序规模较小的情况下,可以简单地直接调用编译器来完成这项工作。然而,在很多情况下程序往往包括大量的代码文件,手动调用编译器变得麻烦无比。尤其要命的是,编译的时候需要考虑源文件之间的依赖情况。例如对于下面的三个文件:

文件main.c:

1 #include <xxx.h>

2 blabla

    文件xxx.h

1 declared some functions or classes

    文件xxx.cpp

1 #include <xxx.h>

2 implemented some functions or classes

    上面三个文件的依赖情况分别为:

1 main.c => xxx.h

2 xxx.cpp => xxx.h

    因此,在xxx.h文件被改变时,将导致main.cxxx.cpp都需要重新编译,而main.cxxx.cpp被改变时则只需要编译相应的文件,并执行链接操作即可(这个例子也说明了为什么.h文件不能轻易变动,可以把.h文件视为模块提供的接口,如同契约一样已经制定就不能轻易变动)。

    这个问题如何解决呢?可以不考虑依赖关系,把所有源文件重新编译——这种方式在我们编写一些玩具代码的时候的确可以,然而在一个中等规模的项目就会成为一个噩梦。。C/C++代码的编译速度本来就慢(这一点自己编译过开源代码同学应该深有体会),如果每次都彻底重新编译的话会浪费大量的时间。Make工具的产生一开始就是用来解决这一问题的(当然不限于此)。

    先上一个最简单的Make用例:

hello.c文件

1 #include <stdio.h>

2 int main()

3 {

4     printf(“hello world! ”);

5     return 0;

6 }

1 $>make hello && ./hello

2 cc hello.c     -o    hello

3 hello world

规则和命令

    Makefile允许我们定义一系列的依赖规则,并根据该依赖规则来执行相应的命令。下面是一个最简单的Makefile

Makefile文件

1 # 简单的依赖文件

2 hello: hello.c

3     gcc -o hello hello.c

    其中第零行是一行注释,同shell脚本一样,Makefile使用#来定义注释。第一行定义了一条依赖规则,冒号左边为需要生成的目标,冒号右边则为生成该目标所需要的文件。值得注意的是,规则的目标和依赖项都可以是多个文件,多个文件之间使用空格分开,形如a b: c d的规则表示目标ab均依赖于cd

    文件的第二行为一个命令。Make工具根据目标和依赖项的修改时间戳来判断是否需要执行命令来生成新的目标,即:如果目标的修改时间较所有的依赖项更新,则表明无需执行命令来重新生成目标;而如果任一依赖项的修改时间较目标的更新,则说明有必要执行命令来重新生成目标。make根据命令的程序退出状态来判断是否执行成功(0为成功,否则失败),如果执行失败则停止生成过程并报错。可以通过设定命令行前缀来改变这一过程,命令行前缀包括以下两种:

  • -make忽略该命令的执行情况,即使失败仍然继续生成

  • @make不打印该命令,通常在执行echo命令时使用该前缀

    下面是一个使用命令行前缀的示例:

1 dash:

2     -rm /some/file/not/exist

3 at:

4     @echo “hello”

    当执行make dash时,rm命令执行失败,但是make的生成目标过程不会停止,而执行make at时,将只在屏幕上打印“hello“,不会打印出echo命令的执行情况。

    在makefile中,规则后面不一定要跟一条命令,即我们可以定义一条啥事也不干的规则。而判断一条语句是规则还是命令是根据行开头是否包含TAB字符,注意,一定要是TAB字符,不能是四个空格或者其它看起来和TAB一样的东东。。这个设计被认为是Unix有史以来最糟糕的设计修补(TAOUP P358)。(幸运的是,VIM能很好地处理这一问题,在我设置了expandtab的情况下还能正确地在命令的第一列插入TAB字符。)

变量的定义和使用

    Makefile中变量的定义和使用方式如下所示:

1 dash:

2     -rm /some/file/not/exist

3 at:

4     @echo “hello”

    变量的定义非常简单,变量名和值用符号“=”分开即可,使用变量则用$(valname)的方式。在make程序解析Makefile时,会对变量进行替换。这里有一个需要注意的地方:make实际上会对Makefile扫描两次——第一次替换所有的变量,第二次才是根据规则执行命令。这意味着对于变量在多处定义时,最终替换的变量值是最后一次对变量指定的值。下面举一个例子:

Makefile文件

1 val = a

2 test:

3     echo $(val)

4 val = b

    执行make test时,显示的结果将是b而不是a。

    除了我们自定义的变量之外,make还包含了一些预定义的变量。例如,变量CC表示系统默认的C编译器(默认值为cc),因此定义编译文件的命令时通常使用的方式是$(CC) -o main $(src)而不是直接使用gcc。这一特点在后面引入Autoconf时非常有用——Autoconf检查系统的默认C编译器并设置CC变量的值,从而使得代码可以在包含不同C编译器的系统上顺利编译。完整的预定义变量可以参见make用户手册。

    在上面提到的例子中,src变量被使用了两次:作为规则的依赖项和命令的参数。为了贯彻执行DRY原则,make还定义了一种称为“自动变量”的变量,用来表示规则中的特定部分。使用自动变量时,上面的例子可以中写为如下方式:

1 src = main.c xxx.c

2 main: $(src)

3     $(CC) -o $@ $+

    其中$@$(@)的简写形式,表示规则的目标部分,而$+则表示规则的所有依赖项。相对于前面的方式,现在的Makefile是不是干净了一些呢?完整的自动变量列表同样包括在make用户手册中。

SUFFIXESPHONY

    假设我们的项目中只有一个文件main.c,那么Makefile很简单:

1 main : main.o

2     gcc -o main main.o

3 main.o: main.c

4     gcc -c main.c

    可是在有100个甚至更多.c文件的情况下,需要对每一个.c文件进行编译,就不得不写很多次如下的代码:

1 xxx.o: xxx.c

2     gcc -c xxx.c

    幸运的是,make提供了后缀匹配功能,从而使用如下代码就可一完成上述功能:

1 .c.o:

2     gcc -c $<

    类似的规则成为后缀规则,make在解析Makefile时将扫描Makefile文件所在目录下的匹配文件,并执行相应的命令。然而这里存在一个问题,即可能存在一个名为“.c.o“的文件,make如何判断这条规则是一条普通的规则还是后缀规则呢?这里就要用到特殊的目标SUFFIXES了:

1 .SUFFIXES: .c .o

    这条规则告诉make将目标为.c.o的规则视为后缀规则,而非名为.c.o的文件。

    与此类似的另一个特殊目标是PHONY,用来定义一些“伪目标”。在Makefile中,我们除了定义一些需要生成的文件外,还可能会执行一些操作,而这些操作是不会生成目标文件的。例如,目前广泛使用make clean清理临时文件,make install用来安装程序。我们需要定义一些没有依赖项的规则:

1 clean:

2     rm *.o

    当执行make clean时,make将查找当前目录,发现没有名为clean的文件,同时该文件也不需要任何依赖项,这种情况下make将总是执行规则对应的命令。然而,如果不幸地在当前目录下刚好存在一个名为clean的文件呢?这时make发现该文件没有任何依赖项,从而认为该目标已是最新的,因此将跳过命令执行阶段。

    特殊目标PHONY就是用来解决这一问题的:

1 .PHONY: clean

    以上规则将告知make程序,clean目标为一个伪目标,从而make程序无需再去检查目录下clean文件的存在与否,而总是执行clean目标所对应的命令。

    (未完待续。。。)

 



转载于:https://www.cnblogs.com/zyobi/archive/2010/10/31/1865703.html

更多相关:

  • 本文来自 运维人生 ,作者:fly是个稻草人链接:http://www.ywadmin.com/?id=76误删除linux系统文件了?不用急,本文将给你一个恢复linux文件的方法,让你轻松应对运维中的各风险问题。方法总比问题多~说在前面的话针对日常维护操作,难免会出现文件误删除的操作。大家熟知linux文件系统不同win有回收...

  • 原文来自SecIN社区—作者:WiHat0x00 什么是WebShell渗透测试工作的一个阶段性目标就是获取目标服务器的操作控制权限,于是WebShell便应运而生。Webshell中的WEB就是web服务,shell就是管理攻击者与操作系统之间的交互。Webshell被称为攻击者通过Web服务器端口对Web服务器有一定的操作权限,而...

  • 断电时文件系统发生了什么?硬盘又发生了什么?下一次开机时写到一半的文件在系统层面还在吗?在底层还在吗?更进一步的, 文件系统如何保证事务性, 会不会存在某种极端情况导致例如最后几个bit还没写完, 文件系统却认为它成功了的情况?回答不限任何文件系统,谢谢!下面是「北极」的回复分享断电的一瞬间,很多事情是无法确定的:1. 你无法确定...

  • 接到项目需求。需要搭建一个页面进行交互,慢慢来b (2).jpg使用python django框架进行页面的搭建在项目文件下打开窗口,输入命令;django-admin startproject helloword#在文件helloword/helloword/创建view.py在view.py文件中输入以代码from django....

  • 常见的错误集合解决方案(一)No.1提示错误'Microsoft.VC90.CRT,version="9.0.21022.8"把Microsoft.NET Framework 3.5.1下面的全部勾选上。No.2解决Qt Designer设计的图标但是VS生成不显示问题描述:在Qt designer中为菜单栏和工具栏设计的图标,但是...

  • 比较详细的教程参见以前的博文 http://blog.csdn.net/tao_627/article/details/60957521 这里只给出简略步骤,没有截图,自始至终使用root操作 目前最新的源码地址 ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/...

  • 继续翻译 5.7.4 The `--print-directory' Option ------------------------------------If you use several levels of recursive `make' invocations, the `-w' or `--print-directory...

  • 1、 make 时钟错误 make: Warning: File `Makefile' has modification time 4.6e+07 s in the future make: 警告:检测到时钟错误。您的创建可能是不完整的。 解决方法:运行下列命令再makefind . -type f -exec touch {} ;...

  • Activiti 规则任务(businessRuleTask) 作者:邓家海 目前国内研究Activiti规则任务businessRuleTask)的文章在网上应该不超出3篇 小觑夜漫酒作伴,破晓黎明当笑言 前言: 最近一直在研究Activiti工作流的自动化,方便日后实现办公自动化奠下基础。然后查了相关资料发现Activity里面有...

  • 用用iptables-ADC 来指定链的规则,-A添加 -D删除 -C 修改iptables- [RI] chain rule num rule-specification[option]用iptables- RI 通过规则的顺序指定iptables-D chain rule num[option]删除指定规则iptables-[L...