AUTOBOOK 2

来源:互联网 发布:西安长城宽带网络 编辑:程序博客网 时间:2024/06/14 11:22

 

(转载)Auto book 中文版(二)

3. 如何运行 configure 和 make

使用 Autoconf 构建的软件包通常带有 ‘configure’ 脚本。要在特定的系统中构建和安装这样一个软件包,用户必须运行该脚本以使目录树按顺序排列作好准备。实际的构建过程则是使用 make 程序进行的。

‘configure’ 脚本测试系统的特性。比如,它可以测试 C 函数库中是否定义了用于 time() 的数据类型 time_t。当构建程序时,’configure’ 脚本就可以向程序提供这些测试结果。

本章解释如何从用户的角度使用 ‘configure’ 脚本。所谓用户是指那些只想拿你的软件包在他们自己的系统上进行编译的人。由于 Autoconf 性能良好,通常只要使用 configure; make 命令就能在任何机器上创建软件包。本章将涉及如何使用 configure,configure 产生的文件,和在编译软件包时能获取的最有用的 ‘Makefile’ 目标,即你想让 make 做的动作(see section ‘Makefile’ 简介)。

3.1 配置

‘configure’ 脚本有大量的命令行选项。尽管一些基本的选项总是存在的,每个软件包的选项集是不同。若执行 ‘configure’ 时使用选项 ‘–help’ 便知有哪些选项可供选择。尽管其中的许多选项是很深奥的,但是在配置有特殊安装要求的软件包时,知道这些选项的存在是很有价值的。下面主意简介一下这些选项:

‘–cache-file=file’
‘configure’ 测试你的系统以确定可用的特性(或错误!)。测试的结果可储存在一个缓存文件中以便加快以后的 configure 执行速度。当在每个子目录中都有 ‘configure’ 脚本时,使用缓存文件可以大大提高配置的速度。

‘–help’
输出帮助信息。即使是有经验的 ‘configure’ 用户有时也需要使用 ‘–help’,因为复杂的项目会在每个项目的配置中包括额外的选项。例如,GCC 软件包中的 ‘configure’ 允许你控制是否由 GCC 优先创建并使用 GNU 汇编器,而不是使用供应商的汇编器。

‘–no-create’
‘configure’ 的主要功能之一是产生输出文件。这个选项防止 ‘configure’ 产生这种输出文件。尽管缓存文件仍会被修改,但你仍可将该选项看作是一种dry run。

‘–quiet’
‘–silent’ 当 ‘configure’ 运行测试时,它会输出简洁的信息来告知用户脚本正在做什么,这是因为 ‘configure’ 的运行可能是非常慢的。如果没有这种信息的输出,用户就无法得知脚本正在做什么。当然使用了这个选项,你也可能不知道它正在做的事!

‘–version’
打印产生 ‘configure’ 脚本的 Autoconf 版本。

‘–prefix=prefix’
‘–prefix’ 是最常用的选项之一。若产生的 ‘Makefile’ 选择使用通过此选项传递的参数,便有可能对要安装的软件包中结构独立的部分进行完全地重新定位。例如,安装像 Emacs 这样的软件包时,下列命令行就将 Emacs 的 Lisp 文件放在 ‘/opt/gnu/share’ 目录中:

$ ./configure --prefix=/opt/gnu

需要强调的一点是:这种行为取决于产生的文件是否使用使用该信息。Automake 为编写这些文件的开发者极大地简化了该过程。GNU Automake 简介 中介绍了 Automake。

‘–exec-prefix=eprefix’
该选项与 ‘–prefix’ 十分相似,只是它对已安装的依赖于体系结构文件进行定位。编译好的 ‘emacs’ 二进制文件就属于这种文件。如果这个选项没有给出,插入到产生文件中的缺省 ‘exec-prefix’ 值就被设置为与 ‘prefix’ 相同的值。

‘–bindir=dir’
指定安装二进制文件的位置。这里所说的二进制文件是用户可以直接使用的程序,而不是一般的二进制文件。

‘–sbindir=dir’
指定安装超级用户二进制文件的位置。通常只有超级用户能执行这些程序。

‘–libexecdir=dir’
指定安装二进制文件的支持文件的位置。与“二进制”文件不同的是:用户不能直接使用这些文件,但上述的二进制文件可以执行它们。

