第一部分 Autotools 基础 介绍

来源:互联网 发布:赚钱最快的方法 知乎 编辑:程序博客网 时间:2024/05/19 21:41
The GNU build system has two goals:
The first is to simplify the development of portable programs.
The second is to simplify the building of programs that are distributed as source code.
The first goal is achieved by the automatic generation of a `configure' shell script, which configures the source code to the installer platform. The second goal is achieved by the automatic generation of Makefiles and other shell scripts that are typically used in the building process.


When we speak of the GNU build system we refer primarily to the following four packages:

   1. Autoconf produces a configuration shell script, named `configure', which probes the installer platform for portability related information which is required to customize makefiles, configuration header files, and other application specific files. Then it proceeds to generate customized versions of these files from generic templates. This way, the user will not need to customize these files manually.
   2. Automake produces makefile templates, `Makefile.in' to be used by Autoconf, from a very high level specification stored in a file called `Makefile.am'. Automake produces makefiles that conform to the GNU makefile standards, taking away the extraordinary effort required to produce them by hand. Automake requires Autoconf in order to be used properly.
   3. Libtool makes it possible to compile position independent code and build shared libraries in a portable manner. It does not require either Autoconf, or Automake and can be used independently. Automake however supports libtool and interoperates with it in a seamless manner.
   4. Autotoolset helps you develop portable source code that conforms to the GNU coding standards by generating various boilerplate files from which you can plunge into developing your software.

