??xml version="1.0" encoding="utf-8" standalone="yes"?>色综合久久中文色婷婷,久久精品国产亚洲AV嫖农村妇女,国产高潮国产高潮久久久91http://www.shnenglu.com/liu1061/category/7456.html生活和工作都要充满激?否则你无法体会到淋漓致的快乐与痛苦zh-cnSat, 28 Jun 2008 14:45:53 GMTSat, 28 Jun 2008 14:45:53 GMT60makefile info!http://www.shnenglu.com/liu1061/articles/54848.htmlT.S LiuT.S LiuFri, 27 Jun 2008 16:05:00 GMThttp://www.shnenglu.com/liu1061/articles/54848.htmlhttp://www.shnenglu.com/liu1061/comments/54848.htmlhttp://www.shnenglu.com/liu1061/articles/54848.html#Feedback0http://www.shnenglu.com/liu1061/comments/commentRss/54848.htmlhttp://www.shnenglu.com/liu1061/services/trackbacks/54848.html
Make工程理?br>到此为止Q读者已了解了如何在Linux下用编辑器~写代码Q如何用Gcc把代码编译成可执行文,q学习了如何使用Gdb来调试程式,那么QQ何的工作看似已完成了Qؓ什么还需要Makeq个工程理器呢Q?br>所谓工E管理器Q顾名思义Q是指管理较多的文的。读者能够试想一下,有一个上百个文的代码构成的目Q假如其中只有一个或数几个文q行了修改,按照之前所学的Gcc~译工具Q就不得不把qQ何的文重新~译一遍,因ؓ~译器ƈ不知道哪些文档是最q更新的Q而只知道需要包含这些文才能把源代码编译成可执行文,于是Q程式员׃能不再重新输入数目如此庞大的文档名以完成最后的~译工作?br>但是Q请读者仔l回想一下本书在3.1.2?br>中所阐述的编译过E,~译q程是分为编译、汇~、链接不同阶D늚Q其中编译阶D仅查语法错误连同函数和变量的声明是否正声明了Q在链接阶段则主要完?br>是函数链接和全局变量的链接。因此,那些没有改变的源代码Ҏ无需重新~译Q而只要把他们重新链接q去p够了。所以,Z希望有一个工E管理器能够
自动识别更新了的文代码Q同时又无需重复输入冗长的命令行Q这PMake工程理器也应q而生了?br>实际上,Make工程理器也是?#8220;自动~译理?#8221;Q这里的“自动”是指他能够根据文档时间戳自动发现更新q的文而减编译的工作量,同时Q他通过dMakefile文的内Ҏ执行大量的编译工作。用户只需~写一ơ简单的~译语句p够了。他大大提高了实际项目的工作效率Q而且几乎MLinux下的目~程均会涉及CQ希望读者能够认真学习本节内宏V?br>3.6.1  Makefile基本l构
Makefile是Maked的惟一配置文档Q因此本节的内容实际是讲述Makefile的编写规则。在一个Makefile中通常包含如下内容Q?br>·  需要由make工具创徏的目标体QtargetQ,通常是目标文或可执行文;
·  要创建的目标体所依赖的文档(dependency_fileQ;
·  创徏每个目标体时需要运行的命oQcommandQ?br>他的格式为:

target: dependency_files
       command

例如Q有两个文分别为hello.c和hello.hQ创建的目标体ؓhello.oQ执行的命o为gcc~译指oQgcc –c hello.cQ那么,对应的Makefilep够写为:

#The simplest example
hello.o: hello.c hello.h
       gcc –c hello.c –o hello.o

接着p够用make了。用make的格式ؓQmake targetQ这样make׃自动dMakefileQ也能够是首字母写makefileQƈ执行对应target的command语句Qƈ会找到相应的依赖文。如下所C:

[root@localhost makefile]# make hello.o
gcc –c hello.c –o hello.o
[root@localhost makefile]# ls
hello.c  hello.h  hello.o  Makefile

能够看到QMakefile执行?#8220;hello.o”对应的命令语句,q生成了“hello.o”目标体?br>

注意
在Makefile中的每一个command前必L“Tab”W,否则在运行make命o时会出错?br>3.6.2  Makefile变量
上面CZ的Makefile在实际中是几乎不存在的,因ؓ他过于简单,仅包含两个文和一个命令,在这U情况下完全不必要编写Makefile而只需在Shell中直接输入即可,在实际中使用的Makefile往往是包含很多的文和命令的Q这也是Makefile产生的原因。下面就可给出稍微复杂一些的Makefileq行讲解Q?br>
sunq:kang.o yul.o
Gcc kang.o bar.o -o myprog
kang.o : kang.c kang.h head.h
Gcc –Wall –O -g –c kang.c -o kang.o
yul.o : bar.c head.h
Gcc - Wall –O -g –c yul.c -o yul.o

在这个Makefile中有三个目标体(targetQ,分别为sunq、kang.o和yul.oQ其中第一个目标体的依赖文就是后两个目标体。假如用户用命?#8220;make sunq”Q则make理器就是找到sunq目标体开始执行?br>q时Qmake会自动检查相x档的旉戟뀂首先,在检?#8220;kang.o”?#8220;yul.o”?#8220;sunq”三个文档的时间戳之前Q他会向下查N些把“kang.o”?#8220;yul.o”做ؓ目标文档的时间戳。比如,“kang.o”的依赖文档ؓQ?#8220;kang.c”?#8220;kang.h”?#8220;head.h”。假如这些文中M一个的旉x“kang.o”斎ͼ则命?#8220;gcc –Wall –O -g –c kang.c -o kang.o”会执行Q从而更新文?#8220;kang.o”。在更新?#8220;kang.o”?#8220;yul.o”之后Qmake会检查最初的“kang.o”?#8220;yul.o”?#8220;sunq”三个文Q只要文?#8220;kang.o”?#8220;yul.o”中的L文旉x“sunq”斎ͼ则第二行命o׃被执行。这Pmake完成了自动查时间戳的工作,开始执行编译工作。这也就是Make工作的基本流E?br>接下来,Zq一步简化编辑和l护MakefileQmake允许在Makefile中创建和使用变量。变量是在Makefile中定义的名字Q用来代替一个文本字W串Q该文本字符串称变量的倹{在具体需要下Q这些D够代替目标体、依赖文档、命令连同makefile文档中其他部分。在Makefile中的变量定义有两U方式:一U是递归展开方式Q另一U是单方式?br>递归展开方式定义的变量是在引用在该变量时q行替换的,卛_如该变量包含了对其他变量的应用,则在引用该变量时一ơ性将内嵌的变量全部展开Q虽然这U类型的变量能够很好地完成用L指oQ但是他也有严重的缺点,如不能在变量后追加内容(因ؓ语句QCFLAGS = $(CFLAGS) -O在变量扩展过E中可能D无穷循环Q?br>Z避免上述问题Q简单扩展型变量的值在定义处展开Qƈ且只展开一ơ,因此他不包含M对其他变量的引用Q从而消除变量的嵌套引用?br>递归展开方式的定义格式ؓQVAR=var
单扩展方式的定义格式为:VARQ?var
Make中的变量使用均用格式ؓQ?(VAR)


注意
变量名是不包?#8220;:”?#8220;#”?#8220;=”l尾I格的Q何字W串。同Ӟ变量名中包含字母、数字连同下划线以外的情况应量避免Q因Z们可能在来被赋予特别的含义?br>变量名是大小写敏感的Q例如变量名“foo”?#8220;FOO”、和“Foo”代表不同的变量?br>推荐在makefile内部使用写字母作ؓ变量名,预留大写字母作ؓ控制隐含规则参数或用户重载命令选项参数的变量名?br>
下面l出了上例中用变量替换修改后的MakefileQ这里用OBJS代替kang.o和yul.oQ用CC代替GccQ用CFLAGS代替“-Wall -O –g”。这样在以后修改Ӟp够只修改变量定义Q而无需修改下面的定义实体,从而大大简化了Makefilel护的工作量?br>l变量替换后的Makefile如下所C:

OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
       $(CC) $(OBJS) -o sunq
kang.o : kang.c kang.h
       $(CC) $(CFLAGS) -c kang.c -o kang.o
yul.o : yul.c yul.h
       $(CC) $(CFLAGS) -c yul.c -o yul.o

能够看到Q此处变量是以递归展开方式定义的?br>Makefile中的变量分ؓ用户自定义变量、预定义变量、自动变量及环境变量。如上例中的OBJS是用户自定义变量,自定义变量的值由用户自行讑֮Q而预定义变量和自动变量ؓ通常在Makefile都会出现的变量,其中部分有默认|也就是常见的讑֮|当然用户能够对其q行修改?br>预定义变量包含了常见~译器、汇~器的名U及其编译选项。下?.14列出了Makefile中常见预定义变量及其部分默认倹{?br>?.14                                                  Makefile中常见预定义变量
????br>?nbsp;   ?br>AR
库文维护程式的名称Q默认gؓar
AS
汇编E式的名Uͼ默认gؓas
CC
C~译器的名称Q默认gؓcc
CPP
C预编译器的名Uͼ默认gؓ$(CC) –E
CXX
C++~译器的名称Q默认gؓg++
FC
FORTRAN~译器的名称Q默认gؓf77
RM
文删除E式的名Uͼ默认gؓrm –f
ARFLAGS
库文档维护程式的选项Q无默认?br>ASFLAGS
汇编E式的选项Q无默认?br>CFLAGS
C~译器的选项Q无默认?br>CPPFLAGS
C预编译的选项Q无默认?br>CXXFLAGS
C++~译器的选项Q无默认?br>FFLAGS
FORTRAN~译器的选项Q无默认?br>
能够看出Q上例中的CC和CFLAGS是预定义变量Q其中由于CC没有采用默认|因此Q需要把“CC=Gcc”明确列出来?br>׃常见的Gcc~译语句中通常包含了目标文档和依赖文档Q而这些文在Makefile文中目标体的一行已有所体现Q因此,Zq一步简化Makefile的编写,引入了自动变量。自动变量通常能够代表~译语句中出现目标文和依赖文档{,q且具备本地含义Q即下一语句中出现的相同变量代表的是下一语句的目标文和依赖文Q。下?.15列出了Makefile中常见自动变量?br>?.15                                                    Makefile中常见自动变?br>命o格式
?nbsp;   ?br>$*
不包含扩展名的目标文档名U?br>$+
M的依赖文档,以空格分开Qƈ以出现的先后为序Q可能包含重复的依赖文
$
W一个依赖文档的名称
$?
M旉x目标文档晚的依赖文Qƈ以空格分开
命o格式
?nbsp;   ?br>$@
目标文的完整名U?br>$^
M不重复的依赖文档Q以I格分开
$%
假如目标是归成员,则该变量表示目标的归成员名U?br>
自动变量的书写比较难讎ͼ但是在熟l了之后会很的方便,误者结合下例中的自动变量改写的Makefileq行记忆?br>
OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
      $(CC) $^ -o $@
kang.o : kang.c kang.h
      $(CC) $(CFLAGS) -c $
yul.o : yul.c yul.h
      $(CC) $(CFLAGS) -c $

另外Q在Makefile中还能够使用环境变量。用环境变量的Ҏ相对比较单,make在启动时会自动读取系l当前已定义了的环境变量Qƈ且会创徏和之具备相同名称和数值的变量。但是,假如用户在Makefile中定义了相同名称的变量,那么用户自定义变量将会覆盖同名的环境变量?br>3.6.3  Makefile规则
Makefile的规则是Makeq行处理的依据,他包括了目标体、依赖文档及其之间的命o语句。一般的QMakefile中的一条语句就是个规则。在上面的例子中Q都昄地指ZMakefile中的规则关系Q如“$(CC) $(CFLAGS) -c $”Q但Z化Makefile的编写,makeq定义了隐式规则和模式规则,下面分别对其进行讲解?br>1Q隐式规?br>隐含规则能够告诉make怎样使用传统的技术完成Q务,q样Q当用户使用他们时就不必周详指定~译的具体细节,而只需把目标文档列出即可。Make会自动搜索隐式规则目录来定如何生成目标文。如上例p够写成:

OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
      $(CC) $^ -o $@

Z么能够省略后两句呢?因ؓMake的隐式规则指出:M“.o”文都可自动?#8220;.c”文使用命o“$(CC) $(CPPFLAGS) $(CFLAGS) -c file.c –o file.o”生成。这?#8220;kang.o”?#8220;yul.o”׃分别调用“$(CC) $(CFLAGS) -c kang.c -o kang.o”?#8220;$(CC) $(CFLAGS) -c yul.c -o yul.o”生成?br>

注意
在隐式规则只能查扑ֈ相同文档名的不同后缀名文档,?#8221;kang.o”文必须?#8221;kang.c”文生成?br>
下表3.16l出了常见的隐式规则目录Q?br>?.16                                                Makefile中常见隐式规则目?br>对应语言后缀?br>?nbsp;   ?br>C~译Q?c变ؓ.o
$(CC) –c $(CPPFLAGS) $(CFLAGS)
C++~译Q?cc?C变ؓ.o
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)
Pascal~译Q?p变ؓ.o
$(PC) -c $(PFLAGS)
Fortran~译Q?r变ؓ-o
$(FC) -c $(FFLAGS)
2Q模式规?br>模式规则是用来定义相同处理规则的多个文的。他不同于隐式规则,隐式规则仅仅能够用make默认的变量来q行操作Q而模式规则还能引入用戯定义变量Qؓ多个文建立相同的规则,从而简化Makefile的编写?br>模式规则的格式类g普通规则,q个规则中的相关文档前必ȝ“%”标明。用模式规则修改后的Makefile的编写如下:

OBJS = kang.o yul.o
CC = Gcc
CFLAGS = -Wall -O -g
sunq : $(OBJS)
      $(CC) $^ -o $@
%.o : %.c
      $(CC) $(CFLAGS) -c $

3.6.4  Make使用
使用make理器很单,只需在make命o的后面键入目标名卛_建立指定的目标,假如直接q行makeQ则建立Makefile中的W一个目标?br>此外make更有丰富的命令行选项Q能够完成各U不同的功能。下?.17列出了常用的make命o行选项?br>?.17                                                        make的命令行选项
命o格式
?nbsp;   ?br>-C dir
d指定目录下的Makefile
-f file
d当前目录下的file文档作ؓMakefile
命o格式
?nbsp;   ?br>-i
忽略M的命令执行错?br>-I dir
指定被包含的Makefile所在目?br>-n
只打印要执行的命令,但不执行q些命o
-p
昄make变量数据库和隐含规则
-s
在执行命令时不显C命?br>-w
假如make在执行过E中改变目录Q则打印当前目录?br>3.7  使用autotools
在上一节Q读者已了解Cmake目理器的强大功能。的,Makefile能够帮助make完成他的使命Q但要承认的是,~写Makefile实不是一件轻杄事,其对于一个较大的目而言更是如此。那么,有没有一U轻杄手段生成Makefile而同时又能让用户享受make的优性呢Q本节要讲的autotoolspd工具正是为此而设的,他只需用户输入单的目标文、依赖文、文档目录等p够轻村֜生成Makefile了,q无疑是q大用户的所希望的。另外,q些工具q能够完成系l配|信息的攉Q从而能够方便地处理各种UL性的问题。也正是Z此,现在Linux上的软g研发一般都用autotools来制作MakefileQ读者在后面的讲qC׃了解到?br>3.7.1  autotools使用程
正如前面所aQautotools是系列工P读者首先要认pȝ是否装了以下工具Q能够用which命oq行查看Q?br>·  aclocal
·  autoscan
·  autoconf
·  autoheader
·  automake
使用autotools主要是利用各个工具的脚本文以生成最后的Makefile。其M程是这LQ?br>·  使用aclocal生成一?#8220;aclocal.m4”文Q该文档主要处理本地的宏定义Q?br>·  改写“configure.scan”文Qƈ其重命名ؓ“configure.in”Qƈ使用autoconf文档生成configure文?br>接下来,W者将通过一个简单的hello.c例子带领读者熟悉autotools生成makefile的过E,׃在这q程中有涉及到较多的脚本文Qؓ了更清楚C解相互之间的关系Q强烈徏议读者实际动手操作以体会其整个过E?br>1Qautoscan
他会在给定目录及其子目录树中查源文档Q若没有l出目录Q就在当前目录及其子目录树中q行查。他会搜索源文以寻找一般的UL性问题ƈ创徏一个文?#8220;configure.scan”Q该文是接下来autoconf要用到的“configure.in”原型。如下所C:

[root@localhost automake]# autoscan
autom4te: configure.ac: no such file or directory
autoscan: /usr/bin/autom4te failed with exit status: 1
[root@localhost automake]# ls
autoscan.log  configure.scan  hello.c

如上所C,autoscan首先会尝试去d“configure.ac”Q同configure.in的配|文档)文Q此时还没有创徏该配|文档,于是他会自动生成一?#8220;configure.in”的原型文?#8220;configure.scan”?br>2Qautoconf
configure.in是autoconf的脚本配|文,他的原型文档“configure.scan”如下所C:

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
#The next one is modified by sunq
#AC_INIT(FULL-PACKAGE-NAME,VERSION,BUG-REPORT-ADDRESS)
AC_INIT(hello,1.0)
# The next one is added by sunq
AM_INIT_AUTOMAKE(hello,1.0)
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

下面对这个脚本文进行解释:
·  ?#8220;#”号开始的行ؓ注释?br>·  AC_PREREQ宏声明本文档需要的autoconf版本Q如本例使用的版?.59?br>· AC_INIT宏用来定义Y件的名称和版本等信息Q在本例中省略了BUG-REPORT-ADDRESSQ一般ؓ作者的e-mail?br>·  AM_INIT_AUTOMAKE是笔者另加的Q他是automake所必备的宏Q也同前面相同,PACKAGE是所要生Y件套件的名称QVERSION是版本编受?br>·  AC_CONFIG_SRCDIR宏用来侦所指定的源码文是否存在,来确定源码目录的?br>效性。在此处为当前目录下的hello.c?br>·  AC_CONFIG_HEADER宏用于生成config.h文Q以便autoheader使用?br>·  AC_CONFIG_FILES宏用于生成相应的Makefile文?br>·  中间的注释间能够d分别用户试E式、测试函数库、测试头文{宏定义?br>接下来首先运行aclocalQ生成一?#8220;aclocal.m4”文Q该文档主要处理本地的宏定义。如下所C:

[root@localhost automake]# aclocal

再接着q行autoconfQ生?#8220;configure”可执行文。如下所C:

[root@localhost automake]# autoconf
[root@localhost automake]# ls
aclocal.m4  autom4te.cache  autoscan.log  configure  configure.in  hello.c
3Qautoheader
接着使用autoheader命oQ他负责生成config.h.in文。该工具通常会从“acconfig.h”文中复制用户附加的W号定义Q因此此处没有附加符号定义,所以无需创徏“acconfig.h”文档。如下所C:

[root@localhost automake]# autoheader
4Qautomake
q一步是创徏Makefile很重要的一步,automake要用的脚本配|文是Makefile.amQ用户需要自己创建相应的文。之后,automake工具转换成Makefile.in。在该例中,W者创建的文为Makefile.am如下所C:

AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS= hello
hello_SOURCES= hello.c

下面对该脚本文档的对应项q行解释?br>·  其中的AUTOMAKE_OPTIONS为配|automake的选项。由于GNUQ在W?章中已有所介绍Q对自己发布的Y件有严格的规范,比如必须附带许可证声明文COPYING{,否则automake执行时会报错。automake提供了三UY件等U:foreign、gnu和gnitsQ让用户选择采用Q默认等Uؓgnu。在本例使用foreign{Q他只检必ȝ文档?br>·  bin_PROGRAMS定义要生的执行文名。假如要产生多个执行文Q每个文档名用空格隔开?br>·  hello_SOURCES定义“hello”q个执行E式所需要的原始文档。假?#8221;hello”q个E式是由多个原始文所产生的,则必L他所用到的Q何原始文都列出来,q用I格隔开。例如:若目标体“hello”需?#8220;hello.c”?#8220;sunq.c”?#8220;hello.h”三个依赖文Q则定义hello_SOURCES=hello.c sunq.c hello.h。要注意的是Q假如要定义多个执行文Q则Ҏ个执行程式都要定义相应的file_SOURCES?br>接下来能够用automake对其生成“configure.in”文Q在q里使用选项“—adding-missing”能够让automake自动d有一些必需的脚本文。如下所C:

[root@localhost automake]# automake --add-missing
configure.in: installing './install-sh'
configure.in: installing './missing'
Makefile.am: installing 'depcomp'
[root@localhost automake]# ls
aclocal.m4      autoscan.log  configure.in  hello.c     Makefile.am  missing
autom4te.cache  configure     depcomp    install-sh  Makefile.in  config.h.in

能够看到Q在automake之后p够生成configure.in文?br>5Q运行configure
在这一步中Q通过q行自动配置配置文档configureQ把Makefile.in变成了最l的Makefile。如下所C:

[root@localhost automake]# ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build enVironment is sane... yes
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for Gcc... Gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether Gcc accepts -g... yes
checking for Gcc option to accept ANSI C... none needed
checking for style of include used by make... GNU
checking dependency style of Gcc... Gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: executing depfiles commands
能够看到Q在q行configure时收集了pȝ的信息,用户能够在configure命o中对其进行方便地配置。在./configure的自定义参数有两U,一U是开兛_Q?-enable-XXX?-disable-XXXQ,另一U是开攑ּQ即后面要填入一串字W(--with-XXX=yyyyQ参数。读者能够自行尝试其使用Ҏ。另外,读者能够查看同一目录下的”config.log”文档Q以方便调试之用?br>到此为止Qmakefilep够自动生成了。回忆整个步骤,用户不再需要定制不同的规则Q而只需要输入简单的文及目录名卛_Q这样就大大方便了用L使用。下面的?.9ȝ了上q过E:

?.9  autotools生成Makefile程?br>3.7.2  使用autotools所生成的Makefile
autotools生成的Makefile除具备普通的~译功能外,q具备以下主要功能(感兴的读者能够查看这个简单的hello.cE式的makefileQ:
1Qmake
键入make默认执行”make all”命oQ即目标体ؓallQ其执行情况如下所C:

[root@localhost automake]# make
if Gcc
-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\"
-DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\"
-DVERSION=\"1.0\"  -I. -I.     -g -O2 -MT hello.o -MD -MP -MF
".deps/hello.Tpo" -c -o hello.o hello.c; \
then mv -f ".deps/hello.Tpo" ".deps/hello.Po"; else rm -f ".deps/hello.Tpo"; exit 1; fi
Gcc  -g -O2   -o hello  hello.o
此时在本目录下就生成了可执行文“hello”Q运?#8220;./hello”能出现正常结果,如下所C:

[root@localhost automake]# ./hello
Hello!Autoconf!
2Qmake install
此时Q会把该E式安装到系l目录中去,如下所C:

[root@localhost automake]# make install
if Gcc
-DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\"
-DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\"
-DVERSION=\"1.0\"  -I. -I.     -g -O2 -MT hello.o -MD -MP -MF
".deps/hello.Tpo" -c -o hello.o hello.c; \
then mv -f ".deps/hello.Tpo" ".deps/hello.Po"; else rm -f ".deps/hello.Tpo"; exit 1; fi
Gcc  -g -O2   -o hello  hello.o
make[1]: Entering directory '/root/workplace/automake'
test -z "/usr/local/bin" || mkdir -p -- "/usr/local/bin"
  /usr/bin/install -c 'hello' '/usr/local/bin/hello'
make[1]: Nothing to be done for 'install-data-am'.
make[1]: LeaVing directory '/root/workplace/automake'

此时Q若直接q行helloQ也能出现正结果,如下所C:

[root@localhost automake]# hello
Hello!Autoconf!
3Qmake clean
此时Qmake会清除之前所~译的可执行文及目标文档(object file, *.oQ,如下所C:

[root@localhost automake]# make clean
test -z "hello" || rm -f hello
rm -f *.o
4Qmake dist
此时Qmake程式和相关的文档打包ؓ一个压~文以供发布,如下所C:

[root@localhost automake]# make dist
[root@localhost automake]# ls hello-1.0-tar.gz
hello-1.0-tar.gz

可见该命令生成了一个hello-1.0-tar.gz的压~文?br>׃面的讲述读者不隄出,autotools实是Y件维护和发布的必备工P也鉴于此Q如今GUN的Y件一般都是由automake来制作的?br>

想一?br>对于automake制作的这cYӞ应如何安装呢Q?br>3.8.3  ~写包含多文档的Makefile
1Q实验目?br>通过对包含多文的Makefile的编写,熟悉各种形式的MakefileQƈ且进一步加深对Makefile中用戯定义变量、自动变量及预定义变量的理解?br>2Q实验过E?br>Q?Q用Vi在同一目录下编辑两个简单的HelloE式Q如下所C:

#hello.c
#include "hello.h"
int main()
{
       printf("Hello everyone!\n");
}
#hello.h
#include

Q?Q仍在同一目录下用Vi~辑MakefileQ且不用变量替换,用一个目标体实现Q即直接hello.c和hello.h~译成hello目标体)。然后用make验证所~写的Makefile是否正确?br>Q?Q将上述Makefile使用变量替换实现。同Lmake验证所~写的Makefile是否正确
Q?Q用~辑另一MakefileQ取名ؓMakefile1Q不使用变量替换Q但用两个目标体实现Q也是首先hello.c和hello.h~译为hello.oQ再hello.o~译为helloQ,再用make?#8221;-f”选项验证q个Makefile1的正性?br>Q?Q将上述Makefile1使用变量替换实现?br>3Q实验步?br>Q?Q用Vi打开上述两个代码文“hello.c”?#8220;hello.h”?br>Q?Q在shell命o行中用Gcc试~译Q用命令:”Gcc hello.c –o hello”Qƈq行hello可执行文档查看结果?br>Q?Q删除此ơ编译的可执行文档:rm hello?br>Q?Q用Vi~辑MakefileQ如下所C:

hello:hello.c hello.h
       Gcc hello.c -o hello

Q?Q退Z存,在shell中键入:makeQ查看结果?br>Q?Q再ơ用Vi打开MakefileQ用变量q行替换Q如下所C:

OBJS :=hello.o
CC :=Gcc
hello:$(OBJS)
       $(CC) $^ -o $@

Q?Q退Z存,在shell中键入:makeQ查看结果?br>Q?Q用Vi~辑Makefile1Q如下所C:

hello:hello.o
       Gcc hello.o -o hello
hello.o:hello.c hello.h
       Gcc -c hello.c -o hello.o

Q?Q退Z存,在shell中键入:make -f Makefile1Q查看结果?br>Q?0Q再ơ用Vi~辑Makefile1Q如下所C:

OBJS1 :=hello.o
OBJS2 :=hello.c hello.h
CC :=Gcc
hello:$(OBJS1)
       $(CC) $^ -o $@
$(OBJS1):$(OBJS2)
       $(CC) -c $

在这里请注意区别“$^”?#8220;$”?br>Q?1Q退Z存,在shell中键入:make -f Makefile1Q查看结?br>4Q实验结?br>各种不同形式的makefile都能完成其正的功能?br>3.8.4  使用autotools生成包含多文的Makefile
1Q实验目?br>通过使用autotools生成包含多文档的MakefileQ进一步掌控autotools的正用方法。同Ӟ掌控Linux下安装Y件的常用Ҏ?br>2Q实验过E?br>Q?Q在原目录下新徏文档夹auto?br>Q?Q利用上例的两个代码文档“hello.c”?#8220;hello.h”Qƈ他们复制到该目录下?br>Q?Q用autoscan生成configure.scan?br>Q?Q编辑configure.scanQ修改相兛_容,q将光命名为configure.in?br>Q?Q用aclocal生成aclocal.m4?br>Q?Q用autoconf生成configure?br>Q?Q用autoheader生成config.in.h?br>Q?Q编辑Makefile.am?br>Q?Q用automake生成Makefile.in?br>Q?0Q用configure生成Makefile?br>Q?1Q用make生成hello可执行文,q在当前目录下运行hello查看l果?br>Q?2Q用make installhello安装到系l目录下Qƈq行Q查看结果?br>Q?3Q用make dist生成hello压羃包?br>Q?4Q解压hello压羃包?br>Q?5Q进入解压目录?br>Q?6Q在该目录下安装hello软g?br>3Q实验步?br>Q?Qmkdir ./auto?br>Q?Qcp hello.* ./autoQ假定原先在“hello.c”文目录下)?br>Q?Q命令:autoscan?br>Q?Q用Vi~辑configure.scan为:

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)
AC_INIT(hello, 1.0)
AM_INIT_AUTOMAKE(hello,1.0)
AC_CONFIG_SRCDIR([hello.h])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT(Makefile)

Q?Q保存退出,q命名为configure.in?br>Q?Q运行:aclocal?br>Q?Q运行:autoconfQƈ用ls查看是否生成了configure可执行文档?br>Q?Q运行:autoheader?br>Q?Q用Vi~辑Makefile.am文档为:

AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
hello_SOURCES=hello.c hello.h

Q?0Q运行:automake?br>Q?1Q运行:./configure?br>Q?2Q运行:make?br>Q?3Q运行:./helloQ查看结果是否正?br>Q?4Q运行:make install?br>Q?5Q运行:helloQ查看结果是否正?br>Q?6Q运行:make dist?br>Q?7Q在当前目录下解压hello-1.0.tar.gzQtar –zxvf hello-1.0.tar.gz?br>Q?8Q进入解压目录:cd ./hello-1.0?br>Q?9Q下面开始Linux下常见的安装软g步骤Q?/configure?br>Q?0Q运行:make?br>Q?1Q运行:./helloQ在正常安装时这一步可省略Q?br>Q?2Q运行:make install?br>Q?3Q运行:helloQ查看结果是否正?br>4Q实验结?br>能够正确使用autotools生成MakefileQƈ且能够安装成功短的Hello软g?br>

T.S Liu 2008-06-28 00:05 发表评论
]]>
自动生成Makefile (?http://www.shnenglu.com/liu1061/articles/54793.htmlT.S LiuT.S LiuFri, 27 Jun 2008 04:33:00 GMThttp://www.shnenglu.com/liu1061/articles/54793.htmlhttp://www.shnenglu.com/liu1061/comments/54793.htmlhttp://www.shnenglu.com/liu1061/articles/54793.html#Feedback0http://www.shnenglu.com/liu1061/comments/commentRss/54793.htmlhttp://www.shnenglu.com/liu1061/services/trackbacks/54793.html在test目录上新建src和include目录Q源文g中src目录下,头文件在include目录。在src目录新徏Makefile.am文gQ编写Makefile.amQ如下:
AUTOMAKE_OPTIONS = foreign
INCLUDES= -I../include
bin_PROGRAMS = main
radio_SOURCES = main.c \
keyboard.c \
lcd.c \
setup.c \
storage.c
 
保存退出?/div>
q回test目录Q再新徏Makefile.am文gQ编写Makefile.am,如下Q?/div>
SUBDIRS = src
保存退出?/div>
 
执行 
autoscan
生成configure.scan文g Q如Q?/div>
autoscan.log  configure.scan  include  Makefile.am  src
~辑configure.scan文gQ如Q?/div>
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
AC_INIT(radio,1.0.0,[wenzel@163.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/make.c])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
#AC_PROG_RANLIB
# Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h termios.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_FORK
AC_PROG_GCC_TRADITIONAL
AC_FUNC_LSTAT
AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
AC_FUNC_MALLOC
AC_TYPE_SIGNAL
AC_CHECK_FUNCS([bzero memset strcasecmp strchr strrchr])
#AC_CONFIG_FILES([Makefile
#                 src/Makefile])
AC_OUTPUT(Makefile src/Makefile)
 
保存退出,改名为:mv configure.scan configure.in
执行Q?/div>
touch NEWS README AUTHORS ChangeLog
再执行:
autoreconf -fvi
 
最后,可以执行Q?/div>
./configure
配置为ARMq_Q?/div>
 ./configure --host=arm --target=arm CC=arm-linux-gcc
可以编译了Q如Q?/div>
make 
make install
make clean
make distclean


T.S Liu 2008-06-27 12:33 发表评论
]]>GNU Automakehttp://www.shnenglu.com/liu1061/articles/54741.htmlT.S LiuT.S LiuFri, 27 Jun 2008 01:43:00 GMThttp://www.shnenglu.com/liu1061/articles/54741.htmlhttp://www.shnenglu.com/liu1061/comments/54741.htmlhttp://www.shnenglu.com/liu1061/articles/54741.html#Feedback0http://www.shnenglu.com/liu1061/comments/commentRss/54741.htmlhttp://www.shnenglu.com/liu1061/services/trackbacks/54741.html阅读全文

T.S Liu 2008-06-27 09:43 发表评论
]]>
转一个automake的教E?/title><link>http://www.shnenglu.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.shnenglu.com/liu1061/articles/54740.html</guid><wfw:comment>http://www.shnenglu.com/liu1061/comments/54740.html</wfw:comment><comments>http://www.shnenglu.com/liu1061/articles/54740.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/liu1061/comments/commentRss/54740.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/liu1061/services/trackbacks/54740.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">使用 GNU autotools 攚w一个Y仉?br><br>本文不是一规范的教程Q而是用一个Y仉目作Z子,演示使用 GNU autotools q行<br>软g理的思\和过E?br><br>??br><br>· CZ目<br>· 软g布局<br>· Makefile 分析<br>· GNU 的Y仉?br>· 准备 autotools<br>· 攚w文件布局<br>· autoscan<br>· configure.ac 的基本结?br>· Makefile 文g的?br>· ~写 Makefile.am<br>软g根目?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>· q行 autotools<br>· SDL 库的侦测<br>· 软g使用的数据文?br>· configure 选项<br>· autotools 脚本<br>· 使用 configure 产生?Makefile<br>· 最l的 configure.ac 文g<br>· l束?br><br>CZ目<br><br>q里借用?Wei Mingzhi <whistler_wmz@users.sf.net> 开发的d游戏来进行演C,?br>此,先对他表C感?<br><br>CZ软g下蝲:<br><br><br><br>软g布局<br><br>下载的软g包解压到一个目?br><br>$ cd ~/work<br>$ tar xjf mahjong.tar.bz2<br><br>可以看到q是一个典型的 Windows 风格的Y仉目布局Q在 mahjong 目录下放着E序?br>源码Q程序运行时使用的数据文件放在子目录下面<br><br>作者还提供了一?MakefileQ一?DOS 风格?!play.bat 批处理文Ӟ一个编译好?br>mj.exe 可执行文件在 Win32 q_上运?!play.bat 可以直接运行程序在 Unix/<br>Linux pȝ上,q入 mahjong 目录Q键?make 命oQ如果一切顺利的话,生?mj ?br>执行文gQ然后在命o行上q行 ./mj E序Q也可以启动d游戏<br><br>对于一?Windows E序来讲Q该软g布局可以说非常清晰明了但?Unix/Linux pȝ<br>上,执行 make 命o可能遇到问题:~译找不到头文gQ或者连接找不到库文件而在<br>make 成功以后Q运行麻程序必dq入?majiong 目录Q才能执行程序如果要?br>其他的程序一P可以在Q意目录用,p专门一个程序修?PATH 环境变量Q或<br>者再写一个启动脚本,q将它复制到 /usr/bin q样的目录下<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 $< -o $@<br>41<br>42 %.o: %.c ${HEADERS}<br>43 ${CC} ${CFLAGS} -c $< -o $@<br><br>Makefile 很清楚:W?20 行定?TARGET 变量?mjQ第 28 行表?make 默认?target<br>也就是生?`mj'Q第 22 行加入编译时的调试信息;W?2526 行用了 sdl-config ?br>具侦?SDL 开发库~译链接信息Q在 26 行还指明需要连?SDL_imageSDL_mixser ?br>SDL_ttf ?br><br>GNU 的Y仉?br><br>一个标准的 GNU 软gQ编译安装都是用下面三个步?<br><br>$ ./configure<br>$ make<br>$ make install<br><br>configure 脚本q行时可以侦系l的环境Q确定Y件安装目录,然后生成 Makefile ?br>件make 调用pȝ中的~译器进行编译和q接make install Y件安装到讑֮的目?br><br><br>用户执行 configure 时可以通过它的命o行参数指定自己所需的编译选项Q比如安装目?br>通过 --prefix=PREFIX 讄Q如果不指定Q缺省情况下 PREFIX ?/usr/local默认?br>装时Q执行文件安装到 /usr/local/bin 目录Q库安装?/usr/local/lib 目录Q数据文<br>件安装到 /usr/local/share 目录<br><br>׃ GNU 的Y仉格方便易用,通用性好Q可UL性高Q现在大多数 Unix/Linux pȝ?br>的自pY仉采用q种方式分发软g<br><br>准备 autotools<br><br>GNU autotools 主要包含三个软gQ?autoconfQautomake ?libtool当前行的有?br>旧两个版本,本例采用的是新版本,分别对应的是Q?autoconf 2.59Q?automake 1.9.6<br>?libtool 1.5.18<br><br>很多 linux 发行版都会默认安装这几个工具本例是在 NetBSD 下进行操作,安装q几?br>软g包是通过 pkgsrcQ它们在 pkgsrc 目录?devel/autoconf devel/automake ?br>devel/libtool<br><br>攚w文件布局<br><br>原来软g的根目录下面攄是程序的源码Q按?GNU 的习惯,它们放?src 子目录,<br>根目录留l?configure q类文g使用Q其他的数据文g保持不变Q仍然放在各自的子目?br><br><br>先创Z个目?majiangQ然后根据需要将 mahjong 目录下的文g复制q来׃是ؓ<br>Unix/Linux pȝq行改写Q原目录里的 win32 相关文g׃用复制到新目?br><br>$ cd ~/work/majiang<br>$ ls<br>data/ docs/ fonts/ images/ music/ sound/ src/<br><br>autoscan<br><br>autoconf 软g包里面的 autoscan 工具可以扫描工作目录Q生成一?configure.ac ?br>模板文g configure.scan<br><br>$ cd ~/work/majiang<br>$ autoscan<br><br>autoscan 命o在当前目录生成的 configure.scan 文g内容?<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># 号开始的行是注释Q其他都?m4 宏命令将它改名ؓ configure.acQ然后在此基?br>q行修改<br><br>configure.ac 的基本结?br><br>configure.ac 文g?autoconf 的输入文Ӟl过 autoconf 处理Q展开里面?m4 宏,<br>输出的是 configure 脚本<br><br>W?4 行声明本文g要求?autoconf 版本Q因为本例用了新版?2.59Q所以在此注?br><br><br>W?5 ?AC_INIT 宏用来定义Y件的名称和版本等信息Q本例写?<br><br>AC_INIT(majiang, 1.0)<br><br>q里省略?BUG-REPORT-ADDRESS 参数Q它是可选项Q一般写成作者的邮g地址<br><br>W?6 ?AC_CONFIG_SRCDIR 宏通过侦测所指定的源码文件是否存在,来确定源码目录的?br>效性可以选择源码目录中的M一个文件作Z表,比如?autoscan 选择?bot.h<br>文gҎ main.cpp:<br><br>AC_CONFIG_SRCDIR([src/main.cpp])<br><br>宏参C使用 `[ ]'Q是Z表明其中的字W串是一个整?br><br>W?7 行的 AC_CONFIG_HEADER 宏用于生?config.h 文gQ里面存?configure 脚本?br>到的信息如果程序需要用其中的定义Q就在源码中加入<br><br>#include <config.h><br><br>其他的一些宏是标准的侦测q程Q可以保留不?br><br>configure.ac 文g要求 AC_INIT 宏必L在开头位|,AC_OUTPUT 攑֜文g末,中间?br>来检编译环境的各种宏没有特别的先后ơ序要求Q由宏之间相互关pd?br><br>Makefile 文g的?br><br>前面 configure.ac 里面的宏Q主要作用是侦测pȝQƈ没有~译相关的设|因?br>信息是写?Makefile.am 里面Q然后用 automake 工具转换?Makefile.inQconfigure<br>脚本执行时再d Makefile.inQƈ与侦信息一起写?Makefile 文g<br><br>?autotools 的命名习惯中Q后~ ac 的文件是 autoconf 的输入文Ӟ后缀 am 的文<br>件是 automake 的输入文Ӟ后缀 in 的文件是 configure 的输入文?autoconf 旧版<br>本中 configure.in {同?configure.acQ虽然新版本也可以识别,但它不符合命名规?br>Q所以新版本的文件应该?ac 后缀<br><br>单的 Makefile.in 可以手动~写Q如果?automake 产生Q需要在 configure.ac<br>里面加入 AM_INIT_AUTOMAKE 宏进行声?br><br>要输?MakefileQ还需要在 configure.ac 中?AC_CONFIG_FILES 宏指明该宏ƈ?br>是只处理 MakefileQ而是?FILE.in 文g转换?FILE 文g因ؓ make 可以遍历子目<br>录,如果子目录中存在 MakefileQ也同时处理在本例?src 目录下是源码Q其他是<br>数据文gQ可以用单独一?Makefile 攑֜根目录下面,也可以用多个 Makefile׃<br>每个子目录的 Makefile 只处理本目录的文Ӟ分工明确Q是模块化的ҎQ推荐?br>因此?configure.ac 里面增加下面的宏Q表CY件根目录和子目录中都需要生?br>Makefile 文g:<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>软g根目?Makefile.am<br><br>׃该目录下面保存的是与 autotools 相关的文Ӟ没有需要编译安装的文gQ所以只?br>明需要进一步处理的子目录信?<br><br>SUBDIRS = src data docs fonts images music sound<br><br>src/Makefile.am<br><br>此目录里是源代码Q最l生?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 文g里变量通过命名判断其含义,保留的字W串间用下划U分?br><br>bin_PROGRAMS 表示列出二进制的E序Qgؓ多个I格分开的程序列表,q里仅有一?mj<br><br><br>mj_SOURCES 列出的是l成 mj E序的文Ӟ文g比较多的时候,每个文g写成一行容易看<br>清楚<br><br>data/Makefile.am<br><br>本目录的文g?mj q行时读取的数据Q它?Makefile.am 可以q样?br><br>mjdatadir = $(pkgdatadir)/data<br>mjdata_DATA = mj.ini titles.txt<br>EXTRA_DIST = $(mjdata_DATA)<br><br>因ؓ datadir 是保留的关键字,所以用 mjdatadir 代替Qpkgdatadir 指向 $prefix/<br>share/FULL-PACKAGE-NAME 目录Q因为在 AC_INIT 中已l声?FULL-PACKAGE-NAME ?br>majiangQpkgdatadir q?$prefix/share/majiang 目录<br><br>其中 mjdatadir ?data 目录下的文g安装?$prefix/share/majiang/data 目录里面<br><br>mjdata_DATA 列出此目录下需要安装的文gQ然后用 EXTRA_DIST 变量注明<br><br>余下几个子目录都?data 目录cM<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>q行 autotools<br><br>准备?configure.ac ?Makefile.amQ就可以?autotools 的命令处理这些文件开?br>可能会出现错误,不过没关p,可以按照错误信息的提C逐步q行修正<br><br>首先要用的?aclocal 命oQ它Ҏ configure.ac 的定义,需要用的 m4 宏定<br>义复制到 aclocal.m4 里面~省Ӟ搜烦 m4 宏是?autoconf 的安装目录和pȝ?br>aclocal 目录如果需要用其他\径下的宏Q可以通过命o行的 -I 选项指定<br><br>接着使用 autoheader 命oQ它负责生成 config.h.in 文gQ这里面?C 语言宏定义也<br>是通过解析 configure.ac 产生<br><br>下来q行 automake 命o处理 Makefile.amQ生?Makefile.inGNU 对自己发布的软g<br>有严格的规范Q比如必附带许可证声明文g COPYING {等Q否?automake 执行时会<br>报错automake 提供了三UY件等U: foreigngnu ?gnitsQ让用户选择采用Q默?br>{?gnu本例使用 foreign {Q它只检必ȝ文g有一些必需的脚本文件可?br>?automake 软g包里复制q来Q在执行时?--add-missing 选项可以?automake ?br>动添加,默认方式是采用符号链接,如加?--copy 选项则可以用复制方式本例中Q?br>automake 的命令如?<br><br>$ automake --foreign --add-missing --copy<br><br>最后,使用 autoconf 命o生成 configure 脚本文g<br><br>SDL 库的侦测<br><br>q个d游戏是基?SDL 库开发的Q一般系l默认不会安装,因此 configure 脚本的一<br>个Q务就是检查用Lpȝ中是否有该Y件包<br><br>autoconf 提供了很多宏可以实现侦测功能Q但首先应该查看 SDL 软g包是否已l提供相<br>应的宏通过 pkgsrc 的工具可以看?<br><br>$ pkg_info -L SDL|grep m4<br>/usr/pkg/share/aclocal/sdl.m4<br><br>?SDL 软g包提供了一?sdl.m4 宏,攑֜pȝ?aclocal 目录?br><br>在这个宏文g的注释中说明了用的Ҏ:<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>后,该宏q输?SDL_CFLAGS ?SDL_LIBS ~译q接选项Q它们实际上是调用<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.9Q于?MINIMUM-VERSION p?1.2.0如果在系l中侦测?br>需要的库,没什么额外的操作Q假如没有找刎ͼ则给出错误信?br><br>AM_PATH_SDL 输出 SDL_CFLAGS ?SDL_LIBS ~译参数Q需要添加到 src/Makefile.am ?br>?<br><br>mj_CPPFLAGS = @SDL_CFLAGS@<br>mj_LDFLAGS = @SDL_LIBS@<br><br>?`@' 包围的变量会?configure 执行时被替换<br><br>?mahjong ?Makefile 中看刎ͼq个软gq要使用 SDL_imageSDL_mixser ?br>SDL_ttf 库,但它们不属于 SDL 软g包,需要另外安装由于这些库?sdl.m4 中也?br>有进行侦,所以自p写一些脚?br><br>autotools 提供了一?AC_CHECK_LIB 宏可以用来检库Q现在就使用它来这几个<br>SDL 库该宏的语法?<br><br>AC_CHECK_LIB (LIBRARY, FUNCTION, [ACTION-IF-FOUND],<br>[ACTION-IF-NOT-FOUND], [OTHER-LIBRARIES])<br><br>W一个参数是库名Q第二个参数是库中的一个函敎ͼW三个参数是到以后q行的动?br>Q第四个参数是未到以后的动作,W五个参数是其他的库<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>软g使用的数据文?br><br>原来 mj d数据是从执行时目录的子目录中dQ但现在数据放?$prefix/share/<br>majiang 目录下,需要通过一U途径让程序可以知道数据文件被安放的位|?br><br>要达到这个目的有很多ҎQ这里采用最直接的一U:数据文件安装目录变量通过<br>CPPFLAGS ~译参数传递给E序<br><br>于是修改 src/Makefile.am ?CPPFLAGS:<br><br>mj_CPPFLAGS = @SDL_CFLAGS@ -DDATA_DIR=\"${datadir}/majiang\"<br><br>相应C?src 目录下的源码Q在d数据文g的地方,读取的路径Ҏ 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 W?22 行定义了 debug 调试选项Q虽然也可以照样攑ֈ src/<br>Makefile.am ?CPPFLAGS 里面实现Q但 autotools 提供了一U更灉|的机?br><br>configure 脚本可以通过选项来设|编译参敎ͼ现增加一?--enable-debug 选项Q需?br>DEBUG Ӟ在命令行上加上它来打开Q默认则关闭<br><br>q项功能是?AC_ARG_ENABLE 宏实?<br><br>AC_ARG_ENABLE (FEATURE, HELP-STRING, [ACTION-IF-GIVEN],<br>[ACTION-IF-NOT-GIVEN])<br><br>其中 FEATURE 是名Uͼ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 输入文g后都需要再ơ运?br>aclocalautomakeautoconf q些命oQؓ了方便v见,可以他们放C?shell<br>脚本里面Q例?<br><br>#! /bin/sh<br>set -x<br>aclocal<br>autoheader<br>automake --foreign --add-missing --copy<br>autoconf<br><br>上面内容保存到 autogen.sh 文gQƈ修改文g属性ؓ 755每次需要重新生?br>configure 脚本Ӟ执行 ./autogen.sh 卛_<br><br>使用 configure 产生?Makefile<br><br>现在执行 ./autogen.sh 得到?configure 脚本已经可以正常工作了,q入 ~/work/<br>majiang 目录Q执?./configureQ可以看到它查系l的q程Q包?SDL ?br>SDL_image {库的侦结果?./configure --help 可以看到 autotools 提供的帮<br>助信?br><br>configure 执行的完毕,输出软g根目录和几个子目录下面的 Makefile 文gq些<br>Makefile 有几个常用的 target:<br><br>· make all<br><br>不加M targetQ默认就?allQ作用是~译软g<br><br>· make install<br><br>安装软g包,如果安装到系l目录,需?root 权限<br><br>· make clean<br><br>清除~译产生的目标文?br><br>· make distclean<br><br>可以同时清除~译的结果和 configure 输出的文?br><br>· make tags<br><br>生成 etags 使用?TAGS 文g<br><br>· make dist<br><br>生成软g发布包,?tar.gz 格式的压~包Q文件名pY件包名和版本l成<br><br>最l的 configure.ac 文g<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>l束?br><br>GNU 的很多工L常给ZU感? 功能很强大,但也很难学autotools 可以说是q类<br>工具的一个典型,它需要用户对 shellmake软g~译m4 宏语aQ以?Unix/Linux<br>操作pȝ各方面知识都有一定的了解使用时又?autoconf automakelibtool 多个<br>工具怺配合^1Q如果要lY件增加国际化功能Q还要再了解和掌?gettextpo {工?br>和规?br><br>与学习其他知识一P所谓难Q其实是不了解,不熟悉本文通过一个范例演CZ?br>autotools 的过E,是让不了解的人熟悉这个工具但真正的理解,q需要将它运用到?br>q软g目当中Q不断地实践Q不断地思考和ȝ<br><br><br><br><br>脚注<br><br>... 多个工具怺配合^1<br>׃本例软g中没有生成库文gQ所以没有涉?libtool 工具的?br></span> <img src ="http://www.shnenglu.com/liu1061/aggbug/54740.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-27 09:42 <a href="http://www.shnenglu.com/liu1061/articles/54740.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>q用autoconf和automake自动生成Makefil http://www.shnenglu.com/liu1061/articles/54675.htmlT.S LiuT.S LiuThu, 26 Jun 2008 07:23:00 GMThttp://www.shnenglu.com/liu1061/articles/54675.htmlhttp://www.shnenglu.com/liu1061/comments/54675.htmlhttp://www.shnenglu.com/liu1061/articles/54675.html#Feedback0http://www.shnenglu.com/liu1061/comments/commentRss/54675.htmlhttp://www.shnenglu.com/liu1061/services/trackbacks/54675.html对于一个UNIX/Linux下CE序员来_一个比较麻烦的工作是写自qMakefile?
可能你有如下l验Q写一个简单的CE序Q自己多写几行gcc命o把E序变成可执行的了;写一个稍微复杂点的程序,源文件个数可能在30个左叻Iq是写一行行的gcc命o麻烦了Q你可能惛_写个makefileQ你可能也在q样做着Q但你某一天会发现你写的这个Makefile可能不是一个所?UNIX/LinuxcL作系l下通用的MakefileQ比如某Z载了你的E序M自己电脑上可能make不了?

