﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-程序人生-文章分类-makefile</title><link>http://www.cppblog.com/liu1061/category/7456.html</link><description>生活和工作都要充满激情,否则你无法体会到淋漓尽致的快乐与痛苦</description><language>zh-cn</language><lastBuildDate>Sat, 28 Jun 2008 14:45:53 GMT</lastBuildDate><pubDate>Sat, 28 Jun 2008 14:45:53 GMT</pubDate><ttl>60</ttl><item><title>makefile info!</title><link>http://www.cppblog.com/liu1061/articles/54848.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Fri, 27 Jun 2008 16:05:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54848.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54848.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54848.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54848.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54848.html</trackback:ping><description><![CDATA[<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new" align=center><a href="http://www.sudu.cn/web/host.php"><strong><img src="http://www.sudu.cn/info/upimg/suduhostad.gif" border=0></strong></a></div>
<table width="100%">
    <tbody>
        <tr>
            <td style="FONT-SIZE: 12pt; FONT-FAMILY: courier new" align=right><strong></strong></td>
        </tr>
    </tbody>
</table>
Make工程管理器<br>到此为止，读者已了解了如何在Linux下使用编辑器编写代码，如何使用Gcc把代码编译成可执行文档，还学习了如何使用Gdb来调试程式，那么，任何的工作看似已完成了，为什么还需要Make这个工程管理器呢？<br>所谓工程管理器，顾名思义，是指管理较多的文档的。读者能够试想一下，有一个上百个文档的代码构成的项目，假如其中只有一个或少数几个文档进行了修改，按照之前所学的Gcc编译工具，就不得不把这任何的文档重新编译一遍，因为编译器并不知道哪些文档是最近更新的，而只知道需要包含这些文档才能把源代码编译成可执行文档，于是，程式员就不能不再重新输入数目如此庞大的文档名以完成最后的编译工作。<br>但是，请读者仔细回想一下本书在3.1.2节<br>中所阐述的编译过程，编译过程是分为编译、汇编、链接不同阶段的，其中编译阶段仅检查语法错误连同函数和变量的声明是否正确声明了，在链接阶段则主要完成<br>是函数链接和全局变量的链接。因此，那些没有改变的源代码根本无需重新编译，而只要把他们重新链接进去就能够了。所以，人们就希望有一个工程管理器能够<br>自动识别更新了的文档代码，同时又无需重复输入冗长的命令行，这样，Make工程管理器也就应运而生了。<br>实际上，Make工程管理器也就是个&#8220;自动编译管理器&#8221;，这里的&#8220;自动&#8221;是指他能够根据文档时间戳自动发现更新过的文档而减少编译的工作量，同时，他通过读入Makefile文档的内容来执行大量的编译工作。用户只需编写一次简单的编译语句就能够了。他大大提高了实际项目的工作效率，而且几乎任何Linux下的项目编程均会涉及到他，希望读者能够认真学习本节内容。<br>3.6.1&nbsp;&nbsp;Makefile基本结构<br>Makefile是Make读入的惟一配置文档，因此本节的内容实际就是讲述Makefile的编写规则。在一个Makefile中通常包含如下内容：<br>&#183;&nbsp;&nbsp;需要由make工具创建的目标体（target），通常是目标文档或可执行文档；<br>&#183;&nbsp;&nbsp;要创建的目标体所依赖的文档（dependency_file）；<br>&#183;&nbsp;&nbsp;创建每个目标体时需要运行的命令（command）。<br>他的格式为：<br><br>target: dependency_files<br>&nbsp; &nbsp;&nbsp; &nbsp; command<br><br>例如，有两个文档分别为hello.c和hello.h，创建的目标体为hello.o，执行的命令为gcc编译指令：gcc &#8211;c hello.c，那么，对应的Makefile就能够写为：<br><br>#The simplest example<br>hello.o: hello.c hello.h<br>&nbsp; &nbsp;&nbsp; &nbsp; gcc &#8211;c hello.c &#8211;o hello.o<br><br>接着就能够使用make了。使用make的格式为：make target，这样make就会自动读入Makefile（也能够是首字母小写makefile）并执行对应target的command语句，并会找到相应的依赖文档。如下所示：<br><br>[root@localhost makefile]# make hello.o<br>gcc &#8211;c hello.c &#8211;o hello.o<br>[root@localhost makefile]# ls<br>hello.c&nbsp;&nbsp;hello.h&nbsp;&nbsp;hello.o&nbsp;&nbsp;Makefile<br><br>能够看到，Makefile执行了&#8220;hello.o&#8221;对应的命令语句，并生成了&#8220;hello.o&#8221;目标体。<br><br><img onmousewheel="return imgzoom(this);" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://book.csdn.net/BookFiles/132/03/image006.jpg');}" alt="" src="http://book.csdn.net/BookFiles/132/03/image006.jpg" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0><br>注意<br>在Makefile中的每一个command前必须有&#8220;Tab&#8221;符，否则在运行make命令时会出错。<br>3.6.2&nbsp;&nbsp;Makefile变量<br>上面示例的Makefile在实际中是几乎不存在的，因为他过于简单，仅包含两个文档和一个命令，在这种情况下完全不必要编写Makefile而只需在Shell中直接输入即可，在实际中使用的Makefile往往是包含很多的文档和命令的，这也是Makefile产生的原因。下面就可给出稍微复杂一些的Makefile进行讲解：<br><br>sunq:kang.o yul.o<br>Gcc kang.o bar.o -o myprog<br>kang.o : kang.c kang.h head.h<br>Gcc &#8211;Wall &#8211;O -g &#8211;c kang.c -o kang.o<br>yul.o : bar.c head.h<br>Gcc - Wall &#8211;O -g &#8211;c yul.c -o yul.o<br><br>在这个Makefile中有三个目标体（target），分别为sunq、kang.o和yul.o，其中第一个目标体的依赖文档就是后两个目标体。假如用户使用命令&#8220;make sunq&#8221;，则make管理器就是找到sunq目标体开始执行。<br>这时，make会自动检查相关文档的时间戳。首先，在检查&#8220;kang.o&#8221;、&#8220;yul.o&#8221;和&#8220;sunq&#8221;三个文档的时间戳之前，他会向下查找那些把&#8220;kang.o&#8221;或&#8220;yul.o&#8221;做为目标文档的时间戳。比如，&#8220;kang.o&#8221;的依赖文档为：&#8220;kang.c&#8221;、&#8220;kang.h&#8221;、&#8220;head.h&#8221;。假如这些文档中任何一个的时间戳比&#8220;kang.o&#8221;新，则命令&#8220;gcc &#8211;Wall &#8211;O -g &#8211;c kang.c -o kang.o&#8221;将会执行，从而更新文档&#8220;kang.o&#8221;。在更新完&#8220;kang.o&#8221;或&#8220;yul.o&#8221;之后，make会检查最初的&#8220;kang.o&#8221;、&#8220;yul.o&#8221;和&#8220;sunq&#8221;三个文档，只要文档&#8220;kang.o&#8221;或&#8220;yul.o&#8221;中的任比文档时间戳比&#8220;sunq&#8221;新，则第二行命令就会被执行。这样，make就完成了自动检查时间戳的工作，开始执行编译工作。这也就是Make工作的基本流程。<br>接下来，为了进一步简化编辑和维护Makefile，make允许在Makefile中创建和使用变量。变量是在Makefile中定义的名字，用来代替一个文本字符串，该文本字符串称为该变量的值。在具体需要下，这些值能够代替目标体、依赖文档、命令连同makefile文档中其他部分。在Makefile中的变量定义有两种方式：一种是递归展开方式，另一种是简单方式。<br>递归展开方式定义的变量是在引用在该变量时进行替换的，即假如该变量包含了对其他变量的应用，则在引用该变量时一次性将内嵌的变量全部展开，虽然这种类型的变量能够很好地完成用户的指令，但是他也有严重的缺点，如不能在变量后追加内容（因为语句：CFLAGS = $(CFLAGS) -O在变量扩展过程中可能导致无穷循环）。<br>为了避免上述问题，简单扩展型变量的值在定义处展开，并且只展开一次，因此他不包含任何对其他变量的引用，从而消除变量的嵌套引用。<br>递归展开方式的定义格式为：VAR=var<br>简单扩展方式的定义格式为：VAR：=var<br>Make中的变量使用均使用格式为：$(VAR)<br><br><img onmousewheel="return imgzoom(this);" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://book.csdn.net/BookFiles/132/03/image006.jpg');}" alt="" src="http://book.csdn.net/BookFiles/132/03/image006.jpg" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0><br>注意<br>变量名是不包括&#8220;:&#8221;、&#8220;#&#8221;、&#8220;=&#8221;结尾空格的任何字符串。同时，变量名中包含字母、数字连同下划线以外的情况应尽量避免，因为他们可能在将来被赋予特别的含义。<br>变量名是大小写敏感的，例如变量名&#8220;foo&#8221;、&#8220;FOO&#8221;、和&#8220;Foo&#8221;代表不同的变量。<br>推荐在makefile内部使用小写字母作为变量名，预留大写字母作为控制隐含规则参数或用户重载命令选项参数的变量名。<br><br>下面给出了上例中用变量替换修改后的Makefile，这里用OBJS代替kang.o和yul.o，用CC代替Gcc，用CFLAGS代替&#8220;-Wall -O &#8211;g&#8221;。这样在以后修改时，就能够只修改变量定义，而无需修改下面的定义实体，从而大大简化了Makefile维护的工作量。<br>经变量替换后的Makefile如下所示：<br><br>OBJS = kang.o yul.o<br>CC = Gcc<br>CFLAGS = -Wall -O -g<br>sunq : $(OBJS)<br>&nbsp; &nbsp;&nbsp; &nbsp; $(CC) $(OBJS) -o sunq<br>kang.o : kang.c kang.h<br>&nbsp; &nbsp;&nbsp; &nbsp; $(CC) $(CFLAGS) -c kang.c -o kang.o<br>yul.o : yul.c yul.h<br>&nbsp; &nbsp;&nbsp; &nbsp; $(CC) $(CFLAGS) -c yul.c -o yul.o<br><br>能够看到，此处变量是以递归展开方式定义的。<br>Makefile中的变量分为用户自定义变量、预定义变量、自动变量及环境变量。如上例中的OBJS就是用户自定义变量，自定义变量的值由用户自行设定，而预定义变量和自动变量为通常在Makefile都会出现的变量，其中部分有默认值，也就是常见的设定值，当然用户能够对其进行修改。<br>预定义变量包含了常见编译器、汇编器的名称及其编译选项。下表3.14列出了Makefile中常见预定义变量及其部分默认值。<br>表3.14&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;Makefile中常见预定义变量<br>命 令 格 式<br>含&nbsp; &nbsp; 义<br>AR<br>库文档维护程式的名称，默认值为ar<br>AS<br>汇编程式的名称，默认值为as<br>CC<br>C编译器的名称，默认值为cc<br>CPP<br>C预编译器的名称，默认值为$(CC) &#8211;E<br>CXX<br>C++编译器的名称，默认值为g++<br>FC<br>FORTRAN编译器的名称，默认值为f77<br>RM<br>文档删除程式的名称，默认值为rm &#8211;f<br>ARFLAGS<br>库文档维护程式的选项，无默认值<br>ASFLAGS<br>汇编程式的选项，无默认值<br>CFLAGS<br>C编译器的选项，无默认值<br>CPPFLAGS<br>C预编译的选项，无默认值<br>CXXFLAGS<br>C++编译器的选项，无默认值<br>FFLAGS<br>FORTRAN编译器的选项，无默认值<br><br>能够看出，上例中的CC和CFLAGS是预定义变量，其中由于CC没有采用默认值，因此，需要把&#8220;CC=Gcc&#8221;明确列出来。<br>由于常见的Gcc编译语句中通常包含了目标文档和依赖文档，而这些文档在Makefile文档中目标体的一行已有所体现，因此，为了进一步简化Makefile的编写，就引入了自动变量。自动变量通常能够代表编译语句中出现目标文档和依赖文档等，并且具备本地含义（即下一语句中出现的相同变量代表的是下一语句的目标文档和依赖文档）。下表3.15列出了Makefile中常见自动变量。<br>表3.15&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; Makefile中常见自动变量<br>命令格式<br>含&nbsp; &nbsp; 义<br>$*<br>不包含扩展名的目标文档名称<br>$+<br>任何的依赖文档，以空格分开，并以出现的先后为序，可能包含重复的依赖文档<br>$<br>第一个依赖文档的名称<br>$?<br>任何时间戳比目标文档晚的依赖文档，并以空格分开 <br>命令格式<br>含&nbsp; &nbsp; 义<br>$@<br>目标文档的完整名称<br>$^<br>任何不重复的依赖文档，以空格分开<br>$%<br>假如目标是归档成员，则该变量表示目标的归档成员名称<br><br>自动变量的书写比较难记，但是在熟练了之后会很的方便，请读者结合下例中的自动变量改写的Makefile进行记忆。<br><br>OBJS = kang.o yul.o<br>CC = Gcc<br>CFLAGS = -Wall -O -g<br>sunq : $(OBJS)<br>&nbsp; &nbsp;&nbsp; &nbsp;$(CC) $^ -o $@<br>kang.o : kang.c kang.h <br>&nbsp; &nbsp;&nbsp; &nbsp;$(CC) $(CFLAGS) -c $<br>yul.o : yul.c yul.h<br>&nbsp; &nbsp;&nbsp; &nbsp;$(CC) $(CFLAGS) -c $<br><br>另外，在Makefile中还能够使用环境变量。使用环境变量的方法相对比较简单，make在启动时会自动读取系统当前已定义了的环境变量，并且会创建和之具备相同名称和数值的变量。但是，假如用户在Makefile中定义了相同名称的变量，那么用户自定义变量将会覆盖同名的环境变量。<br>3.6.3&nbsp;&nbsp;Makefile规则<br>Makefile的规则是Make进行处理的依据，他包括了目标体、依赖文档及其之间的命令语句。一般的，Makefile中的一条语句就是个规则。在上面的例子中，都显示地指出了Makefile中的规则关系，如&#8220;$(CC) $(CFLAGS) -c $&#8221;，但为了简化Makefile的编写，make还定义了隐式规则和模式规则，下面就分别对其进行讲解。<br>1．隐式规则<br>隐含规则能够告诉make怎样使用传统的技术完成任务，这样，当用户使用他们时就不必周详指定编译的具体细节，而只需把目标文档列出即可。Make会自动搜索隐式规则目录来确定如何生成目标文档。如上例就能够写成：<br><br>OBJS = kang.o yul.o<br>CC = Gcc<br>CFLAGS = -Wall -O -g<br>sunq : $(OBJS)<br>&nbsp; &nbsp;&nbsp; &nbsp;$(CC) $^ -o $@<br><br>为什么能够省略后两句呢？因为Make的隐式规则指出：任何&#8220;.o&#8221;文档都可自动由&#8220;.c&#8221;文档使用命令&#8220;$(CC) $(CPPFLAGS) $(CFLAGS) -c file.c &#8211;o file.o&#8221;生成。这样&#8220;kang.o&#8221;和&#8220;yul.o&#8221;就会分别调用&#8220;$(CC) $(CFLAGS) -c kang.c -o kang.o&#8221;和&#8220;$(CC) $(CFLAGS) -c yul.c -o yul.o&#8221;生成。<br><br><img onmousewheel="return imgzoom(this);" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://book.csdn.net/BookFiles/132/03/image006.jpg');}" alt="" src="http://book.csdn.net/BookFiles/132/03/image006.jpg" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0><br>注意<br>在隐式规则只能查找到相同文档名的不同后缀名文档，如&#8221;kang.o&#8221;文档必须由&#8221;kang.c&#8221;文档生成。<br><br>下表3.16给出了常见的隐式规则目录：<br>表3.16&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;Makefile中常见隐式规则目录<br>对应语言后缀名<br>规&nbsp; &nbsp; 则<br>C编译：.c变为.o<br>$(CC) &#8211;c $(CPPFLAGS) $(CFLAGS)<br>C++编译：.cc或.C变为.o<br>$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)<br>Pascal编译：.p变为.o<br>$(PC) -c $(PFLAGS)<br>Fortran编译：.r变为-o<br>$(FC) -c $(FFLAGS)<br>2．模式规则<br>模式规则是用来定义相同处理规则的多个文档的。他不同于隐式规则，隐式规则仅仅能够用make默认的变量来进行操作，而模式规则还能引入用户自定义变量，为多个文档建立相同的规则，从而简化Makefile的编写。<br>模式规则的格式类似于普通规则，这个规则中的相关文档前必须用&#8220;%&#8221;标明。使用模式规则修改后的Makefile的编写如下：<br><br>OBJS = kang.o yul.o<br>CC = Gcc<br>CFLAGS = -Wall -O -g<br>sunq : $(OBJS)<br>&nbsp; &nbsp;&nbsp; &nbsp;$(CC) $^ -o $@<br>%.o : %.c<br>&nbsp; &nbsp;&nbsp; &nbsp;$(CC) $(CFLAGS) -c $<br><br>3.6.4&nbsp;&nbsp;Make使用<br>使用make管理器很简单，只需在make命令的后面键入目标名即可建立指定的目标，假如直接运行make，则建立Makefile中的第一个目标。<br>此外make更有丰富的命令行选项，能够完成各种不同的功能。下表3.17列出了常用的make命令行选项。<br>表3.17&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;make的命令行选项<br>命令格式<br>含&nbsp; &nbsp; 义<br>-C dir<br>读入指定目录下的Makefile<br>-f file<br>读入当前目录下的file文档作为Makefile<br>命令格式<br>含&nbsp; &nbsp; 义<br>-i<br>忽略任何的命令执行错误<br>-I dir<br>指定被包含的Makefile所在目录<br>-n<br>只打印要执行的命令，但不执行这些命令<br>-p<br>显示make变量数据库和隐含规则<br>-s<br>在执行命令时不显示命令<br>-w<br>假如make在执行过程中改变目录，则打印当前目录名<br>3.7&nbsp;&nbsp;使用autotools<br>在上一小节，读者已了解到了make项目管理器的强大功能。的确，Makefile能够帮助make完成他的使命，但要承认的是，编写Makefile确实不是一件轻松的事，尤其对于一个较大的项目而言更是如此。那么，有没有一种轻松的手段生成Makefile而同时又能让用户享受make的优越性呢？本节要讲的autotools系列工具正是为此而设的，他只需用户输入简单的目标文档、依赖文档、文档目录等就能够轻松地生成Makefile了，这无疑是广大用户的所希望的。另外，这些工具还能够完成系统配置信息的收集，从而能够方便地处理各种移植性的问题。也正是基于此，现在Linux上的软件研发一般都用autotools来制作Makefile，读者在后面的讲述中就会了解到。<br>3.7.1&nbsp;&nbsp;autotools使用流程<br>正如前面所言，autotools是系列工具，读者首先要确认系统是否装了以下工具（能够用which命令进行查看）。<br>&#183;&nbsp;&nbsp;aclocal<br>&#183;&nbsp;&nbsp;autoscan<br>&#183;&nbsp;&nbsp;autoconf<br>&#183;&nbsp;&nbsp;autoheader<br>&#183;&nbsp;&nbsp;automake<br>使用autotools主要就是利用各个工具的脚本文档以生成最后的Makefile。其总体流程是这样的：<br>&#183;&nbsp;&nbsp;使用aclocal生成一个&#8220;aclocal.m4&#8221;文档，该文档主要处理本地的宏定义；<br>&#183;&nbsp;&nbsp;改写&#8220;configure.scan&#8221;文档，并将其重命名为&#8220;configure.in&#8221;，并使用autoconf文档生成configure文档。<br>接下来，笔者将通过一个简单的hello.c例子带领读者熟悉autotools生成makefile的过程，由于在这过程中有涉及到较多的脚本文档，为了更清楚地了解相互之间的关系，强烈建议读者实际动手操作以体会其整个过程。<br>1．autoscan<br>他会在给定目录及其子目录树中检查源文档，若没有给出目录，就在当前目录及其子目录树中进行检查。他会搜索源文档以寻找一般的移植性问题并创建一个文档&#8220;configure.scan&#8221;，该文档就是接下来autoconf要用到的&#8220;configure.in&#8221;原型。如下所示：<br><br>[root@localhost automake]# autoscan<br>autom4te: configure.ac: no such file or directory<br>autoscan: /usr/bin/autom4te failed with exit status: 1<br>[root@localhost automake]# ls<br>autoscan.log&nbsp;&nbsp;configure.scan&nbsp;&nbsp;hello.c<br><br>如上所示，autoscan首先会尝试去读入&#8220;configure.ac&#8221;（同configure.in的配置文档）文档，此时还没有创建该配置文档，于是他会自动生成一个&#8220;configure.in&#8221;的原型文档&#8220;configure.scan&#8221;。<br>2．autoconf<br>configure.in是autoconf的脚本配置文档，他的原型文档&#8220;configure.scan&#8221;如下所示：<br><br>#&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;-*- Autoconf -*-<br># Process this file with autoconf to produce a configure script.<br>AC_PREREQ(2.59)<br>#The next one is modified by sunq<br>#AC_INIT(FULL-PACKAGE-NAME,VERSION,BUG-REPORT-ADDRESS)<br>AC_INIT(hello,1.0)<br># The next one is added by sunq<br>AM_INIT_AUTOMAKE(hello,1.0)<br>AC_CONFIG_SRCDIR([hello.c])<br>AC_CONFIG_HEADER([config.h])<br># Checks for programs.<br>AC_PROG_CC<br># Checks for libraries.<br># Checks for header files.<br># Checks for typedefs, structures, and compiler characteristics.<br># Checks for library functions.<br>AC_CONFIG_FILES([Makefile])<br>AC_OUTPUT<br><br>下面对这个脚本文档进行解释：<br>&#183;&nbsp;&nbsp;以&#8220;#&#8221;号开始的行为注释。<br>&#183;&nbsp;&nbsp;AC_PREREQ宏声明本文档需要的autoconf版本，如本例使用的版本2.59。<br>&#183; AC_INIT宏用来定义软件的名称和版本等信息，在本例中省略了BUG-REPORT-ADDRESS，一般为作者的e-mail。<br>&#183;&nbsp;&nbsp;AM_INIT_AUTOMAKE是笔者另加的，他是automake所必备的宏，也同前面相同，PACKAGE是所要产生软件套件的名称，VERSION是版本编号。<br>&#183;&nbsp;&nbsp;AC_CONFIG_SRCDIR宏用来侦测所指定的源码文档是否存在，来确定源码目录的有<br>效性。在此处为当前目录下的hello.c。<br>&#183;&nbsp;&nbsp;AC_CONFIG_HEADER宏用于生成config.h文档，以便autoheader使用。<br>&#183;&nbsp;&nbsp;AC_CONFIG_FILES宏用于生成相应的Makefile文档。<br>&#183;&nbsp;&nbsp;中间的注释间能够添加分别用户测试程式、测试函数库、测试头文档等宏定义。<br>接下来首先运行aclocal，生成一个&#8220;aclocal.m4&#8221;文档，该文档主要处理本地的宏定义。如下所示：<br><br>[root@localhost automake]# aclocal<br><br>再接着运行autoconf，生成&#8220;configure&#8221;可执行文档。如下所示：<br><br>[root@localhost automake]# autoconf<br>[root@localhost automake]# ls<br>aclocal.m4&nbsp;&nbsp;autom4te.cache&nbsp;&nbsp;autoscan.log&nbsp;&nbsp;configure&nbsp;&nbsp;configure.in&nbsp;&nbsp;hello.c<br>3．autoheader<br>接着使用autoheader命令，他负责生成config.h.in文档。该工具通常会从&#8220;acconfig.h&#8221;文档中复制用户附加的符号定义，因此此处没有附加符号定义，所以无需创建&#8220;acconfig.h&#8221;文档。如下所示：<br><br>[root@localhost automake]# autoheader<br>4．automake<br>这一步是创建Makefile很重要的一步，automake要用的脚本配置文档是Makefile.am，用户需要自己创建相应的文档。之后，automake工具转换成Makefile.in。在该例中，笔者创建的文档为Makefile.am如下所示：<br><br>AUTOMAKE_OPTIONS=foreign<br>bin_PROGRAMS= hello<br>hello_SOURCES= hello.c<br><br>下面对该脚本文档的对应项进行解释。<br>&#183;&nbsp;&nbsp;其中的AUTOMAKE_OPTIONS为配置automake的选项。由于GNU（在第1章中已有所介绍）对自己发布的软件有严格的规范，比如必须附带许可证声明文档COPYING等，否则automake执行时会报错。automake提供了三种软件等级：foreign、gnu和gnits，让用户选择采用，默认等级为gnu。在本例使用foreign等级，他只检测必须的文档。<br>&#183;&nbsp;&nbsp;bin_PROGRAMS定义要产生的执行文档名。假如要产生多个执行文档，每个文档名用空格隔开。<br>&#183;&nbsp;&nbsp;hello_SOURCES定义&#8220;hello&#8221;这个执行程式所需要的原始文档。假如&#8221;hello&#8221;这个程式是由多个原始文档所产生的，则必须把他所用到的任何原始文档都列出来，并用空格隔开。例如：若目标体&#8220;hello&#8221;需要&#8220;hello.c&#8221;、&#8220;sunq.c&#8221;、&#8220;hello.h&#8221;三个依赖文档，则定义hello_SOURCES=hello.c sunq.c hello.h。要注意的是，假如要定义多个执行文档，则对每个执行程式都要定义相应的file_SOURCES。<br>接下来能够使用automake对其生成&#8220;configure.in&#8221;文档，在这里使用选项&#8220;—adding-missing&#8221;能够让automake自动添加有一些必需的脚本文档。如下所示：<br><br>[root@localhost automake]# automake --add-missing<br>configure.in: installing './install-sh'<br>configure.in: installing './missing'<br>Makefile.am: installing 'depcomp'<br>[root@localhost automake]# ls<br>aclocal.m4&nbsp; &nbsp;&nbsp; &nbsp;autoscan.log&nbsp;&nbsp;configure.in&nbsp;&nbsp;hello.c&nbsp; &nbsp;&nbsp;&nbsp;Makefile.am&nbsp;&nbsp;missing<br>autom4te.cache&nbsp;&nbsp;configure&nbsp; &nbsp;&nbsp;&nbsp;depcomp&nbsp; &nbsp; install-sh&nbsp;&nbsp;Makefile.in&nbsp;&nbsp;config.h.in<br><br>能够看到，在automake之后就能够生成configure.in文档。<br>5．运行configure<br>在这一步中，通过运行自动配置配置文档configure，把Makefile.in变成了最终的Makefile。如下所示：<br><br>[root@localhost automake]# ./configure<br>checking for a BSD-compatible install... /usr/bin/install -c<br>checking whether build enVironment is sane... yes<br>checking for gawk... gawk<br>checking whether make sets $(MAKE)... yes<br>checking for Gcc... Gcc<br>checking for C compiler default output file name... a.out<br>checking whether the C compiler works... yes<br>checking whether we are cross compiling... no<br>checking for suffix of executables...<br>checking for suffix of object files... o<br>checking whether we are using the GNU C compiler... yes<br>checking whether Gcc accepts -g... yes<br>checking for Gcc option to accept ANSI C... none needed<br>checking for style of include used by make... GNU<br>checking dependency style of Gcc... Gcc3<br>configure: creating ./config.status<br>config.status: creating Makefile<br>config.status: executing depfiles commands<br>能够看到，在运行configure时收集了系统的信息，用户能够在configure命令中对其进行方便地配置。在./configure的自定义参数有两种，一种是开关式（--enable-XXX或--disable-XXX），另一种是开放式，即后面要填入一串字符（--with-XXX=yyyy）参数。读者能够自行尝试其使用方法。另外，读者能够查看同一目录下的&#8221;config.log&#8221;文档，以方便调试之用。<br>到此为止，makefile就能够自动生成了。回忆整个步骤，用户不再需要定制不同的规则，而只需要输入简单的文档及目录名即可，这样就大大方便了用户的使用。下面的图3.9总结了上述过程：<br><strong><img onmousewheel="return imgzoom(this);" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://book.csdn.net/BookFiles/132/03/image012.gif');}" alt="" src="http://book.csdn.net/BookFiles/132/03/image012.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0><br></strong>图3.9&nbsp;&nbsp;autotools生成Makefile流程图<br>3.7.2&nbsp;&nbsp;使用autotools所生成的Makefile<br>autotools生成的Makefile除具备普通的编译功能外，还具备以下主要功能（感兴趣的读者能够查看这个简单的hello.c程式的makefile）：<br>1．make<br>键入make默认执行&#8221;make all&#8221;命令，即目标体为all，其执行情况如下所示：<br><br>[root@localhost automake]# make<br>if Gcc<br>-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\"<br>-DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\"<br>-DVERSION=\"1.0\"&nbsp;&nbsp;-I. -I.&nbsp; &nbsp;&nbsp;&nbsp;-g -O2 -MT hello.o -MD -MP -MF<br>".deps/hello.Tpo" -c -o hello.o hello.c; \<br>then mv -f ".deps/hello.Tpo" ".deps/hello.Po"; else rm -f ".deps/hello.Tpo"; exit 1; fi<br>Gcc&nbsp;&nbsp;-g -O2&nbsp; &nbsp;-o hello&nbsp;&nbsp;hello.o<br>此时在本目录下就生成了可执行文档&#8220;hello&#8221;，运行&#8220;./hello&#8221;能出现正常结果，如下所示：<br><br>[root@localhost automake]# ./hello<br>Hello!Autoconf!<br>2．make install<br>此时，会把该程式安装到系统目录中去，如下所示：<br><br>[root@localhost automake]# make install<br>if Gcc<br>-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\"<br>-DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\"<br>-DVERSION=\"1.0\"&nbsp;&nbsp;-I. -I.&nbsp; &nbsp;&nbsp;&nbsp;-g -O2 -MT hello.o -MD -MP -MF<br>".deps/hello.Tpo" -c -o hello.o hello.c; \<br>then mv -f ".deps/hello.Tpo" ".deps/hello.Po"; else rm -f ".deps/hello.Tpo"; exit 1; fi<br>Gcc&nbsp;&nbsp;-g -O2&nbsp; &nbsp;-o hello&nbsp;&nbsp;hello.o<br>make[1]: Entering directory '/root/workplace/automake'<br>test -z "/usr/local/bin" || mkdir -p -- "/usr/local/bin"<br>&nbsp;&nbsp;/usr/bin/install -c 'hello' '/usr/local/bin/hello'<br>make[1]: Nothing to be done for 'install-data-am'.<br>make[1]: LeaVing directory '/root/workplace/automake'<br><br>此时，若直接运行hello，也能出现正确结果，如下所示：<br><br>[root@localhost automake]# hello<br>Hello!Autoconf!<br>3．make clean<br>此时，make会清除之前所编译的可执行文档及目标文档（object file, *.o），如下所示：<br><br>[root@localhost automake]# make clean<br>test -z "hello" || rm -f hello<br>rm -f *.o<br>4．make dist<br>此时，make将程式和相关的文档打包为一个压缩文档以供发布，如下所示：<br><br>[root@localhost automake]# make dist<br>[root@localhost automake]# ls hello-1.0-tar.gz<br>hello-1.0-tar.gz<br><br>可见该命令生成了一个hello-1.0-tar.gz的压缩文档。<br>由上面的讲述读者不难看出，autotools确实是软件维护和发布的必备工具，也鉴于此，如今GUN的软件一般都是由automake来制作的。<br><br><img onmousewheel="return imgzoom(this);" onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://book.csdn.net/BookFiles/132/03/image013.jpg');}" alt="" src="http://book.csdn.net/BookFiles/132/03/image013.jpg" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0><br>想一想<br>对于automake制作的这类软件，应如何安装呢？<br>3.8.3&nbsp;&nbsp;编写包含多文档的Makefile<br>1．实验目的<br>通过对包含多文档的Makefile的编写，熟悉各种形式的Makefile，并且进一步加深对Makefile中用户自定义变量、自动变量及预定义变量的理解。<br>2．实验过程<br>（1）用Vi在同一目录下编辑两个简单的Hello程式，如下所示：<br><br>#hello.c<br>#include "hello.h"<br>int main()<br>{<br>&nbsp; &nbsp;&nbsp; &nbsp; printf("Hello everyone!\n");<br>}<br>#hello.h<br>#include <br><br>（2）仍在同一目录下用Vi编辑Makefile，且不使用变量替换，用一个目标体实现（即直接将hello.c和hello.h编译成hello目标体）。然后用make验证所编写的Makefile是否正确。<br>（3）将上述Makefile使用变量替换实现。同样用make验证所编写的Makefile是否正确<br>（4）用编辑另一Makefile，取名为Makefile1，不使用变量替换，但用两个目标体实现（也就是首先将hello.c和hello.h编译为hello.o，再将hello.o编译为hello），再用make的&#8221;-f&#8221;选项验证这个Makefile1的正确性。<br>（5）将上述Makefile1使用变量替换实现。<br>3．实验步骤<br>（1）用Vi打开上述两个代码文档&#8220;hello.c&#8221;和&#8220;hello.h&#8221;。<br>（2）在shell命令行中用Gcc尝试编译，使用命令：&#8221;Gcc hello.c &#8211;o hello&#8221;，并运行hello可执行文档查看结果。<br>（3）删除此次编译的可执行文档：rm hello。<br>（4）用Vi编辑Makefile，如下所示：<br><br>hello:hello.c hello.h<br>&nbsp; &nbsp;&nbsp; &nbsp; Gcc hello.c -o hello<br><br>（5）退出保存，在shell中键入：make，查看结果。<br>（6）再次用Vi打开Makefile，用变量进行替换，如下所示：<br><br>OBJS :=hello.o<br>CC :=Gcc<br>hello:$(OBJS)<br>&nbsp; &nbsp;&nbsp; &nbsp; $(CC) $^ -o $@<br><br>（7）退出保存，在shell中键入：make，查看结果。<br>（8）用Vi编辑Makefile1，如下所示：<br><br>hello:hello.o<br>&nbsp; &nbsp;&nbsp; &nbsp; Gcc hello.o -o hello<br>hello.o:hello.c hello.h<br>&nbsp; &nbsp;&nbsp; &nbsp; Gcc -c hello.c -o hello.o<br><br>（9）退出保存，在shell中键入：make -f Makefile1，查看结果。<br>（10）再次用Vi编辑Makefile1，如下所示：<br><br>OBJS1 :=hello.o<br>OBJS2 :=hello.c hello.h<br>CC :=Gcc<br>hello:$(OBJS1)<br>&nbsp; &nbsp;&nbsp; &nbsp; $(CC) $^ -o $@<br>$(OBJS1):$(OBJS2)<br>&nbsp; &nbsp;&nbsp; &nbsp; $(CC) -c $<br><br>在这里请注意区别&#8220;$^&#8221;和&#8220;$&#8221;。<br>（11）退出保存，在shell中键入：make -f Makefile1，查看结果<br>4．实验结果<br>各种不同形式的makefile都能完成其正确的功能。<br>3.8.4&nbsp;&nbsp;使用autotools生成包含多文档的Makefile<br>1．实验目的<br>通过使用autotools生成包含多文档的Makefile，进一步掌控autotools的正确使用方法。同时，掌控Linux下安装软件的常用方法。<br>2．实验过程<br>（1）在原目录下新建文档夹auto。<br>（2）利用上例的两个代码文档&#8220;hello.c&#8221;和&#8220;hello.h&#8221;，并将他们复制到该目录下。<br>（3）使用autoscan生成configure.scan。<br>（4）编辑configure.scan，修改相关内容，并将其重命名为configure.in。<br>（5）使用aclocal生成aclocal.m4。<br>（6）使用autoconf生成configure。<br>（7）使用autoheader生成config.in.h。<br>（8）编辑Makefile.am。<br>（9）使用automake生成Makefile.in。<br>（10）使用configure生成Makefile。<br>（11）使用make生成hello可执行文档，并在当前目录下运行hello查看结果。<br>（12）使用make install将hello安装到系统目录下，并运行，查看结果。<br>（13）使用make dist生成hello压缩包。<br>（14）解压hello压缩包。<br>（15）进入解压目录。<br>（16）在该目录下安装hello软件。<br>3．实验步骤<br>（1）mkdir ./auto。<br>（2）cp hello.* ./auto（假定原先在&#8220;hello.c&#8221;文档目录下）。<br>（3）命令：autoscan。<br>（4）使用Vi编辑configure.scan为：<br><br>#&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;-*- Autoconf -*-<br># Process this file with autoconf to produce a configure script.<br><br>AC_PREREQ(2.59)<br>AC_INIT(hello, 1.0)<br>AM_INIT_AUTOMAKE(hello,1.0)<br>AC_CONFIG_SRCDIR([hello.h])<br>AC_CONFIG_HEADER([config.h])<br># Checks for programs.<br>AC_PROG_CC<br># Checks for libraries.<br># Checks for header files.<br># Checks for typedefs, structures, and compiler characteristics.<br># Checks for library functions.<br>AC_OUTPUT(Makefile)<br><br>（5）保存退出，并重命名为configure.in。<br>（6）运行：aclocal。<br>（7）运行：autoconf，并用ls查看是否生成了configure可执行文档。<br>（8）运行：autoheader。<br>（9）用Vi编辑Makefile.am文档为：<br><br>AUTOMAKE_OPTIONS=foreign<br>bin_PROGRAMS=hello<br>hello_SOURCES=hello.c hello.h<br><br>（10）运行：automake。<br>（11）运行：./configure。<br>（12）运行：make。<br>（13）运行：./hello，查看结果是否正确。<br>（14）运行：make install。<br>（15）运行：hello，查看结果是否正确。<br>（16）运行：make dist。<br>（17）在当前目录下解压hello-1.0.tar.gz：tar &#8211;zxvf hello-1.0.tar.gz。<br>（18）进入解压目录：cd ./hello-1.0。<br>（19）下面开始Linux下常见的安装软件步骤：./configure。<br>（20）运行：make。<br>（21）运行：./hello（在正常安装时这一步可省略）。<br>（22）运行：make install。<br>（23）运行：hello，查看结果是否正确。<br>4．实验结果<br>能够正确使用autotools生成Makefile，并且能够安装成功短小的Hello软件。<br>
<img src ="http://www.cppblog.com/liu1061/aggbug/54848.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-28 00:05 <a href="http://www.cppblog.com/liu1061/articles/54848.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自动生成Makefile (转)</title><link>http://www.cppblog.com/liu1061/articles/54793.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Fri, 27 Jun 2008 04:33:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54793.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54793.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54793.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54793.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54793.html</trackback:ping><description><![CDATA[<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">在test目录上新建src和include目录，源文件中src目录下，头文件在include目录。在src目录新建Makefile.am文件，编写Makefile.am，如下：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AUTOMAKE_OPTIONS = foreign</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">INCLUDES= -I../include<br>bin_PROGRAMS = main<br>radio_SOURCES = main.c \<br>keyboard.c \<br>lcd.c \<br>setup.c \<br>storage.c</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">保存退出。</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">返回test目录，再新建Makefile.am文件，编写Makefile.am,如下：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">SUBDIRS&nbsp;=&nbsp;src </div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">保存退出。</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">执行&nbsp; <br>autoscan <br>生成configure.scan文件 ，如：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">autoscan.log&nbsp; configure.scan&nbsp; include&nbsp; Makefile.am&nbsp; src</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">编辑configure.scan文件，如：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -*- Autoconf -*-<br># Process this file with autoconf to produce a configure script.</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AC_PREREQ(2.61)<br>AC_INIT(radio,1.0.0,[wenzel@163.com])<br>AM_INIT_AUTOMAKE<br>AC_CONFIG_SRCDIR([src/make.c])<br>AC_CONFIG_HEADER([config.h])</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"># Checks for programs.<br>AC_PROG_CC</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"># Checks for libraries.<br>#AC_PROG_RANLIB<br># Checks for header files.<br>AC_HEADER_DIRENT<br>AC_HEADER_STDC<br>AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h termios.h unistd.h])</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"># Checks for typedefs, structures, and compiler characteristics.<br>AC_C_CONST<br>AC_TYPE_SIZE_T</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"># Checks for library functions.<br>AC_FUNC_CLOSEDIR_VOID<br>AC_FUNC_FORK<br>AC_PROG_GCC_TRADITIONAL<br>AC_FUNC_LSTAT<br>AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK<br>AC_FUNC_MALLOC<br>AC_TYPE_SIGNAL<br>AC_CHECK_FUNCS([bzero memset strcasecmp strchr strrchr])</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">#AC_CONFIG_FILES([Makefile<br>#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src/Makefile])<br>AC_OUTPUT(Makefile src/Makefile)</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">保存退出，改名为：mv&nbsp;configure.scan&nbsp;configure.in </div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">执行：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">touch&nbsp;NEWS&nbsp;README&nbsp;AUTHORS&nbsp;ChangeLog </div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">再执行：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">autoreconf&nbsp;-fvi </div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">最后，可以执行：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">./configure</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">配置为ARM平台：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;./configure --host=arm --target=arm CC=arm-linux-gcc</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">就可以编译了，如：</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make&nbsp; <br>make&nbsp;install <br>make&nbsp;clean</div>
<div style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make distclean</div>
<img src ="http://www.cppblog.com/liu1061/aggbug/54793.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-27 12:33 <a href="http://www.cppblog.com/liu1061/articles/54793.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GNU Automake</title><link>http://www.cppblog.com/liu1061/articles/54741.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Fri, 27 Jun 2008 01:43:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54741.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54741.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54741.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54741.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54741.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Automake是一个从文件`Makefile.am'自动生成`Makefile.in' 的工具。每个`Makefile.am'基本上是一系列make的宏定义（make规则也会偶尔出现）。生成的`Makefile.in's服从GNU Makefile标准。 GNU Makefile标准文档（参见GNU编码标准中的&#8216;Makefile惯例&#8217;节）长、复杂，而且会发生改变。Au...&nbsp;&nbsp;<a href='http://www.cppblog.com/liu1061/articles/54741.html'>阅读全文</a><img src ="http://www.cppblog.com/liu1061/aggbug/54741.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-27 09:43 <a href="http://www.cppblog.com/liu1061/articles/54741.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转一个automake的教程</title><link>http://www.cppblog.com/liu1061/articles/54740.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Fri, 27 Jun 2008 01:42:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54740.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54740.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54740.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54740.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54740.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">使用 GNU autotools 改造一个软件项目<br><br>本文不是一篇规范的教程，而是用一个软件项目作为例子，演示使用 GNU autotools 进行<br>软件管理的思路和过程<br><br>目 录<br><br>&#183; 示例项目<br>&#183; 软件布局<br>&#183; Makefile 分析<br>&#183; GNU 的软件风格<br>&#183; 准备 autotools<br>&#183; 改造文件布局<br>&#183; autoscan<br>&#183; configure.ac 的基本结构<br>&#183; Makefile 文件的产生<br>&#183; 编写 Makefile.am<br>软件根目录 Makefile.am<br>src/Makefile.am<br>data/Makefile.am<br>docs/Makefile.am<br>fonts/Makefile.am<br>images/Makefile.am<br>music/Makefile.am<br>sound/Makefile.am<br><br>&#183; 运行 autotools<br>&#183; SDL 库的侦测<br>&#183; 软件使用的数据文件<br>&#183; configure 选项<br>&#183; autotools 脚本<br>&#183; 使用 configure 产生的 Makefile<br>&#183; 最终的 configure.ac 文件<br>&#183; 结束语<br><br>示例项目<br><br>这里借用了 Wei Mingzhi &lt;whistler_wmz@users.sf.net&gt; 开发的麻将游戏来进行演示，在<br>此，先对他表示感谢!<br><br>示例软件下载:<br><br><br><br>软件布局<br><br>将下载的软件包解压到一个目录<br><br>$ cd ~/work<br>$ tar xjf mahjong.tar.bz2<br><br>可以看到这是一个典型的 Windows 风格的软件项目布局，在 mahjong 目录下放着程序的<br>源码，程序运行时使用的数据文件放在子目录下面<br><br>作者还提供了一个 Makefile，一个 DOS 风格的 !play.bat 批处理文件，一个编译好的<br>mj.exe 可执行文件在 Win32 平台上运行 !play.bat 就可以直接运行程序在 Unix/<br>Linux 系统上，进入 mahjong 目录，键入 make 命令，如果一切顺利的话，将生成 mj 可<br>执行文件，然后在命令行上运行 ./mj 程序，也可以启动麻将游戏<br><br>对于一个 Windows 程序来讲，该软件布局可以说非常清晰明了但在 Unix/Linux 系统<br>上，执行 make 命令就可能遇到问题：编译找不到头文件，或者连接找不到库文件而在<br>make 成功以后，运行麻将程序必须先进入该 majiong 目录，才能执行程序如果要像<br>其他的程序一样，可以在任意目录使用，就要专门为这一个程序修改 PATH 环境变量，或<br>者再写一个启动脚本，并将它复制到 /usr/bin 这样的目录下<br><br>Makefile 分析<br><br>1 #<br>2 # Copyright (c) 2005, Wei Mingzhi. All rights reserved.<br>3 #<br>4 # Use, redistributions and modifications of this file is<br>5 # unrestricted provided the above copyright notice is<br>6 # preserved.<br>7 #<br>8<br>9 OBJ = \<br>10 bot.o config.o game.o general.o hand.o ini.o main.o \<br>11 player.o text.o tile.o util.o<br>12<br>13 HEADERS = \<br>14 bot.h game.h general.h hand.h ini.h main.h player.h \<br>15 tile.h<br>16<br>17 CC = gcc<br>18 CXX = g++<br>19<br>20 TARGET = mj<br>21<br>22 BASEFLAGS = -g3 -D_DEBUG=1<br>23 #BASEFLAGS = -s -O3<br>24<br>25 CFLAGS = ${BASEFLAGS} `sdl-config --cflags`<br>26 LDFLAGS = ${BASEFLAGS} `sdl-config --libs` -lSDL_image -lSDL_mixer -lSDL_ttf<br>27<br>28 all: ${TARGET}<br>29<br>30 ${TARGET}: ${OBJ}<br>31 ${CXX} ${LDFLAGS} -o ${TARGET} ${OBJ}<br>32<br>33 clean:<br>34 rm -f *.o ${TARGET}<br>35<br>36 distclean:<br>37 rm -f *.o ${TARGET}<br>38<br>39 %.o: %.cpp ${HEADERS}<br>40 ${CXX} ${CFLAGS} -c $&lt; -o $@<br>41<br>42 %.o: %.c ${HEADERS}<br>43 ${CC} ${CFLAGS} -c $&lt; -o $@<br><br>Makefile 很清楚：第 20 行定义 TARGET 变量为 mj，第 28 行表明 make 默认的 target<br>也就是生成 `mj'；第 22 行加入编译时的调试信息；第 2526 行使用了 sdl-config 工<br>具侦测 SDL 开发库编译链接信息，在 26 行还指明需要连接 SDL_imageSDL_mixser 和<br>SDL_ttf 库<br><br>GNU 的软件风格<br><br>一个标准的 GNU 软件，编译安装都是使用下面三个步骤:<br><br>$ ./configure<br>$ make<br>$ make install<br><br>configure 脚本运行时可以侦测系统的环境，确定软件安装目录，然后生成 Makefile 文<br>件make 调用系统中的编译器进行编译和连接make install 将软件安装到设定的目录<br><br><br>用户执行 configure 时可以通过它的命令行参数指定自己所需的编译选项，比如安装目录<br>通过 --prefix=PREFIX 设置，如果不指定，缺省情况下 PREFIX 是 /usr/local默认安<br>装时，执行文件安装到 /usr/local/bin 目录，库安装到 /usr/local/lib 目录，数据文<br>件安装到 /usr/local/share 目录<br><br>由于 GNU 的软件风格方便易用，通用性好，可移植性高，现在大多数 Unix/Linux 系统上<br>的自由软件都采用这种方式分发软件<br><br>准备 autotools<br><br>GNU autotools 主要包含三个软件： autoconf，automake 和 libtool当前流行的有新<br>旧两个版本，本例采用的是新版本，分别对应的是： autoconf 2.59， automake 1.9.6<br>和 libtool 1.5.18<br><br>很多 linux 发行版都会默认安装这几个工具本例是在 NetBSD 下进行操作，安装这几个<br>软件包是通过 pkgsrc，它们在 pkgsrc 目录为 devel/autoconf devel/automake 和<br>devel/libtool<br><br>改造文件布局<br><br>原来软件的根目录下面放的是程序的源码，按照 GNU 的习惯，将它们放到 src 子目录，<br>根目录留给 configure 这类文件使用，其他的数据文件保持不变，仍然放在各自的子目录<br><br><br>先创建一个目录 majiang，然后根据需要将 mahjong 目录下的文件复制过来由于是为<br>Unix/Linux 系统进行改写，原目录里的 win32 相关文件就不用复制到新目录<br><br>$ cd ~/work/majiang<br>$ ls<br>data/ docs/ fonts/ images/ music/ sound/ src/<br><br>autoscan<br><br>autoconf 软件包里面的 autoscan 工具可以扫描工作目录，生成一个 configure.ac 的<br>模板文件 configure.scan<br><br>$ cd ~/work/majiang<br>$ autoscan<br><br>autoscan 命令在当前目录生成的 configure.scan 文件内容为:<br><br>1 # -*- Autoconf -*-<br>2 # Process this file with autoconf to produce a configure script.<br>3<br>4 AC_PREREQ(2.59)<br>5 AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)<br>6 AC_CONFIG_SRCDIR([src/bot.h])<br>7 AC_CONFIG_HEADER([config.h])<br>8<br>9 # Checks for programs.<br>10 AC_PROG_CXX<br>11 AC_PROG_CC<br>12<br>13 # Checks for libraries.<br>14<br>15 # Checks for header files.<br>16 AC_HEADER_STDC<br>17 AC_CHECK_HEADERS([limits.h malloc.h stdlib.h string.h unistd.h])<br>18<br>19 # Checks for typedefs, structures, and compiler characteristics.<br>20 AC_HEADER_STDBOOL<br>21 AC_C_CONST<br>22 AC_C_INLINE<br>23<br>24 # Checks for library functions.<br>25 AC_FUNC_MALLOC<br>26 AC_FUNC_REALLOC<br>27 AC_CHECK_FUNCS([memset strcasecmp strchr strdup])<br>28 AC_OUTPUT<br><br># 号开始的行是注释，其他都是 m4 宏命令将它改名为 configure.ac，然后在此基础上<br>进行修改<br><br>configure.ac 的基本结构<br><br>configure.ac 文件是 autoconf 的输入文件，经过 autoconf 处理，展开里面的 m4 宏，<br>输出的是 configure 脚本<br><br>第 4 行声明本文件要求的 autoconf 版本，因为本例使用了新版本 2.59，所以在此注明<br><br><br>第 5 行 AC_INIT 宏用来定义软件的名称和版本等信息，本例写成:<br><br>AC_INIT(majiang, 1.0)<br><br>这里省略了 BUG-REPORT-ADDRESS 参数，它是可选项，一般写成作者的邮件地址<br><br>第 6 行 AC_CONFIG_SRCDIR 宏通过侦测所指定的源码文件是否存在，来确定源码目录的有<br>效性可以选择源码目录中的任何一个文件作为代表，比如将 autoscan 选择的 bot.h<br>文件改成 main.cpp:<br><br>AC_CONFIG_SRCDIR([src/main.cpp])<br><br>宏参数中使用 `[ ]'，是为了表明其中的字符串是一个整体<br><br>第 7 行的 AC_CONFIG_HEADER 宏用于生成 config.h 文件，里面存放 configure 脚本侦<br>测到的信息如果程序需要使用其中的定义，就在源码中加入<br><br>#include &lt;config.h&gt;<br><br>其他的一些宏是标准的侦测过程，可以保留不动<br><br>configure.ac 文件要求 AC_INIT 宏必须放在开头位置，AC_OUTPUT 放在文件末，中间用<br>来检测编译环境的各种宏没有特别的先后次序要求，由宏之间相互关系决定<br><br>Makefile 文件的产生<br><br>前面 configure.ac 里面的宏，主要作用是侦测系统，并没有编译相关的设置因为这些<br>信息是写在 Makefile.am 里面，然后用 automake 工具转换成 Makefile.in，configure<br>脚本执行时再读取 Makefile.in，并与侦测信息一起写到 Makefile 文件<br><br>在 autotools 的命名习惯中，后缀 ac 的文件是 autoconf 的输入文件，后缀 am 的文<br>件是 automake 的输入文件，后缀 in 的文件是 configure 的输入文件 autoconf 旧版<br>本中 configure.in 等同于 configure.ac，虽然新版本也可以识别，但它不符合命名规则<br>，所以新版本的文件应该使用 ac 后缀<br><br>简单的 Makefile.in 可以手动编写，如果使用 automake 产生，需要在 configure.ac<br>里面加入 AM_INIT_AUTOMAKE 宏进行声明<br><br>要输出 Makefile，还需要在 configure.ac 中使用 AC_CONFIG_FILES 宏指明该宏并不<br>是只处理 Makefile，而是将 FILE.in 文件转换为 FILE 文件因为 make 可以遍历子目<br>录，如果子目录中存在 Makefile，也将同时处理在本例中 src 目录下是源码，其他是<br>数据文件，可以使用单独一个 Makefile 放在根目录下面，也可以用多个 Makefile由于<br>每个子目录的 Makefile 只处理本目录的文件，分工明确，是模块化的方法，推荐使用<br>因此在 configure.ac 里面增加下面的宏，表示软件根目录和子目录中都需要生成<br>Makefile 文件:<br><br>AC_CONFIG_FILES([Makefile<br>src/Makefile<br>data/Makefile<br>docs/Makefile<br>fonts/Makefile<br>images/Makefile<br>music/Makefile<br>sound/Makefile])<br><br>编写 Makefile.am<br><br>软件根目录 Makefile.am<br><br>由于该目录下面保存的是与 autotools 相关的文件，没有需要编译安装的文件，所以只注<br>明需要进一步处理的子目录信息:<br><br>SUBDIRS = src data docs fonts images music sound<br><br>src/Makefile.am<br><br>此目录里是源代码，最终生成 mj 可执行文件，在其 Makefile.am 中写入<br><br>bin_PROGRAMS = mj<br><br>mj_SOURCES = bot.h \<br>bot.cpp \<br>config.cpp \<br>game.h \<br>game.cpp \<br>general.h \<br>general.cpp \<br>hand.h \<br>hand.cpp \<br>ini.h \<br>ini.cpp \<br>main.h \<br>main.cpp \<br>player.h \<br>player.cpp \<br>text.cpp \<br>tile.h \<br>tile.cpp \<br>util.cpp<br><br>am 文件里变量通过命名判断其含义，保留的字符串间用下划线分隔<br><br>bin_PROGRAMS 表示列出二进制的程序，值为多个空格分开的程序列表，这里仅有一个 mj<br><br><br>mj_SOURCES 列出的是组成 mj 程序的文件，文件比较多的时候，每个文件写成一行容易看<br>清楚<br><br>data/Makefile.am<br><br>本目录的文件是 mj 运行时读取的数据，它的 Makefile.am 可以这样写<br><br>mjdatadir = $(pkgdatadir)/data<br>mjdata_DATA = mj.ini titles.txt<br>EXTRA_DIST = $(mjdata_DATA)<br><br>因为 datadir 是保留的关键字，所以用 mjdatadir 代替，pkgdatadir 指向 $prefix/<br>share/FULL-PACKAGE-NAME 目录，因为在 AC_INIT 中已经声明 FULL-PACKAGE-NAME 为<br>majiang，pkgdatadir 就等于 $prefix/share/majiang 目录<br><br>其中 mjdatadir 让 data 目录下的文件安装到 $prefix/share/majiang/data 目录里面<br><br>mjdata_DATA 列出此目录下需要安装的文件，然后用 EXTRA_DIST 变量注明<br><br>余下几个子目录都与 data 目录类似<br><br>docs/Makefile.am<br><br>docsdir = $(pkgdatadir)/docs<br>docs_DATA = gkai00mp.txt gpl.html readme.txt<br>EXTRA_DIST = $(docs_DATA)<br><br>fonts/Makefile.am<br><br>fontsdir = $(pkgdatadir)/fonts<br>fonts_DATA = brush.ttf gkai00mp.ttf<br>EXTRA_DIST = $(fonts_DATA)<br><br>images/Makefile.am<br><br>imagesdir = $(pkgdatadir)/images<br>images_DATA = bgame.jpg \<br>mjgirl1a.jpg \<br>mjgirl2a.jpg \<br>mjgirl3a.jpg \<br>mjgirl4a.jpg \<br>tiles.jpg \<br>electron.jpg \<br>mjgirl1b.jpg \<br>mjgirl2b.jpg \<br>mjgirl3b.jpg \<br>mjgirl4b.jpg \<br>gameover.jpg \<br>mjgirl1c.jpg \<br>mjgirl2c.jpg \<br>mjgirl3c.jpg \<br>mjgirl4c.jpg<br>EXTRA_DIST = $(images_DATA)<br><br>music/Makefile.am<br><br>musicdir = $(pkgdatadir)/music<br>music_DATA = bet.ogg \<br>bonus.ogg \<br>music.ogg \<br>musicb.ogg \<br>musice.ogg \<br>win.ogg \<br>bgame.ogg \<br>gameover.ogg \<br>music1.ogg \<br>musicc.ogg \<br>musicp.ogg<br>EXTRA_DIST = $(music_DATA)<br><br>sound/Makefile.am<br><br>sounddir = $(pkgdatadir)/sound<br>sound_DATA = boom.wav \<br>ding.wav \<br>discard.wav \<br>discard2.wav \<br>flash.wav \<br>snd1.wav \<br>snd2.wav \<br>snd3.wav \<br>snd4.wav<br>EXTRA_DIST = $(sound_DATA)<br><br>运行 autotools<br><br>准备好 configure.ac 和 Makefile.am，就可以用 autotools 的命令处理这些文件开始<br>可能会出现错误，不过没关系，可以按照错误信息的提示逐步进行修正<br><br>首先要使用的是 aclocal 命令，它根据 configure.ac 的定义，将需要使用的 m4 宏定<br>义复制到 aclocal.m4 里面缺省时，搜索 m4 宏是从 autoconf 的安装目录和系统的<br>aclocal 目录如果需要使用其他路径下的宏，可以通过命令行的 -I 选项指定<br><br>接着使用 autoheader 命令，它负责生成 config.h.in 文件，这里面的 C 语言宏定义也<br>是通过解析 configure.ac 产生<br><br>下来运行 automake 命令处理 Makefile.am，生成 Makefile.inGNU 对自己发布的软件<br>有严格的规范，比如必须附带许可证声明文件 COPYING 等等，否则 automake 执行时会<br>报错automake 提供了三种软件等级： foreigngnu 和 gnits，让用户选择采用，默认<br>等级为 gnu本例使用 foreign 等级，它只检测必须的文件有一些必需的脚本文件可以<br>从 automake 软件包里复制过来，在执行时使用 --add-missing 选项可以让 automake 自<br>动添加，默认方式是采用符号链接，如加上 --copy 选项则可以使用复制方式本例中，<br>automake 的命令如下:<br><br>$ automake --foreign --add-missing --copy<br><br>最后，使用 autoconf 命令生成 configure 脚本文件<br><br>SDL 库的侦测<br><br>这个麻将游戏是基于 SDL 库开发的，一般系统默认不会安装，因此 configure 脚本的一<br>个任务就是检查用户的系统中是否有该软件包<br><br>autoconf 提供了很多宏可以实现侦测功能，但首先应该查看 SDL 软件包是否已经提供相<br>应的宏通过 pkgsrc 的工具可以看到:<br><br>$ pkg_info -L SDL|grep m4<br>/usr/pkg/share/aclocal/sdl.m4<br><br>即 SDL 软件包提供了一个 sdl.m4 宏，放在系统的 aclocal 目录下<br><br>在这个宏文件的注释中说明了使用的方法:<br><br>dnl AM_PATH_SDL([MINIMUM-VERSION,[ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]])<br>dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS<br><br>也就是说在 configure.ac 里面调用 AM_PATH_SDL 宏，就可以侦测 SDL找到 SDL 库以<br>后，该宏还输出 SDL_CFLAGS 和 SDL_LIBS 编译连接选项，它们实际上就是调用<br>`sdl-config --cflags` 和 `sdl-config --libs`<br><br>于是在 configure.ac 里面加入 AM_PATH_SDL 宏<br><br># Checks for libraries.<br>SDL_VERSION=1.2.0<br>AM_PATH_SDL($SDL_VERSION,<br>:,<br>AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!])<br>)<br><br>当前 SDL 的版本为 1.2.9，于是 MINIMUM-VERSION 就设为 1.2.0如果在系统中侦测到<br>需要的库，没什么额外的操作，假如没有找到，则给出错误信息<br><br>AM_PATH_SDL 输出 SDL_CFLAGS 和 SDL_LIBS 编译参数，需要添加到 src/Makefile.am 里<br>面:<br><br>mj_CPPFLAGS = @SDL_CFLAGS@<br>mj_LDFLAGS = @SDL_LIBS@<br><br>用 `@' 包围的变量会在 configure 执行时被替换<br><br>从 mahjong 的 Makefile 中看到，这个软件还要使用 SDL_imageSDL_mixser 和<br>SDL_ttf 库，但它们不属于 SDL 软件包，需要另外安装由于这些库在 sdl.m4 中也没<br>有进行侦测，所以自己要写一些脚本<br><br>autotools 提供了一个 AC_CHECK_LIB 宏可以用来检测库，现在就使用它来检测这几个<br>SDL 库该宏的语法为:<br><br>AC_CHECK_LIB (LIBRARY, FUNCTION, [ACTION-IF-FOUND],<br>[ACTION-IF-NOT-FOUND], [OTHER-LIBRARIES])<br><br>第一个参数是库名，第二个参数是库中的一个函数，第三个参数是检测到以后进行的动作<br>，第四个参数是未检测到以后的动作，第五个参数是其他的库<br><br>对于 SDL_imageSDL_mixer 和 SDL_ttf 对应的使用方法如下:<br><br># Check for SDL_image library<br>AC_CHECK_LIB(SDL_image, IMG_LoadPNG_RW, , AC_MSG_ERROR([<br>*** Unable to find SDL_image libary with PNG support<br>(http://www.libsdl.org/projects/SDL_image/)<br>]), `sdl-config --libs`)<br><br># Check for SDL_mixer library<br>AC_CHECK_LIB(SDL_mixer, Mix_LoadOGG_RW, , AC_MSG_ERROR([<br>*** Unable to find SDL_mixer libary with OGG support<br>(http://www.libsdl.org/projects/SDL_mixer/)<br>]), `sdl-config --libs`)<br><br># Check for SDL_ttf library<br>AC_CHECK_LIB(SDL_ttf, TTF_OpenFont, , AC_MSG_ERROR([<br>*** Unable to find SDL_ttf libary<br>(http://www.libsdl.org/projects/SDL_ttf/)<br>]), `sdl-config --libs`)<br><br>软件使用的数据文件<br><br>原来 mj 读取数据是从执行时目录的子目录中读取，但现在将数据放到 $prefix/share/<br>majiang 目录下，需要通过一种途径让程序可以知道数据文件被安放的位置<br><br>要达到这个目的有很多方法，这里采用最直接的一种：将数据文件安装目录变量通过<br>CPPFLAGS 编译参数传递给程序<br><br>于是修改 src/Makefile.am 的 CPPFLAGS:<br><br>mj_CPPFLAGS = @SDL_CFLAGS@ -DDATA_DIR=\"${datadir}/majiang\"<br><br>相应地修改 src 目录下的源码，在读取数据文件的地方，将读取的路径改成 DATA_DIR<br>里对应的子目录例如，原先 config.cpp 中是:<br><br>void LoadCfg()<br>{<br>cfg.Load("data/mj.ini");<br>}<br><br>现改成:<br><br>void LoadCfg()<br>{<br>char ini_file[260];<br>sprintf(ini_file, "%s/data/mj.ini", DATA_DIR);<br>cfg.Load(ini_file);<br>}<br><br>configure 选项<br><br>原来 mahjong 的 Makefile 第 22 行定义了 debug 调试选项，虽然也可以照样放到 src/<br>Makefile.am 的 CPPFLAGS 里面实现，但 autotools 提供了一种更灵活的机制<br><br>configure 脚本可以通过选项来设置编译参数，现增加一个 --enable-debug 选项，需要<br>DEBUG 时，在命令行上加上它来打开，默认则关闭<br><br>这项功能是使用 AC_ARG_ENABLE 宏实现:<br><br>AC_ARG_ENABLE (FEATURE, HELP-STRING, [ACTION-IF-GIVEN],<br>[ACTION-IF-NOT-GIVEN])<br><br>其中 FEATURE 是名称，HELP_STRING 为说明信息，在使用 ./configure --help 时可以看<br>到最后两个分别对应打开和关闭时的操作<br><br>现在将 DEBUG 功能加入 configure.ac:<br><br>AC_ARG_ENABLE(debug,<br>[ --enable-debug turn on debug],<br>CXXFLAGS="$CXXFLAGS -g3 -D_DEBUG=1")<br><br>autotools 脚本<br><br>每次修改了 configure.ac 或 Makefile.am 等 autotools 输入文件后都需要再次运行<br>aclocalautomakeautoconf 这些命令，为了方便起见，可以将他们放到一个 shell<br>脚本里面，例如:<br><br>#! /bin/sh<br>set -x<br>aclocal<br>autoheader<br>automake --foreign --add-missing --copy<br>autoconf<br><br>将上面内容保存到 autogen.sh 文件，并修改文件属性为 755每次需要重新生成<br>configure 脚本时，执行 ./autogen.sh 即可<br><br>使用 configure 产生的 Makefile<br><br>现在执行 ./autogen.sh 得到的 configure 脚本已经可以正常工作了，进入 ~/work/<br>majiang 目录，执行 ./configure，可以看到它检查系统的过程，包括 SDL 和<br>SDL_image 等库的侦测结果使用 ./configure --help 可以看到 autotools 提供的帮<br>助信息<br><br>configure 执行的完毕，输出软件根目录和几个子目录下面的 Makefile 文件这些<br>Makefile 有几个常用的 target:<br><br>&#183; make all<br><br>不加任何 target，默认就是 all，作用是编译软件<br><br>&#183; make install<br><br>安装软件包，如果安装到系统目录，需要 root 权限<br><br>&#183; make clean<br><br>清除编译产生的目标文件<br><br>&#183; make distclean<br><br>可以同时清除编译的结果和 configure 输出的文件<br><br>&#183; make tags<br><br>生成 etags 使用的 TAGS 文件<br><br>&#183; make dist<br><br>生成软件发布包，为 tar.gz 格式的压缩包，文件名由软件包名和版本组成<br><br>最终的 configure.ac 文件<br><br># -*- Autoconf -*-<br># Process this file with autoconf to produce a configure script.<br><br>AC_PREREQ(2.59)<br>AC_INIT([majiang], [1.0])<br>AC_CONFIG_SRCDIR([src/main.cpp])<br>AC_CONFIG_HEADER([config.h])<br><br>AC_CANONICAL_HOST<br>AC_CANONICAL_TARGET<br>AM_INIT_AUTOMAKE<br><br># Checks for programs.<br>AC_PROG_CXX<br>AC_PROG_CC<br><br>AC_LANG(C++)<br><br># Checks for libraries.<br>SDL_VERSION=1.2.0<br>AM_PATH_SDL($SDL_VERSION,<br>:,<br>AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!])<br>)<br><br># Check for SDL_image library<br>AC_CHECK_LIB(SDL_image, IMG_LoadPNG_RW, , AC_MSG_ERROR([<br>*** Unable to find SDL_image libary with PNG support<br>(http://www.libsdl.org/projects/SDL_image/)<br>]), `sdl-config --libs`)<br><br># Check for SDL_mixer library<br>AC_CHECK_LIB(SDL_mixer, Mix_LoadOGG_RW, , AC_MSG_ERROR([<br>*** Unable to find SDL_mixer libary with OGG support<br>(http://www.libsdl.org/projects/SDL_mixer/)<br>]), `sdl-config --libs`)<br><br># Check for SDL_ttf library<br>AC_CHECK_LIB(SDL_ttf, TTF_OpenFont, , AC_MSG_ERROR([<br>*** Unable to find SDL_ttf libary<br>(http://www.libsdl.org/projects/SDL_ttf/)<br>]), `sdl-config --libs`)<br><br># Checks for header files.<br>AC_HEADER_STDC<br>AC_CHECK_HEADERS([limits.h malloc.h stdlib.h string.h unistd.h])<br><br># Checks for typedefs, structures, and compiler characteristics.<br>AC_HEADER_STDBOOL<br>AC_C_CONST<br>AC_C_INLINE<br><br># Checks for library functions.<br>AC_FUNC_MALLOC<br>AC_FUNC_REALLOC<br>AC_CHECK_FUNCS([memset strcasecmp strchr strdup])<br><br>AC_ARG_ENABLE(debug,<br>[ --enable-debug turn on debug],<br>CXXFLAGS="$CXXFLAGS -g3 -D_DEBUG=1")<br><br>AC_CONFIG_FILES([Makefile<br>src/Makefile<br>data/Makefile<br>docs/Makefile<br>fonts/Makefile<br>images/Makefile<br>music/Makefile<br>sound/Makefile])<br>AC_OUTPUT<br><br>结束语<br><br>GNU 的很多工具经常给人一种感觉: 功能很强大，但也很难学autotools 可以说是这类<br>工具的一个典型，它需要用户对 shellmake软件编译m4 宏语言，以及 Unix/Linux<br>操作系统各方面知识都有一定的了解使用时又要 autoconf automakelibtool 多个<br>工具相互配合^1，如果要给软件增加国际化功能，还要再了解和掌握 gettextpo 等工具<br>和规则<br><br>与学习其他知识一样，所谓难，其实是不了解，不熟悉本文通过一个范例演示使用<br>autotools 的过程，是让不了解的人熟悉这个工具但真正的理解，还需要将它运用到自<br>己的软件项目当中，不断地实践，不断地思考和总结<br><br><br><br><br>脚注<br><br>... 多个工具相互配合^1<br>由于本例软件中没有生成库文件，所以没有涉及 libtool 工具的使用<br></span>
<img src ="http://www.cppblog.com/liu1061/aggbug/54740.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-27 09:42 <a href="http://www.cppblog.com/liu1061/articles/54740.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>运用autoconf和automake自动生成Makefil </title><link>http://www.cppblog.com/liu1061/articles/54675.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Thu, 26 Jun 2008 07:23:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54675.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54675.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54675.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54675.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54675.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">对于一个UNIX/Linux下C程序员来说，一个比较麻烦的工作就是写自己的Makefile。 <br>可能你有如下经验：写一个简单的C程序，自己多写几行gcc命令就把程序变成可执行的了；写一个稍微复杂点的程序，源文件个数可能在30个左右，还是写一行行的gcc命令就麻烦了，你可能想到写个makefile，你可能也在这样做着；但你某一天会发现你写的这个Makefile可能不是一个所有 UNIX/Linux类操作系统下通用的Makefile，比如某人下载了你的程序去他自己电脑上可能make不了。 <br><br>这样，你就有必要了解并学会运用autoconf和automake了。 <br>autoconf是一个用于生成可以自动地配置软件源代码包以适应多种UNIX类系统的shell脚本的工具。由autoconf生成的配置脚本在运行的时候不需要用户的手工干预；通常它们甚至不需要手工给出参数以确定系统的类型。相反，它们对软件包可能需要的各种特征进行独立的测试。在每个测试之前，它们打印一个单行的消息以说明它们正在进行的检测，以使得用户不会因为等待脚本执行完毕而焦躁。因此，它们在混合系统或者从各种常见UNIX变种定制而成的系统中工作的很好。你也省了工作，没必要维护文件以储存由各个UNIX变种、各个发行版本所支持的特征的列表。 <br>automake是一个从文件Makefile.am自动生成Makefile.in的工具。每个Makefile.am基本上是一系列make的宏定义（make规则也会偶尔出现）生成的Makefile.in，服从GNU Makefile标准。 <br>为了生成Makefile.in，automake需要perl。但是由automake创建的发布完全服从GNU标准，并且在创建中不需要perl。 <br><br>在开始使用autoconf和automake之前，首先确认你的系统安装有GNU的如下软件： <br>1. automake <br>2. autoconf <br>3. m4 <br>4. perl <br>5. 如果你需要产生共享库（shared library）则还需要GNU Libtool <br><br>介绍方法之前大家看一下下面这个图，先记下autoconf和automake工作的几个步骤： <br><img src="http://zhoulifa.bokee.com/inc/auto.gif" border=0> <br><br>步骤解释如下： <br>1、由你的源文件通过autoscan命令生成configure.scan文件，然后修改configure.scan文件并重命名为configure.in <br>2、由aclocal命令生成aclocal.m4 <br>3、由autoconf命令生成configure <br>4、编辑一个Makefile.am文件并由automake命令生成Makefile.in文件 <br>5、运行configure命令生成Makefile <br><br>automake支持三种目录层次：flat、shallow和deep。 <br>一个flat包指的是所有文件都在一个目录中的包。为这类包提供的Makefile.am不需要SUBDIRS这个宏。这类包的一个例子是termutils。对应咱们程序员来说：就是所有源文件及自己写的头文件都位于当前目录里面，且没有子目录。 <br>一个deep包指的是所有的源代码都被储存在子目录中的包；顶层目录主要包含配置信息。GNU cpio是这类包的一个很好的例子，GNU tar也是。deep包的顶层Makefile.am将包括宏SUBDIRS，但没有其它定义需要创建的对象的宏。对应咱们程序员来说：就是所有源文件及自己写的头文件都位于当前目录的一个子目录里面，而当前目录里没有任何源文件。 <br>一个shallow包指的是主要的源代码储存在顶层目录中，而各个部分（典型的是库）则储存在子目录中的包。automake本身就是这类包（GNU make也是如此，它现在已经不使用automake）。对应咱们程序员来说：就是主要源文件在当前目录里，而其它一些实现各部分功能的源文件各自位于不同目录。 <br><br>前两个层次的程序编辑方法非常简单，按照上述步骤一步步即可。而第三种层次shallow稍微复杂一点，但这是我们经常写程序用到的结构。下面以一个例子说明shallow层次结构的源文件如何自动生成Makefile文件。 <br>例子源程序结构如下： <br>hello是我们的工作目录，hello目录下有main.c源文件和comm、tools、db、network、interface等五个目录。 comm目录下有comm.c和comm.h源文件及头文件，tools目录下有tools.c和tools.h，同样其它目录分别有db.c、 db.h、network.c、network.h、interface.c、interface.h等一些源文件。 <br><br>按照如下步骤来自动生成Makefile吧： <br>1、进入hello目录，运行autoscan命令，命令如下： <br>cd hello <br>autoscan <br>2、ls会发现多了一个configure.scan文件。修改此文件，在AC_INIT宏之后加入AM_INIT_AUTOMAKE(hello, 1.0)，这里hello是你的软件名称，1.0是版本号，即你的这些源程序编译将生成一个软件hello-1.0版。然后把 configure.scan文件的最后一行AC_OUTPUT宏填写完整变成AC_OUTPUT(Makefile)，表明autoconf和 automake最终将生成Makefile文件。最后把configure.scan文件改名为configure.in。最终 configure.in文件内容如下： <br><br>dnl Process this file with autoconf to produce a configure script. <br>AC_INIT(target.c) <br>AM_INIT_AUTOMAKE(hello, 1.0) <br>dnl Checks for programs. <br>AC_PROG_CC <br><br>dnl Checks for libraries. <br><br>dnl Checks for header files. <br><br>dnl Checks for typedefs, structures, and compiler characteristics. <br><br>dnl Checks for library functions. <br><br>AC_OUTPUT(Makefile) <br><br>3、运行aclocal命令，ls会发现多了一个aclocal.m4文件。 <br>4、然后运行autoconf命令，ls将发现生成了一个可执行的configure命令。 <br>5、编辑一个Makefile.am文件，文件内容如下： <br>AUTOMAKE_OPTIONS=foreign <br>bin_PROGRAMS=hello <br>hello_SOURCES=main.c comm/comm.c comm/comm.h tools/tools.c tools/tools.h db/db.c db/db.h network/network.c network/network.h interface/interface.c interface/interface.h <br>这表明你最后将通过一个make命令利用上述hello_SOURCES源文件生成一个hello的程序。 <br>6、运行automake --add-missing命令。屏幕提示如下： <br>automake: configure.in: installing `./install-sh' <br>automake: configure.in: installing `./mkinstalldirs' <br>automake: configure.in: installing `./missing' <br>7、然后你可以运行之前生成的configure命令来生成一个Makefile文件，输入./configure命令即可。 <br>8、编辑Makefile文件，找到$(LINK)所在的那一行，本来生成的文件内容如下： <br>@rm -f hello <br>$(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS) <br>在这两行之间增加几行变成： <br>@rm -f hello <br>@mv -f comm.o comm <br>@mv -f tools.o tools <br>@mv -f db.o db <br>@mv -f network.o network <br>@mv -f interface.o interface <br>$(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS) <br>这是因为默认生成的Makefile将在编译后把所有目标文件置于当前目录，而在进行链接(link)时又会到各个子目录去找相应的目标文件。 <br>当然，为了完整，建议各位在clean部分加上如下一些行： <br>@rm -f comm/comm.o <br>@rm -f tools/tools.o <br>@rm -f db/db.o <br>@rm -f network/network.o <br>@rm -f interface/interface.o <br><br>好了，经过上述这些步骤后，现在你可以来编译生成你自己的可执行程序了。输入一个make all吧，然后就可以运行./hello来看你的程序运行了。 <br><br>运用autoconf和automake的最大好处是，你的程序以源程序方式发布后，其它所有人只需要依次输入 <br>./configure <br>make <br>make install <br>命令就可以把你的程序安装在自己的电脑上运行了。所有符合GNU标准的UNIX/Linux都不需要再修改Makefile里的任何字符。</p>
[@more@] 
<img src ="http://www.cppblog.com/liu1061/aggbug/54675.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-26 15:23 <a href="http://www.cppblog.com/liu1061/articles/54675.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>autoconf 和 automake 生成 Makefile 文件 (转)</title><link>http://www.cppblog.com/liu1061/articles/54653.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Thu, 26 Jun 2008 04:01:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54653.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54653.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54653.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54653.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54653.html</trackback:ping><description><![CDATA[<table cellSpacing=0 cellPadding=0 width=160 align=right border=0>
    <tbody>
        <tr>
            <td width=10><img height=1 alt="" src="http://www.ibm.com/i/c.gif" width=10></td>
            <td>
            <table cellSpacing=0 cellPadding=0 width=150 border=0>
                <tbody>
                    <tr>
                        <td>文档选项</td>
                    </tr>
                </tbody>
            </table>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td width=150>
                        <table cellSpacing=0 cellPadding=0 width=143 border=0>
                            <img height=1 alt="" src="http://www.ibm.com/i/c.gif" width=8>
                            <form name=email action=https://www.ibm.com/developerworks/secure/email-it.jsp>
                                <input type=hidden value="本文介绍了在 linux 系统中，通过 Gnu autoconf 和 automake 生成 Makefile 的方法。主要探讨了生成 Makefile 的来龙去脉及其机理，接着详细介绍了配置 Configure.in 的方法及其规则。" name=body><input type=hidden value="例解 autoconf 和 automake 生成 Makefile 文件" name=subject><input type=hidden value=cn name=lang> <script language=JavaScript type=text/javascript>
                                <!--
                                document.write('
                                <tr valign="top">
                                    <td width="8"><img src="//www.ibm.com/i/c.gif" src_cetemp="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td>
                                    <td width="16"><img src="//www.ibm.com/i/v14/icons/em.gif" src_cetemp="//www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="将此页作为电子邮件发送" /></td>
                                    <td width="122">
                                    <p><a class="smallplainlink" href="javascript:document.email.submit();" href_cetemp="javascript:document.email.submit();"><strong>将此页作为电子邮件发送</strong></a></p>
                                    </td>
                                </tr>
                                ');
                                //-->
                                </script>
                                <tbody>
                                    <tr vAlign=top>
                                        <td width=8><img height=1 alt="" src="http://www.ibm.com/i/c.gif" width=8></td>
                                        <td width=16><img height=16 alt=将此页作为电子邮件发送 src="http://www.ibm.com/i/v14/icons/em.gif" width=16 vspace=3></td>
                                        <td width=122>
                                        <p><a href="javascript:document.email.submit();">将此页作为电子邮件发送</a></p>
                                        </td>
                                    </tr>
                                    <noscript>
                                    <tr valign="top">
                                        <td width="8"><img alt="" height="1" width="8" src="//www.ibm.com/i/c.gif"/></td>
                                        <td width="16"><img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif"/></td>
                                        <td class="small" width="122">
                                        <p><span class="ast">未显示需要 JavaScript 的文档选项</span></p>
                                        </td>
                                    </tr>
                                    </noscript>
                                </form>
                                <tr vAlign=top>
                                    <td width=8><img height=1 alt="" src="http://www.ibm.com/i/c.gif" width=8></td>
                                    <td width=16><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/dn.gif" width=16 vspace=3 border=0></td>
                                    <td width=122>
                                    <p><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#download">样例代码</a></p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        </td>
                    </tr>
                </tbody>
            </table>
            <!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!--end RESERVED FOR FUTURE USE INCLUDE FILES--><br></td>
        </tr>
    </tbody>
</table>
<p>级别： 初级</p>
<p><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#author">杨 小华</a> (<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#110;&#111;&#114;&#109;&#97;&#108;&#110;&#111;&#116;&#101;&#98;&#111;&#111;&#107;&#64;&#49;&#50;&#54;&#46;&#99;&#111;&#109;&#63;&#115;&#117;&#98;&#106;&#101;&#99;&#116;&#61;&#20363;&#35299;&#32;&#97;&#117;&#116;&#111;&#99;&#111;&#110;&#102;&#32;&#21644;&#32;&#97;&#117;&#116;&#111;&#109;&#97;&#107;&#101;&#32;&#29983;&#25104;&#32;&#77;&#97;&#107;&#101;&#102;&#105;&#108;&#101;&#32;&#25991;&#20214;">normalnotebook@126.com</a>), Linux 内核研究员<br><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#author">苏 春艳</a>, 在读研究生<br></p>
<p>2006 年 9 月 21 日</p>
<blockquote>本文介绍了在 linux 系统中，通过 Gnu autoconf 和 automake 生成 Makefile 的方法。主要探讨了生成 Makefile 的来龙去脉及其机理，接着详细介绍了配置 Configure.in 的方法及其规则。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p><a name=N10060>引子</a></p>
<p>无论是在Linux还是在Unix环境中，make都是一个非常重要的编译命令。不管是自己进行项目开发还是安装应用软件，我们都经常要用到make或 make install。利用make工具，我们可以将大型的开发项目分解成为多个更易于管理的模块，对于一个包括几百个源文件的应用程序，使用make和 makefile工具就可以轻而易举的理顺各个源文件之间纷繁复杂的相互关系。</p>
<p>但是如果通过查阅make的帮助文档来手工编写Makefile,对任何程序员都是一场挑战。幸而有GNU 提供的Autoconf及Automake这两套工具使得编写makefile不再是一个难题。</p>
<p>本文将介绍如何利用 GNU Autoconf 及 Automake 这两套工具来协助我们自动产生 Makefile文件，并且让开发出来的软件可以像大多数源码包那样，只需"./configure", "make","make install" 就可以把程序安装到系统中。</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#main">回页首</a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=N1006F>模拟需求</a></p>
<p>假设源文件按如下目录存放，如图1所示，运用autoconf和automake生成makefile文件。</p>
<br><a name=N1007A>图 1文件目录结构</a><br><img height=190 alt="图 1文件目录结构" src="http://www.ibm.com/developerworks/cn/linux/l-makefile/images/image001.jpg" width=217 border=0> <br>
<p style="FONT-SIZE: 12pt">假设src是我们源文件目录，include目录存放其他库的头文件，lib目录存放用到的库文件，然后开始按模块存放，每个模块都有一个对应的目录，模块下再分子模块，如apple、orange。每个子目录下又分core，include，shell三个目录，其中core和shell目录存放.c文件，include的存放.h文件，其他类似。</p>
<p>样例程序功能：基于多线程的数据读写保护（联系作者获取整个autoconf和automake生成的Makefile工程和源码，E-mail：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#110;&#111;&#114;&#109;&#97;&#108;&#110;&#111;&#116;&#101;&#98;&#111;&#111;&#107;&#64;&#49;&#50;&#54;&#46;&#99;&#111;&#109;">normalnotebook@126.com</a>）。</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#main">回页首</a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=N10094>工具简介</a></p>
<p>所必须的软件：autoconf/automake/m4/perl/libtool（其中libtool非必须）。</p>
<p>autoconf是一个用于生成可以自动地配置软件源码包，用以适应多种UNIX类系统的shell脚本工具，其中autoconf需要用到 m4，便于生成脚本。automake是一个从Makefile.am文件自动生成Makefile.in的工具。为了生成Makefile.in，automake还需用到perl，由于automake创建的发布完全遵循GNU标准，所以在创建中不需要perl。libtool是一款方便生成各种程序库的工具。</p>
<p>目前automake支持三种目录层次：flat、shallow和deep。</p>
<p>1) flat指的是所有文件都位于同一个目录中。</p>
<p>就是所有源文件、头文件以及其他库文件都位于当前目录中，且没有子目录。Termutils就是这一类。</p>
<p>2) shallow指的是主要的源代码都储存在顶层目录，其他各个部分则储存在子目录中。</p>
<p>就是主要源文件在当前目录中，而其它一些实现各部分功能的源文件位于各自不同的目录。automake本身就是这一类。</p>
<p>3) deep指的是所有源代码都被储存在子目录中；顶层目录主要包含配置信息。</p>
<p>就是所有源文件及自己写的头文件位于当前目录的一个子目录中，而当前目录里没有任何源文件。 GNU cpio和GNU tar就是这一类。</p>
<p>flat类型是最简单的，deep类型是最复杂的。不难看出，我们的模拟需求正是基于第三类deep型，也就是说我们要做挑战性的事情：)。注：我们的测试程序是基于多线程的简单程序。</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#main">回页首</a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=N100B8>生成 Makefile 的来龙去脉</a></p>
<p>首先进入 project 目录，在该目录下运行一系列命令，创建和修改几个文件，就可以生成符合该平台的Makefile文件，操作过程如下：</p>
<p>1) 运行autoscan命令</p>
<p>2) 将configure.scan 文件重命名为configure.in，并修改configure.in文件</p>
<p>3) 在project目录下新建Makefile.am文件，并在core和shell目录下也新建makefile.am文件</p>
<p>4) 在project目录下新建NEWS、 README、 ChangeLog 、AUTHORS文件</p>
<p>5) 将/usr/share/automake-1.X/目录下的depcomp和complie文件拷贝到本目录下</p>
<p>6) 运行aclocal命令</p>
<p>7) 运行autoconf命令</p>
<p>8) 运行automake -a命令</p>
<p>9) 运行./confiugre脚本</p>
<p>可以通过图2看出产生Makefile的流程，如图所示：</p>
<br><a name=N100E1>图 2生成Makefile流程图</a><br><img height=338 alt="图 2生成Makefile流程图" src="http://www.ibm.com/developerworks/cn/linux/l-makefile/images/image002.gif" width=468 border=0> <br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#main">回页首</a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=N100F1>Configure.in的八股文</a></p>
<p>当我们利用autoscan工具生成confiugre.scan文件时，我们需要将confiugre.scan重命名为confiugre.in文件。confiugre.in调用一系列autoconf宏来测试程序需要的或用到的特性是否存在，以及这些特性的功能。</p>
<p>下面我们就来目睹一下confiugre.scan的庐山真面目：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre># Process this file with autoconf to produce a configure script.
            AC_PREREQ(2.59)
            AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
            AC_CONFIG_SRCDIR([config.h.in])
            AC_CONFIG_HEADER([config.h])
            # Checks for programs.
            AC_PROG_CC
            # Checks for libraries.
            # FIXME: Replace `main' with a function in `-lpthread':
            AC_CHECK_LIB([pthread], [main])
            # Checks for header files.
            # Checks for typedefs, structures, and compiler characteristics.
            # Checks for library functions.
            AC_OUTPUT
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>每个configure.scan文件都是以AC_INIT开头，以AC_OUTPUT结束。我们不难从文件中看出confiugre.in文件的一般布局：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>AC_INIT
            测试程序
            测试函数库
            测试头文件
            测试类型定义
            测试结构
            测试编译器特性
            测试库函数
            测试系统调用
            AC_OUTPUT
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>上面的调用次序只是建议性质的，但我们还是强烈建议不要随意改变对宏调用的次序。</p>
<p>现在就开始修改该文件：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>$mv configure.scan configure.in
            $vim configure.in
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>修改后的结果如下：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>            #                                -*- Autoconf -*-
            # Process this file with autoconf to produce a configure script.
            AC_PREREQ(2.59)
            AC_INIT(test, 1.0, normalnotebook@126.com)
            AC_CONFIG_SRCDIR([src/ModuleA/apple/core/test.c])
            AM_CONFIG_HEADER(config.h)
            AM_INIT_AUTOMAKE(test,1.0)
            # Checks for programs.
            AC_PROG_CC
            # Checks for libraries.
            # FIXME: Replace `main' with a function in `-lpthread':
            AC_CHECK_LIB([pthread], [pthread_rwlock_init])
            AC_PROG_RANLIB
            # Checks for header files.
            # Checks for typedefs, structures, and compiler characteristics.
            # Checks for library functions.
            AC_OUTPUT([Makefile
            src/lib/Makefile
            src/ModuleA/apple/core/Makefile
            src/ModuleA/apple/shell/Makefile
            ])
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>其中要将AC_CONFIG_HEADER([config.h])修改为：AM_CONFIG_HEADER(config.h), 并加入AM_INIT_AUTOMAKE(test,1.0)。由于我们的测试程序是基于多线程的程序，所以要加入AC_PROG_RANLIB，不然运行automake命令时会出错。在AC_OUTPUT输入要创建的Makefile文件名。</p>
<p>由于我们在程序中使用了读写锁，所以需要对库文件进行检查，即AC_CHECK_LIB([pthread], [main])，该宏的含义如下：</p>
<br><img height=166 alt="" src="http://www.ibm.com/developerworks/cn/linux/l-makefile/images/table1.gif" width=537 border=0> <br>
<p>其中，LIBS是link的一个选项，详细请参看后续的Makefile文件。由于我们在程序中使用了读写锁，所以我们测试pthread库中是否存在pthread_rwlock_init函数。</p>
<p>由于我们是基于deep类型来创建makefile文件，所以我们需要在四处创建Makefile文件。即：project目录下，lib目录下，core和shell目录下。 </p>
<p>Autoconf提供了很多内置宏来做相关的检测，限于篇幅关系，我们在这里对其他宏不做详细的解释，具体请参看参考文献1和参考文献2，也可参看autoconf信息页。</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#main">回页首</a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=N1014D>实战Makefile.am</a></p>
<p>Makefile.am是一种比Makefile更高层次的规则。只需指定要生成什么目标，它由什么源文件生成，要安装到什么目录等构成。</p>
<p>表一列出了可执行文件、静态库、头文件和数据文件，四种书写Makefile.am文件个一般格式。</p>
<br><a name=N1015B>表 1Makefile.am一般格式</a><br><img height=351 alt="表 1Makefile.am一般格式" src="http://www.ibm.com/developerworks/cn/linux/l-makefile/images/table2.gif" width=522 border=0> <br>
<p>对于可执行文件和静态库类型，如果只想编译，不想安装到系统中，可以用noinst_PROGRAMS代替bin_PROGRAMS，noinst_LIBRARIES代替lib_LIBRARIES。</p>
<p>Makefile.am还提供了一些全局变量供所有的目标体使用：</p>
<br><a name=N10173>表 2 Makefile.am中可用的全局变量</a><br><img height=221 alt="表 2 Makefile.am中可用的全局变量" src="http://www.ibm.com/developerworks/cn/linux/l-makefile/images/table3.gif" width=523 border=0> <br>
<p>在Makefile.am中尽量使用相对路径，系统预定义了两个基本路径：</p>
<br><a name=N10188>表 3Makefile.am中可用的路径变量</a><br><img height=112 alt="表 3Makefile.am中可用的路径变量" src="http://www.ibm.com/developerworks/cn/linux/l-makefile/images/table4.gif" width=522 border=0> <br>
<p>在上文中我们提到过安装路径，automake设置了默认的安装路径：</p>
<p>1) 标准安装路径</p>
<p>默认安装路径为：$(prefix) = /usr/local，可以通过./configure --prefix=&lt;new_path&gt;的方法来覆盖。</p>
<p>其它的预定义目录还包括：bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc等等。</p>
<p>2) 定义一个新的安装路径</p>
<p>比如test, 可定义testdir = $(prefix)/test, 然后test_DATA =test1 test2，则test1，test2会作为数据文件安装到$(prefix)/ /test目录下。</p>
<p>我们首先需要在工程顶层目录下（即project/）创建一个Makefile.am来指明包含的子目录：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>SUBDIRS=src/lib src/ModuleA/apple/shell src/ModuleA/apple/core
            CURRENTPATH=$(shell /bin/pwd)
            INCLUDES=-I$(CURRENTPATH)/src/include -I$(CURRENTPATH)/src/ModuleA/apple/include
            export INCLUDES
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>由于每个源文件都会用到相同的头文件，所以我们在最顶层的Makefile.am中包含了编译源文件时所用到的头文件，并导出，见蓝色部分代码。</p>
<p>我们将lib目录下的swap.c文件编译成libswap.a文件，被apple/shell/apple.c文件调用，那么lib目录下的Makefile.am如下所示：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>noinst_LIBRARIES=libswap.a
            libswap_a_SOURCES=swap.c
            INCLUDES=-I$(top_srcdir)/src/includ
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>细心的读者可能就会问：怎么表1中给出的是bin_LIBRARIES，而这里是noinst_LIBRARIES？这是因为如果只想编译，而不想安装到系统中，就用noinst_LIBRARIES代替bin_LIBRARIES，对于可执行文件就用noinst_PROGRAMS代替bin_PROGRAMS。对于安装的情况，库将会安装到$(prefix)/lib目录下，可执行文件将会安装到${prefix}/bin。如果想安装该库，则Makefile.am示例如下：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>bin_LIBRARIES=libswap.a
            libswap_a_SOURCES=swap.c
            INCLUDES=-I$(top_srcdir)/src/include
            swapincludedir=$(includedir)/swap
            swapinclude_HEADERS=$(top_srcdir)/src/include/swap.h
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>最后两行的意思是将swap.h安装到${prefix}/include /swap目录下。</p>
<p>接下来，对于可执行文件类型的情况，我们将讨论如何写Makefile.am？对于编译apple/core目录下的文件，我们写成的Makefile.am如下所示：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>noinst_PROGRAMS=test
            test_SOURCES=test.c
            test_LDADD=$(top_srcdir)/src/ModuleA/apple/shell/apple.o $(top_srcdir)/src/lib/libswap.a
            test_LDFLAGS=-D_GNU_SOURCE
            DEFS+=-D_GNU_SOURCE
            #LIBS=-lpthread
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>由于我们的test.c文件在链接时，需要apple.o和libswap.a文件，所以我们需要在test_LDADD中包含这两个文件。对于Linux下的信号量/读写锁文件进行编译，需要在编译选项中指明-D_GNU_SOURCE。所以在test_LDFLAGS中指明。而test_LDFLAGS只是链接时的选项，编译时同样需要指明该选项，所以需要DEFS来指明编译选项，由于DEFS已经有初始值，所以这里用+=的形式指明。从这里可以看出，Makefile.am中的语法与Makefile的语法一致，也可以采用条件表达式。如果你的程序还包含其他的库，除了用AC_CHECK_LIB宏来指明外，还可以用LIBS来指明。</p>
<p>如果你只想编译某一个文件，那么Makefile.am如何写呢？这个文件也很简单，写法跟可执行文件的差不多，如下例所示：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>noinst_PROGRAMS=apple
            apple_SOURCES=apple.c
            DEFS+=-D_GNU_SOURCE
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>我们这里只是欺骗automake，假装要生成apple文件，让它为我们生成依赖关系和执行命令。所以当你运行完automake命令后，然后修改apple/shell/下的Makefile.in文件，直接将LINK语句删除，即：</p>
<br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td>
            <pre>&#8230;&#8230;.
            clean-noinstPROGRAMS:
            -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
            apple$(EXEEXT): $(apple_OBJECTS) $(apple_DEPENDENCIES)
            @rm -f apple$(EXEEXT)
            #$(LINK) $(apple_LDFLAGS) $(apple_OBJECTS) $(apple_LDADD) $(LIBS)
            &#8230;&#8230;.
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>
<p>通过上述处理，就可以达到我们的目的。从图1中不难看出为什么要修改Makefile.in的原因，而不是修改其他的文件。</p>
<br><br>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td><img height=1 alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%"><br><img height=6 alt="" src="http://www.ibm.com/i/c.gif" width=8 border=0></td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=0 align=right>
    <tbody>
        <tr align=right>
            <td><img height=4 alt="" src="http://www.ibm.com/i/c.gif" width="100%"><br>
            <table cellSpacing=0 cellPadding=0 border=0>
                <tbody>
                    <tr>
                        <td vAlign=center><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width=16 border=0><br></td>
                        <td vAlign=top align=right><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/#main">回页首</a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=download>下载</a></p>
