[图片] What is Portability? 在进行分析什么值得去检测, 如何检测之前, 抛出一个问题: 到底什么是可移植性? 可移植性是一种代码的质量, 可以使得编译和运行在各种各样的平台上. 在 Autoconf 的背景下, 可移植性通常指的是可以运行在类 Unix 的系统上--有时候包含 Windows. ..

"configure.in" 的书写

What is Portability?

在进行分析什么值得去检测, 如何检测之前, 抛出一个问题: 到底什么是可移植性? 可移植性是一种代码的质量, 可以使得编译和运行在各种各样的平台上. 在 Autoconf 的背景下, 可移植性通常指的是可以运行在类 Unix 的系统上--有时候包含 Windows.
当我第一次使用 Autoconf, 很难决定到底去检测什么在"configure.in".当时在做的一些项目是在 SunOS 4 上. 但是很是有兴趣移植到其他的 Unix 平台上(比如 Solaris).
我采用的方法虽然可行但是相对耗时且痛苦: 我编写了一个最小的'configure.in', 然后继续简单地尝试在 Solaris 上构建我的程序. 每次遇到构建问题时, 我都会更新'configure.in'和我的源代码并重新启动. 正确构建后, 我开始测试是否存在与可移植性相关的运行时问题.
因为我没有从一个相对可移植的基础开始, 也因为我不知道可用于帮助添加 Autoconf 支持的工具. 如果可能的话, 最好先编写可移植代码.
世界上有许多类 Unix 系统, 这些系统虽然仍在运行, 但只能被认为是过时的. 虽然将某些程序移植到所有这样的系统存在可能性,但通常尝试也没什么实际的用处. 移植就是一个困难的过程, 特别是考虑到通常无法在所有平台上进行测试, 并且这些平台每年都会发布具有自己的 bug 和特性的新操作系统.
我们提倡一种实用的可移植性方法: 我们编写的程序针对的是一个相当大的, 但也相当现代的类 Unix 系统. 由于在我们的可移植性框架中发现了缺陷, 我们更新'configure.in'和我们的源代码, 然后继续. 在实践中, 这才是一种有效的方法.

Brief introduction to portable sh

如果你读过好多的"configure.in"文件, 你会发现这个文件的书写使用的是一种非比寻常的风格. 比如说, 你很少见一个程序是"["样书写的; 这片我们不会深入太多细节关于这个脚本怎么去写, 这个会在后面详细的说道的.
与可移植性的其他方面一样, 在'configure.in'和'Makefile.am'中编写 shell 脚本的方法应该取决于设定的的目标. 一些平台已经臭名昭着地打破了 sh 实现. 例如, Ultrix sh 没有实现unset. 当然, GNU Autotools 是以最可移植的方式编写的, 避免对可能性的定制扩展进行了限制.
另外, sh 脚本本身做得很少, 大多数实际工作是由单独的程序完成的, 每个程序都有自己潜在的可移植性问题. 例如, 某些选项在系统之间不可移植, 并且并不是每个系统上都会存在可见的公共程序 - 因此不仅要知道哪些 sh 结构不可移植, 而且还必须知道哪些程序可以(或不能)使用, 以及这些程序的哪些选项是可移植的.
这个看起来很难以实现, 但其实写一个可移植脚本程序不是那么难 - 只要对规则了如指掌了. 但是要想达到这个境界, 这个过程还是需要耗费点时间的.
了解你可能会关心哪些架构是值得的 - 如果你正在编写一个可移植度高的程序, 比如 Emacs 或 gcc, 那么你会做出不同的选择, 而不是你正在编写的东西只能运行在各种 Linux 版本上. 此外, 在"configure.in"中使用不可移植代码的成本相对较低 - 通常, 在找到不可移植的结构时, 按需重写片段代码相当容易.

Ordering Tests

除了编写可移植的 sh 代码的问题之外, 第一次编写"configure.in"面临的另一个问题是确定运行各种测试的顺序. Autoconf 通过 Autoscan(以后会详细讲述到)间接的建议了标准顺序:

AC_ARG_ENABLE(getenv-properties,
         [  --disable-getenv-properties 
         don’t set system properties from GCJ_PROPERTIES]) 

 dnl Whether GCJ_PROPERTIES is used depends on the target.
         if test -n "$enable_getenv_properties";then 
 		enable_getenv_properties=${enable_getenv_properties_default-yes}
         fi 

	 if test "$enable_getenv_properties" = no; then
		AC_DEFINE(DISABLE_GETENV_PROPERTIES) 
	 fi

What to check for

决定要检查的内容实际上是编写"configure.in"的重中之重. 一旦参考了 Autoconf 手册, 那么编写特定测试的"方法"应该不是什么复杂的事儿. 但是"when"可能仍然存在一定的不确定性.
各种类 Unix 系统之间存在着一个显着的分歧, 即相同的程序并不会出现在所有的系统上, 即使它们存在, 它们并不总是以相同的方式工作. 对于这些问题, 建议在可能的情况下遵循 GNU 编码标准的建议: 使用相对有限的一组程序中最常见的选项. 如果做不到这一点, 尝试使用 POSIX 指定的程序和选项, 或者通过检查关心的平台上的已知问题来扩充这种方法.
对工具的和差异性的检查通常只是一小部分. 更多的是对函数和库的检查.
除了像"libc"这样的核心库, 像"libm"和像"libX11"这样的库(不被认为是系统库), 对于不同 Unix 系统之间的库名或内容几乎没有保持一致的. 尽管如此, 库也是很容易处理的. 因为关于库的决定几乎总是只影响各种"Makefile". 这意味着检查另一个库通常不需要对源代码进行重大更改. 此外, 因为添加新的库进行测试对开发周期的影响很小 - 实际上只是重新运行"configure"然后重新链接. 可以采用不严格的库方法来提高效率. 比如说, 针对于想要部署的平台上进行库的测试就行了, 然后基于这些 base 进行定制化更改.
假设遇到链接问题. 怎么处理它? 首先要做的是使用nm查看系统库来查看是否存在缺失的函数. 如果是, 并且它在你知道的库中, 只需添加另一个"AC_ CHECK_LIB". 注意, 仅仅在库中查找函数是不够的, 因为在某些系统上, 某些"标准"库是不合需要的. 比如说"libucb"是你应该避免使用的最常见的库.
如果在系统库中找不到该函数, 那么就遇到了一个比较棘手的问题: 非可移植的函数. 针对于缺失函数基本上有三种方法. 下面我们讨论函数, 但实际上这些方法或多或少适用于 typedef, 结构体和全局变量.

AC_CHECK_FUNCS(inet_aton inet_addr, break)

使用这些检查结果的代码看起来像:

#if HAVE_INET_ATON
 ... use inet_aton here 
 #else
#if HAVE_INET_ADDR 
 ... use inet_addr here
#else 
#error Function missing!
#endif
#endif

注意, 如果函数不存在, 我们如何使它成为编译时错误. 通常, 最好在构建过程中尽早发生错误.

回帖   
请输入回帖内容...