微信公众号:Nginx源码分析
关注可了解更多的Nginx
知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!
回顾
来,看下图:
图中还剩下
auto/feature
和auto/include
脚本没有分析,其他的几个辅助脚本已经分析完了。那么本文就详细分析一下一个非常非常重要的脚本,
auto/feature
.
写在分析之前
为什么说auto/feature
脚本非常重要呢?
因为该脚本对于不同的宿主系统,可以测试当前的宿主系统是否支持某个特性。nginx
会根据测试结果选用不同的实现方式。
比如auto/feature
可以测试当前系统是否支持epoll
,如果支持,nginx
就使用这种高效率的io
多路复用机制。如果不支持,那么就可能选用select
或者poll
机制等。总之,无论如何,总会让你的机器能够成功的运行nginx
.
auto/feature 脚本
测试宿主系统是否支持某个特性。
输入参数
ngx_feature
: 要测试的特性名称,该参数主要用于向终端和NGX_AUTOCONF_ERR
文件中输出日志,便于后面的分析。
ngx_feature_name
: define
的变量名
ngx_feature_run
: 表示对编译之后文件的处理方式
ngx_feature_incs
:包含c
源文件所需的头文件。下面的ngx_feature_path
参数是这些头文件所在的目录
ngx_feature_path
:包含了编译程序时设置的头文件目录
ngx_feature_libs
:编译源文件时依赖的库文件
ngx_feature_test
:测试当前特性时要执行的代码
输出参数
ngx_found
: 表示是否拥有该特性,如果为yes
表示有该特性。
若为no
,表示没有该特性。
功能
测试是否支持某个特性。
示例
我们以测试epoll
特性的代码为例来说明auto/feature
的用法。
1# epoll, EPOLLET version
2
3ngx_feature="epoll"
4ngx_feature_name="NGX_HAVE_EPOLL"
5ngx_feature_run=yes
6ngx_feature_incs="#include <sys/epoll.h>"
7ngx_feature_path=
8ngx_feature_libs=
9ngx_feature_test="int efd = 0, fd = 1, n;
10 struct epoll_event ee;
11 ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
12 ee.data.ptr = NULL;
13 efd = epoll_create(100);
14 if (efd == -1) return 1;"
15. auto/feature
16
17if [ $ngx_found = yes ]; then
18 have=NGX_HAVE_CLEAR_EVENT . auto/have
19 CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
20 EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
21 EVENT_FOUND=YES
22fi
复制代码
脚本内容
1echo $ngx_n "checking for $ngx_feature ...$ngx_c"
2
3cat << END >> $NGX_AUTOCONF_ERR
4
5----------------------------------------
6checking for $ngx_feature
7
8END
9
10ngx_found=no
11
12if test -n "$ngx_feature_name"; then
13 ngx_have_feature=`echo $ngx_feature_name \
14 | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
15fi
16
17if test -n "$ngx_feature_path"; then
18 for ngx_temp in $ngx_feature_path; do
19 ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
20 done
21fi
22
23cat << END > $NGX_AUTOTEST.c
24
25#include <sys/types.h>
26$NGX_INCLUDE_UNISTD_H
27$ngx_feature_incs
28
29int main() {
30 $ngx_feature_test;
31 return 0;
32}
33
34END
35
36
37ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \
38 -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs"
39
40ngx_feature_inc_path=
41
42eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1"
43
44
45if [ -x $NGX_AUTOTEST ]; then
46
47 case "$ngx_feature_run" in
48
49 yes)
50 # /bin/sh is used to intercept "Killed" or "Abort trap" messages
51 if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
52 echo " found"
53 ngx_found=yes
54
55 if test -n "$ngx_feature_name"; then
56 have=$ngx_have_feature . auto/have
57 fi
58
59 else
60 echo " found but is not working"
61 fi
62 ;;
63
64 value)
65 # /bin/sh is used to intercept "Killed" or "Abort trap" messages
66 if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
67 echo " found"
68 ngx_found=yes
69
70 cat << END >> $NGX_AUTO_CONFIG_H
71
72#ifndef $ngx_feature_name
73#define $ngx_feature_name `$NGX_AUTOTEST`
74#endif
75
76END
77 else
78 echo " found but is not working"
79 fi
80 ;;
81
82 bug)
83 # /bin/sh is used to intercept "Killed" or "Abort trap" messages
84 if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
85 echo " not found"
86
87 else
88 echo
" found"
89 ngx_found=yes
90
91 if test -n "$ngx_feature_name"; then
92 have=$ngx_have_feature . auto/have
93 fi
94 fi
95 ;;
96
97 *)
98 echo " found"
99 ngx_found=yes
100
101 if test -n "$ngx_feature_name"; then
102 have=$ngx_have_feature . auto/have
103 fi
104 ;;
105
106 esac
107
108else
109 echo
" not found"
110
111 echo "----------" >> $NGX_AUTOCONF_ERR
112 cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR
113 echo "----------" >> $NGX_AUTOCONF_ERR
114 echo $ngx_test >> $NGX_AUTOCONF_ERR
115 echo "----------" >> $NGX_AUTOCONF_ERR
116fi
117
118rm $NGX_AUTOTEST*
复制代码
脚本分析
我们以示例中测试epoll
特性的代码分析这个脚本。
1).
向终端和NGX_AUTOCONF_ERR
中输出测试信息
1echo $ngx_n "checking for $ngx_feature ...$ngx_c"
2
3cat << END >> $NGX_AUTOCONF_ERR
4
5----------------------------------------
6checking for $ngx_feature
7
8END
复制代码
我们之前分析的几乎所有脚本文件的第一步都是这个功能。主要是方便查找错误使用。
2).
初始化一些变量
1ngx_found=no
2
3if test -n "$ngx_feature_name"; then
4 ngx_have_feature=`echo $ngx_feature_name \
5 | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
6fi
复制代码
上面首先初始化一个ngx_found
,这个变量表示的是当前测试的特性是否存在。
接着,根据传进来的ngx_feature_name
参数生成一个ngx_have_feature
变量。
生成规则:把ngx_feature_name
的小写字母全部换成大写字母。所以对于这个示例来说,最终的ngx_have_feature
的值为NGX_HAVE_EPOLL
。
3).
设置头文件目录
1if test -n "$ngx_feature_path"; then
2
for ngx_temp in $ngx_feature_path; do
3 ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
4 done
复制代码
根据传进来的入参ngx_feature_path
设置编译测试程序所需要的头文件。生成结果保存到ngx_feature_inc_path
变量中。
4).
生成自动测试程序
根据传进来的ngx_feature_test
参数生成一个测试特性的c
源文件。
1cat << END > $NGX_AUTOTEST.c
2
3#include <sys/types.h>
4$NGX_INCLUDE_UNISTD_H
5$ngx_feature_incs
6
7int main() {
8 $ngx_feature_test;
9 return 0;
10}
11
12END
复制代码
本例生成的c
源文件代码如下:
1#include <sys/types.h>
2#include <unistd.h>
3#include <sys/epoll.h>
4
5int main() {
6 int efd = 0, fd = 1, n;
7 struct epoll_event ee;
8 ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
9 ee.data.ptr = NULL;
10 efd = epoll_create(100);
11 if (efd == -1) return 1;;
12 return 0;
13}
复制代码
这个c
源文件也是一个很简单的代码。
5).
编译自动测试程序
1ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \
2 -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs"
3
4ngx_feature_inc_path=
5
6eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1"
复制代码
上面的编译指令ngx_test
的值如下:
1gcc -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -o objs/autotest objs/autotest.c
复制代码
编译之后生成的目标文件是objs/autotest
文件。
6).
执行自动测试程序
我们先看一下如果没有编译成功的话,会执行什么东东。
1echo " not found"
2
3 echo "----------" >> $NGX_AUTOCONF_ERR
4 cat $NGX_AUTOTEST
.c >> $NGX_AUTOCONF_ERR
5 echo "----------" >> $NGX_AUTOCONF_ERR
6 echo $ngx_test >> $NGX_AUTOCONF_ERR
7 echo "----------" >> $NGX_AUTOCONF_ERR
复制代码
其实这也是nginx
惯用的手法,就是把这些测试信息保存到NGX_AUTOCONF_ERR
错误日志文件中,便于查找错误原因。
7).
如果编译成功了该咋办呢?
这部分代码也是比较长,我们分别讨论。
根据ngx_feature_run
的值,可以分为如下几部分:
①.ngx_feature_run
的值为yes
:
1yes)
2 if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
3 echo " found"
4 ngx_found=yes
5
6 if test -n "$ngx_feature_name"; then
7 have=$ngx_have_feature . auto/have
8
fi
9
10 else
11 echo " found but is not working"
12 fi
13 ;;
复制代码
如果执行成功的话,会把ngx_found
设置为yes
。这个变量在后面会用到。
然后调用auto/have
脚本在NGX_AUTO_CONFIG_H
文件中增加一个宏定义。
②.ngx_feature_run
的值为value
:
在这种情况下,编译只有的源文件执行结果是一个数值。最终生成一个宏定义代表该数值。
1value)
2 # /bin/sh is used to intercept "Killed" or "Abort trap" messages
3 if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
4 echo " found"
5 ngx_found=yes
6
7 cat << END >> $NGX_AUTO_CONFIG_H
8
9#ifndef $ngx_feature_name
10#define $ngx_feature_name `$NGX_AUTOTEST`
11#endif
12
13END
14 else
15 echo " found but is not working"
16 fi
17 ;;
复制代码
这种情况是计算一个结果,然后把结果通过宏的方式添加到NGX_AUTO_CONFIG_H
文件中。
③.ngx_feature_run
的值为bug
.
1 bug)
2 # /bin/sh is used to intercept "Killed" or "Abort trap" messages
3 if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
4 echo " not found"
5
6 else
7 echo " found"
8 ngx_found=yes
9
10 if test -n "$ngx_feature_name"; then
11
have=$ngx_have_feature . auto/have
12 fi
13 fi
14 ;;
复制代码
这种情况的处理方式和yes
的处理方式刚好相反。
④.ngx_feature_run
为其他值。
1*)
2 echo " found"
3 ngx_found=yes
4
5 if test -n "$ngx_feature_name"; then
6 have=$ngx_have_feature . auto/have
7 fi
8 ;;
复制代码
只是简单的增加一个宏定义。
8).
删除临时文件
1rm $NGX_AUTOTEST*
复制代码
9).
脚本执行完之后的工作
我们上面已经写到了,auto/feature
输出了一个参数ngx_found
,这个参数表示当前宿主系统是否含有此特性。
我们看一下当测试完epoll
之后的处理。
1if [ $ngx_found = yes ]; then
2 have=NGX_HAVE_CLEAR_EVENT . auto/have
3 CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
4 EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
5 EVENT_FOUND=YES
6fi
复制代码
这里就是一些特殊的处理,当宿主系统包含该特性之后的一些后续逻辑。
调试方法
由于在脚本中很多地方都调用了auto/feature
脚本,如果我们想调试的话,不是特别方便,可以通过在源代码中添加下面的代码进行调试:
1 if test -n "$ngx_feature_name" ;then
2 # 这里的NGX_SYS_NERR是我们想要调试的特性
3 #我们可以在里层的if语句中完整各种功能进行调试
4 if [ "$ngx_feature_name" = "NGX_SYS_NERR" ];then
5 cat $NGX_AUTOTEST.c;
6 echo `$NGX_AUTOTEST`;
7 fi
8fi
复制代码
总结
我们详细的分析了auto/feature
脚本的功能。这个脚本的作用就是测试在当前的宿主系统上面是否支持某个特性。
后面的文章我们会接着分析nginx
的源码,敬请期待。顺便关注我的个公众号(Nginx源码分析
)。
喜欢本文的朋友们,欢迎长按下图关注订阅号Nginx源码分析,更多精彩内容第一时间送达