‘–datadir=dir’
指定普通数据文件的位置。

‘–sysconfdir=dir
指定用在单一机器上的只读数据的位置。

‘–sharedstatedir=dir’
指定可修改数据的位置,这些数据可以被多个机器共享。

‘–localstatedir=dir’
指定可修改数据的位置,但是这些数据只是对单一机器特定。

‘–libdir=dir’
指定目标代码库的安装位置。

‘–includedir=dir’
指定 C 头文件的安装位置。用于其它语言(如 C++)的头文件也可以安装在这里。

‘–oldincludedir=dir’
指定不是用于 GCC 编译器的 C头文件的安装地址。

‘–infodir=dir’
指定 Info 格式文档文件的安装地址。Info 是 GNU 项目使用的文档格式。

‘–mandir=dir’
指定manual手册页的安装地址。

‘–srcdir=dir’
该选项并不影响安装。它告诉 ‘configure’
源码文件的位置。通常不需要指定该选项,因为 ‘configure’ 脚本通常与源文件处于同一目录。

‘–program-prefix=prefix’
指定在安装程序时加到该程序名的前缀。例如,在配置命名为 ‘tar’ 的程序时,使用 ‘–program-prefix=g’ 会使安装的程序被命名为 ‘gtar’。与其它的安装选项一样,该 ‘configure’ 选项只在被 ‘Makefile.in’ 文件使用时才起作用。

‘–program-suffix=suffix’
指定在安装程序时加到该程序名的后缀。

‘–program-transform-name=program’
这里的 program 应是 sed 脚本。当安装程序时,通过 ’sed -e program’ 将其原有的名字替换为新名字。

‘–build=build’
指定软件包将在何种系统上构建。如果没有具体指定,缺省值与主机的配置名相同。

‘–host=host’
指定软件包将在何种系统上运行──即be hosted。如果没有具体指定,主机的类型通过执行 ‘config.guess’ 来决定。

‘–target=target’
指定软件包目标系统的种类。该选项能确定应使用的语言工具如编译器、汇编器之类的种类。如果没有具体指定,缺省与主机的配置名相同。

‘–disable-feature’
一些软件包可以选择为大型的选项(如使用Kerberos认证系统或仍处于实验阶段的编译优化检查)提供编译时的配置能力。如果缺省是使用这些特性,通过 ‘–disable-feature’ 就可以不再使用相应的特性,这里的 feature 是特性的名字。例如:

$ ./configure --disable-gui

‘–enable-feature[=arg]‘
相反,一些软件包可以提供缺省不使用的特性。当 feature 为特性的指定名时,使用 ‘–enable-feature’ 可使这些特性生效。一个特性可以接受一个可选的参数。例如:

$ ./configure --enable-buffers=128

使用 ‘–enable-feature=no’ 可产生与使用上述的 ‘–disable-feature’ 同样的效果。

‘–with-package[=arg]‘
在自由软件社区,有个很好的趋势:在可能的情况下重新使用已经存在的软件包和库。当通过 ‘configure’ 配置源码目录时,可以给它提供一些关于已经安装的其它软件包的信息。例如,BLT 界面工具箱依赖于 Tcl 和 Tk。为了配置 BLT,也许需要向 ‘configure’ 提供已安装的 Tcl 和 Tk 的信息:

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

使用 ‘–with-package=no’ 可产生与使用下面将阐述的 ‘–without-package’ 同样的效果。

‘–without-package’
有时候,你也许不希望你的软件包与你系统上已经安装的软件包相互操作。例如,你也许不希望你的新编译器使用 GNU ld。你可以通过使用下面的选项达到目的:

$ ./configure --without-gnu-ld

‘–x-includes=dir’
这个选项实际上是 ‘–with-package’ 的一个特例。当最初开发 Autoconf 时,人们通常用 ‘configure’ 替代 Imake 来创建在 X Window 系统上运行的程序。选项 ‘–x-includes’ 提供了一种方法来指导 ‘configure’ 脚本找到包含 X11 头文件的目录。

‘–x-libraries=dir’
同样地,选项 ‘–x-libraries’ 选项提供了一种方法指导 ‘configure’ 找到包含 X11 函数库的目录。

没有必要在源码目录中运行 ‘configure’,这种做法也很不方便。若精心编写,由 ‘configure’ 产生的 ‘Makefile’ 就能够在一个独立于源码的目录中构建软件包。在其它目录树中构建软件包的好书是很明显的,若在源码目录中执行这个任务,则目标文件之类的派生文件会使源码 目录显得非常混乱。同时也无法在不同的系统或者是使用不同的配置来传将目标文件。因此,最好使用三个目录:源码目录、构建目录和安装目录。下面的例子就是如何用这种方法创建 GNU 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

现在已经配置了构建目录 ‘build’,可以继续构建软件包并将它安装在缺省位置 ‘/usr/local’ 中:

  $ make all && make install

3.2 配置过程产生的文件

在执行 ‘configure’ 后,你会在构建目录中发现很多文件。由 ‘configure’ 创建的构建目录结构和文件数量会随软件包的不同而不同。下面简述每个产生出的文件,在 Generated File Dependencies 中阐述了它们之间的关系:

‘config.cache’
‘configure’能缓存特性测试结果,并用它们来加快后续的测试。这个文件包含了缓冲数据,它是一个纯文本文件,可以手工修改或在需要时删除。

‘config.log’
运行 ‘configure’ 时,它会输出一组信息来描述它所做的每项测试及其结果。shell 和 ‘configure’ 调用的一些工具所产生的信息远比 ‘configure’ 输出的信息多,但是为了便于用户理解输出而将这些信息隐藏了。这些信息被重定向到 ‘config.log’ 文件中。当 ‘configure’ 不能正常工作或测试结果无法理解时,首先要查看的就是,’config.log’ 文件。常见的情况是,当 ‘configure’ 在 Solaris 系统上运行时,它会告诉你无法找到可用的 C 编译器。检查 ‘config.log’ 便可发现 Solaris 的缺省程序 ‘/usr/ucb/cc’ 总会告速用户可选 C 编译器没有安装。

‘config.status’
‘configure’ 产生的名为 ‘config.status’ 的shell脚本可用于重新产生当前配置。也就是说,所有产生文件将被再一次产生。如果给出选项 ‘–recheck’,这个脚本也能用于重新运行 ‘configure’ 脚本。

‘config.h’
许多使用 ‘configure’ 的软件包是用 C 或 C++ 编写的。’configure’ 执行的测试中包括了检查 C 和 C++ 语言的不同以及它们各自的实现。在运行 ‘configure’ 时,可以有选择地将预处理指令 #define 放置在一个配置头文件中,这个文件通常名为 ‘config.h’,这样在编写源代码时就可以处理这些差异。源文件可以 #include 这个 ‘config.h’ 文件并进行相应修改,如:

#if HAVE_CONFIG_H#  include <config.h>#endif /* HAVE_CONFIG_H */#if HAVE_UNISTD_H#  include <unistd.h>#endif /* HAVE_UNISTD_H */

我们建议你一定要使用一个配置头文件。

‘Makefile’ ‘configure’ 的常用功能之一便是产生 ‘Makefile’ 和其它文件。正如已经强调的一样,’Makefile’ 只是一个通常由 ‘configure’ 脚本从相应的输入文件(常被称为 ‘Makefile.in’)中产生的文件。下面将描述如何使用 make 来处理 ‘Makefile’。当然在其他情况下,用这种方式产生文件也是十分有帮助的。例如,Java 开发者也许会希望使用从 ‘defs.java.in’ 中产生的 ‘defs.java’ 文件。

3.3 Makefile 最有用的目的

现在’configure’ 生成一个如 ‘Makefile’的输出文件。 大多数项目包含一个有众所周知的一系列目标的’Makefile’ (see section 目标和依赖关系)。一个目标就是你想实现的一个任务 – 一般是使用所有的程序属于同一个包 (一般认为是全部的目标)。在你的构建目录里, 下面的命令会像一个配置包一样工作:

make all 构建所有文件。

make check 执行程序里所有的自测试模块。

make install 安装在特定的目录里。

make clean 删除所有生成文件.、。

有另外一些很少的常用目标,尤其是包里面有一个automake生成的遵从 GNU ‘Makefile’标准的’Makefile’文件时。你可以查看’Makefile’了解其它的目标。

3.4 配置名

GNU Autotools 用配置名命名所有的计算机系统,这是标准格式的系统名称。

例如 ’sparc-sun-solaris2.7′、’i586-pc-linux-gnu’ 和 ‘i386-pc-cygwin’ 都是配置名。

所有的配置名都由三部分组成。在一些文挡中,仍将它们称为配置三连符。一个配置三连符是 cpu-manufacturer-operating_system。现在,在像 GNU/Linux 这样区分内核和操作系统的系统中,配置名可以由四部分组成。在上述情况下,配置名就是 cpu-manufacturer-kernel-operating_system。

当在如 ‘configure’ 等工具的选项中使用配置名时,通常不需要指定整个名字。特别的是,通常省略中间部分(下文描述的 manufacturer),而形成 ‘i386-linux’ 或 ’sparc-sunos’ 这样的字符串。shell 脚本 ‘config.sub’ 可将省略形式翻译成标准形式。

在大部分的 Unix 版本中,shell 脚本 ‘config.guess’ 将为它所运行的系统输出正确的配置名。它可通过运行标准的 uname 程序和检查系统的其它性质达到上述目标。在一些系统中,’config.guess’ 要求可用的 C 编译器或汇编器。

因为 ‘config.guess’ 通常能为机器决定配置名,用户或开发者在特殊情况下(如创建交互编译器)才需要指定配置名。

下面将对配置名中每一部分进行描述:

cpu 系统使用的处理器。典型的如 ‘i386′ 或 ’sparc’。也可以使用更具体的变量,如 ‘mipsel’ 表示小端模式的 MIPS 处理器。

manufacturer 指定系统的生产商,这也是配置名中最自由的一部分。通常是 ‘unknown’。其他常用的字符串有表示兼容 IBM PC 系统的 ‘pc’,或者是工作站供应商的名称,如’sun’。

operating_system 系统使用的操作系统的名称。如 ’solaris2.5′ 或 ‘winnt4.0′。这里没有对版本数作出特殊的限制。因此,可以看到像 ‘aix4.1.4.0′ 这样的字符串。

配置名可以被用于描述所有种类的系统,包括不运行任何操作系统的嵌入式系统。在这种情况下,配置名的这部分通常被用于表示目标文件格式,如 ‘elf’ 或 ‘coff’。

kernel 这主要用于 GNU/Linux 系统。典型的 GNU/Linux 配置名是 ‘i586-pc-linux-gnulibc1′。在这种情况下,内核 ‘linux’ 与操作系统 ‘gnulibc1′ 是分开的。

‘configure’ 能够很好地控制二进制文件的格式。在主机上使用交叉编译器便可构建目标机器上的软件包,而不必直接在目标机器上构建软件包。此外,如果你尝试构建的软件包本身就可以在交叉配置的环境中运行,那么构建软件包所使用的系统和软件包运行的系统可以不同。例如:

为 GNU/Linux 系统编译一个简单的软件包。 host = build = target = ‘i586-pc-linux-gnu’

在 GNU/Linux 系统上交叉编译一个将运行于 IBM AIX 机器的软件包: build = ‘i586-pc-linux-gnu’, host = target = ‘rs6000-ibm-aix3.2′

在 GNU/Linux 系统中构建一个运行于 Solaris 的 MIPS-ECOFF 交叉编译器: build = ‘i586-pc-linux-gnu’, host = ’sparc-sun-solaris2.4′, target = ‘mips-idt-ecoff’

4. ‘Makefile’ 简介

Makefiles规定文件之间的依赖关系。它还规定了如何理顺这些关系来达到一个总的目标(即target)。由make处理 Makefiles。其他工具书详细描述了Makefiles的语法及Make的各种应用。本章节将概述Makefiles,其中的信息足以在 Makefile.am(参见第七部分的 Introducing GNU Automake)(see section GNU Automake 简介)和Makefile.in中编写定制的规则。

4.1 目标和依赖关系

make 程序通过更新目标的所有依赖关系来更新目标。这些依赖关系可能有更进一步的依赖关系。因此,当处理一个典型的 ‘Makefile’ 时,一个潜在的复杂依赖关系图就形成了。以下是一个简单的 ‘Makefile’:

all: foofoo: foo.o bar.o baz.o.c.o:        $(CC) $(CFLAGS) -c $< -o $@.l.c:        $(LEX) $< && mv lex.yy.c $@

我们可以画出如下的依赖关系图:

               all                |               foo                |        .-------+-------.       /        |        /    foo.o     bar.o     baz.o      |         |         |    foo.c     bar.c     baz.c                          |                        baz.l

除非 ‘Makefile’ 包含 make 指令,否则所有的目标都应当是文件名,而且必须制定规则来创建这些文件或者以某种方式更新它们。

当依赖关系中有叶子节点时, ‘Makefile’ 就必须包含一组 shell 命令,通过这些命令来更新依赖关系。更新一词经常给 make 的用户造成困扰,这里它的意思是目标的时间戳要比被依赖者的时间戳晚。此外,这些 shell 命令都是在自己的子 shell 中运行。除非 ‘Makefile’ 中对 make 有其他的指示,否则每个命令必须以 0 退出码表示成功运行。

可以编写能被无条件执行的目标规则。要达到该目的只需规定目标没有被依赖者。以下是一条多数使用者都应当熟悉的简单规则:

clean:-rm *.o core

4.2 Makefile 语法

‘Makefile’ 有一套令初用者十分头疼的特殊语法。现在有很多不同的 make 实现,其中有些提供了不可移植的扩展。以下将对 ‘Makefile’ 语法作一个简单描述。就可移植性而言,它可能比你已习惯的语法更严格。

注释以 ‘#’ 开头直到该行结束。它们可以在除命令序列之外的任何地方出现,因为如果解释出现在命令序列中,它们会被运行命令的 shell 打断。下面的 ‘Makefile’ 表示三个各自带依赖关系的独立目标。

target1:  dep1 dep2 ... depN<tab>  cmd1<tab>  cmd2<tab>  ...<tab>  cmdNtarget2:  dep4 dep5<tab>  cmd1<tab>  cmd2dep4 dep5:<tab>  cmd1

目标规则处于一行的开头并以冒号结尾。冒号后面是由空格键分隔的依赖关系列表。紧接着是一系列包含 shell 命令的行。这些 shell 命令将由子 shell 运行(缺省是 Bourne shell)。每一行都必须由字符 tab 开头。这是 make 的初用者常犯的错误。

当将字符 @ 放在命令的开头时,make 在执行命令前就不再显示它们。如果在命令行前有字符 -,那么当命令以非零退出码返回时规则仍可继续。这两个字符也可以一起使用。

4.3 宏

一些有用的宏可以在 ‘Makefile’ 的任何地方使用。像 shell 的变量一样,宏以符号 $ 开头。我们的第一个 ‘Makefile’ 使用了一些宏,例如:

$(CC) $(CFLAGS) -c $< -o $@

这里的语法形式 ‘$(..)’ 是 make 变量的展开符。用 ‘var=value’ 可以定义 make 变量。

CC = ec++

在 ‘Makefile’ 中 ec++ 会替代 $(CC)。make 有一些内建的参数和缺省值。’$(CC)’ 的缺省值为 cc。

其他的内建宏也有自己的固定意义。其中最常见的两个宏是 $@ 和 $<。它们代表目标名和它所在规则的第一个依赖对象。$@ 可以在任何规则中使用,但是在某些 make 的版本中,$< 只能后缀规则中使用。以下是个简单的 ‘Makefile’ 文件:

all:    dummy@echo "$@ depends on dummy"dummy:touch $@

以下是 make 在处理上述的 ‘Makefile’ 文件时将输出的内容:

$ maketouch dummyall depends on dummy

在GNU Make 的使用手册对这些宏有更详细的叙述。

4.4 后缀规则

要简化 ‘Makefile’,有一类名为后缀规则的特殊语法规则。它是指用通配符形式来匹配目标。我们的第一个 ‘Makefile’ 文件使用了一些通配符形式。例如:

.c.o:$(CC) $(CFLAGS) -c $< -o $@

除非有更特殊的规则与目标相匹配,否则上述规则将与任何以 ‘.o’ 结尾的目标相匹配。

原创粉丝点击