Autobook读书笔记

自动化工具的历史
1. unix系统的多样性
相对于在本书中讨论的其他项目,Autoconf是第一个被开发出来的。这个工具的开发是由于Unix操作系统的多样性。自Unix诞生以来,很多公司根据自己的需要对Unix进行了修改,如SunOS,HP-UX等。虽然几乎所有的Unix都非常类似,但是其中有各种各样的区别,如头文件,系统库中函数的区别。虽然有了POSIX标准的介入,但是这种情况依旧没有改变。这使得项目以代码的形式发布遇到了很大的困难。即使是在代码中使用#ifdeft去区别不同的系统,这也只会使代码更加混乱。因此需要有一种更好的方法去掌握不同Unix系统中的区别。
 
2. 第一个可配置项目
 
直到1992年,有四种不同的系统被开发出来,用来方便代码移植,其中就包括Cygnus的configure脚本语言和GNU的Autoconf包。这些方法都是把build过程分成两步,首先配置,然后再build。所以的系统,在build这步都是使用的标准的Unix下的make。make程序会根据在Makefile中的规则,去编译项目。在configure这步,是用来产生Makefile等在build过程中需要使用的文件。
 
3. 可配置项目的发展
 
1994年,Autoconf被发明,它集成了Cygnus的configure脚本和Gcc的configure的特点。包含了支持使用系统特定的头文件和makefile片断,并且支持交叉编译。
 
4. Automake发展
 
到了1994年,Autoconf已经是一个可以在不同的Unix系统中操作的solid framework了。不过,程序员仍然需要手工编辑大型的Makefile.in文件来使用它。Autoconf产生的configure脚本把Makefile.in文件的内容编译到Makefile中。
 
Makefile.in文件用来描述如何去build一个项目,许多项目的build过程非常类似,在当时复制Makefile.in文件是个很好的方法。
 
真正推动Automake,是一个开发者,编写了automake,类似于Autoconf。这名开发者编写了一个Makefile.am文件,使用简单的语法,并且生成Makefile.in文件。这个想法是基于Autoconf可以把Makefile.in文件转换成Makefile文件。
 
5. Libtool发展
 
Unix系统,随着发展,加入了对于共享库的支持。
 
共享库不同于常规库和静态库,是一个单独的文件。一个程序可以使用共享库但不需要包含共享库德一份copy,只需要包含库的名字既可。可以很多程序使用一个共享库。
 
 
如何运行configure和make
 
使用Autoconf构造的软件包包含一个configure脚本。用户可以通过运行这个脚本在各自的系统上来编译和安装。简单的通过make来编译。
 
configure脚本测试系统的特性。如,这个脚步可能通过使用time()函数测试time_t在C库中的定义,并将测试的结果反馈到编译中。
 
接下来,将从一个需要把一个代码包编译并且安装到自己系统的用户的角度来介绍如何调用configure脚本。
 
1. Configuring
 
configure有很多命令行的选项。除了一些基本的选项,每个代码包的选项都不一样。可以通过--help来查看。
 
--cache-file=file

configure对系统进行测试以决定相应的功能是否起作用。测试的结果被保存在cache文件中,加速接下来被configure调用。一个快速而稳定的cache文件将在配置大型项目时是configure在速度方面有更好的表现;


--help
打印帮助信息。每个软件包都有自己的帮助信息,可以参考。


--no-cache
configure一个主要的功能就是产生输出文件。这个选项防止configure产生输出文件,可以认为这是一种configure前的预演,虽然cache已经被修改了


--quite
--silent
当configure运行它的测试时,会把它正在做的事情告诉用户,这当然会降低一些运行速度。可以通过这两个选项关闭。


--version
打印Autoconf版本。


--prefix=prefix
prefix选项会被经常使用,这个选项决定了软件包中与系统构架相关部分的安装目录,例如,你需要把Emacs中的Emacs Lisp相关文件安装在/opt/gnu/share目录下,可以使用
./configure --prefix=/opt/gnu
需要强调的是这个行为依赖于文件如何使用这个信息。


--exec-prefix=eprefix
设置软件包中与系统构架无关的文件安装目录,如emacs二进制文件,如果没有设置这个选项,安装目录和prefix相同。


