本文介绍: nginx源码目录nginx模块化以及功能划分是紧密结合,这也使得我们可以很方便地找到相关功能代码我们先来看一下nginx源码目录结构使用tree命令看一下:主要目录详情如下:Nginx编译流程configure开始:configure脚本将根据我们输入选项系统环境参与来生成所需的文件包含源文件与Makefile文件)。configure调用系列auto脚本实现编译环境初始化auto脚本由一系列脚本组成,他们有一些是实现一些通用功能由其它脚本调用(如have),有一些则

Nginx源码目录结构

nginx源码目录nginx模块化以及功能划分是紧密结合,这也使得我们可以很方便地找到相关功能代码。我们先来看一下nginx源码的目录结构

使用tree命令看一下
在这里插入图片描述

主要目录详情如下

Nginxconfigure原理

Nginx的编译流程从configure开始:configure脚本将根据我们输入的选项、系统环境参与来生成所需的文件包含源文件与Makefile文件)。configure调用一系列auto脚本来实现编译环境的初始化

auto脚本

auto脚本由一系列脚本组成,他们有一些是实现一些通用功能由其它脚本来调用(如have),有一些则是完成一些特定的功能(如option)。

结合configure的代码来分析

. auto/options
. auto/init
. auto/sources

这是configure源码开始执行的前三行,依次交由auto目录下面的optioninitsources处理

再看configure文件

# NGX_DEBUG是在auto/options文件中处理的,如果有--with-debug选项,则其值是YES
if [ $NGX_DEBUG = YES ]; then
    have=NGX_DEBUG . auto/have
fi

