⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 13.htm

📁 学习MAkefile相关的好资料
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<P><FONT face="Courier New">下面的这个例子中有两个目标是模式的:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; %.tab.c %.tab.h: %.y<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bison -d $&lt;</FONT></P>
<P><FONT face="Courier New">这条规则告诉make把所有的[.y]文件都以"bison -d &lt;n&gt;.y"执行,然后生成"&lt;n&gt;.tab.c"和"&lt;n&gt;.tab.h"文件。(其中,"&lt;n&gt;"表示一个任意字符串)。如果我们的执行程序"foo"依赖于文件"parse.tab.o"和"scan.o",并且文件"scan.o"依赖于文件"parse.tab.h",如果"parse.y"文件被更新了,那么根据上述的规则,"bison -d parse.y"就会被执行一次,于是,"parse.tab.o"和"scan.o"的依赖文件就齐了。(假设,"parse.tab.o"由"parse.tab.c"生成,和"scan.o"由"scan.c"生成,而"foo"由"parse.tab.o"和"scan.o"链接生成,而且foo和其[.o]文件的依赖关系也写好,那么,所有的目标都会得到满足)</FONT></P>
<P><BR><STRONG><FONT face="Courier New">3、自动化变量</FONT></STRONG></P>
<P><FONT face="Courier New">在上述的模式规则中,目标和依赖文件都是一系例的文件,那么我们如何书写一个命令来完成从不同的依赖文件生成相应的目标?因为在每一次的对模式规则的解析时,都会是不同的目标和依赖文件。</FONT></P>
<P><FONT face="Courier New">自动化变量就是完成这个功能的。在前面,我们已经对自动化变量有所提涉,相信你看到这里已对它有一个感性认识了。所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。</FONT></P>
<P><FONT face="Courier New">下面是所有的自动化变量及其说明:</FONT></P>
<P><FONT face="Courier New"><STRONG>$@</STRONG><BR>&nbsp;&nbsp;&nbsp; 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。</FONT></P>
<P><FONT face="Courier New"><STRONG>$%</STRONG><BR>&nbsp;&nbsp;&nbsp; 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。</FONT></P>
<P><FONT face="Courier New"><STRONG>$&lt;</STRONG><BR>&nbsp;&nbsp;&nbsp; 依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$&lt;"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。</FONT></P>
<P><FONT face="Courier New"><STRONG>$?</STRONG><BR>&nbsp;&nbsp;&nbsp; 所有比目标新的依赖目标的集合。以空格分隔。</FONT></P>
<P><FONT face="Courier New"><STRONG>$^</STRONG><BR>&nbsp;&nbsp;&nbsp; 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。</FONT></P>
<P><FONT face="Courier New"><STRONG>$+</STRONG><BR>&nbsp;&nbsp;&nbsp; 这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。</FONT></P>
<P><FONT face="Courier New"><STRONG>$*</STRONG> <BR>&nbsp;&nbsp; 这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$*"就是空值。</FONT></P>
<P><FONT face="Courier New">当你希望只对更新过的依赖文件进行操作时,"$?"在显式规则中很有用,例如,假设有一个函数库文件叫"lib",其由其它几个object文件更新。那么把object文件打包的比较有效率的Makefile规则是:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; lib : foo.o bar.o lose.o win.o<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ar r lib $?</FONT></P>
<P><FONT face="Courier New">在上述所列出来的自动量变量中。四个变量($@、$&lt;、$%、$*)在扩展时只会有一个文件,而另三个的值是一个文件列表。这七个自动化变量还可以取得文件的目录名或是在当前目录下的符合模式的文件名,只需要搭配上"D"或"F"字样。这是GNU make中老版本的特性,在新版本中,我们使用函数"dir"或"notdir"就可以做到了。"D"的含义就是Directory,就是目录,"F"的含义就是File,就是文件。</FONT></P>
<P><FONT face="Courier New">下面是对于上面的七个变量分别加上"D"或是"F"的含义:</FONT></P>
<P><FONT face="Courier New"><STRONG>$(@D)</STRONG><BR>&nbsp;&nbsp;&nbsp; 表示"$@"的目录部分(不以斜杠作为结尾),如果"$@"值是"dir/foo.o",那么"$(@D)"就是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。</FONT></P>
<P><FONT face="Courier New"><STRONG>$(@F)</STRONG><BR>&nbsp;&nbsp;&nbsp; 表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir $@)"。</FONT></P>
<P><FONT face="Courier New"><STRONG>"$(*D)"<BR>"$(*F)"</STRONG><BR>&nbsp;&nbsp;&nbsp; 和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,"$(*D)"返回"dir",而"$(*F)"返回"foo"</FONT></P>
<P><FONT face="Courier New"><STRONG>"$(%D)"<BR>"$(%F)"</STRONG><BR>&nbsp;&nbsp;&nbsp; 分别表示了函数包文件成员的目录部分和文件部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。</FONT></P>
<P><FONT face="Courier New"><STRONG>"$(&lt;D)"<BR>"$(&lt;F)"</STRONG><BR>&nbsp;&nbsp;&nbsp; 分别表示依赖文件的目录部分和文件部分。</FONT></P>
<P><FONT face="Courier New"><STRONG>"$(^D)"<BR>"$(^F)"</STRONG><BR>&nbsp;&nbsp;&nbsp; 分别表示所有依赖文件的目录部分和文件部分。(无相同的)</FONT></P>
<P><FONT face="Courier New"><STRONG>"$(+D)"<BR>"$(+F)"</STRONG><BR>&nbsp;&nbsp;&nbsp; 分别表示所有依赖文件的目录部分和文件部分。(可以有相同的)</FONT></P>
<P><FONT face="Courier New"><STRONG>"$(?D)"<BR>"$(?F)"</STRONG><BR>&nbsp;&nbsp;&nbsp; 分别表示被更新的依赖文件的目录部分和文件部分。</FONT></P>
<P><FONT face="Courier New">最后想提醒一下的是,对于"$&lt;",为了避免产生不必要的麻烦,我们最好给$后面的那个特定字符都加上圆括号,比如,"$(&lt;)"就要比"$&lt;"要好一些。</FONT></P>
<P><FONT face="Courier New">还得要注意的是,这些变量只使用在规则的命令中,而且一般都是"显式规则"和"静态模式规则"(参见前面"书写规则"一章)。其在隐含规则中并没有意义。</FONT></P>
<P><STRONG><FONT face="Courier New">4、模式的匹配</FONT></STRONG></P>
<P><FONT face="Courier New">一般来说,一个目标的模式有一个有前缀或是后缀的"%",或是没有前后缀,直接就是一个"%"。因为"%"代表一个或多个字符,所以在定义好了的模式中,我们把"%"所匹配的内容叫做"茎",例如"%.c"所匹配的文件"test.c"中"test"就是"茎"。因为在目标和依赖目标中同时有"%"时,依赖目标的"茎"会传给目标,当做目标中的"茎"。</FONT></P>
<P><FONT face="Courier New">当一个模式匹配包含有斜杠(实际也不经常包含)的文件时,那么在进行模式匹配时,目录部分会首先被移开,然后进行匹配,成功后,再把目录加回去。在进行"茎"的传递时,我们需要知道这个步骤。例如有一个模式"e%t",文件"src/eat"匹配于该模式,于是"src/a"就是其"茎",如果这个模式定义在依赖目标中,而被依赖于这个模式的目标中又有个模式"c%r",那么,目标就是"src/car"。("茎"被传递)</FONT></P>
<P><BR><STRONG><FONT face="Courier New">5、重载内建隐含规则</FONT></STRONG></P>
<P><FONT face="Courier New">你可以重载内建的隐含规则(或是定义一个全新的),例如你可以重新构造和内建隐含规则不同的命令,如:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; %.o : %.c<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date)</FONT></P>
<P><FONT face="Courier New">你可以取消内建的隐含规则,只要不在后面写命令就行。如:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; %.o : %.s</FONT></P>
<P><FONT face="Courier New">同样,你也可以重新定义一个全新的隐含规则,其在隐含规则中的位置取决于你在哪里写下这个规则。朝前的位置就靠前。</FONT></P>
<P><BR><STRONG><FONT face="Courier New">六、老式风格的"后缀规则"</FONT></STRONG></P>
<P><FONT face="Courier New">后缀规则是一个比较老式的定义隐含规则的方法。后缀规则会被模式规则逐步地取代。因为模式规则更强更清晰。为了和老版本的Makefile兼容,GNU make同样兼容于这些东西。后缀规则有两种方式:"双后缀"和"单后缀"。</FONT></P>
<P><FONT face="Courier New">双后缀规则定义了一对后缀:目标文件的后缀和依赖目标(源文件)的后缀。如".c.o"相当于"%o : %c"。单后缀规则只定义一个后缀,也就是源文件的后缀。如".c"相当于"% : %.c"。</FONT></P>
<P><FONT face="Courier New">后缀规则中所定义的后缀应该是make所认识的,如果一个后缀是make所认识的,那么这个规则就是单后缀规则,而如果两个连在一起的后缀都被make所认识,那就是双后缀规则。例如:".c"和".o"都是make所知道。因而,如果你定义了一个规则是".c.o"那么其就是双后缀规则,意义就是".c"是源文件的后缀,".o"是目标文件的后缀。如下示例:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; .c.o:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $&lt;</FONT></P>
<P><FONT face="Courier New">后缀规则不允许任何的依赖文件,如果有依赖文件的话,那就不是后缀规则,那些后缀统统被认为是文件名,如:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; .c.o: foo.h<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $&lt;</FONT></P>
<P><FONT face="Courier New">这个例子,就是说,文件".c.o"依赖于文件"foo.h",而不是我们想要的这样:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; %.o: %.c foo.h<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $&lt;</FONT></P>
<P><FONT face="Courier New">后缀规则中,如果没有命令,那是毫无意义的。因为他也不会移去内建的隐含规则。</FONT></P>
<P><FONT face="Courier New">而要让make知道一些特定的后缀,我们可以使用伪目标".SUFFIXES"来定义或是删除,如:</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; .SUFFIXES: .hack .win</FONT></P>
<P><FONT face="Courier New">把后缀.hack和.win加入后缀列表中的末尾。</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; .SUFFIXES:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 删除默认的后缀<BR>&nbsp;&nbsp;&nbsp; .SUFFIXES: .c .o .h&nbsp;&nbsp; # 定义自己的后缀</FONT></P>
<P><FONT face="Courier New">先清楚默认后缀,后定义自己的后缀列表。</FONT></P>
<P><FONT face="Courier New">make的参数"-r"或"-no-builtin-rules"也会使用得默认的后缀列表为空。而变量"SUFFIXE"被用来定义默认的后缀列表,你可以用".SUFFIXES"来改变后缀列表,但请不要改变变量"SUFFIXE"的值。</FONT></P>
<P><STRONG><BR><FONT face="Courier New">七、隐含规则搜索算法</FONT></STRONG></P>
<P><FONT face="Courier New">比如我们有一个目标叫 T。下面是搜索目标T的规则的算法。请注意,在下面,我们没有提到后缀规则,原因是,所有的后缀规则在Makefile被载入内存时,会被转换成模式规则。如果目标是"archive(member)"的函数库文件模式,那么这个算法会被运行两次,第一次是找目标T,如果没有找到的话,那么进入第二次,第二次会把"member"当作T来搜索。</FONT></P>
<P><FONT face="Courier New">1、把T的目录部分分离出来。叫D,而剩余部分叫N。(如:如果T是"src/foo.o",那么,D就是"src/",N就是"foo.o")</FONT></P>
<P><FONT face="Courier New">2、创建所有匹配于T或是N的模式规则列表。</FONT></P>
<P><FONT face="Courier New">3、如果在模式规则列表中有匹配所有文件的模式,如"%",那么从列表中移除其它的模式。</FONT></P>
<P><FONT face="Courier New">4、移除列表中没有命令的规则。</FONT></P>
<P><FONT face="Courier New">5、对于第一个在列表中的模式规则:<BR>&nbsp;&nbsp;&nbsp; 1)推导其"茎"S,S应该是T或是N匹配于模式中"%"非空的部分。<BR>&nbsp;&nbsp;&nbsp; 2)计算依赖文件。把依赖文件中的"%"都替换成"茎"S。如果目标模式中没有包含斜框字符,而把D加在第一个依赖文件的开头。<BR>3)测试是否所有的依赖文件都存在或是理当存在。(如果有一个文件被定义成另外一个规则的目标文件,或者是一个显式规则的依赖文件,那么这个文件就叫"理当存在")<BR>&nbsp;&nbsp;&nbsp; 4)如果所有的依赖文件存在或是理当存在,或是就没有依赖文件。那么这条规则将被采用,退出该算法。</FONT></P>
<P><FONT face="Courier New">6、如果经过第5步,没有模式规则被找到,那么就做更进一步的搜索。对于存在于列表中的第一个模式规则:<BR>&nbsp;&nbsp;&nbsp; 1)如果规则是终止规则,那就忽略它,继续下一条模式规则。<BR>2)计算依赖文件。(同第5步)<BR>3)测试所有的依赖文件是否存在或是理当存在。<BR>4)对于不存在的依赖文件,递归调用这个算法查找他是否可以被隐含规则找到。<BR>5)如果所有的依赖文件存在或是理当存在,或是就根本没有依赖文件。那么这条规则被采用,退出该算法。</FONT></P>
<P><FONT face="Courier New">7、如果没有隐含规则可以使用,查看".DEFAULT"规则,如果有,采用,把".DEFAULT"的命令给T使用。</FONT></P>
<P><FONT face="Courier New">一旦规则被找到,就会执行其相当的命令,而此时,我们的自动化变量的值才会生成。<BR></FONT></P><FONT face="Courier New">
<P align=right><STRONG><FONT face="Courier New">&lt;-</FONT></STRONG><A href="http://www.csdn.net/develop/read_article.asp?id=21025"><FONT face="Courier New" color=#0000ff><STRONG>上一页</STRONG></FONT></A><STRONG><FONT face="Courier New">&nbsp; <A href="http://www.csdn.net/Develop/Read_Article.asp?Id=21131"><FONT color=#0000ff>下一页</FONT></A>-&gt;</FONT></STRONG></P>
<P><STRONG><FONT face="Courier New">(版权所有,转载时请注明作者和出处)</FONT></STRONG></P></FONT></span>
<br />
<div style="font-size: 14px; line-height: 25px;"><strong>作者Blog:</strong><a id="ArticleContent1_ArticleContent1_AuthorBlogLink" href="http://blog.csdn.net/haoel/" target="_blank">http://blog.csdn.net/haoel/</a></div>
<div style="font-size: 14px; line-height: 25px; color:#900;"><strong>相关文章</strong></div>
<table id="ArticleContent1_ArticleContent1_RelatedArticles" cellspacing="0" border="0">
	<tr>
		<td>
    <a href="/article/29/29472.shtm">标准C++类string的Copy-On-Write技术(三)</a>
  </td>
	</tr><tr>
		<td>
    <a href="/article/29/29470.shtm">标准C++类string的Copy-On-Write技术(二)</a>
  </td>
	</tr><tr>
		<td>
    <a href="/article/29/29469.shtm">标准C++类string的Copy-On-Write技术(一)</a>
  </td>
	</tr><tr>
		<td>
    <a href="/article/23/23559.shtm">以程序的方式操纵NTFS的文件权限(下)</a>
  </td>
	</tr><tr>
		<td>
    <a href="/article/23/23558.shtm">以程序的方式操纵NTFS的文件权限(中)</a>
  </td>
	</tr>