一句话:用户看见的是configure文件,makefile模板和config模板。
(1) 对于用户来讲,configure文件被用户执行,以填充makefile模板(比如用什么编译器,用什么参数来链接,-D宏定义等)和config模板(就是把所有的#undef,按需要改成#define)。 这刚好为了上面的目的一。
(2) 对于包的开发者来讲,makefile模板是Makefile.in,它是通过写Makefile.am,然后由Automake生成。config模板是config.h.in,由Autoheader扫描你写的configure.in,看里面你想检测哪些宏,就生成这个含所有宏的模板文件,就是一条条#undef xxx。configure文件是写configure.in,然后由Autoconf生成。 这刚好为了上面目的二。

而Libtool是单独的工具,但是,被嵌入到了Automake中,即,可以在Makefile.am中调用Libtool. 至于Autotoolset又是另外一个工具集了。


一些工作能够被简化:
    1. Building multidirectory software packages. It is much more difficult to use raw make recursively. Having simplified this step, the developer is encouraged to organize per source code in a deep directory tree rather than lump everything under the same directory. Developers that use raw make often can't justify the inconvenience of recursive make and prefer to disorganize their source code. With the GNU tools this is no longer necessary.
     2. Automatic configuration. You will never have to tell your users that they need to edit your Makefile. You yourself will not have to edit your Makefiles as you move new versions of your code back and forth between different machines.
     3. Automatic makefile generation. Writing makefiles involves a lot of repetition, and in large projects very error-prone. Also, certain portions of a good makefile, such as the `install' and `uninstall' targets are very critical because they are run by the superuser. They must be written without any bugs! The GNU build system automates makefile writing. You are only required to write `Makefile.am' files that are much more terse and easy to maintain.
     4. Support for test suites. You can very easily write test suite code, and by adding one extra line in your `Makefile.am' make a check target available such that you can compile and run the entire test suite by running make check.
    5. Automatic distribution building. The GNU build tools are meant to be used in the development of free software, therefore if you have a working build system in place for your programs, you can create a source code distribution out of it by running make distcheck.
    6. Shared libraries. Building shared libraries becomes as easy as building static libraries.



两顶帽子:
the developer hat: 你是代码体系的制造者,需要装一系列文档中所列工具(automake,autoconf...)
the installer hat: 你是代码的使用者,只想安装,仅仅需要make和shell。


make dist和make distcheck的区别:
他们都是用于对当前状态的开发目录打包,打成可安装包(能configure,make,make install)。前者基本就是打包,当然也会查一些文件是否缺失。后者除了打包,还要尝试一些测试,包括解包,并模拟用户运行configure等来看是否正常。想要多检查或自定义检查(test suit)就用distcheck。


5.4 Understanding the hello world example
这一节很重要,要看细节。
但总体上告诉我们,我们需要写两个文件:Makefile.am和configure.in
Makefile.am是逻辑语言,没有执行部分。目的是简化Makefile的各种编写。
configure.in是顺序执行的,里面加入的各个宏都是拿来执行的,目的是探测系统。
(比如你要编译C++程序,就要加入AC_PROG_CXX宏,这个宏会检测系统的g++编译器,在生成makefile时采用该编译器来书写。)
而看看生成的:
configure:由aclocal.m4和configure.in合成,前者是后者中宏的定义,他们通过autoconf合成configure文件。当然,aclocal.m4要先用aclocal生成(aclocal实际上去/usr/share/aclocal目录中的各个.m4文件中,去找你在configure.in中使用的宏的定义,并拷贝过来,生成aclocal.m4文件!)
Makefile:由configure和Makefile.in生成。当然Makefile.in要由Makefile.am生成,Makefile.in就是Makefile.am翻译成的,就是一些东西还待确定的Makefile。


configure将Makefile.in转化成Makefile实际要做的:
1. 替换一些编译的宏,比如编译器,编译选项...(这也揭露了为什么要使用autotools──各个平台上编译链工具和编译选项不同。不光是由于2,2是程序的宏,比如某系统支不支持某API)
2. 替换一些程序的宏,常用方式是生成含#define的头文件,或者给编译器传-D参数



模板: ──── 下面是手册中给出的例子,但是我真正用的模板,已经比这个更新了,见下面 acmkdir的模板。
`configure.in'

    AC_INIT(hello.c)               #任意一个文件即可(初始化一些东西)
    AM_CONFIG_HEADER(config.h)     #生成的配置头文件名
    AM_INIT_AUTOMAKE(hello,0.1)    #make dist打包名和版本号(用于初始化和automake相关的东西)
    AC_PROG_CC                     #探测C编译器类型
    AC_PROG_INSTALL                #生成install-sh这个“安装工具”,安装make好的东西
    AC_OUTPUT(Makefile)            #表明哪些目录下应该让Makefile.in生成Makefile

`Makefile.am'

    bin_PROGRAMS = hello           #格式是 xx 的 xx 有哪些,这里读:二进制的程序有hello。
    hello_SOURCES = hello.c

`hello.c'
    #ifdef HAVE_CONFIG_H           #怎么回事?当然是-DHAVE_CONFIG_H写在了Makefile中的编译器命令行
    #include <config.h>            #而如果不用AM_CONFIG_HEADER,则会直接用-Dxxx传很多参数,而不是
    #endif                         #放在config.h中。详细见下面说明。

    #include <stdio.h>
    main()
    {
        printf("Howdy, pardner!/n");
    }

为了生成configure文件:
% aclocal                                 # 提供configure.in中你写的宏的实际脚本,它实际上去/usr/share/aclocal目录中的各个.m4文件中,去找你在configure.in中使用的宏的定义,并拷贝过来,生成aclocal.m4文件!
% autoconf                                # 生成configure文件
% touch NEWS README AUTHORS ChangeLog     # automake需要这些破东西
% autoheader                              # 生成config.h.in模板,供configure填充
% automake -a                             # 生成Makefile.in模板,供configure填充
上面的顺序是重要的。


说明:不使用autoheader和AM_CONFIG_HEADER(config.h),那么所有的程序的宏,都通过-D传给编译器,下面是节录编译和链接:
gcc -DPACKAGE_NAME=/"/" -DPACKAGE_TARNAME=/"/" -DPACKAGE_VERSION=/"/" -DPACKAGE_STRING=/"/" -DPACKAGE_BUGREPORT=/"/" -DPACKAGE=/"hello/" -DVERSION=/"0.1/" -I.     -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.c
mv -f .deps/hello.Tpo .deps/hello.Po
gcc -g -O2   -o hello hello.o
可以看到,出现大量的-D,而如果使用autoheader和AM_CONFIG_HEADER,那么只有-DHAVE_CONFIG_H被传递给gcc,其他的程序的宏,通过放在config.h文件中,然后用户在hello.c中include一下,就行了。下面是节录编译和链接:
gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.c
mv -f .deps/hello.Tpo .deps/hello.Po
gcc -g -O2   -o hello hello.o



版本:
0.1 和 0.1.1的区别:
0.1是official版本号:0表示主版本,1表示次版本。主版本增加,要有很大功能提升和稳定性提升。次版本增加,只需要改掉一个bug就可以。
0.1.1是unofficial版本号:最后一个1是表示开发者内部交流使用,比如改了半个bug,算个成就,就加个1在末尾。如果用户要当小白鼠,可以用unofficial的。



使用 acmkdir 工具:
acmkdir是Autotoolset工具集中的一个,可以帮你建立好“工程”,就是含有那一堆文件的目录,类似于VC的工程向导。
要省事的话可以用这个。用法是 “acmkdir -t 顶层目录类型”。
默认的类型是支持C++检测的,用在configure.in(或.ac)中的宏是LF打头的一系列。
如果你要用传统的宏,可以 -t traditional,这样就会看到这个手册里熟悉的一些宏了。

--------- 如何使用 acmkdir 来加快你的项目创建:----------
它只有一种工程树模式:顶层的Makefile.am里含有:
EXTRA_DIST = reconf configure
SUBDIRS = m4 src doc
表明,会在m4,src,doc下去执行你要Make的东西。
所以,用完acmkdir后,要做的事只有三件:
(1) 修改 configure.ac 为如下:(修改的原因是:有些宏多了,有些少了)
AC_INIT([sheep],                        # 工程名,会被在./reconf时,写到一些文件中
        [0.0.1],                        # 版本号,自己写,同样会被写到文件中,和打包的名字后
        [Yi Feng yifengcn@gmail.com],   # 先写作者姓名,再写邮箱,会被写到文件中,如Author
        [sheep])                        # 打包的名字。比如make distcheck会生成 sheep-0.0.1.tar.bz2
AC_CONFIG_AUX_DIR(config)               # 将一些辅助文件,存放在config目录中(否则顶层目录文件过多)
AM_CONFIG_HEADER(config.h)              # 说明,要使用config.h做为宏定义的文件
AM_INIT_AUTOMAKE([dist-bzip2])          # 这里面当然很多参数,而[dist-bzip2]表示打包按bz2打包,默认是gz
#放在config.h中。详细见下面说明。

AC_PROG_CC                              # 检测用什么C编译器
AC_PROG_CXX                             # 检测用什么C++编译器
AC_PROG_INSTALL                         # 生成安装脚本 install-sh
AC_PROG_RANLIB                          # 使用ranlib(如果你要生成库的话)
AC_PROG_MAKE_SET                        # 如果你的源文件要按照多层目录来组织

AC_CONFIG_FILES([                       # 生成的所有Makefile的位置,这其实是给Automake看的!!
        Makefile                        # Automake会读取configure.ac文件,然后在这些位置生成Makefile.in
        README
        doc/Makefile
        m4/Makefile
        src/Makefile
])

AC_OUTPUT                               # 将各个Makefile生成之!(从各个Makefile.in)

(2) 把你的源文件,放在src下,然后修改src下的Makefile.am即可。
    bin_PROGRAMS = sheep
    sheep_SOURCES = sheep.cpp
然后源文件里,在最上面写:
    #ifdef HAVE_CONFIG_H         
    #include <config.h>           
    #endif                       

(3) 再回到顶层目录,./reconf一下,就OK了。reconf内容如下:
#!/bin/sh
rm -f config.cache
aclocal -I m4
autoconf
autoheader
automake -a
exit

之后,就可以那老三步来编译了。当然,如果你觉得它写的configure.in太多东西,可以自己改。



作者对编程的建议:
为了避免麻烦,请这样:
(1) 将问题细分,将每个子问题,编成一个库。
(2) 剩下的问题,就是测试和组装库成可执行文件。
这样的话,好处很多 ──── 便于测试,便于排错,便于控制问题规模



make distclean   vs   make clean:
有时对文件做了某种改动,比如从.c改为了.cpp,就发现莫名奇妙的无法make错误,这时应该 make distclean 一下,这会清除掉所有 make 产生的东西,而不仅仅是目标文件。实际上,是清除了如 .deps 文件夹,这文件夹里的文件有目标文件和源文件和头文件的依赖关系等,如果仅仅 make clean是不会清除的,这在文件名发生变化时(如从.c变为.cpp),可能导致无法再make的错误,保错说,还是希望找.c,但是找不到。
原创粉丝点击