<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <th scope=col>名字</th>
            <th scope=col align=right>大小</th>
            <th scope=col>下载方法</th>
        </tr>
        <tr>
            <td noWrap>project.rar</td>
            <td noWrap align=right>
            <td noWrap><a href="http://www.ibm.com/developerworks/cn/linux/l-makefile/project.rar">HTTP</a></td>
        </tr>
    </tbody>
</table>
<table cellSpacing=0 cellPadding=0 border=0>
    <tbody>
        <tr vAlign=top>
            <td colSpan=5><img height=12 alt="" src="http://www.ibm.com/i/c.gif" width=12 border=0></td>
        </tr>
        <tr>
            <td><img height=16 alt="" src="http://www.ibm.com/i/v14/icons/fw.gif" width=16></td>
            <td><a href="http://www.ibm.com/developerworks/cn/whichmethod.html">关于下载方法的信息</a></td>
            <td><img height=1 alt="" src="http://www.ibm.com/i/c.gif" width=50></td>
        </tr>
    </tbody>
</table>
<br><br>
<p><a name=resources>参考资料 </a></p>
<ol>
    <li>Kurt Wall，张辉译 《GNU/Linux编程指南》 清华大学出版社
    <li>Robert Mecklenburg，《GNU Make项目管理（第三版）》 东南大学出版社 2006
    <li><a href="http://www.cngnu.org/technology/index.html">http://www.cngnu.org/technology/index.html</a> </li>