q样Q你有必要了解q学会运用autoconf和automake了?
autoconf是一个用于生成可以自动地配置软g源代码包以适应多种UNIXcȝl的shell脚本的工兗由autoconf生成的配|脚本在q行的时候不需要用L手工q预Q通常它们甚至不需要手工给出参C定pȝ的类型。相反,它们对Y件包可能需要的各种特征q行独立的测试。在每个试之前Q它们打C个单行的消息以说明它们正在进行的,以得用户不会因为等待脚本执行完毕而焦w。因此,它们在؜合系l或者从各种常见UNIX变种定制而成的系l中工作的很好。你也省了工作,没必要维护文件以储存由各个UNIX变种、各个发行版本所支持的特征的列表?
automake是一个从文gMakefile.am自动生成Makefile.in的工兗每个Makefile.am基本上是一pdmake的宏定义Qmake规则也会偶尔出现Q生成的Makefile.inQ服从GNU Makefile标准?
Z生成Makefile.inQautomake需要perl。但是由automake创徏的发布完全服从GNU标准Qƈ且在创徏中不需要perl?

在开始用autoconf和automake之前Q首先确认你的系l安装有GNU的如下YӞ
1. automake
2. autoconf
3. m4
4. perl
5. 如果你需要生共享库Qshared libraryQ则q需要GNU Libtool