--bindir=dir
决定安装二进制文件的目录,安装同时会产生其他自然的二进制文件,这里的二进制文件是用户可以直接执行的程序。


--sbindir=dir
制定安装超级用户的二进制文件目录。只有超级用户可以执行的程序。


--libexecdir=dir
指定安装可执行的支持文件。与二进制可执行文件比较,这些文件不会被用户直接执行,但是有可能被二进制可执行文件调用,间接执行。

 

--datadir=dir
制定存储一般数据文件的目录
 

--sysconfdir=dir
指定只读配置文件目录,本机使用
 

--sharedstatedir=dir
指定可被修改了,可被其他机器读取的数据的目录
 

--localstatedir=dir
指定可被修改,但是单个机器的配置数据的目录
 

--libdir=dir

指定目标文件库的安装目录
 

--includedir=dir
指定C语言头文件的安装目录,C++的头文件也将安装到这个目录
 

--oldinlcudedir=dir
指定除了GCC之外其他编译器的头文件安装目录。
 

--infodir=dir
指定Info format documentation文件的安装目录,Info是指GNU项目使用的标准格式文档

der=1>
--mandir=dir指定手册的安装目录 
 

--srcdir=dir

这个选项和安装无关。它只是告诉configure去哪寻找代码文件。一般来说configure和代码文件在同一个目录,所以不需要指定。 
 

--program-prefix=prefix
在安装的时候为项目名称加上指定的前缀,如--program-prefix=g,名为tar的项目将会更名为gtar。这个选项只有在被Makefile.in文件使用时才生效。 
 

--program-suffix=suffix

指定程序的后缀名 
 

--program-transform-name=program
这里的program是一个sed脚本。当程序被安装时,将运行sed -e script,来产生安装名 
 

--build=build
指定包中编译的目标系统,如果没有指定,则默认把为configuration同名的为host 
 

--host=host

指定软件将运行的系统类型,如果没有指定,则使用config.guess来判断 
 

--target=target

指定代码包面向的系统类型,主要影响编译器和汇编编译器,如没有指定,是用与主机同名的configuration 
 

--disable-feature

不启用某些feature 
 

--enable-feature[=arg]
启用某些feature 
 

--with-package

在开源软件中,应该尽可能的重复使用已有的软件包和库。当一个代码结构树被configure所配置的同时,有可能会有关于其它已安装包的提示。如,BLT widget依赖于Tcl和Tk。所以必须在configure加上对Tcl和Tk的检测的提示,如

./configure --with-tcl=/usr/local --with-tk=/usr/local

 

--without-package

某些时候,安装新的包可能会影响系统中已经存在的包。 
 

--x-includes=dir

包含X11头文件的目录 
 

--x-libraries=dir

指引configure寻找包含X11的库的目录
 
在代码树种运行configure是很多余,繁杂的一种编译方式。相对来说,一个从configure产生的,可读性良好的Makefile可以在新的目录中进行编译。这样使编译出来的目标文件不至于搞乱代码目录。所以,建议使用三种目录,代码目录,编译目录和安装目录。
 
下面给出一个编译malloc的例子

$ gtar zxf mmalloc-1.0.tar.gz
$ mkdir build && cd build
$ ../mmalloc-1.0/configure

 
正确的话屏幕上将打印

  creating cache ./config.cache
  checking for gcc... gcc
  checking whether the C compiler (gcc  ) works... yes
  checking whether the C compiler (gcc  ) is a cross-compiler... no
  checking whether we are using GNU C... yes
  checking whether gcc accepts -g... yes
  checking for a BSD compatible install... /usr/bin/install -c
  checking host system type... i586-pc-linux-gnu
  checking build system type... i586-pc-linux-gnu
  checking for ar... ar
  checking for ranlib... ranlib
  checking how to run the C preprocessor... gcc -E
  checking for unistd.h... yes
  checking for getpagesize... yes
  checking for working mmap... yes
  checking for limits.h... yes
  checking for stddef.h... yes
  updating cache ../config.cache
  creating ./config.status

这时候,整个代码数被配置完成,可以进行编译和安装,默认安装到/usr/local

$ make all && make install

 
 
configure过程产生了哪些文件?
 
当使用了configure之后,会发现在代码树下会产生很多新的文件。当然每个包产生的文件都会有所区别
 
config.cache
 
