微信公众号:Nginx源码分析
关注可了解更多的Nginx
知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!
回顾
我们在上一篇文章中详细的分析了auto/types/sizeof
脚本源码,本文我们继续分析auto/types
目录下的脚本文件。我们首先回顾一下nginx
中的大致辅助脚本图片,如下图:
本文讲述一下
auto/types/typedef
脚本,
auto/types/typedef脚本
Nginx
的脚本名称以及变量名称都是非常的直截了当,我们完全可以见名知意,这是我们在写代码的时候要学习借鉴的地方。从这个脚本的名称中我们即可以看到,它的作用就是生成typedef
声明的。
auto/types/sizeof脚本
参数
ngx_type
:类型1
ngx_types
:类型2
功能
判断ngx_type
和ngx_types
是否存在,根据判断条件生成相应的typedef
语句。
示例
我们这次先看一下脚本使用的示例,从而全面了解一下这个脚本。
在auto/unix
脚本中,调用了auto/types/typedef
脚本,如下:
ngx_type="uint64_t"; ngx_types="u_int64_t"; . auto/types/typedef
脚本内容
echo $ngx_n "checking for $ngx_type ...$ngx_c"
cat << END >> $NGX_AUTOCONF_ERR
----------------------------------------
checking for $ngx_type
END
ngx_found=no
for ngx_try in $ngx_type $ngx_types
do
cat << END > $NGX_AUTOTEST.c
#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netinet/in.h>
$NGX_INCLUDE_INTTYPES_H
int main() {
$ngx_try i = 0;
return 0;
}
END
ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
-o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
if [ -x $NGX_AUTOTEST ]; then
if [ $ngx_try = $ngx_type ]; then
echo " found"
ngx_found=yes
else
echo ", $ngx_try used"
ngx_found=$ngx_try
fi
fi
rm -f $NGX_AUTOTEST
if [ $ngx_found = no ]; then
echo $ngx_n " $ngx_try not found$ngx_c"
echo "----------" >> $NGX_AUTOCONF_ERR
cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR
echo "----------" >> $NGX_AUTOCONF_ERR
echo $ngx_test >> $NGX_AUTOCONF_ERR
echo "----------" >> $NGX_AUTOCONF_ERR
else
break
fi
done
if [ $ngx_found = no ]; then
echo
echo "$0: error: can not define $ngx_type"
exit 1
fi
if [ $ngx_found != yes ]; then
echo "typedef $ngx_found $ngx_type;" >> $NGX_AUTO_CONFIG_H
fi
脚本分析
我们按照示例的调用例子进行脚本分析。
1).
首先是向控制台输出信息
我们在前面的文章中分析过ngx_c
变量,这里不再赘述。
echo $ngx_n "checking for $ngx_type ...$ngx_c"
我们在终端上可以看到如下内容:
checking for uint64_t ...
2).
向NGX_AUTOCONF_ERR
中生成内容。
cat << END >> $NGX_AUTOCONF_ERR
----------------------------------------
checking for $ngx_type
END
END
所以,实际上向NGX_AUTOCONF_ERR
中写入的内容是:
checking for uint64_t
从前面的文章到现在,我们可以看出来,Nginx
的每一步都有完善的日志,这对于监控程序的执行流程以及分析错误原因是非常有帮助的。
3).
生成测试程序
ngx_found=no
这里首先将ngx_found
的内容赋值为no
,这个变量在后面用来表示是否存在我们要检测的数据类型。
接着,auto/types/typedef
脚本通过一个for
循环遍历传进来的ngx_type
和ngx_types
,每次循环处理过程都是一样。我们分析一下这个for
循环。
对于每次循环,都会根据当前遍历到的变量生成一份测试用的c
源码,如下:
cat << END > $NGX_AUTOTEST.c
#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netinet/in.h>
$NGX_INCLUDE_INTTYPES_H
int main() {
$ngx_try i = 0;
return 0;
}
END
实际对于我们示例的情况,第一次循环生成的代码如下:
#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <inttypes.h>
int main() {
uint64_t i = 0;
return 0;
}
这个源文件真的是很简单,main
函数中只有一行实际的代码。这行代码的作用很简单:如果uint64_i
这个类型存在的话,那么这个源文件肯定能编译成功,并且最终生成可以执行的目标文件。我们可以通过检测最终的目标文件是否可以被执行来间接的判断uint64_t
类型是否存在。
4).
编译上面生成的源文件
ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
-o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
上面的ngx_test
就是一个编译语句,具体内容如下:
gcc -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -o objs/autotest objs/autotest.c
紧接着的eval
语句会执行ngx_test
的内容,也就是执行编译语句,生成可以执行文件objs/autotest
。
5).
执行可执行程序
if [ -x $NGX_AUTOTEST ]; then
if [ $ngx_try = $ngx_type ]; then
# $ngx_type是传给for循环的第一个循环参数。所以如果能够执行到这里,则说明第一个参数$ngx_type代表的类型存在
echo " found"
ngx_found=yes
else
# 如果执行到这里,那么说明$ngx_type代表的变量类型不存在,但是$ngx_types代表的变量类型存在, 这个时候 ngx_found就会被赋值为$ngx_types类型
echo ", $ngx_try used"
ngx_found=$ngx_try
fi
fi
nginx
判断如果第4
步生成的目标文件是是可执行文件-x $NGX_AUTOTEST
,那么执行该目标文件.
这段代码的详细分析我已经在代码里面进行了注释。
6).
删除目标文件
rm -f $NGX_AUTOTEST
Nginx
会在运行完可执行文件之后就将该文件删除,所以实际上我们在Nginx
的目录中是不能看到这些文件的,它们都是临时文件。
7).
根据上面的执行结果进行错误输出
if [ $ngx_found = no ]; then
echo $ngx_n " $ngx_try not found$ngx_c"
echo "----------" >> $NGX_AUTOCONF_ERR
cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR
echo "----------" >> $NGX_AUTOCONF_ERR
echo $ngx_test >> $NGX_AUTOCONF_ERR
echo "----------" >> $NGX_AUTOCONF_ERR
else
# 如果当前的数据类型存在,那么就break,不再进行下面的for循环
break
fi
如果当前遍历的变量类型并不存在,会进行日志输出。
首先,在控制台上面输出unit64_t not found
(我们假设当前检测的uint64_t
类型不存在)。
然后,把生成的检测数据类型的c
源文件以及便一直令保存到NGX_AUTOCONF_ERR
文件中,便于进行错误分析。
8).
循环结束后的处理
这里要分三种种情况,如下:
① ``ngx_type
和ngx_types
都不存在。那么执行下面的脚本:
if [ $ngx_found = no ]; then
echo
echo "$0: error: can not define $ngx_type"
exit 1
fi
这部分脚本会向控制台输出一行错误信息,告诉nginx
不能使用当前的变量类型,然后结束脚本。
②
ngx_type
存在。如果是这种情况的话,ngx_found
的值是yes
,这样的话,auto/types/typedef
脚本就直接结束了。
③ ngx_type
类型不存在,但是ngx_types
存在。这个时候ngx_found
的值是ngx_types
的值。所以会执行下面的脚本:
if [ $ngx_found != yes ]; then
echo "typedef $ngx_found $ngx_type;" >> $
fi
也就是向NGX_AUTO_CONFIG_H
头文件中生成一个typedef
语句。如下:
typedef $ngx_types $ngx_type;
也即是把ngx_type
作为$ngx_types
的别名,这样程序中就可以一直使用ngx_type
这种类型。
对于本例来说,假设满足第③
种条件的话,就会生成一个如下的typedef
语句:
typedef u_int64_t uint64_t;
到此为止,我们已经分析完了auto/types/typedef
脚本。
总结
本文详细的分析了auto/types/sizeof
脚本的功能:测试一个c
语言数据类型在特定操作系统上的长度,根据长度进行不同的操作。
其实我们通过这几篇文章可以发现一个东东,Nginx
的许多脚本都是自动生成的,说实话,我以前看的源码比较少,也没有关注过这种大型工程的配置文件,真的是一种非常巧妙的方法,我们可以多多借鉴。
后面的文章我们会接着分析nginx
的其他辅助脚本,敬请期待。顺便关注我的个公众号(Nginx源码分析
)。