可以看出,configure通过have定义NGX_DEBUG :通过定义,输出到config头文件中,然后程序可以判断这个宏是否定义,来实现不同的逻辑。(实际上这段代码表示的就是是否启用debug调试nginx源码

继续configure

# 编译器选项
. auto/cc/conf
# 头文件支持定义
if [ "$NGX_PLATFORM" != win32 ]; then
	. auto/headers
fi
# 操作系统相关的配置的检测
. auto/os/conf
# unix体系下的通用配置检测
if [ "$NGX_PLATFORM" != win32 ]; then
	. auto/unix
fi

依次调用auto中其它几个文件,来进行环境的检测,包括编译器操作系统相关。

  • auto/feature:nginx的configure会自动检测不同平台特性,靠的就是auto/feature的实现。此工具的核心思想是,输出一小段代表性c程序然后设置好编译选项,再进行编译连接运行,再对结果进行分析

    再来看auto/feature的代码

    # 初始化输出结果为no
    ngx_found=no
    
    # 将特性名称小写转换大写
    if test -n "$ngx_feature_name"; then
        ngx_have_feature=`echo $ngx_feature_name 
                       | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
    fi
    
    # 将所有include目录转换成编译选项
    if test -n "$ngx_feature_path"; then
        for ngx_temp in $ngx_feature_path; do
            ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
        done
    fi
    
    # 生成临时的小段c程序代码。
    # $ngx_feature_incs变量是程序需要include的头文件
    # $ngx_feature_test是测试代码
    cat << END > $NGX_AUTOTEST.c
    
    #include <sys/types.h>
    $NGX_INCLUDE_UNISTD_H
    $ngx_feature_incs
    
    int main(void) {
        $ngx_feature_test;
        return 0;
    }
    
    END
    
    # 编译命令
    # 编译之后的目标文件是 $NGX_AUTOTEST,后面会判断这个文件是否存在来判断是否编译成功
    ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path 
              -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs"
    
    ngx_feature_inc_path=
    
    # 执行编译过程
    # 编译成功后,会生成$NGX_AUTOTEST命名的文件
    eval "/bin/sh -c "$ngx_test" >> $NGX_AUTOCONF_ERR 2>&amp;1"
    
    # 如果文件存在,则编译成功
    if [ -x $NGX_AUTOTEST ]; then
    
        case "$ngx_feature_run" in
        
    		# 需要运行来判断是否支持特性
    		# 测试程序能否正常执行(即程序退出后的状态是否是0),如果正常退出,则特性测试成功,设置ngx_found为
            yes)
            	# 如果程序正常退出,退出码为0,则程序执行成功,我们可以在测试代码里面手动返回非0来表示程序出错
                # /bin/sh is used to intercept "Killed" or "Abort trap" messages
                if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&amp;1; then
                    echo " found"
                    ngx_found=yes
    				
    				# 添加宏定义,宏的值为1
                    if test -n "$ngx_feature_name"; then
                        have=$ngx_have_feature . auto/have
                    fi
    
                else
                    echo " found but is not working"
                fi
            ;;
    
    		# 需要运行程序来判断是否支持特性,如果支持,将程序标准输出的结果作为宏的值
            value)
                # /bin/sh is used to intercept "Killed" or "Abort trap" messages
                if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&amp;1; then
                    echo " found"
                    ngx_found=yes
    
    				# 与yes不一样的是,value会将程序从标准输出里面打印出来的值,设置为ngx_feature_name宏变量的值
    				# 在此种情况下,程序需要设置ngx_feature_name变量名
                    cat << END >> $NGX_AUTO_CONFIG_H
    
    #ifndef $ngx_feature_name
    #define $ngx_feature_name  `$NGX_AUTOTEST`
    #endif
    
    END
                else
                    echo " found but is not working"
                fi
            ;;
    
    		# 与yes正好相反
            bug)
                # /bin/sh is used to intercept "Killed" or "Abort trap" messages
                if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&amp;1; then
                    echo " not found"
    
                else
                    echo " found"
                    ngx_found=yes
    
                    if test -n "$ngx_feature_name"; then
                        have=$ngx_have_feature . auto/have
                    fi
                fi
            ;;
    
    		# 不需要运行程序,最后定义宏变量
            *)
                echo " found"
                ngx_found=yes
    
                if test -n "$ngx_feature_name"; then
                    have=$ngx_have_feature . auto/have
                fi
            ;;
    
        esac
    
    else
    	# 编译失败
        echo " not found"
    
    	# 编译失败,会保存信息日志文件中
        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
    fi
    
    # 最后删除生成的临时文件
    rm -rf $NGX_AUTOTEST*
    
  • auto/cc/conf:这一步主要是检测编译器,并设置编译器相关的选项。它先调用auto/cc/name来得到编译器的名称,然后根据编译器选择执行不同的编译器相关的文件如gcc执行auto/cc/gcc来设置编译器相关的一些选项。

  • auto/include:这个工具用来检测是头文件是否支持。需要检测的头文件放在$ngx_include里面,如果支持,则$ngx_found变量的值为yes,并且会产生NGX_HAVE_{ngx_include}的宏定义。

  • auto/headers:生成头文件的宏定义。生成的定义放在objs/ngx_auto_headers.h里面。

    ngx_include="unistd.h";      . auto/include
    ngx_include="inttypes.h";    . auto/include
    ngx_include="limits.h";      . auto/include
    ngx_include="sys/filio.h";   . auto/include
    ngx_include="sys/param.h";   . auto/include
    ngx_include="sys/mount.h";   . auto/include
    ngx_include="sys/statvfs.h"; . auto/include
    ngx_include="crypt.h";       . auto/include
    
  • auto/os/conf:针对不同的操作系统平台特性的检测,并针对不同的操作系统,设置不同的CORE_INCS、CORE_DEPS、CORE_SRCS变量。nginx跨平台的支持就是在这个地方体现出来的。

  • auto/unix针对unix体系的通用配置或系统调用的检测,如poll等事件处理系统调用的检测等。

继续configure

# 生成模块列表
. auto/modules
# 配置库的依赖
. auto/lib/conf

configure接下来定义一些宏常量,主要是是文件路径方面的

case ".$NGX_PREFIX" in
    .)
        NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx}
        have=NGX_PREFIX value=""$NGX_PREFIX/"" . auto/define
    ;;

    .!)
        NGX_PREFIX=
    ;;

    *)
        have=NGX_PREFIX value=""$NGX_PREFIX/"" . auto/define
    ;;
esac

if [ ".$NGX_CONF_PREFIX" != "." ]; then
    have=NGX_CONF_PREFIX value=""$NGX_CONF_PREFIX/"" . auto/define
fi

have=NGX_SBIN_PATH value=""$NGX_SBIN_PATH"" . auto/define
have=NGX_CONF_PATH value=""$NGX_CONF_PATH"" . auto/define
have=NGX_PID_PATH value=""$NGX_PID_PATH"" . auto/define
have=NGX_LOCK_PATH value=""$NGX_LOCK_PATH"" . auto/define
have=NGX_ERROR_LOG_PATH value=""$NGX_ERROR_LOG_PATH"" . auto/define

if [ ".$NGX_ERROR_LOG_PATH" = "." ]; then
    have=NGX_ERROR_LOG_STDERR . auto/have
fi

have=NGX_HTTP_LOG_PATH value=""$NGX_HTTP_LOG_PATH"" . auto/define
have=NGX_HTTP_CLIENT_TEMP_PATH value=""$NGX_HTTP_CLIENT_TEMP_PATH""
. auto/define
have=NGX_HTTP_PROXY_TEMP_PATH value=""$NGX_HTTP_PROXY_TEMP_PATH""
. auto/define
have=NGX_HTTP_FASTCGI_TEMP_PATH value=""$NGX_HTTP_FASTCGI_TEMP_PATH""
. auto/define
have=NGX_HTTP_UWSGI_TEMP_PATH value=""$NGX_HTTP_UWSGI_TEMP_PATH""
. auto/define
have=NGX_HTTP_SCGI_TEMP_PATH value=""$NGX_HTTP_SCGI_TEMP_PATH""
. auto/define

configure最后工作就是生成Makefile文件

# 生成objs/makefile文件
. auto/make

# 生成关于库的编译选项到makefile文件
. auto/lib/make

# 生成与安装相关的makefile文件内容,并生成最外层的makefile文件
. auto/install

# STUB
. auto/stubs

have=NGX_USER value=""$NGX_USER"" . auto/define
have=NGX_GROUP value=""$NGX_GROUP"" . auto/define

if [ ".$NGX_BUILD" != "." ]; then
    have=NGX_BUILD value=""$NGX_BUILD"" . auto/define
fi

# 编译的最后阶段汇总信息
. auto/summary

模块编译顺序

nginx模块的顺序很重要,会直接影响到程序的功能。而且,nginx和部分模块,也有着自己特定的顺序要求,比如ngx_http_write_filter_module模块一定要在filter模块的最后一步执行。想查看模块的执行顺序,可以objs/ngx_modules.c这个文件中找到,这个文件在configure之后生成。

objs/ngx_modules.c文件示例

ngx_module_t *ngx_modules[] = {
	// 全局core模块
	&amp;ngx_core_module,
	&amp;ngx_errlog_module,
	&amp;ngx_conf_module,
	&amp;ngx_emp_server_module,
	&ngx_emp_server_core_module,
	// event模块
	&ngx_events_module,
	&ngx_event_core_module,
	&ngx_kqueue_module,
	// 正则模块
	&ngx_regex_module,
	// http模块
	&ngx_http_module,
	&ngx_http_core_module,
	&ngx_http_log_module
	&ngx_http_upstream_module,
	// http handler模块
	&ngx_http_static_module,
	&ngx_http_autoindex_module,
	&ngx_http_index_module,
	&ngx_http_auth_basic_module,
	&ngx_http_access_module,
	&ngx_http_limit_conn_module,
	&ngx_http_limit_req_module,
	&ngx_http_geo_module,
	&ngx_http_map_module,
	&ngx_http_split_clients_module,
	&ngx_http_referer_module,
	&ngx_http_rewrite_module,
	&ngx_http_proxy_module,
	&ngx_http_fastcgi_module,
	&ngx_http_uwsgi_module,
	&ngx_http_scgi_module,
	&ngx_http_memcached_module,
	&ngx_http_empty_gif_module,
	&ngx_http_browser_module,
	&ngx_http_upstream_ip_hash_module,
	&ngx_http_upstream_keepalive_module,
	//此处是第三方handler模块
	
	// http filter模块
	&ngx_http_write_filter_module,
	&ngx_http_header_filter_module,
	&ngx_http_chunked_filter_module,
	&ngx_http_range_header_filter_module,
	&ngx_http_gzip_filter_module,
	&ngx_http_postpone_filter_module,
	&ngx_http_ssi_filter_module,
	&ngx_http_charset_filter_module,
	&ngx_http_userid_filter_module,
	&ngx_http_headers_filter_module,
	// 第三方filter模块
	&ngx_http_copy_filter_module,
	&ngx_http_range_body_filter_module,
	&ngx_http_not_modified_filter_module,
	NULL
}

http handler模块与http filter模块的顺序很重要,我们主要关注一下这两类模块。

  • http handler模块
    对于content phase之前的handler,同一个阶段的handler,模块是顺序执行的。
    比如上面的示例代码中,ngx_http_auth_basic_module与ngx_http_access_module这两个模块都是在access phase阶段,由于ngx_http_auth_basic_module在前面,所以会先执行。
    由于content phase只会有一个执行,所以不存在顺序问题。另外,我们加载的第三方handler模块永远是在最后执行。

  • http filter模块
    filter模块会将所有的filter handler排成一个倒序链,所以在最前面最后执行。
    上面的例子中,ngx_http_write_filter_module最后执行,ngx_http_not_modified_filter_module最先执行。

    注意:我们加载的第三方filter模块是在copy_filter模块之后,headers_filter模块之前执行。


结束

原文地址:https://blog.csdn.net/Stars____/article/details/129874565

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_16119.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注