Py学习  »  NGINX

手把手学习nginx源码--auto/feature脚本

郑尔多斯 • 4 年前 • 391 次点击  
阅读 44

手把手学习nginx源码--auto/feature脚本

微信公众号:Nginx源码分析
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!

回顾

来,看下图:

辅助脚本
辅助脚本

图中还剩下auto/featureauto/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_pathdo
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_pathdo
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 == -1return 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源码分析,更多精彩内容第一时间送达
Nginx源码分析
Nginx源码分析
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/36382
 
391 次点击