</ol>
<img src ="http://www.cppblog.com/liu1061/aggbug/54653.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-26 12:01 <a href="http://www.cppblog.com/liu1061/articles/54653.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux系统下Autoconf/AutoMake学习笔记</title><link>http://www.cppblog.com/liu1061/articles/54635.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Thu, 26 Jun 2008 02:31:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54635.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54635.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54635.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54635.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54635.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 10pt; FONT-FAMILY: courier new"><font color=#666666>1、autoscan<br>　　autoscan是用来扫描源代码目录生成configure.scan文件的。autoscan可以用目录名做为参数，但如果你不使用参数的话，那么autoscan将认为使用的是当前目录。autoscan将扫描你所指定目录中的源文件，并创建configure.scan文件。<br><br>　　2、configure.scan<br>　　configure.scan包含了 <br>　　系统配置的基本选项，里面都是一些宏定义。我们需要将它改名为configure.in<br><br>　　3、aclocal<br>　　aclocal是一个perl脚本程序。aclocal根据configure.in文件的内容，自动生成aclocal.m4文件。 aclocal的定义是："aclocal - create aclocal.m4 by scanning configure.ac"。<br><br>　　4、autoconf<br>　　autoconf是用来产生configure文件的。configure是一个脚本，它能设置源程序来适应各种不同的操作系统平台，并且根据不同的系统来产生合适的Makefile，从而可以使你的源代码能在不同的操作系统平台上被编译出来。<br><br>　　configure.in文件的内容是一些宏，这些宏经过autoconf处理后会变成检查系统特性、环境变量、软件必须的参数的shell脚本。configure.in文件中的宏的顺序并没有规定，但是你必须在所有宏的最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏。<br><br>　　在configure.ini中：<br><br>　　#号表示注释，这个宏后面的内容将被忽略。<br><br>　　AC_INIT(FILE) <br><br>　　这个宏用来检查源代码所在的路径。<br><br>　　AM_INIT_AUTOMAKE(PACKAGE, VERSION) <br><br>　　这个宏是必须的，它描述了我们将要生成的软件包的名字及其版本号：PACKAGE是软件包的名字，VERSION是版本号。当你使用make dist命令时，它会给你生成一个类似helloworld-1.0.tar.gz的软件发行包，其中就有对应的软件包的名字和版本号。<br><br>　　AC_PROG_CC<br><br>　　这个宏将检查系统所用的C编译器。<br><br>　　AC_OUTPUT(FILE)<br><br>　　这个宏是我们要输出的Makefile的名字。<br><br>　　我们在使用automake时，实际上还需要用到其他的一些宏，但我们可以用aclocal来帮我们自动产生。执行aclocal后我们会得到aclocal.m4文件。<br><br>　　产生了configure.in和aclocal.m4两个宏文件后，我们就可以使用autoconf来产生configure文件了。<br><br>　　5、Makefile.am<br>　　Makefile.am是用来生成Makefile.in的，需要你手工书写。Makefile.am中定义了一些内容：<br><br>　　AUTOMAKE_OPTIONS <br><br>　　这个是automake的选项。在执行automake时，它会检查目录下是否存在标准GNU软件包中应具备的各种文件，例如AUTHORS、ChangeLog、NEWS等文件。我们将其设置成foreign时，automake会改用一般软件包的标准来检查。<br><br>　　bin_PROGRAMS<br><br>　　这个是指定我们所要产生的可执行文件的文件名。如果你要产生多个可执行文件，那么在各个名字间用空格隔开。<br><br>　　helloworld_SOURCES <br><br>　　这个是指定产生"helloworld"时所需要的源代码。如果它用到了多个源文件，那么请使用空格符号将它们隔开。比如需要 helloworld.h，helloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c。<br><br>　　如果你在bin_PROGRAMS定义了多个可执行文件，则对应每个可执行文件都要定义相对的filename_SOURCES。<br><br>　　6、automake<br>　　我们使用automake --add-missing来产生Makefile.in。<br><br>　　选项--add-missing的定义是"add missing standard files to package"，它会让automake加入一个标准的软件包所必须的一些文件。<br><br>　　我们用automake产生出来的Makefile.in文件是符合GNU Makefile惯例的，接下来我们只要执行configure这个shell脚本就可以产生合适的Makefile文件了。<br><br>　　7、Makefile<br>　　在符合GNU Makefiel惯例的Makefile中，包含了一些基本的预先定义的操作：<br><br>　　make<br><br>　　根据Makefile编译源代码，连接，生成目标文件，可执行文件。<br><br>　　make clean<br><br>　　清除上次的make命令所产生的object文件(后缀为".o"的文件)及可执行文件。<br><br>　　make install<br><br>　　将编译成功的可执行文件安装到系统目录中，一般为/usr/local/bin目录。<br><br>　　make dist<br><br>　　产生发布软件包文件(即distribution package)。这个命令将会将可执行文件及相关文件打包成一个tar.gz压缩的文件用来作为发布软件的软件包。<br><br>　　它会在当前目录下生成一个名字类似"PACKAGE-VERSION.tar.gz"的文件。PACKAGE和VERSION，是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE, VERSION)。<br><br>　　make distcheck<br><br>　　生成发布软件包并对其进行测试检查，以确定发布包的正确性。这个操作将自动把压缩包文件解开，然后执行configure命令，并且执行make，来确认编译不出现错误，最后提示你软件包已经准备好，可以发布了。<br><br>　　distclean <br><br>　　类似make clean，但同时也将configure生成的文件全部删除掉，包括Makefile。</font><br></span>
<img src ="http://www.cppblog.com/liu1061/aggbug/54635.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-26 10:31 <a href="http://www.cppblog.com/liu1061/articles/54635.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux 下如何用autoconf和automake两个工具生成Makefile （转）</title><link>http://www.cppblog.com/liu1061/articles/54543.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Wed, 25 Jun 2008 03:46:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/54543.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/54543.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/54543.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/54543.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/54543.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>作为Linux下的程序开发人员，大家一定都遇到过Makefile，用make命令来编译自己写的程序确实是很方便。一般情况下，大家都是手工写一个简单Makefile，如果要想写出一个符合自由软件惯例的Makefile就不那么容易了。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　在本文中，将给大家介绍如何使用&nbsp;&nbsp;autoconf和automake两个工具来帮助我们自动地生成符合自由软件惯例的Makefile，这样就可以象常见的GNU程序一样，只要使用&#8220;./configure&#8221;，&#8220;make&#8221;，&#8220;make instal&#8221;就可以把程序安装到Linux系统中去了。这将特别适合想做开放源代码软件的程序开发人员，又或如果你只是自己写些小的Toy程序，那么这个文章对你也会有很大的帮助。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　一、Makefile介绍</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　Makefile是用于自动编译和链接的，一个工程有很多文件组成，每一个文件的改变都会导致工程的重新链接，但是不是所有的文件都需要重新编译，Makefile中纪录有文件的信息，在make时会决定在链接的时候需要重新编译哪些文件。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　Makefile的宗旨就是：让编译器知道要编译一个文件需要依赖其他的哪些文件。当那些依赖文件有了改变，编译器会自动的发现最终的生成文件已经过时，而重新编译相应的模块。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　Makefile的基本结构不是很复杂，但当一个程序开发人员开始写Makefile时，经常会怀疑自己写的是否符合惯例，而且自己写的Makefile经常和自己的开发环境相关联，当系统环境变量或路径发生了变化后，Makefile可能还要跟着修改。这样就造成了手工书写Makefile的诸多问题，automake恰好能很好地帮助我们解决这些问题。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　使用automake，程序开发人员只需要写一些简单的含有预定义宏的文件，由autoconf根据一个宏文件生成configure，由automake根据另一个宏文件生成Makefile.in，再使用configure依据Makefile.in来生成一个符合惯例的Makefile。下面我们将详细介绍Makefile的automake生成方法。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　二、使用的环境</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　本文所提到的程序是基于Linux发行版本：Fedora Core release 1，它包含了我们要用到的autoconf，automake。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　三、从helloworld入手</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　我们从大家最常使用的例子程序helloworld开始。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　下面的过程如果简单地说来就是：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　新建三个文件：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　　helloworld.c<br>　　　configure.in<br>　　　Makefile.am</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　然后执行：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>aclocal; autoconf; automake --add-missing; ./configure; make; ./helloworld</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　就可以看到Makefile被产生出来，而且可以将helloworld.c编译通过。</font></p>
<font face=宋体>很简单吧，几条命令就可以做出一个符合惯例的Makefile，感觉如何呀。</font>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　现在开始介绍详细的过程：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　1、建目录</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　在你的工作目录下建一个helloworld目录，我们用它来存放helloworld程序及相关文件，如在/home/my/build下：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>$ mkdir helloword<br>$ cd helloworld</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　2、 helloworld.c</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　然后用你自己最喜欢的编辑器写一个hellowrold.c文件，如命令：vi helloworld.c。使用下面的代码作为helloworld.c的内容。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>int main(int argc, char** argv)<br>{<br>printf("Hello, Linux World!\n");<br>return 0;<br>}</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　完成后保存退出。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　现在在helloworld目录下就应该有一个你自己写的helloworld.c了。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　3、生成configure</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　我们使用autoscan命令来帮助我们根据目录下的源代码生成一个configure.in的模板文件。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　命令：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>$ autoscan<br>$ ls<br>configure.scan helloworld.c</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　执行后在hellowrold目录下会生成一个文件：configure.scan，我们可以拿它作为configure.in的蓝本。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　现在将configure.scan改名为configure.in，并且编辑它，按下面的内容修改，去掉无关的语句：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>============================configure.in内容开始=========================================<br># -*- Autoconf -*-<br># Process this file with autoconf to produce a configure script.</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>AC_INIT(helloworld.c)<br>AM_INIT_AUTOMAKE(helloworld, 1.0)</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体># Checks for programs.<br>AC_PROG_CC</font></p>
<font face=宋体>AC_PROG_CC</font>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体># Checks for libraries.</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体># Checks for header files.</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体># Checks for typedefs, structures, and compiler characteristics.</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体># Checks for library functions.<br>AC_OUTPUT(Makefile)<br>============================configure.in内容结束=========================================</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>　　然后执行命令aclocal和autoconf，分别会产生aclocal.m4及configure两个文件：</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>$ aclocal<br>$ls<br>aclocal.m4 configure.in helloworld.c<br>$ autoconf<br>$ ls<br>aclocal.m4 autom4te.cache configure configure.in helloworld.c</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体><br>　　大家可以看到configure.in内容是一些宏定义，这些宏经autoconf处理后会变成检查系统特性、环境变量、软件必须的参数的shell脚本。</font></p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　autoconf 是用来生成自动配置软件源代码脚本（configure）的工具。configure脚本能独立于autoconf运行，且在运行的过程中，不需要用户的干预。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　要生成configure文件，你必须告诉autoconf如何找到你所用的宏。方式是使用aclocal程序来生成你的aclocal.m4。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　aclocal根据configure.in文件的内容，自动生成aclocal.m4文件。aclocal是一个perl 脚本程序，它的定义是：&#8220;aclocal - create aclocal.m4 by scanning configure.ac&#8221;。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　autoconf从configure.in这个列举编译软件时所需要各种参数的模板文件中创建configure。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　autoconf需要GNU m4宏处理器来处理aclocal.m4，生成configure脚本。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　m4是一个宏处理器。将输入拷贝到输出，同时将宏展开。宏可以是内嵌的，也可以是用户定义的。除了可以展开宏，m4还有一些内建的函数，用来引用文件，执行命令，整数运算，文本操作，循环等。m4既可以作为编译器的前端，也可以单独作为一个宏处理器。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">4、新建Makefile.am</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　新建Makefile.am文件，命令：</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>$ vi Makefile.am</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>　　内容如下:</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>AUTOMAKE_OPTIONS=foreign<br>bin_PROGRAMS=helloworld<br>helloworld_SOURCES=helloworld.c</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>　　automake会根据你写的Makefile.am来自动生成Makefile.in。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　Makefile.am中定义的宏和目标,会指导automake生成指定的代码。例如，宏bin_PROGRAMS将导致编译和连接的目标被生成。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　5、运行automake</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　命令：</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>$ automake --add-missing<br>configure.in: installing `./install-sh'<br>configure.in: installing `./mkinstalldirs'<br>configure.in: installing `./missing'<br>Makefile.am: installing `./depcomp'</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>　　automake会根据Makefile.am文件产生一些文件，包含最重要的Makefile.in。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　6、执行configure生成Makefile</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>$ ./configure<br>checking for a BSD-compatible install... /usr/bin/install -c<br>checking whether build environment is sane... yes<br>checking for gawk... gawk<br>checking whether make sets $(MAKE)... yes<br>checking for gcc... gcc<br>checking for C compiler default output... a.out<br>checking whether the C compiler works... yes<br>checking whether we are cross compiling... no<br>checking for suffix of executables...<br>checking for suffix of object files... o<br>checking whether we are using the GNU C compiler... yes<br>checking whether gcc accepts -g... yes<br>checking for gcc option to accept ANSI C... none needed<br>checking for style of include used by make... GNU<br>checking dependency style of gcc... gcc3<br>configure: creating ./config.status<br>config.status: creating Makefile<br>config.status: executing depfiles commands<br>$ ls -l Makefile<br>-rw-rw-r-- 1 yutao yutao 15035 Oct 15 10:40 Makefile</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>　　你可以看到，此时Makefile已经产生出来了。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　7、使用Makefile编译代码</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>$ make<br>if gcc -DPACKAGE_NAME="" -DPACKAGE_TARNAME="" -DPACKAGE_VERSION="" -</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">DPACKAGE_STRING="" -DPACKAGE_BUGREPORT="" -DPACKAGE="helloworld" -DVERSION="1.0"</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">-I. -I. -g -O2 -MT helloworld.o -MD -MP -MF ".deps/helloworld.Tpo" \<br>-c -o helloworld.o `test -f 'helloworld.c' || echo './'`helloworld.c; \<br>then mv -f ".deps/helloworld.Tpo" ".deps/helloworld.Po"; \<br>else rm -f ".deps/helloworld.Tpo"; exit 1; \<br>fi<br>gcc -g -O2 -o helloworld helloworld.o&nbsp;</p>
运行helloworld
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>$ ./helloworld<br>Hello, Linux World!</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>　　这样helloworld就编译出来了，你如果按上面的步骤来做的话，应该也会很容易地编译出正确的helloworld文件。你还可以试着使用一些其他的make命令，如make clean，make install，make dist，看看它们会给你什么样的效果。感觉如何？自己也能写出这么专业的Makefile，老板一定会对你刮目相看。<br>四、深入浅出</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　针对上面提到的各个命令，我们再做些详细的介绍。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　1、 autoscan</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　autoscan是用来扫描源代码目录生成configure.scan文件的。autoscan可以用目录名做为参数，但如果你不使用参数的话，那么autoscan将认为使用的是当前目录。autoscan将扫描你所指定目录中的源文件，并创建configure.scan文件。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　2、 configure.scan</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　configure.scan包含了&nbsp;<br>&nbsp;<br>&nbsp;<br>&nbsp;&nbsp;<br>&nbsp;<br>&nbsp;<br>系统配置的基本选项，里面都是一些宏定义。我们需要将它改名为configure.in</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　3、 aclocal</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　aclocal是一个perl 脚本程序。aclocal根据configure.in文件的内容，自动生成aclocal.m4文件。aclocal的定义是：&#8220;aclocal - create aclocal.m4 by scanning configure.ac&#8221;。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　4、 autoconf</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　autoconf是用来产生configure文件的。configure是一个脚本，它能设置源程序来适应各种不同的操作系统平台，并且根据不同的系统来产生合适的Makefile，从而可以使你的源代码能在不同的操作系统平台上被编译出来。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　configure.in文件的内容是一些宏，这些宏经过autoconf 处理后会变成检查系统特性、环境变量、软件必须的参数的shell脚本。configure.in文件中的宏的顺序并没有规定，但是你必须在所有宏的最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　在configure.ini中：</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　#号表示注释，这个宏后面的内容将被忽略。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　AC_INIT(FILE)</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　这个宏用来检查源代码所在的路径。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AM_INIT_AUTOMAKE(PACKAGE, VERSION)&nbsp;</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　这个宏是必须的，它描述了我们将要生成的软件包的名字及其版本号：PACKAGE是软件包的名字，VERSION是版本号。当你使用make dist命令时，它会给你生成一个类似helloworld-1.0.tar.gz的软件发行包，其中就有对应的软件包的名字和版本号。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AC_PROG_CC</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　这个宏将检查系统所用的C编译器。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AC_OUTPUT(FILE)</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　这个宏是我们要输出的Makefile的名字。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　我们在使用automake时，实际上还需要用到其他的一些宏，但我们可以用aclocal 来帮我们自动产生。执行aclocal后我们会得到aclocal.m4文件。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　产生了configure.in和aclocal.m4 两个宏文件后，我们就可以使用autoconf来产生configure文件了。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　5、 Makefile.am</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　Makefile.am是用来生成Makefile.in的，需要你手工书写。Makefile.am中定义了一些内容：</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AUTOMAKE_OPTIONS</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　这个是automake的选项。在执行automake时，它会检查目录下是否存在标准GNU软件包中应具备的各种文件，例如AUTHORS、ChangeLog、NEWS等文件。我们将其设置成foreign时，automake会改用一般软件包的标准来检查。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">bin_PROGRAMS</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　这个是指定我们所要产生的可执行文件的文件名。如果你要产生多个可执行文件，那么在各个名字间用空格隔开。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">helloworld_SOURCES</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　这个是指定产生&#8220;helloworld&#8221;时所需要的源代码。如果它用到了多个源文件，那么请使用空格符号将它们隔开。比如需要helloworld.h，helloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　如果你在bin_PROGRAMS定义了多个可执行文件，则对应每个可执行文件都要定义相对的filename_SOURCES。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　6、 automake</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　我们使用automake --add-missing来产生Makefile.in。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　选项--add-missing的定义是&#8220;add missing standard files to package&#8221;，它会让automake加入一个标准的软件包所必须的一些文件。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　我们用automake产生出来的Makefile.in文件是符合GNU Makefile惯例的，接下来我们只要执行configure这个shell 脚本就可以产生合适的 Makefile 文件了。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　7、 Makefile</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　在符合GNU Makefiel惯例的Makefile中，包含了一些基本的预先定义的操作：</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　根据Makefile编译源代码，连接，生成目标文件，可执行文件。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make clean</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　清除上次的make命令所产生的object文件（后缀为&#8220;.o&#8221;的文件）及可执行文件。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make install</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　将编译成功的可执行文件安装到系统目录中，一般为/usr/local/bin目录。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make dist</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　产生发布软件包文件（即distribution package）。这个命令将会将可执行文件及相关文件打包成一个tar.gz压缩的文件用来作为发布软件的软件包。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　它会在当前目录下生成一个名字类似&#8220;PACKAGE-VERSION.tar.gz&#8221;的文件。PACKAGE和VERSION，是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE, VERSION)。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make distcheck</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　生成发布软件包并对其进行测试检查，以确定发布包的正确性。这个操作将自动把压缩包文件解开，然后执行configure命令，并且执行make，来确认编译不出现错误，最后提示你软件包已经准备好，可以发布了。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">===============================================<br>helloworld-1.0.tar.gz is ready for distribution<br>===============================================<br>make distclean</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　类似make clean，但同时也将configure生成的文件全部删除掉，包括Makefile。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　五、结束语</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　通过上面的介绍，你应该可以很容易地生成一个你自己的符合GNU惯例的Makefile文件及对应的项目文件。</p>
<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">　　如果你想写出更复杂的且符合惯例的Makefile，你可以参考一些开放代码的项目中的configure.in和Makefile.am文件，比如：嵌入式数据库sqlite，单元测试cppunit。</p>
<img src ="http://www.cppblog.com/liu1061/aggbug/54543.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-25 11:46 <a href="http://www.cppblog.com/liu1061/articles/54543.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>