configure可以cache系统检测的结果并加速之后的测试。这个文件包含了缓存数据,不过以文本的方式进行保存,可以根据需要进行修改。
 
config.log
 
当configure运行时,会输出所有的执行的测试信息和测试结果。这些是非常实用的信息,同时也保存在config.log中。比如,当在Solaris系统中运行configure,有可能会提示无法找到一个可用的C语言编译器。当检查config.log之后,会发现Soliaris默认查找的程序是/usr/ucb/cc,因此出错。
 
config.status
 
configure产生了一个shell脚本,叫做config.status,可以被用来重新生成配置。所有已经产生的文件都可以通过这个脚本来重新产生。这个脚本也可以通过configure --recheck来使用
 
config.h
 
很多用C或者C++为语言的代码包使用configure。某些测试可以检查C和C++中的变量。这样可以使代码增加兼容性。在config.h中用头文件,进行预处理是一个好方法。

Makefile
 
configure会产生Makefile和其他文件。Makefile是configure从正确的输入文件中产生的,一般为Makefile.in。接下来将会描述这个由Makefile.in产生Makefile的过程。
 
 
常用的Makefile targets
 
现在configure已经产生了输出文件,如Makefile等。大多数项目包含一个Makefile作为一个基本的目标。目标在这里指make中的一个任务名,通常编译在包中的所有程序(make all)。
 
make all
编译所有文件
 
make check
运行包中带有的自检测试。
 
make install
安装包到所选的目录
 
make clean
清除所有编译文件
 
 
Configuration Names
 
GNU的Autotools工具命名了所有的系统类型,用configuration name进行了便准命名。
 
如,sparc-sun-solaris2.7, i586-pc-linux-gnu, i386-pc-cygwin等。
 
每一个配置名分成三个部分,在某些文档中被称为configuration triplets。也可以把配置名分为四部分,增加一个部分说明内核和操作系统,如cpu-manufacturer-kernel-operating_system。
 
当在configure中使用配置名的时候,不需要指定完整的配置名。某些时候,中间部分可以被忽略,如i386-linux等,shell脚本config.sub被用来补充这些忽略的部分。
 
对于大部分的Unix变量,shell脚本config.guess将根据系统打印争取的配置名。它通过标准的uname程序,并且检查其他的系统特征。在某些系统中,config.guess需要C和汇编编译器。
 
因为config.guess可以判断一个系统的配置名,所以当建立交叉编译工具时,必须手工指定配置名。


cpu
The type of processor used on the system. This is typically something like `i386' or `sparc'. More specific variants are used as well, such as `mipsel' to indicate a little endian MIPS processor.

manufacturer
A somewhat freeform field which indicates the manufacturer of the system. This is often simply `unknown'. Other common strings are `pc' for an IBM PC compatible system, or the name of a workstation vendor, such as `sun'.

operating_system
The name of the operating system which is run on the system. This will be something like `solaris2.5' or `winnt4.0'. There is no particular restriction on the version number, and strings like `aix4.1.4.0' are seen.
Configuration names may be used to describe all sorts of systems, including embedded systems which do not run any operating system. In this case, the field is normally used to indicate the object file format, such as `elf' or `coff'.


kernel
This is used mainly for GNU/Linux systems. A typical GNU/Linux configuration name is `i586-pc-linux-gnulibc1'. In this case the kernel, `linux', is separated from the operating system, `gnulibc1'.
`configure' allows fine control over the format of binary files. It is not necessary to build a package for a given kind of machine on that machine natively--instead, a cross-compiler can be used. Moreover, if the package you are trying to build is itself capable of operating in a cross configuration, then the build system need not be the same kind of machine used to host the cross-configured package once the package is built! Consider some examples:


Compiling a simple package for a GNU/Linux system.
host = build = target = `i586-pc-linux-gnu'

Cross-compiling a package on a GNU/Linux system that is intended to
run on an IBM AIX machine: build = `i586-pc-linux-gnu', host = target = `rs6000-ibm-aix3.2'

Building a Solaris-hosted MIPS-ECOFF cross-compiler on a GNU/Linux
system. build = `i586-pc-linux-gnu', host = `sparc-sun-solaris2.4', target = `mips-idt-ecoff'

 

 

你可能感兴趣的:(unix,脚本,读书,System,Build,makefile)