configure原理
一、必要性
作为源代码发行的软件,希望在尽可能多的环境上可以运行,这些环境包括了操作系统的类型,硬件系统、开发环境的不同的方面;另一方面,在Linux系统中没有一种统一的位置可以确定系统中是否支持某种功能,例如:无 法确认这个系统是否安装了gcc工具,它的位置在哪里,该操作系统是否支持mmap功能、甚至是环境是大端字节序还是小端字节序等属性,所以需要通过执行 configure来动态的尝试确定源代码构建和运行环境需要的属性情况。最重要的目的是替换Makefile中的指定变量,
二、各种配置文件说明
configure.ac 该文件为autoconfigure文件使用的一个文件,该文件用来生成configure文件,这个文件一般是开发者维护,我们安装该软件的时候只需要执行configure就可以,这个configure.ac我们一般不用理会
configure 这个是我们需要监测环境的主要入口文件,使用该文件可以生成Makefile文件,它会替换Makefile中需要替换的变量。
config.guess 这个是在构建环境上运行的一个脚本,它用来猜测构建机的配置环境,因为这个脚本是在构建机上运行,所以它可以动态执行uname等命令来获得构建机的环境,所以我们一般不要指定这个变量,从而让脚本自动获得。
config.sub 这个是将host target build变量正则化的一个脚本,它的sub就是substitute的缩写。因为用户提供的build可能并不符合脚本正规的四元组或者三元组的结构,所以这个脚本将它转换为标准的格式,从而可以进行格式化处理。
config.log 该文件在执行configure文件时动态生成,其中包含了一些行号信息,表示一个文件在哪一行执行,以及执行的什么命令,从而可以知道测试是在哪个位置中完成的。
congfigure.status 这是一个脚本文件,该脚本可以执行,运行该脚本可以生成一个当前相同的配置,从而避免再次执行configure这个比较庞大的代码。也就是config.log生成的是文本文件,而config.status生成的则是命令脚本文件。
config.cache 这个同样是一个动态生成的脚本,用来加快配置速度,如果一个配置选项在之前已经测试过,这个值会保存在这个文件中,当再次执行configure的时候会首先从这个脚本中读取缓存的配置文件,并在输出中显示cached,从而表示是一个缓冲输出
三、主要功能实现
1、config.sub
它主要是将配置环境转换为三元组或者四元组。其核心代码为
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os所有最后两项是 KERNEL-OS类型的配置输出落入该分支。例如powerpc-linux-gnu,其它的执行下面的一个分支。
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
*)
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ $basic_machine != $1 ]
then os=`echo $1 | sed 's/.*-/-/'`最后一个-为OS类型,之前的所有均为机器类型。例如powerpc-linux,powerpc-IBM-linux,
else os=; fi
;;
esac
2、configure中对环境的替换
ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
$as_echo "$ac_cv_build" >&6; }
case $ac_cv_build in
*-*-*) ;;
*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
esac
build=$ac_cv_build
ac_save_IFS=$IFS; IFS='-'
set x $ac_cv_build
shift
build_cpu=$1
build_vendor=$2
shift; shift
# Remember, the first character of IFS is used to create $*,
# except with old shells:
build_os=$*
这些变量一般是底层的Makefile需要替换的变量,并根据这些变量定义一些宏值,或者执行一些特殊配置。
3、cache文件的使用和处理
可以通过命令行中 --cache-file=来进行设置
-cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
cache_file=$ac_optarg ;;
…………
if test -r "$cache_file"; then
# Some versions of bash will fail to source /dev/null (special
# files actually), so we avoid doing that.
if test -f "$cache_file"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
$as_echo "$as_me: loading cache $cache_file" >&6;}
case $cache_file in
[\\/]* | ?:[\\/]* ) . "$cache_file";;
*) . "./$cache_file";; 执行cache文件。
esac
fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
$as_echo "$as_me: creating cache $cache_file" >&6;}
>$cache_file
fi
其中cache文件中变量的值统一以 ac_av_前缀开始,这个约定大家要注意一下,其中分别代表AutoConfigure AutoValue。
4、config.status
从configure可以看出,在该文件的最后,很多的代码都是用来项这个文件添加内容的,所以也就是说这个文件的内容是M4动态生成的,我们知道的作用就好了,该文件通过CONFIG_STATUS 变量进行引用。从使用上看,我们也可以定义同名的宏覆盖这个文件名。
5、config.log的使用
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by $as_me, which was
generated by GNU Autoconf 2.64. Invocation command line was
$ $0 $@
_ACEOF
exec 5>>config.log
直接把文件的第五项文件描述符定向到config.log,从而之后所有项5号文件描述符输出的内容都将会放在config.log文件中。
6、其它使用的一些命令
sed 的 t 命令,这个在configure的最后有使用。根据说明文档,它的作用是前面的一个sed的substitute命令如果成功的话,就跳转到t后面的标 签,这个主要是为了进行递归处理,如果一个变量替换之后还需要替换,那么就可以使用这个命令。它常用在匹配的环境中,例如() @@等。这个可以认为是最为原始的一个条件跳转,configure中使用的是 t t ,其中 t也是一个label的位置。
b 命令这个是一个无条件跳转,一般在一个匹配条件之后或者一个无条件跳转,如果不指定label,则跳转到文件结束。
; 这个是为了支持一行可以有多个sed命令而设置的命令,就像cmd中的&和bash中的;一样。
expr 命令,这 个是Linux下的一个标准命令,它可以进行简单的算数运算,重要的是它还可以进行字符串的匹配运算,这一点是通常的算数表达式不具备的特征。在bash 的源代码中哟一个expr.c,但是注意这个不是一个bash的内置命令,它只是给bash的eval调用的一个工具文件。