介绍Ҏ之前大家看一下下面这个图Q先Cautoconf和automake工作的几个步骤:


步骤解释如下Q?
1、由你的源文仉过autoscan命o生成configure.scan文gQ然后修改configure.scan文gq命名为configure.in
2、由aclocal命o生成aclocal.m4
3、由autoconf命o生成configure
4、编辑一个Makefile.am文gq由automake命o生成Makefile.in文g
5、运行configure命o生成Makefile

automake支持三种目录层次Qflat、shallow和deep?
一个flat包指的是所有文仉在一个目录中的包。ؓq类包提供的Makefile.am不需要SUBDIRSq个宏。这cd的一个例子是termutils。对应咱们程序员来说Q就是所有源文g及自己写的头文g都位于当前目录里面,且没有子目录?
一个deep包指的是所有的源代码都被储存在子目录中的包Q顶层目录主要包含配|信息。GNU cpio是这cd的一个很好的例子QGNU tar也是。deep包的层Makefile.am包括宏SUBDIRSQ但没有其它定义需要创建的对象的宏。对应咱们程序员来说Q就是所有源文g及自己写的头文g都位于当前目录的一个子目录里面Q而当前目录里没有M源文件?
一个shallow包指的是主要的源代码储存在顶层目录中Q而各个部分(典型的是库)则储存在子目录中的包。automake本n是q类包(GNU make也是如此Q它现在已经不用automakeQ。对应咱们程序员来说Q就是主要源文g在当前目录里Q而其它一些实现各部分功能的源文g各自位于不同目录?

前两个层ơ的E序~辑Ҏ非常单,按照上述步骤一步步卛_。而第三种层次shallowE微复杂一点,但这是我们经常写E序用到的结构。下面以一个例子说明shallow层次l构的源文g如何自动生成Makefile文g?
例子源程序结构如下:
hello是我们的工作目录Qhello目录下有main.c源文件和comm、tools、db、network、interface{五个目录?comm目录下有comm.c和comm.h源文件及头文Ӟtools目录下有tools.c和tools.hQ同样其它目录分别有db.c?db.h、network.c、network.h、interface.c、interface.h{一些源文g?

按照如下步骤来自动生成Makefile吧:
1、进入hello目录Q运行autoscan命oQ命令如下:
cd hello
autoscan
2、ls会发现多了一个configure.scan文g。修Ҏ文gQ在AC_INIT宏之后加入AM_INIT_AUTOMAKE(hello, 1.0)Q这里hello是你的Y件名Uͼ1.0是版本号Q即你的q些源程序编译将生成一个Y件hello-1.0版。然后把 configure.scan文g的最后一行AC_OUTPUT宏填写完整变成AC_OUTPUT(Makefile)Q表明autoconf?automake最l将生成Makefile文g。最后把configure.scan文g改名为configure.in。最l?configure.in文g内容如下Q?

dnl Process this file with autoconf to produce a configure script.
AC_INIT(target.c)
AM_INIT_AUTOMAKE(hello, 1.0)
dnl Checks for programs.
AC_PROG_CC

dnl Checks for libraries.

dnl Checks for header files.

dnl Checks for typedefs, structures, and compiler characteristics.

dnl Checks for library functions.

AC_OUTPUT(Makefile)

3、运行aclocal命oQls会发现多了一个aclocal.m4文g?
4、然后运行autoconf命oQls发现生成了一个可执行的configure命o?
5、编辑一个Makefile.am文gQ文件内容如下:
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
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
q表明你最后将通过一个make命o利用上述hello_SOURCES源文件生成一个hello的程序?
6、运行automake --add-missing命o。屏q提C如下:
automake: configure.in: installing `./install-sh'
automake: configure.in: installing `./mkinstalldirs'
automake: configure.in: installing `./missing'
7、然后你可以q行之前生成的configure命o来生成一个Makefile文gQ输?/configure命o卛_?
8、编辑Makefile文gQ找?(LINK)所在的那一行,本来生成的文件内容如下:
@rm -f hello
$(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS)
在这两行之间增加几行变成Q?
@rm -f hello
@mv -f comm.o comm
@mv -f tools.o tools
@mv -f db.o db
@mv -f network.o network
@mv -f interface.o interface
$(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS)
q是因ؓ默认生成的Makefile在~译后把所有目标文件置于当前目录,而在q行链接(link)时又会到各个子目录去扄应的目标文g?
当然Qؓ了完_各位在clean部分加上如下一些行Q?
@rm -f comm/comm.o
@rm -f tools/tools.o
@rm -f db/db.o
@rm -f network/network.o
@rm -f interface/interface.o

好了Q经q上q这些步骤后Q现在你可以来编译生成你自己的可执行E序了。输入一个make all吧,然后可以运?/hello来看你的E序q行了?

q用autoconf和automake的最大好处是Q你的程序以源程序方式发布后Q其它所有h只需要依ơ输?
./configure
make
make install
命o可以把你的E序安装在自q电脑上运行了。所有符合GNU标准的UNIX/Linux都不需要再修改Makefile里的M字符?/p> [@more@]

T.S Liu 2008-06-26 15:23 发表评论
]]>
autoconf ?automake 生成 Makefile 文g (?http://www.shnenglu.com/liu1061/articles/54653.htmlT.S LiuT.S LiuThu, 26 Jun 2008 04:01:00 GMThttp://www.shnenglu.com/liu1061/articles/54653.htmlhttp://www.shnenglu.com/liu1061/comments/54653.htmlhttp://www.shnenglu.com/liu1061/articles/54653.html#Feedback0http://www.shnenglu.com/liu1061/comments/commentRss/54653.htmlhttp://www.shnenglu.com/liu1061/services/trackbacks/54653.html
文选项
此作为电子邮件发?src="http://www.ibm.com/i/v14/icons/em.gif"

此作为电子邮件发?/a>

未显C需?JavaScript 的文档选项

样例代码


U别Q?初

?华 (normalnotebook@126.com), Linux 内核研究?br>?春艳, 在读研究?br>

2006 q?9 ?21 ?/p>

本文介绍了在 linux pȝ中,通过 Gnu autoconf ?automake 生成 Makefile 的方法。主要探讨了生成 Makefile 的来龙去脉及其机理,接着详细介绍了配|?Configure.in 的方法及其规则?/blockquote>

引子

无论是在Linuxq是在Unix环境中,make都是一个非帔R要的~译命o。不是自己q行目开发还是安装应用YӞ我们都经常要用到make?make install。利用make工具Q我们可以将大型的开发项目分解成为多个更易于理的模块,对于一个包括几百个源文件的应用E序Q用make?makefile工具可以轻而易丄理顺各个源文件之间纷J复杂的怺关系?/p>

但是如果通过查阅make的帮助文档来手工~写Makefile,对Q何程序员都是一场挑战。幸而有GNU 提供的Autoconf及Automakeq两套工具得编写makefile不再是一个难题?/p>

本文介l如何利?GNU Autoconf ?Automake q两套工h协助我们自动产生 Makefile文gQƈ且让开发出来的软g可以像大多数源码包那P只需"./configure", "make","make install" 可以把E序安装到系l中?/p>



回页?/a>


模拟需?/a>

假设源文件按如下目录存放Q如?所C,q用autoconf和automake生成makefile文g?/p>
?1文g目录l构
?1文g目录l构

假设src是我们源文g目录Qinclude目录存放其他库的头文Ӟlib目录存放用到的库文gQ然后开始按模块存放Q每个模块都有一个对应的目录Q模块下再分子模块,如apple、orange。每个子目录下又分coreQincludeQshell三个目录Q其中core和shell目录存放.c文gQinclude的存?h文gQ其他类伹{?/p>

样例E序功能Q基于多U程的数据读写保护(联系作者获取整个autoconf和automake生成的Makefile工程和源码,E-mailQ?a href="mailto:normalnotebook@126.com">normalnotebook@126.comQ?/p>



回页?/a>


工具?/a>

所必须的YӞautoconf/automake/m4/perl/libtoolQ其中libtool非必)?/p>

autoconf是一个用于生成可以自动地配置软g源码包,用以适应多种UNIXcȝl的shell脚本工具Q其中autoconf需要用?m4Q便于生成脚本。automake是一个从Makefile.am文g自动生成Makefile.in的工兗ؓ了生成Makefile.inQautomakeq需用到perlQ由于automake创徏的发布完全遵循GNU标准Q所以在创徏中不需要perl。libtool是一ƾ方便生成各U程序库的工兗?/p>

目前automake支持三种目录层次Qflat、shallow和deep?/p>

1) flat指的是所有文仉位于同一个目录中?/p>

是所有源文g、头文g以及其他库文仉位于当前目录中,且没有子目录。Termutils是q一cR?/p>

2) shallow指的是主要的源代码都储存在顶层目录,其他各个部分则储存在子目录中?/p>

是主要源文件在当前目录中,而其它一些实现各部分功能的源文g位于各自不同的目录。automake本n是q一cR?/p>

3) deep指的是所有源代码都被储存在子目录中;层目录主要包含配置信息?/p>

是所有源文g及自己写的头文g位于当前目录的一个子目录中,而当前目录里没有M源文件?GNU cpio和GNU tar是q一cR?/p>

flatcd是最单的Qdeepcd是最复杂的。不隄出,我们的模拟需求正是基于第三类deep型,也就是说我们要做挑战性的事情Q?。注Q我们的试E序是基于多U程的简单程序?/p>



回页?/a>


生成 Makefile 的来龙去?/a>

首先q入 project 目录Q在该目录下q行一pd命oQ创建和修改几个文gQ就可以生成W合该^台的Makefile文gQ操作过E如下:

1) q行autoscan命o

2) configure.scan 文g重命名ؓconfigure.inQƈ修改configure.in文g

3) 在project目录下新建Makefile.am文gQƈ在core和shell目录下也新徏makefile.am文g

4) 在project目录下新建NEWS?README?ChangeLog 、AUTHORS文g

5) ?usr/share/automake-1.X/目录下的depcomp和complie文g拯到本目录?/p>

6) q行aclocal命o

7) q行autoconf命o

8) q行automake -a命o

9) q行./confiugre脚本

可以通过?看出产生Makefile的流E,如图所C:


?2生成Makefile程?/a>
?2生成Makefile程? src=




回页?/a>


Configure.in的八股文

当我们利用autoscan工具生成confiugre.scan文gӞ我们需要将confiugre.scan重命名ؓconfiugre.in文g。confiugre.in调用一pdautoconf宏来试E序需要的或用到的Ҏ是否存在,以及q些Ҏ的功能?/p>

下面我们来目睹一下confiugre.scan的庐q面目Q?/p>
# 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
            

每个configure.scan文g都是以AC_INIT开_以AC_OUTPUTl束。我们不难从文g中看出confiugre.in文g的一般布局Q?/p>
AC_INIT
            试E序
            试函数?
            试头文?
            试cd定义
            试l构
            试~译器特?
            试库函?
            试pȝ调用
            AC_OUTPUT
            

上面的调用次序只是徏议性质的,但我们还是强烈徏议不要随意改变对宏调用的ơ序?/p>

现在开始修改该文gQ?/p>
$mv configure.scan configure.in
            $vim configure.in
            

修改后的l果如下Q?/p>
            #                                -*- 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
            ])
            

其中要将AC_CONFIG_HEADER([config.h])修改为:AM_CONFIG_HEADER(config.h), q加入AM_INIT_AUTOMAKE(test,1.0)。由于我们的试E序是基于多U程的程序,所以要加入AC_PROG_RANLIBQ不然运行automake命o时会出错。在AC_OUTPUT输入要创建的Makefile文g名?/p>

׃我们在程序中使用了读写锁Q所以需要对库文件进行检查,即AC_CHECK_LIB([pthread], [main])Q该宏的含义如下Q?/p>

其中QLIBS是link的一个选项Q详l请参看后箋的Makefile文g。由于我们在E序中用了d锁,所以我们测试pthread库中是否存在pthread_rwlock_init函数?/p>

׃我们是基于deepcd来创建makefile文gQ所以我们需要在四处创徏Makefile文g。即Qproject目录下,lib目录下,core和shell目录下?

Autoconf提供了很多内|宏来做相关的检,限于幅关系Q我们在q里对其他宏不做详细的解释,具体请参看参考文?和参考文?Q也可参看autoconf信息c?/p>



回页?/a>


实战Makefile.am

Makefile.am是一U比Makefile更高层次的规则。只需指定要生成什么目标,它由什么源文g生成Q要安装C么目录等构成?/p>

表一列出了可执行文g、静态库、头文g和数据文Ӟ四种书写Makefile.am文g个一般格式?/p>
?1Makefile.am一般格?/a>
?1Makefile.am一般格? src=

对于可执行文件和静态库cdQ如果只想编译,不想安装到系l中Q可以用noinst_PROGRAMS代替bin_PROGRAMSQnoinst_LIBRARIES代替lib_LIBRARIES?/p>

Makefile.amq提供了一些全局变量供所有的目标体用:


?2 Makefile.am中可用的全局变量
?2 Makefile.am中可用的全局变量

在Makefile.am中尽量用相对\径,pȝ预定义了两个基本路径Q?/p>
?3Makefile.am中可用的路径变量
?3Makefile.am中可用的路径变量

在上文中我们提到q安装\径,automake讄了默认的安装路径Q?/p>

1) 标准安装路径

默认安装路径为:$(prefix) = /usr/localQ可以通过./configure --prefix=<new_path>的方法来覆盖?/p>

其它的预定义目录q包括:bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc{等?/p>

2) 定义一个新的安装\?/p>

比如test, 可定义testdir = $(prefix)/test, 然后test_DATA =test1 test2Q则test1Qtest2会作为数据文件安装到$(prefix)/ /test目录下?/p>

我们首先需要在工程层目录下(即project/Q创Z个Makefile.am来指明包含的子目录:


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
            

׃每个源文仉会用到相同的头文Ӟ所以我们在最层的Makefile.am中包含了~译源文件时所用到的头文gQƈ导出Q见蓝色部分代码?/p>

我们lib目录下的swap.c文g~译成libswap.a文gQ被apple/shell/apple.c文g调用Q那么lib目录下的Makefile.am如下所C:


noinst_LIBRARIES=libswap.a
            libswap_a_SOURCES=swap.c
            INCLUDES=-I$(top_srcdir)/src/includ
            

l心的读者可能就会问Q怎么?中给出的是bin_LIBRARIESQ而这里是noinst_LIBRARIESQ这是因为如果只想编译,而不惛_装到pȝ中,qnoinst_LIBRARIES代替bin_LIBRARIESQ对于可执行文gqnoinst_PROGRAMS代替bin_PROGRAMS。对于安装的情况Q库会安装?(prefix)/lib目录下,可执行文件将会安装到${prefix}/bin。如果想安装该库Q则Makefile.amCZ如下Q?/p>
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
            

最后两行的意思是swap.h安装?{prefix}/include /swap目录下?/p>

接下来,对于可执行文件类型的情况Q我们将讨论如何写Makefile.amQ对于编译apple/core目录下的文gQ我们写成的Makefile.am如下所C:


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
            

׃我们的test.c文g在链接时Q需要apple.o和libswap.a文gQ所以我们需要在test_LDADD中包含这两个文g。对于Linux下的信号?d锁文件进行编译,需要在~译选项中指?D_GNU_SOURCE。所以在test_LDFLAGS中指明。而test_LDFLAGS只是链接时的选项Q编译时同样需要指明该选项Q所以需要DEFS来指明编译选项Q由于DEFS已经有初始|所以这里用+=的Ş式指明。从q里可以看出QMakefile.am中的语法与Makefile的语法一_也可以采用条件表辑ּ。如果你的程序还包含其他的库Q除了用AC_CHECK_LIB宏来指明外,q可以用LIBS来指明?/p>

如果你只想编译某一个文Ӟ那么Makefile.am如何写呢Q这个文件也很简单,写法跟可执行文g的差不多Q如下例所C:


noinst_PROGRAMS=apple
            apple_SOURCES=apple.c
            DEFS+=-D_GNU_SOURCE
            

我们q里只是ƺ骗automakeQ假装要生成apple文gQ让它ؓ我们生成依赖关系和执行命令。所以当你运行完automake命o后,然后修改apple/shell/下的Makefile.in文gQ直接将LINK语句删除Q即Q?/p>
…….
            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)
            …….
            

通过上述处理Q就可以辑ֈ我们的目的。从?中不隄Zؓ什么要修改Makefile.in的原因,而不是修改其他的文g?/p>




回页?/a>


下蝲

名字 大小 下蝲Ҏ
project.rar HTTP
关于下蝲Ҏ的信?/a>


参考资?

  1. Kurt WallQ张辉译 《GNU/Linux~程指南?清华大学出版C?
  2. Robert MecklenburgQ《GNU Make目理Q第三版Q?东南大学出版C?2006
  3. http://www.cngnu.org/technology/index.html


T.S Liu 2008-06-26 12:01 发表评论
]]>Linuxpȝ下Autoconf/AutoMake学习W记http://www.shnenglu.com/liu1061/articles/54635.htmlT.S LiuT.S LiuThu, 26 Jun 2008 02:31:00 GMThttp://www.shnenglu.com/liu1061/articles/54635.htmlhttp://www.shnenglu.com/liu1061/comments/54635.htmlhttp://www.shnenglu.com/liu1061/articles/54635.html#Feedback0http://www.shnenglu.com/liu1061/comments/commentRss/54635.htmlhttp://www.shnenglu.com/liu1061/services/trackbacks/54635.html1、autoscan
  autoscan是用来扫描源代码目录生成configure.scan文g的。autoscan可以用目录名做ؓ参数Q但如果你不使用参数的话Q那么autoscan认Z用的是当前目录。autoscan扫描你所指定目录中的源文Ӟq创建configure.scan文g?br>
  2、configure.scan
  configure.scan包含?
  pȝ配置的基本选项Q里面都是一些宏定义。我们需要将它改名ؓconfigure.in

  3、aclocal
  aclocal是一个perl脚本E序。aclocalҎconfigure.in文g的内容,自动生成aclocal.m4文g?aclocal的定义是Q?aclocal - create aclocal.m4 by scanning configure.ac"?br>
  4、autoconf
  autoconf是用来生configure文g的。configure是一个脚本,它能讄源程序来适应各种不同的操作系l^収ͼq且Ҏ不同的系l来产生合适的MakefileQ从而可以你的源代码能在不同的操作pȝq_上被~译出来?br>
  configure.in文g的内Ҏ一些宏Q这些宏l过autoconf处理后会变成查系l特性、环境变量、Y件必ȝ参数的shell脚本。configure.in文g中的宏的序q没有规定,但是你必d所有宏的最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏?br>
  在configure.ini中:

  #可C注释,q个宏后面的内容被忽略?br>
  AC_INIT(FILE)

  q个宏用来检查源代码所在的路径?br>
  AM_INIT_AUTOMAKE(PACKAGE, VERSION)

  q个宏是必须的,它描qC我们要生成的Y件包的名字及其版本号QPACKAGE是Y件包的名字,VERSION是版本号。当你用make dist命oӞ它会l你生成一个类似helloworld-1.0.tar.gz的Y件发行包Q其中就有对应的软g包的名字和版本号?br>
  AC_PROG_CC

  q个宏将查系l所用的C~译器?br>
  AC_OUTPUT(FILE)

  q个宏是我们要输出的Makefile的名字?br>
  我们在用automakeӞ实际上还需要用到其他的一些宏Q但我们可以用aclocal来帮我们自动产生。执行aclocal后我们会得到aclocal.m4文g?br>
  产生了configure.in和aclocal.m4两个宏文件后Q我们就可以使用autoconf来生configure文g了?br>
  5、Makefile.am
  Makefile.am是用来生成Makefile.in的,需要你手工书写。Makefile.am中定义了一些内容:

  AUTOMAKE_OPTIONS

  q个是automake的选项。在执行automakeӞ它会查目录下是否存在标准GNU软g包中应具备的各种文gQ例如AUTHORS、ChangeLog、NEWS{文件。我们将其设|成foreignӞautomake会改用一般Y件包的标准来查?br>
  bin_PROGRAMS

  q个是指定我们所要生的可执行文件的文g名。如果你要生多个可执行文gQ那么在各个名字间用I格隔开?br>
  helloworld_SOURCES

  q个是指定?helloworld"时所需要的源代码。如果它用到了多个源文gQ那么请使用I格W号它们隔开。比如需?helloworld.hQhelloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c?br>
  如果你在bin_PROGRAMS定义了多个可执行文gQ则对应每个可执行文仉要定义相对的filename_SOURCES?br>
  6、automake
  我们使用automake --add-missing来生Makefile.in?br>
  选项--add-missing的定义是"add missing standard files to package"Q它会让automake加入一个标准的软g包所必须的一些文件?br>
  我们用automake产生出来的Makefile.in文g是符合GNU Makefile惯例的,接下来我们只要执行configureq个shell脚本可以生合适的Makefile文g了?br>
  7、Makefile
  在符合GNU Makefiel惯例的Makefile中,包含了一些基本的预先定义的操作:

  make

  ҎMakefile~译源代码,q接Q生成目标文Ӟ可执行文件?br>
  make clean

  清除上次的make命o所产生的object文g(后缀?.o"的文?及可执行文g?br>
  make install

  编译成功的可执行文件安装到pȝ目录中,一般ؓ/usr/local/bin目录?br>
  make dist

  产生发布软g包文?即distribution package)。这个命令将会将可执行文件及相关文g打包成一个tar.gz压羃的文件用来作为发布Y件的软g包?br>
  它会在当前目录下生成一个名字类?PACKAGE-VERSION.tar.gz"的文件。PACKAGE和VERSIONQ是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE, VERSION)?br>
  make distcheck

  生成发布软g包ƈ对其q行试查,以确定发布包的正性。这个操作将自动把压~包文g解开Q然后执行configure命oQƈ且执行makeQ来认~译不出现错误,最后提CZ软g包已l准备好Q可以发布了?br>
  distclean

  cMmake cleanQ但同时也将configure生成的文件全部删除掉Q包括Makefile?/font>


T.S Liu 2008-06-26 10:31 发表评论
]]>
linux 下如何用autoconf和automake两个工具生成Makefile Q{Q?/title><link>http://www.shnenglu.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.shnenglu.com/liu1061/articles/54543.html</guid><wfw:comment>http://www.shnenglu.com/liu1061/comments/54543.html</wfw:comment><comments>http://www.shnenglu.com/liu1061/articles/54543.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/liu1061/comments/commentRss/54543.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/liu1061/services/trackbacks/54543.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>作ؓLinux下的E序开发h员,大家一定都遇到qMakefileQ用make命o来编译自己写的程序确实是很方ѝ一般情况下Q大安是手工写一个简单MakefileQ如果要惛_Z个符合自pY件惯例的Makefile׃那么Ҏ了?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  在本文中Q将l大家介l如何?nbsp; autoconf和automake两个工具来帮助我们自动地生成W合自由软g惯例的MakefileQ这样就可以象常见的GNUE序一P只要使用“./configure”Q?#8220;make”Q?#8220;make instal”可以把E序安装到Linuxpȝ中去了。这特别适合惛_开放源代码软g的程序开发h员,又或如果你只是自己写些小的ToyE序Q那么这个文章对你也会有很大的帮助?/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是用于自动编译和链接的,一个工E有很多文gl成Q每一个文件的改变都会D工程的重新链接,但是不是所有的文g都需要重新编译,Makefile中纪录有文g的信息,在make时会军_在链接的时候需要重新编译哪些文件?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  Makefile的宗旨就是:让编译器知道要编译一个文仉要依赖其他的哪些文g。当那些依赖文g有了改变Q编译器会自动的发现最l的生成文g已经q时Q而重新编译相应的模块?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  Makefile的基本结构不是很复杂Q但当一个程序开发h员开始写MakefileӞl常会怀疑自己写的是否符合惯例,而且自己写的Makefilel常和自q开发环境相兌Q当pȝ环境变量或\径发生了变化后,Makefile可能q要跟着修改。这样就造成了手工书写Makefile的诸多问题,automake恰好能很好地帮助我们解决q些问题?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  使用automakeQ程序开发h员只需要写一些简单的含有预定义宏的文Ӟ由autoconfҎ一个宏文g生成configureQ由automakeҎ另一个宏文g生成Makefile.inQ再使用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=宋体>  本文所提到的程序是ZLinux发行版本QFedora Core release 1Q它包含了我们要用到的autoconfQautomake?/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=宋体>  我们从大家最怋用的例子E序helloworld开始?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  下面的过E如果简单地说来是Q?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  新徏三个文gQ?/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=宋体>  然后执行Q?/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=宋体>很简单吧Q几条命令就可以做出一个符合惯例的MakefileQ感觉如何呀?/font> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  现在开始介l详l的q程Q?/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=宋体>  在你的工作目录下Z个helloworld目录Q我们用它来存放helloworldE序及相xӞ如在/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文gQ如命oQvi helloworld.c。用下面的代码作ؓhelloworld.c的内宏V?/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命o来帮助我们根据目录下的源代码生成一个configure.in的模板文件?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  命oQ?/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.scanQ我们可以拿它作为configure.in的蓝本?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  现在configure.scan改名为configure.inQƈ且编辑它Q按下面的内容修改,L无关的语句:</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内容l束=========================================</font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><font face=宋体>  然后执行命oaclocal和autoconfQ分别会产生aclocal.m4及configure两个文gQ?/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内容是一些宏定义Q这些宏lautoconf处理后会变成查系l特性、环境变量、Y件必ȝ参数的shell脚本?/font></p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  autoconf 是用来生成自动配|Y件源代码脚本QconfigureQ的工具。configure脚本能独立于autoconfq行Q且在运行的q程中,不需要用Lq预?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  要生成configure文gQ你必须告诉autoconf如何扑ֈ你所用的宏。方式是使用aclocalE序来生成你的aclocal.m4?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  aclocalҎconfigure.in文g的内容,自动生成aclocal.m4文g。aclocal是一个perl 脚本E序Q它的定义是Q?#8220;aclocal - create aclocal.m4 by scanning configure.ac”?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  autoconf从configure.inq个列D~译软g时所需要各U参数的模板文g中创建configure?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  autoconf需要GNU m4宏处理器来处理aclocal.m4Q生成configure脚本?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  m4是一个宏处理器。将输入拯到输出,同时宏展开。宏可以是内嵌的Q也可以是用户定义的。除了可以展开宏,m4q有一些内建的函数Q用来引用文Ӟ执行命oQ整数运,文本操作Q@环等。m4既可以作为编译器的前端,也可以单独作Z个宏处理器?/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文gQ命令:</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"> </p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>$ vi Makefile.am</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"> </p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>  内容如下:</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"> </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"> </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导致编译和q接的目标被生成?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  5、运行automake</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  命oQ?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"> </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"> </p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>  automake会根据Makefile.am文g产生一些文Ӟ包含最重要的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"> </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"> </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"> </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 </p> q行helloworld <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"> </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"> </p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new"><br>  q样helloworldq译出来了Q你如果按上面的步骤来做的话Q应该也会很Ҏ地编译出正确的helloworld文g。你q可以试着使用一些其他的make命oQ如make cleanQmake installQmake distQ看看它们会l你什么样的效果。感觉如何?自己也能写出q么专业的MakefileQ老板一定会对你刮目相看?br>四、深入浅?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  针对上面提到的各个命令,我们再做些详l的介绍?/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文g的。autoscan可以用目录名做ؓ参数Q但如果你不使用参数的话Q那么autoscan认Z用的是当前目录。autoscan扫描你所指定目录中的源文Ӟq创建configure.scan文g?/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> <br> <br>  <br> <br> <br>pȝ配置的基本选项Q里面都是一些宏定义。我们需要将它改名ؓ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 脚本E序。aclocalҎconfigure.in文g的内容,自动生成aclocal.m4文g。aclocal的定义是Q?#8220;aclocal - create aclocal.m4 by scanning configure.ac”?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  4?autoconf</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  autoconf是用来生configure文g的。configure是一个脚本,它能讄源程序来适应各种不同的操作系l^収ͼq且Ҏ不同的系l来产生合适的MakefileQ从而可以你的源代码能在不同的操作pȝq_上被~译出来?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  configure.in文g的内Ҏ一些宏Q这些宏l过autoconf 处理后会变成查系l特性、环境变量、Y件必ȝ参数的shell脚本。configure.in文g中的宏的序q没有规定,但是你必d所有宏的最前面和最后面分别加上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">  #可C注释,q个宏后面的内容被忽略?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  AC_INIT(FILE)</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  q个宏用来检查源代码所在的路径?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AM_INIT_AUTOMAKE(PACKAGE, VERSION) </p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  q个宏是必须的,它描qC我们要生成的Y件包的名字及其版本号QPACKAGE是Y件包的名字,VERSION是版本号。当你用make dist命oӞ它会l你生成一个类似helloworld-1.0.tar.gz的Y件发行包Q其中就有对应的软g包的名字和版本号?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AC_PROG_CC</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  q个宏将查系l所用的C~译器?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">AC_OUTPUT(FILE)</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  q个宏是我们要输出的Makefile的名字?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  我们在用automakeӞ实际上还需要用到其他的一些宏Q但我们可以用aclocal 来帮我们自动产生。执行aclocal后我们会得到aclocal.m4文g?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  产生了configure.in和aclocal.m4 两个宏文件后Q我们就可以使用autoconf来生configure文g了?/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">  q个是automake的选项。在执行automakeӞ它会查目录下是否存在标准GNU软g包中应具备的各种文gQ例如AUTHORS、ChangeLog、NEWS{文件。我们将其设|成foreignӞautomake会改用一般Y件包的标准来查?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">bin_PROGRAMS</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  q个是指定我们所要生的可执行文件的文g名。如果你要生多个可执行文gQ那么在各个名字间用I格隔开?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">helloworld_SOURCES</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  q个是指定?#8220;helloworld”时所需要的源代码。如果它用到了多个源文gQ那么请使用I格W号它们隔开。比如需要helloworld.hQhelloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  如果你在bin_PROGRAMS定义了多个可执行文gQ则对应每个可执行文仉要定义相对的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的定义是“add missing standard files to package”Q它会让automake加入一个标准的软g包所必须的一些文件?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  我们用automake产生出来的Makefile.in文g是符合GNU Makefile惯例的,接下来我们只要执行configureq个shell 脚本可以生合适的 Makefile 文g了?/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~译源代码,q接Q生成目标文Ӟ可执行文件?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make clean</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  清除上次的make命o所产生的object文gQ后~?#8220;.o”的文Ӟ及可执行文g?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">make install</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  编译成功的可执行文件安装到pȝ目录中,一般ؓ/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">  产生发布软g包文Ӟ即distribution packageQ。这个命令将会将可执行文件及相关文g打包成一个tar.gz压羃的文件用来作为发布Y件的软g包?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  它会在当前目录下生成一个名字类?#8220;PACKAGE-VERSION.tar.gz”的文件。PACKAGE和VERSIONQ是我们在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">  生成发布软g包ƈ对其q行试查,以确定发布包的正性。这个操作将自动把压~包文g解开Q然后执行configure命oQƈ且执行makeQ来认~译不出现错误,最后提CZ软g包已l准备好Q可以发布了?/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">  cMmake cleanQ但同时也将configure生成的文件全部删除掉Q包括Makefile?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  五、结束语</p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  通过上面的介l,你应该可以很Ҏ地生成一个你自己的符合GNU惯例的Makefile文g及对应的目文g?/p> <p style="FONT-SIZE: 12pt; FONT-FAMILY: courier new">  如果你想写出更复杂的且符合惯例的MakefileQ你可以参考一些开放代码的目中的configure.in和Makefile.am文gQ比如:嵌入式数据库sqliteQ单元测试cppunit?/p> <img src ="http://www.shnenglu.com/liu1061/aggbug/54543.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/liu1061/" target="_blank">T.S Liu</a> 2008-06-25 11:46 <a href="http://www.shnenglu.com/liu1061/articles/54543.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.g753.cn" target="_blank">99Ʒþ</a>| <a href="http://www.bken.cn" target="_blank">þù޸ۿ</a>| <a href="http://www.txhyhf.cn" target="_blank">2021ٸþþþþþþþ</a>| <a href="http://www.jojo-m.cn" target="_blank">þۺ³³</a>| <a href="http://www.sywanfu.cn" target="_blank">˺ݺۺϾþ</a>| <a href="http://www.85062.com.cn" target="_blank">þ޾Ʒ</a>| <a href="http://www.s5273.cn" target="_blank">˾þۺϾƷAVר </a>| <a href="http://www.bkkg.net.cn" target="_blank">޾Ʒרþþ</a>| <a href="http://www.uhpd.cn" target="_blank">2020˾þþƷ</a>| <a href="http://www.vfqt.cn" target="_blank">ҹƷþþþþëƬ</a>| <a href="http://www.auto-insurance.cn" target="_blank">Ļþи</a>| <a href="http://www.rljps.cn" target="_blank">AVվþþƷ</a>| <a href="http://www.epcinet.cn" target="_blank">þAV</a>| <a href="http://www.meedow.cn" target="_blank">ھƷþþĻ</a>| <a href="http://www.wz65.cn" target="_blank">99þѹػ</a>| <a href="http://www.leaow.cn" target="_blank">Ʒþۺ123</a>| <a href="http://www.hywsgc.cn" target="_blank">ľþþþ</a>| <a href="http://www.ghfsp.cn" target="_blank">ŷձþþƷ</a>| <a href="http://www.yingyu3g.cn" target="_blank">þþƷ99ɫĻ</a>| <a href="http://www.zhaobiao365.cn" target="_blank">޾Ʒ˾þþ</a>| <a href="http://www.ccgangjiegou.cn" target="_blank">þ99Ʒ99þ6</a>| <a href="http://www.kukuoo.cn" target="_blank">þþƷ</a>| <a href="http://www.haobanben.cn" target="_blank">þþƷ۲ӰԺ</a>| <a href="http://www.baolaiqi.com.cn" target="_blank">þۺϳ</a>| <a href="http://www.audtw.cn" target="_blank">ƷþþþþĻ</a>| <a href="http://www.zusang.cn" target="_blank">Ʒþۺ</a>| <a href="http://www.officene.com.cn" target="_blank">Ʒþþþþùţţapp</a>| <a href="http://www.fly5.com.cn" target="_blank">þþƷа</a>| <a href="http://www.tst5.cn" target="_blank">ŷƷһƷþ</a>| <a href="http://www.zuk4.cn" target="_blank">þþþþþþ66ƷƬ</a>| <a href="http://www.30ww.cn" target="_blank">ĻƷѾþ5151</a>| <a href="http://www.ctcscs.cn" target="_blank">޾þˬ˾Ʒ</a>| <a href="http://www.kinhi.cn" target="_blank">99reֻоƷȾþ</a>| <a href="http://www.hystech.cn" target="_blank">þۺɫɫ</a>| <a href="http://www.yingkounews.com.cn" target="_blank">þþƷh</a>| <a href="http://www.zazhui.cn" target="_blank">ҹƷþþþþþ</a>| <a href="http://www.9yyg.cn" target="_blank">þþþþüƷþþ </a>| <a href="http://www.gkcv.cn" target="_blank">ó˾þAvѸ </a>| <a href="http://www.gpfo.cn" target="_blank">ŷպƷþ</a>| <a href="http://www.ha-jc.cn" target="_blank">պƷþĻ</a>| <a href="http://www.xiewanliang.cn" target="_blank">Ʒѿþþ㽶</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>