</table>
</td>
              </tr>
            </table>
            <a name="#Comment"></a>
            <table width="100%" border="0" cellpadding="0">
              <tr>
                <td>
                  



  <table cellSpacing=0 cellPadding=0 width="100%" align=center bgColor=#006699 border=0>
    <tr bgColor=#006699>
      <td id=white align=center width=556 bgColor=#006699>
      <font color=#ffffff >对该文的评论</font> </td>
    </tr>
  </table>
  
<div align=right>
<a id="CommnetList1_CommnetList1_Morelink" href="http://comment.csdn.net/Comment.aspx?c=2&amp;s=21081">【评论】</a>
<a id="CommnetList1_CommnetList1_Hyperlink1" href="javascript:window.close();">【关闭】</a>
<a href="mailto:webmaster@csdn.net">【报告bug】</a>
</div>
<br>
                </td>
              </tr>
            </table>
          </TD>
        </TR>
      </TABLE>
    </form>
    
<!-- 版权 -->
<hr width="770" noShade size="1" align="center">
<table cellspacing="0" cellpadding="0" width="500" border="0" align="center">
	<tr>
		<td valign="bottom" height="10" align="center">
			<a href="http://www.csdn.net/intro/intro.asp?id=2">网站简介</a>
			-
			<a href="http://www.csdn.net/intro/intro.asp?id=5">广告服务</a>
			-
			<a href="http://www.csdn.net/map/map.shtm">网站地图</a>
			-
			<a href="http://www.csdn.net/help/help.asp">帮助信息</a>
			-
			<a href="http://www.csdn.net/intro/intro.asp?id=2">联系方式</a>
			-
			<a href="http://www.csdn.net/english">English</a>
		</td>
		<td align="center" rowspan="3"><a href="http://www.hd315.gov.cn/beian/view.asp?bianhao=010202001032100010"><img height="48" src="/images/biaoshi.gif" width="40" border="0"></a></td>
	</tr>
	<tr>
		<td valign="top" align="center">北京百联美达美数码科技有限公司 版权所有 京ICP证020026号</td>
	</tr>
	<tr align="center">
		<td valign="top"><font face="Verdana">Copyright &copy; CSDN.NET, Inc. All Rights Reserved</font></td>
	</tr>
	<tr><td height="15"></td></tr>
</table>
<!-- /版权 -->

    <script>
      document.write("<img src=http://count.csdn.net/count/pageview1.asp?columnid=4&itemid=11 border=0 width=0 height=0>");
    </script>
  </body>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -