Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 操作系统 > Linux > 为多个 UNIX 平台编写软件
【标  题】:为多个 UNIX 平台编写软件
【关键字】:UNIX
【来  源】:http://blog.csdn.net/ideas/archive/2006/08/29/1136361.aspx

为多个 UNIX 平台编写软件

Your Ad Here

为多个 UNIX 平台编写软件

developerWorks
第 1 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容


级别: 中级

Martin Brown, 自由作家, Consultant

2006 年 8 月 28 日

如果为多个 UNIX® 平台编写软件,您会注意到在两个平台上编译软件非常困难。本教程将讨论一些工具和技巧,可以使在代码级支持不同的 UNIX 平台的过程变得相当容易。其原因不是缺乏工具或二进制兼容性问题,而是设置标准 UNIX 环境的头文件和函数的问题。

开始之前

在本教程中,您将了解为了在各种 UNIX® 平台上实现兼容而对应用程序进行构建和迁移操作时的相关问题。我们的重点不是特定的平台差异,而是将为您提供相关知识和工具,让您自己进行决策,以便实现您的 UNIX 应用程序的广泛兼容性。

关于本教程

开发在多个平台上编译和构建的软件可能是一项非常复杂的任务。不同的 UNIX 变体间存在的各种大大小小的差异可能会导致问题。这既包括缺少工具和库的情况,又包括用于构建代码的头文件中存在差异的情况。考虑到这些差异后,您的代码的可移植性将更强,而这正是本教程中要讨论的主题。您还将了解如何使用 GNU 自动工具,以消除迁移和开发过程中的复杂和麻烦。





回页首


先决条件

您将需要访问您系统上的 C 编译器,以对一些示例进行试验。为了对示例自动工具会话进行试验,您需要能够访问通过 GNU 网站提供的自动配置/自动工具包。





回页首


 
   
前一页 第 2 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容


UNIX 不兼容性

之所以在构建应用程序时 UNIX 会出现问题,是因为所有 UNIX 分发并非完全相同(虽然很多都是基于标准组件和理念)。理解这些差异的影响是在不同环境中构建应用程序的第一步。

背景知识

有许多不同的 UNIX 变体,包括各种免费版本,如各种 BSD (Berkeley Systems Division) 变体(FreeBSD、OpenBSD、NetBSD)和 Linux®。这些差异最初源自 UNIX 变体所使用的源 UNIX 分发。有两个源变体,来自 AT&T 的版本(最终发展为了目前的 SVR4)和加州大学伯克利分校(University of California Berkeley,UCB)所开发的版本(目前称为 BSD 版本)。

不同的公司的 UNIX 操作系统均以这其中的一个基本版本为基础,然后添加了供应商特定的扩展和增强功能。一些公司(特别是 Sun)更改了其 UNIX 支持的源。例如,Sun 就从 SunOS 中的 BSD 核心变成了在 Solaris 中使用 SVR4 核心。

System V Release 4 是现在商业分发中最常见的版本,包括基于原始 AT&T 核心且带有一些添加的 BSD 元素的核心。

结果是,尽管从技术而言,不同的 UNIX 版本(AIX®、HP-UX、Solaris 等)都是 UNIX,但系统之间存在的差异意味着采用了不同的库、头文件(甚至用于进行构建的工具也不同),从而意味着无法将 C 源代码方便地从一个平台迁移到另一个平台。

实际函数可能没有更改;而不同的仅是函数的位置和定义。





回页首


POSIX 兼容性

POSIX 组织进行了大量的工作,以对各种不同系统进行标准化,包括操作系统、实用工具和编程语言。这些标准涵盖了许多方面,既包括“标准”函数及其应返回的内容,也包括这些函数所依赖的 OS 的功能和特性。

对于 UNIX,有关的主要 POSIX 标准是 1003.1,该标准定义了应用程序和操作系统间的接口。

多家不同的公司均已采用了 POSIX 标准,包括 Sun Microsystems、IBM、Digital 和 Hewlett Packard。甚至 Microsoft 也在 Microsoft Windows 内提供了 POSIX 兼容层。

POSIX 1003.1 标准(也称为 POSIX.1)定义用于在 OS 内执行特定操作的函数名,包括参数、格式和调用顺序。该标准还指定预期的返回值和其他错误(包括错误代码相关的标准)

总之,任何符合 POSIX 的函数调用应在各种操作系统上都能正常工作,而无需进行任何修改。例如,chdir() 函数就已在 POSIX 标准中定义,因此函数:int chdir(const char *path); 应该在所有符号 POSIX 标准的 UNIX 变体上可用,不同环境中的参数值(一个字符串)、返回值(一个整数值)和错误消息应该相同。

如果所构建的应用程序基于特定 UNIX 变体,则将您的系统迁移到 POSIX 标准是实现更好兼容性的第一步,但这并不能消除所有问题。





回页首


评估手边的任务

第一个任务是确定将要移植的应用程序的复杂性。典型的应用程序包含很多不同的元素。需要确定哪些元素需要进行重新开发,哪些需要加以调整,以兼容更多平台。

需要调查研究的元素包括:

  • 核心 C 代码——大部分 C 代码都具有跨平台兼容性。C 源代码中的大部分不兼容现象都与不同元素所依赖的库和头文件有关。
  • 所需的库——不同的 UNIX 变体包括一系列不同的库和工具,一些甚至可能使用第三方库作为标准库。
  • 构建环境——Makefile 是大部分应用程序的标准构建环境。
  • 所需的工具——某些应用程序可能需要在希望在其中进行构建的所有平台内都具有特定工具,如 yacclexrpcgen 和其他工具。

当然,大部分 C 代码都具有平台兼容性。现在的大部分 C 编译器都基于相关标准,因此对代码进行编译不存在问题。相反,进行移植时出现的大部分问题都与库、头文件和构建环境中的限制相关。





回页首

前一页 第 3 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容


常见的冲突区域

在这一部分,我们将讨论一些与处理头文件、库、构建工具和环境相关的重要问题。

构建工具和环境

移植过程的核心元素是可用的构建工具和环境。如果使用标准 Makefile,则这个过程要容易得多,但仍然需要考虑一些关键的差异。

例如,需要对提供的 C 编译器、C 预处理程序和工具(yacclex 和其他工具)进行标识。还需要考虑命令行选项和不同工具的过程差异。

例如,大部分 UNIX 变体都提供 cc 作为 C 编译器,提供了独立的 C 预处理程序 cpp。不过,有些人可能喜欢使用 cc 的命令行选项 -E 来运行预处理程序。

可以通过使用免费软件工具来简化环境和相关过程,如 gccbisonflex,但同样要注意相关限制和差异。

例如,标准 UNIX yacc 可创建名为 y.tab.c 和 y.tab.h 的文件(要求时),但 bison 将基于源名称创建文件(例如,从 parser.y 生成 parser.tab.c)。您需要考虑此差异。

另外,也要注意位于不同平台的不同位置上的不同工具。例如,Solaris 包括了 make 作为标准编译器(但不是 C 编译器),它位于 /usr/ccs/bin/make,而不是在很多其他平台上所使用的缺省路径,如 /usr/bin/make。

处理 Makefile 级别的这些差异的最简单方式(不使用 GNU 自动工具)是为每个环境创建独立的 Makefile,根据平台调用每个 Makefile。然后就能在使用 make 时使用恰当的 Makefile。

$ make -f Makefile.solaris

您仍然需要手动管理文件间的个体差异,但相应的过程应该会简单得多。





回页首


使用 C 预处理程序

通常,通过使用 C 预处理程序指令来选择不同的代码片段,可以处理头文件和大部分体系结构和功能差异。

系统能够正常工作的原因是由于 C 代码在使用 C 预处理程序 (cpp) 前已经进行了编译。在编译期间,预处理程序将查找定义,并使用一系列执行比较运算的宏来标识是否存在特定定义。然后将在特定平台内进行构建时指定该定义。

您事实上可能已经使用了指令来允许调试代码。例如,您可能会在 Solaris x86 环境内构建应用程序时指定以下定义:

#define SOLARISX86

通过头文件或在编译器的命令行上包含定义,可以指定此定义:

$ cc -DSOLARISX86

在源代码内,将随后通过检查此定义来标识要使用的正确源代码。例如,在清单 1 中就给出了定义的一个特例。


清单 1. 选择异常
                    
#ifdef SOLARISX86
/* do solaris specific code */
#else
/* do other Unix code */
#endif

还可以在 if..else..endif 部分中使用 #ifndef 来检查是否已定义某个指令,使用 #elif 来检查其他的指令。

可以在整个源代码中使用相同的系统。例如,可以使用它包含不同的头文件(清单 2)和在 localtime() 函数处理前处理遇到的差异。


清单 2. 选择头文件
                    
#ifdef SOLARISX86
#include <iso/time_iso.h>
#else 
#include <time.h>
#endif

需要在整个代码中都采用相同的原则(假定知道需要什么内容)。





回页首


头文件差异

在不同的 UNIX 变体之间进行迁移所遇到的最常见问题是操作系统中提供的用于定义结构、变量类型和函数的头文件。

一些头文件具有不同位置。例如,limits.h 的内容或多或少算得上是 UNIX 平台上的标准头文件,但位于不同的目录中。例如,在 AIX 内,将使用以下代码导入该头文件:

#include <sys/limits.h>

但在 Solaris 内要使用以下代码:

#include <limits.h>

在某些情况下,所需的信息或许不位于相同的文件中,或者与在原始平台中使用的定义不同,或者直接不可用。

在前一种情况,您需要找到所需的函数定义、结构或变量的位置。最后的方法是使用 grep 来搜索位置,如下面的代码中所示(在 Solaris 主机上查找 PIPE_MAX 定义)。

$ find /usr/include -exec grep -il PIPE_MAX {} \;
/usr/include/sys/param.h
/usr/include/limits.h

所查找的定义与源平台上的定义匹配时,则可以根据情况插入备选定义。不过,请注意,不要更改系统或库调用的含义;更改前台函数定义并不会改变基础库函数。

如果定义不存在,则可能表明其所依赖的库或接口不存在。





回页首


库差异

不同的 UNIX 变体将组件放入不同的库中,可能要求包括一系列其他平台不需要的库。此类情况的一个典型例子就是网络方面的库。在很多 UNIX 平台上,构建网络应用程序所必需的库将在链接时自动包含到应用程序中。

不过,在 Solaris 内,必须具体地添加这些库,才能将其与您的应用程序链接:

$ cc -o server server.c -lnsl -lsocket -lresolv

没有办法列出很多不同 UNIX 变体和函数的所有不同选项和可能的差异。解决此问题的唯一办法是按应用程序进行处理。尝试编译应用程序,等待缺少符号警告。

例如,如果未包含数学库,可能得到与清单 3 中所示的类似的错误。


清单 3. 缺少符号错误
                    
calcparse.tab.o: In function `yyparse':
calcparse.tab.c:(.text+0x53a): undefined reference to 'pow'
calcparse.tab.c:(.text+0x573): undefined reference to 'fmod'
calcparse.tab.c:(.text+0x5bb): undefined reference to 'log'
calcparse.tab.c:(.text+0x818): undefined reference to 'cos'
calcparse.tab.c:(.text+0x829): undefined reference to 'tan'
calcparse.tab.c:(.text+0x83c): undefined reference to 'cos'
calcparse.tab.c:(.text+0x849): undefined reference to 'tan'
calcparse.tab.c:(.text+0x856): undefined reference to 'asin'
calcparse.tab.c:(.text+0x863): undefined reference to 'acos'
calcparse.tab.c:(.text+0x870): undefined reference to 'atan'
collect2: ld returned 1 exit status

获得了缺少符号的列表后,可以查找目标平台上的手册页,并标识所需的库。

对于完全缺少的函数,可能需要自己构建这些函数,或从第三方库提供。例如,GNU glibc 包含很多您可能依赖的本机 UNIX C 库中不提供的函数。

自己构建函数时,可以创建包含不同平台的函数定义的单个 C 源文件,然后使用前面显示的直接方法来选择是否在不同平台上构建相应的函数。





回页首


字节顺序差异

除了头文件和库的基本知识之外,下面将开始了解非常特定于平台的差异,而此类差异通常更难于解决。

这些差异中的最基本的就是主机 CPU 的字节顺序。字节顺序会影响如何引用和访问多字节数据的方式。这是由于 CPU 操作方式造成的。

Big Endian CPU(包括 SPARC、PA-RISC 和 PowerPC)采用首先引用最高有效位的方式引用信息,而 Little Endian CPU(主要是 Intel)则采用首先引用最低有效位的方式引用信息。这样可能会导致将地址完全反向,如会从 ABCD 反向为 DCBA。

这并不会影响字符串,因为字符串基于单个字节,但这会影响多字节值(如 32 位地址),因为其中的字节顺序会导致在 Big endian CPU 和 Little endian CPU 上以不同的方式对待值。

此问题并不能简单地得到解决,但可以采用很多方法来引用和存储信息,而不依赖对多字节数据的直接访问,从而避免此问题。





回页首


处理、发送信号及 IPC

不同 UNIX 变体内的不同 fork() 和线程实现之间存在较小的差异。例如,并非所有 UNIX 变体都支持所有 fork*() 函数。IRIX 支持 m_fork() 函数,该函数实际上与各个线程库中的一个类似。不过,即使在线程领域内,不同的实现和标准并未得到广泛的推广。

不同 UNIX 变体支持一系列不同的信号。很多核心信号都保持了一致性;例如,SIGHUP 的值为 1SIGKILL 的值为 NINE,但并不依赖于在所有平台上提供特定于 OS 的信号的可用性,如 SIGJVM1(特定于 Solaris)。通常只有 15 以下的信号才在大多数平台上完全相同。超过 15 (SIGTERM) 的信号完全特定于 OS。

还要注意,进程间通信(Interprocess Communication,IPC)方法并未标准化。尽管大部分 UNIX 变体支持 SVR4 IPC,仍然注意并没有这方面的全面支持。通常应采用更为开放的 IPC 标准,如命名管道。





回页首


前一页 第 4 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容


使用 GNU 自动工具

目前所讨论的方法的唯一问题在于,这些方法均要求进行大量的管理工作,以引入和组织不同的元素。它们要求能够访问需要支持的所有不同的平台;为了囊括所有的不同选项和备选方法,可能会大幅度增加开发时间。

GNU 自动工具概述

GNU 自动工具包是一个可产生配置规则和文件的框架集的系统。在新目标主机上运行配置脚本时,它会检查操作系统和基础代码的要求,并产生合适的头文件配置和构建环境(基于标准 Makefile),以用于在该主机上构建应用程序。

如果在计算机上构建过开放源代码应用程序,则可能会注意到以下序列:

$ ./configure
$ make
$ make install

configure 脚本是源代码分发的一部分。它使用一系列配置文件来确定进行构建所需的各种元素。自动工具系统的主要好处在于,它具有能确定在其上执行脚本的主机上的配置和组件可用性的脚本功能(通过与产生工作构建环境的源代码所需元素进行比较)。

由于自动工具系统依赖于特定平台的已预先知道的值的组合(例如,它知道目标类型、库和头文件可用性),并结合用于确定特定函数和头文件的可用性的运行时驱动信息,因此整个流程可以正常工作。

对于很多应用程序,您并不需要为了提高兼容性而对代码进行手动更改。另外,甚至不需要知道 configure 脚本的目标主机。我曾经开发过使用自动系统的应用程序,可成功在 HP-UX、Solaris(SPARC 和 x86)、Linux、Mac OS X 和 BSD 上进行编译和构建,而无需对代码进行任何更改。

显然,为了获得系统提供的各种好处,必须首先告知自动工具环境通常将如何构建应用程序,并使用自动工具系统扫描您的源代码,从而确定为了让您的应用程序正常工作所需的函数、库和其他组件。





回页首


设置项目结构

使用自动工具的第一步是为应用程序创建合适的结构。对于此示例,将使用简单的计算器应用程序(请参见下载),该应用程序依赖于一个词法分析组件(要求使用 lex)和一个语法组件(要求使用 yacc)以及数个支持特定操作的其他文件。可以在清单 4 中看到相关的文件列表。


清单 4. 计算器的源文件
                    
total 28
-rwxrwx--x  1 mc mcslp  458 Jan 25 17:19 Makefile*
-rwxrwx--x  1 mc mcslp  129 Apr 16  1997 calc.h*
-rwxrwx--x  1 mc mcslp 4216 Jun 11  1997 calcparse.y*
-rwxrwx--x  1 mc mcslp  136 Jun  8  1997 const.c*
-rwxrwx--x  1 mc mcslp  643 Apr 16  1997 fmath.c*
-rwxrwx--x  1 mc mcslp 1095 Jan 25 17:16 lex.l*

清单 5 中显示了手动编写的用于构建计算器的 Makefile。


清单 5. 一个手动编写的 Makefile
                    
YFLAGS        = -d

PROGRAM       = calc

OBJS          = calcparse.tab.o lex.yy.o fmath.o const.o

SRCS          = calcparse.tab.c lex.yy.c fmath.c const.c

CC            = gcc      #C compiler

all:            $(PROGRAM)

.c.o:           $(SRCS)
                $(CC) -c $*.c -o $@ -O

calcparse.tab.c:        calcparse.y
                bison $(YFLAGS) calcparse.y

lex.yy.c:       lex.l 
                flex lex.l

calc:           $(OBJS)
                $(CC) $(OBJS)  -o $@ -lfl -lm


clean:;         rm -f $(OBJS) core *~ \#* *.o $(PROGRAM) \
                y.* lex.yy.* calcparse.tab.*

为了将应用程序设置为与自动工具一起使用,请删除 Makefile,创建一个新目录(可以将其命名为 calc),然后创建一个子目录 (src),以便将所有源文件复制到其中。清单 6 可以看到此布局——已经可以使用自动工具。


清单 6. 已经可以与自动工具一起构建的源文件
                    
./calc
./calc/src
./calc/src/calc.h
./calc/src/calcparser.c
./calc/src/calcparser.h
./calc/src/calcparser.y
./calc/src/const.c
./calc/src/fmath.c
./calc/src/lex.c
./calc/src/lex.l

现在已经可以开始使用自动工具进行配置了。





回页首


创建核心 Makefile

需要在源目录的每个目录(包括项目的根)中创建一个 Makefile.am 文件。根中的 Makefile.am 用于引用其他目录的内容;每个源目录中的 Makefile.am 仅用于定义该目录中信息的构建过程和要求。

因此,对于您的示例,calc 中的 Makefile.am 将与以下所示的文本类似:

SUBDIRS=src

这直接指定了包含将使用配置系统配置(和构建)的环境的子目录列表。

您的 src 目录中的 Makefile.am 文件应与清单 7 中所示类似。


清单 7. 用于构建缺省目标的 src/Makefile.am 框架
                    
calcprgdir=../
calcprg_PROGRAMS=calc
calc_SOURCES=lex.l calcparser.y fmath.c const.c
AM_YFLAGS=-d
calc_LDADD=-lfl -lm 

各行的前缀非常重要:前缀用于标识选项应用到的目标。

清单 7 中的第一行指定执行 make 安装时应用程序的最终目标目录。构建此演示程序时,将使用父目录作为目标安装。

第二行指定将生成的应用程序的名称。第三行列出构建目标所需的源文件。请注意,尽管您的应用程序依赖于独立工具(即 lex 或 flex 和 yacc 或 bison)生成的 C 文件,但并不需要显式地指定此阶段。这是因为自动工具包已经基于其扩展名知道了如何从这些源文件构建 C 源代码。

第四行设置了一个常规选项,以将 -d 命令行选项添加到 yacc 解析器。另外,yacc/bison 的使用是使用自动工具系统的的预配置知识的另一个例子。自动工具知道 UNIX 平台可能已经安装了 yacc;如果没有 yacc,就安装了 GNU yacc 工具 bison。两个工具会生成相同的信息,但这些信息位于不同的文件中;为了方便起见,bison 包含了一个 yacc 兼容模式。当自动工具为代码生成的 configure 脚本在系统上执行时,它将确定提供的是 yacc 还是 bison,并自动调整此阶段的命令行。

清单 4 中的最后一行指定构建此目标所需的其他库。请注意,只需要按照使用 cc 时一样的方法指定库名称;configure 脚本将确定这些库所在的位置,以及在构建目标时是否需要向目录添加特定目录。

配置了基本构建过程后,需要让自动工具扫描源代码,并确定源代码中可能在不同环境中具有不同源和定义的函数和其他元素。





回页首


扫描源代码

configure.ac 文件定义您源代码中特定于配置的元素。此文件的内容用于生成必要的配置脚本,以最终在目标主机上的构建环境进行配置。

您不必自己创建此文件;可以使用 autoscan 函数来自动生成此文件的框架版本。

$ autoscan
autom4te-2.59: configure.ac: no such file or directory
autoscan-2.59: /usr/bin/autom4te-2.59 failed with exit status: 1

不要担心错误——这些错误仅指示并没有可作为扫描基础的 configure.ac 文件。第一次运行此工具时,会创建名为 configure.scan 的文件。可以在清单 8 中看到此文件包含的内容。


清单 8. 缺省自动扫描配置
                    
#                                               -*- Autoconf -*-
# 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([src/calc.h])
AC_CONFIG_HEADER([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.
# FIXME: Replace `main' with a function in `-lfl':
AC_CHECK_LIB([l], [main])
# FIXME: Replace `main' with a function in `-lm':
AC_CHECK_LIB([m], [main])

# Checks for header files.
AC_FUNC_ALLOCA
AC_HEADER_STDC
AC_CHECK_HEADERS([stddef.h stdlib.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST

# Checks for library functions.
AC_CHECK_FUNCS([pow])

AC_CONFIG_FILES([src/Makefile])
AC_OUTPUT

FIXME 元素可给出需要编辑的良好指示。首先,将该文件从 configure.scan 重命名为 configure.ac。

需要在此处重新配置一系列元素。从 AC_PREREQ 开始,对各个值进行更改,以反映包的名称、版本和联系人电子邮件地址。

然后添加代码行来配置系统进行 automake

AM_INIT_AUTOMAKE

还需要更新 AC_CHECK_LIB 行,以在所使用的库内检查特定函数。对于此应用程序,只需要确保数学库 (-lm) 可用。最后,还需要添加两行,以包含用于运行 lex 和 yacc 的配置定义和对其依赖的文件。

结果文件应与清单 9 中所示类似。


清单 9. 最终的 configure.ac
                    
AC_INIT(calc, 1.0, mc at mcslp.com)
AC_CONFIG_SRCDIR([src/calc.h])
AM_INIT_AUTOMAKE
AC_CONFIG_HEADER([config.h])

# Checks for programs.
AC_PROG_CC
AM_PROG_LEX(src/lex.l)
AC_PROG_YACC(src/calc.y)

# Checks for libraries.
AC_CHECK_LIB([m], [sin])

# Checks for header files.
AC_FUNC_ALLOCA
AC_HEADER_STDC
AC_CHECK_HEADERS([stddef.h stdlib.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST

# Checks for library functions.
AC_CHECK_FUNCS([pow])

AC_CONFIG_FILES([src/Makefile])
AC_OUTPUT

该文件将由 autoconf 用于确定构建应用程序所需的函数。





回页首


修改源

自动工具系统通过生成配置文件和一个 config.h 头文件进行工作;相比之下,后者要重要得多,将用于包含构建脚本所需的所有必要定义信息。

需要将 config.h 头文件添加到 C 源文件,以便在编译期间加载配置信息。

可能要需要对代码进行其他一些次要的更改。例如,配置脚本假定 cal.c 之类的 yacc 文件将产生两个文件,calc.h 和 calc.c。请确保这不会覆盖任何现有内容或直接更改 yacc 源文件,以便文件生成不会覆盖您的现有文件。





回页首


创建配置脚本

现在已经有了一个 Makefile 框架和项目的配置框架。您需要将此转换为四个不同的组件:

  • 头文件框架 (config.h.in),包含项目的具体兼容性信息。
  • aclocal.m4 文件,一个 m4 宏,用于构建必要的宏来转换配置文件。
  • Makefile.in,一个针对每个目录和子目录的模板 Makefile。
  • 配置脚本 (configure),在确定构建环境时考虑以上所有组件,并创建必要的头文件和 Makefile 来构建应用程序。

此过程包含四个步骤。首先,生成 m4 宏:

$ aclocal

可以忽略此命令生成的任何警告,但应对错误加以注意;这些错误可能指示 configure.ac 中存在键入错误。然后,创建模板头文件:

$ autoheader

现在可以生成模板 Makefile 了。在进行此操作前,应该创建属于标准工具配置的一系列文件。这些文件包括:

  • COPYING——复制您的源的规则——GPL 的缺省设置。
  • AUTHORS——作者列表。
  • ChangeLog——源和版本的更改历史记录。
  • INSTALL——安装应用程序的步骤。
  • NEWS——应用程序相关的新闻。
  • README——关于应用程序的简单自述文件。

暂时可以只创建空文件:

$ touch INSTALL NEWS README AUTHORS ChangeLog COPYING

现在可以创建 Makefile 模板了:

$ automake -ac

-a 选项告知 automake 添加缺少的文件,-c 选项将这些缺少的文件复制到目录中。

最后,需要生成配置脚本,以在目标主机上实际执行已确定的配置:

$ autoconf

清单 10 所示为整个序列(及示例输出)。


清单 10. 配置构建序列
                    
$ aclocal
/usr/share/aclocal/pth.m4:43: warning: underquoted definition of _AC_PTH_ERROR
  run info '(automake)Extending aclocal'
  or see http://sources.redhat.com/automake/automake.html#Extending-aclocal
/usr/share/aclocal/pth.m4:55: warning: underquoted definition of _AC_PTH_VERBOSE
/usr/share/aclocal/pth.m4:61: warning: underquoted definition of AC_CHECK_PTH
/usr/share/aclocal/glib.m4:8: warning: underquoted definition of AM_PATH_GLIB
$ autoheader
$ automake -ac
$ autoconf

如果检查根目录,应该可以标识各个主要组件,如 configure 脚本 config.h.in 和 Makefile.in,如此处的清单 11 中所示。


清单 11. 示例目录结构
                    
-rw-rw-rw-   1 root mcslp      0 Jan 25 15:45 AUTHORS
-rw-r--r--   1 root mcslp  18002 Jan 25 15:45 COPYING
-rw-rw-rw-   1 root mcslp      0 Jan 25 15:45 ChangeLog
-rw-r--r--   1 root mcslp   9498 Jan 25 15:45 INSTALL
-rw-rw-rw-   1 root mcslp     12 Jan 25 15:44 Makefile.am
-rw-rw-rw-   1 root mcslp  18101 Jan 25 16:06 Makefile.in
-rw-rw-rw-   1 root mcslp      0 Jan 25 15:45 NEWS
-rw-rw-rw-   1 root mcslp      0 Jan 25 15:45 README
-rw-rw-rw-   1 root mcslp  31731 Jan 25 15:52 aclocal.m4
drwxr-xr-x   7 root mcslp    238 Jan 25 15:52 autom4te.cache/
-rw-rw-rw-   1 root mcslp   2563 Jan 25 15:52 config.h.in
-rw-rw-rw-   1 root mcslp   2634 Jan 25 15:51 config.h.in~
-rwxrwxrwx   1 root mcslp 174254 Jan 25 15:52 configure*
-rw-rw-rw-   1 root mcslp    690 Jan 25 15:52 configure.ac
-rw-rw-rw-   1 root mcslp    718 Jan 25 15:50 configure.ac~
-rwxr-xr-x   1 root mcslp  15936 Jan 25 15:45 depcomp*
-rwxr-xr-x   1 root mcslp   9233 Jan 25 15:45 install-sh*
-rwxr-xr-x   1 root mcslp  11014 Jan 25 15:45 missing*
drwxrwxrwx  16 root mcslp    544 Jan 25 16:08 src/

现在可以尝试对应用程序进行配置了。





回页首


试验新配置

要试验配置,直接运行 configure 即可。可以在清单 12 中看到用于确定所需的不同库和头文件的脚本。


清单 12. 示例配置脚本执行
                    
$ ./configure
checking for a BSD-compatible install... /bin/install -c
checking whether build environment is sane... yes
/bin/sh: /mnt/mc/Active: No such file or directory
configure: WARNING: `missing' script is too old or missing
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
checking for flex... flex
checking for yywrap in -lfl... yes
checking lex output file root... lex.yy
checking whether yytext is a pointer... yes
checking for bison... bison -y
checking for sin in -lm... yes
checking how to run the C preprocessor... gcc -E
checking for egrep... grep -E
checking for working alloca.h... yes
checking for alloca... yes
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking stddef.h usability... yes
checking stddef.h presence... yes
checking for stddef.h... yes
checking for stdlib.h... (cached) yes
checking for an ANSI C-conforming const... yes
checking for pow... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating config.h
config.status: executing depfiles commands

然后可以运行 make 来构建应用程序(请参阅清单 13)。


清单 13. 运行 make
                    
$ make
make  all-recursive
make[1]: Entering directory `/export/data/calc'
Making all in src
make[2]: Entering directory `/export/data/calc/src'
bison -y  -d calcparser.y
flex   lex.l
if gcc -DHAVE_CONFIG_H -I. -I. -I..     
-g -O2 -MT fmath.o -MD -MP -MF ".deps/fmath.Tpo" -c -o fmath.o fmath.c; \
then mv -f ".deps/fmath.Tpo" ".deps/fmath.Po"; else rm -f ".deps/fmath.Tpo"; 
   exit 1; fi
sed '/^#/ s|lex.yy\.c|lex.c|' lex.yy.c >lex.c
rm -f lex.yy.c
if gcc -DHAVE_CONFIG_H -I. -I. -I..     
-g -O2 -MT tmath.o -MD -MP -MF ".deps/tmath.Tpo" -c -o tmath.o tmath.c; \
then mv -f ".deps/tmath.Tpo" ".deps/tmath.Po"; else rm -f ".deps/tmath.Tpo"; 
   exit 1; fi
if gcc -DHAVE_CONFIG_H -I. -I. -I..     
-g -O2 -MT const.o -MD -MP -MF ".deps/const.Tpo" -c -o const.o const.c; \
then mv -f ".deps/const.Tpo" ".deps/const.Po"; else rm -f ".deps/const.Tpo"; 
   exit 1; fi
if test -f y.tab.h; then \
  to=`echo "calcparser_H" | sed \
           -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
           -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \
  sed -e "/^#/!b" -e "s/Y_TAB_H/$to/g" -e "s|y\.tab\.h|calcparser.h|" \
            y.tab.h >calcparser.ht; \
  rm -f y.tab.h; \
  if cmp -s calcparser.ht calcparser.h; then \
    rm -f calcparser.ht ;\
  else \
    mv calcparser.ht calcparser.h; \
  fi; \
fi
if test -f y.output; then \
  mv y.output calcparser.output; \
fi
sed '/^#/ s|y\.tab\.c|calcparser.c|' y.tab.c 
   >calcparser.ct && mv calcparser.ct calcparser.c
if gcc -DHAVE_CONFIG_H -I. -I. -I..     -
 g -O2 -MT lex.o -MD -MP -MF ".deps/lex.Tpo" -c -o lex.o lex.c; \
then mv -f ".deps/lex.Tpo" ".deps/lex.Po"; else rm -f ".deps/lex.Tpo"; exit 1; fi
rm -f y.tab.c
if gcc -DHAVE_CONFIG_H -I. -I. -I..     
 -g -O2 -MT calcparser.o -MD -MP -MF ".deps/calcparser.Tpo" 
-c -o calcparser.o calcparser.c; \
then mv -f ".deps/calcparser.Tpo" ".deps/calcparser.Po"; 
else rm -f ".deps/calcparser.Tpo"; exit 1; fi
gcc  -g -O2   -o calc  calcparser.o lex.o fmath.o tmath.o const.o -lfl -lm -lm 
make[2]: Leaving directory `/export/data/calc/src'
make[2]: Entering directory `/export/data/calc'
make[2]: Nothing to be done for `all-am'.
make[2]: Leaving directory `/export/data/calc'
make[1]: Leaving directory `/export/data/calc'
You can try out the application just to make it has been built properly:
$ ./src/calc
45*69
3105

可以通过使用 distclean 目标在构建目录中还原为未构建未配置状态。

$ make distclean

通过 NFS 连接共享文件并使用此方法在每次构建后进行“复位”,可以方便地在多个平台上进行测试,而不必将分发复制到每个主机上。





回页首


自动工具的局限

自动工具系统可帮助处理构建多平台兼容应用程序的大量复杂性,但并不是最终的解决方案。

自动工具解决方案无法考虑不属于分发文件一部分的特殊库、第三方库或您自己的库(虽然没有任何事情会阻止您添加它们,或者创建特定自动工具配置)。

自动工具也不能说明所使用的任何特定于 OS 的元素。如果所依赖的库或函数是 Solaris 特有的(例如,它是 Solaris 内核接口所特有的),则自动工具将无法解决此问题。

自动工具系统只能解决主要的 UNIX 问题及 C 库差异、其头文件关系和编译链接元素所需的构建环境。它无法为软件移植目的而模拟其他库和内核环境。

这并不意味着不应该使用自动工具;它可能是最有效的构建环境移植工具——但不要期望它能带来奇迹。为了最有效地使用自动工具,必须随时准备将其与本教程前面讨论的其他技术一起使用,以确保广泛的兼容性。

最后,无论进行多少工作,都不能替代使用目标平台进行实际测试。自动工具可以会简化构建过程,但不要期望它能消除进行调试和测试的需求。





回页首


前一页 第 5 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容


总结

开发在多个 UNIX 平台下工作的应用程序必须了解影响编译和连接过程的基本问题。几乎在所有情况下,出现的问题与两个截然不同的领域相关:支持标准系统和内核功能的头文件,以及用于支持特定扩展和功能的库。隐藏在这些差异背后的是特定操作系统限制的复杂问题。例如,不同 UNIX 变体支持的信号的差异可能会带来问题。

其中的一些差异可以通过使用相关技巧绕过差异和问题来减少。为了简化头文件、库和构建环境问题,可以使用 GNU 提供的自动工具/自动配置包。这将通过结合使用已知差异和发现脚本来在构建过程中确定目标上的环境,然后构建一个合适的构建脚本和头文件来处理特定于平台的问题。

自动工具可以简化构建过程,但它并不是设计用来处理平台间的所有差异的。例如,它无法处理缺少的函数、库和核心 OS 差异,但它将在差异处理中扮演很重要的角色。





回页首

前一页 第 6 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容



下载

描述 名字 大小 下载方法
Calc source for autotools example mcb-calculatar.tar.gz 120KB  FTP
关于下载方法的信息 Get Adobe® Reader®
前一页 第 7 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容


参考资料

学习

讨论




回页首

前一页 第 8 页,共 9 页 后一页


对本教程的评价

帮助我们改进这些内容


关于作者

Martin Brown 成为职业作家已经超过 7 个年头。他所撰写的书籍和文章涵盖了各种各样的主题。他所擅长的领域包括大量开发语言和平台——Perl、Python、Java、JavaScript、Basic、Pascal、Modula-2、C、C++、Rebol、Gawk、Shellscript、Windows、Solaris、Linux、BeOS、Mac OS/X 等等——以及 Web 编程、系统管理与集成。Martin 是 Microsoft 的主题专家(Subject Matter Expert,SME),并长期为 ServerWatch.com、LinuxToday.com 和 IBM developerWorks 供稿。他也是 Computerworld、The Apple Blog 及其他站点的博客。您可以通过他的网站 http://www.mcslp.com 与他联系。

madplay 在ARM上的移植:【上一篇】
FLTK,优秀的图形库:【下一篇】
【相关文章】
  • 关于Unix下操作INI文件 解决办法。
  • C语言的UNIX界面中两个版本的open函数
  • Unix 下使用 DB: “go” shell
  • ScoUNIX命令集
  • 我喜欢Unix
  • dos文件转换为unix文件(去掉dos文件的^M)
  • 对话 UNIX: 掌握强大的命令行
  • UNIX 文件系统基本操作
  • 使用 UNIX find 命令的高级技术
  • 让 UNIX 和 Linux 一起工作
  • 【随机文章】
  • 生成无重复的随机数
  • pow10 ( )【C语言库函数源代码】
  • 从动态SQL中返回值
  • 母版页调用内容页的方法的简单实现
  • 如何在主页中控制浏览权限
  • 64位中文Vista+中文Project2007存在的一个时间校验的bug
  • Sun One Calendar Server Installation Guide[下载]
  • 搜索引擎之中文分词实现(java版)
  • 用Excel设计电子计分册
  • RMI的工作原理
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.