Nginx开发HTTP模块(二):如何将自己的HTTP模块编译进Nginx

如何将自己的HTTP模块编译进Nginx

Nginx提供了一种简单的方式将第三方的模块编译进Nginx中:

  • 首先把源代码文件全部放到一个目录下
  • 同时在该目录中编写一个文件用于通知Nginx如何编译本模块,这个文件名必须为config
  • 只要在configure脚本执行时加入参数–add-module=PATH(PATH就是上面我们给定的源代码、config文件的保存目录),就可以在执行正常编译安装流程时完成Nginx编译工作
  • 执行完configure脚本后Nginx会生成objs/Makefile和objs/ngx_modules.c文件,完全可以自己去修改这两个文件

config文件的写法

config文件其实是一个可执行的Shell脚本。如果只想开发一个HTTP模块,那么config文件中需要定义以下3各变量:

  • ngx_addon_name:尽在configure执行时使用,一般设置为模块名称。
  • HTTP_MODULES:保存所有的HTTP模块名称,每个HTTP模块间由空格符相连。在重新设置HTTP_MODULES变量时,不要直接覆盖它,因为configure调用到自定义的config脚本前,已经将各个HTTP模块设置到HTTP_MODULES变量中,要像如下这样设置:
	"$HTTP_MODULES nginx_http_mytest_module"
  • NGX_ADDON_SRCS:用于指定新增模块的源代码,多个待编译的源代码间以空格符项链。注意,在设置NGX_ADDON_SRCS时可以使用$ngx_addon_dir变量,它等价于configure执行时–add-module=PATH的PATH参数。

因此,对于mytest模块,可以这样编写config文件:

ngx_addon_name=ngx_http_mytest_module
HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"

补充:可以在config文件中自定义的部分:

  • $NGX_ADDON_SRCS:指定新增模块的源代码
  • $HTTP_FILTER_MODULES:Nginx的过滤模块
  • $CORE_MODULES:Nginx的核心模块
  • $EVENT_MODULES:Nginx的事件模块
  • $HTTP_MODULES:Nginx的HTTP模块
  • $HTTP_HEADERS_FILTER_MODULES:HTTP头部过滤模块
  • $NGX_ADDON_DEPS:指定了模块依赖的路径

利用configure脚本将定制的模块加入到Nginx中

下面完整地解释以下configure脚本是如何与config文件配合把定制的第三方模块加入到Nginx中的。

  • 在执行configure --add-module=PATH命令时,PATH就是第三方模块所在的路径。在configure中,通过auto/options脚本设置了NGX_ADDONS变量
    --add-module=*)		NGX_ADDONS="$NGX_ADDONS $value" ;;
    
  • 在configure命令执行到auto/modules脚本时,将在生成的ngx_module.c文件中加入定制的第三方模块。
    if test -n "$NGX_ADDONS"; then
    	echo configuring additional modules
    	for ngx_addon_dir in $NGX_ADDONS
    	do
    		echo "adding module in $ngx_addon_dir"
    		
    		ngx_module_type=
        	ngx_module_name=
        	ngx_module_incs=
        	ngx_module_deps=
        	ngx_module_srcs=
        	ngx_module_libs=
        	ngx_module_order=
        	ngx_module_link=ADDON
    		
    		if test -f "ngx_addon_dir/config; then
    			# 在这里执行自定义的config脚本
    			. $ngx_addon_dir/config
    			echo " + $ngx_addon_name was configured"
    		else
    			echo "$0: error: no $ngx_addon_dir/config was found"
    			exit 1
    		fi
    	done
    fi
    
    $NGX_ADDONS可以包含多个目录,对于每个目录,如果其中存在config文件就会执行。之后,auto/modules脚本开始创建ngx_modules.c文件,这个文件的关键点就是定义了ngx_module_t *ngx_modules[] ngx_modules数组,确定该用哪一个模块来处理。
  • 下面来看一下auto/modules是如何生成数组的:
    modules="$CORE_MODULES $EVENT_MODULES"
    if [ $USE_OPENSSL = YES ]; then
    	modules="$modules $OPENSSL_MODULE"
    	CORE_DEPS="$CORE_DEPS $OPENSSL_DEPS"
    	CORE_SRCS="$CODE_SRCS $OPENSSL_SRCS"
    fi
    
    if [ $HTTP = YES ]; then
    	modules="$modules $HTTP_MODULES $HTTP_FILTER_MODULES \
    			 $HTTP_HEADERS_FILTER_MODULE \
    			 $HTTP_AUX_FILTER_MODULES \
    			 $HTTP_COPY_FILTER_MODULE \
    			 $HTTP_RANGE_BODY_FILTER_MODULE \
    			 $HTTP_NOT_MODIFIED_FILTER_MODULE"
    	NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(HTTP_DEPS)"
    fi
    
    首先,auto/modules会按顺序生成modules变量。注意,这里的$HTTP_MODULES等已经在config文件中重定义了。这时,modules变量是包含所有模块的。然后开始生成ngx_modules.c文件:
    cat << END								> $NGX_MODULES_C
    #include <ngx_config.h>
    #include <ngx_core.h>
    
    $NGX_PRAGMA
    END
    for mod in $modules
    do
    echo "extern ngx_module_t $mod;"		>>  $NGX_MODULES_C
    done
    
    echo									>> $NGX_MODULES_C
    echo 'ngx_module_t *ngx_modules[] = {'	>> $NGX_MODULES_C
    
    for mod in $modules
    do
    	# 向ngx_modules数组里添加Nginx模块
    	echo "	&$mod,"						>> $NGX_MODULES_C
    done
    
    cat << END								>> $NGX_MODULES_C
    	NULL
    }
    

这样就已经确定了Nginx在运行时会调用自定义的模块,而auto/make脚本负责把相关模块编译进Nginx。

  • 在Makefile中生成编译第三方模块的源代码(auto/make)如下:
if test -n "$NGX_ADDON_SRCS"; then

    ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"

    for ngx_src in $NGX_ADDON_SRCS
    do
        ngx_obj="addon/`basename \`dirname $ngx_src\``"

        ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \
            | sed -e "s/\//$ngx_regex_dirsep/g"`

        ngx_obj=`echo $ngx_obj \
            | sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
                  -e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
                  -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
                  -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`

        ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`

        cat << END                                            >> $NGX_MAKEFILE

$ngx_obj:   \$(ADDON_DEPS)$ngx_cont$ngx_src
    $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX

END
    done

fi

下面这段代码用于将各个模块的目标文件设置导ngx_obj变量中,紧接着会生成Makefile里的链接代码,并将所有的目标文件、库文件链接成二进制程序。

for ngx_src in $NGX_ADDON_SRCS
do
    ngx_obj="addon/`basename \`dirname $ngx_src\``"

    test -d $NGX_OBJS/$ngx_obj || mkdir -p $NGX_OBJS/$ngx_obj

    ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \
        | sed -e "s/\//$ngx_regex_dirsep/g"`

    ngx_all_srcs="$ngx_all_srcs $ngx_obj"
done

...

cat << END                                                    >> $NGX_MAKEFILE

build:  binary modules manpage

binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext

$NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer
    \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_binext$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
    $ngx_rcc
$ngx_long_end

modules:
END

第三方模块就是这样嵌入导Nginx程序中的。

另外一种方法——直接修改Makefile文件(不推荐):

有时我们需要重新决定ngx_module_t *ngx_modules[]数组中各个模块的顺序,或者在编译源代码时需要加入一些独特的编译选项,那么可以在执行完configure后,对生成的objs/ngx_modules.c和objs/Makefile文件直接进行修改。

  • 修改objs/ngx_modules.c:

    • 首先要添加新增的第三方模块的声明:
      extern ngx_module_t ngx_http_mytest_module;
      
    • 其次,在合适的地方将模块加入到ngx_modules数组中。
      ngx_module_t *ngx_modules[] = {
      	...
      	&ngx_http_upstream_ip_hash_module,
      	&ngx_http_mytest_module,
      	&ngx_http_write_filter_module,
      	...
      }
      
      注意:模块的顺序很重要,如果同时又两个模块表示对同一个请求感兴趣,那么只有顺序在前的模块会被调用。
  • 修改objs/Makefile时需要增加编译源代码的部分,例如:

    objs/addon/httpmodule/ngx_http_mytest_module.o:  $(ADDON_DEPS) \
    ../sample/http_modules//ngx_http_mytest_module.c $(CC) -c $(CFLAGS) $(ALL_INCS) \
        -o objs/addon/http/httpmodule/ngx_http_mytest_module.o \
        ../sample/httpmodule//ngx_http_mytest_module.c
    
  • 还需要把目标文件链接到Nginx中:

    objs/nginx: objs/src/core/nginx.o \
    ...
    objs/addon/ngx-http-concat/ngx_http_concat_module.o \
    objs/ngx_modules.o
    
    $(LINK) -o objs/nginx \
    objs/src/core/nginx.o \
    ...
    objs/addon/ngx-http-concat/ngx_http_concat_module.o \
    objs/ngx_modules.o \
    -ldl -lpthread -lcrypt -lpcre -lssl -lcrypto -ldl -lpthread -lz \
    

    注意:请慎用这种直接修改Makefile和ngx_modules.c的方法,不正确的修改可能导致Nginx工作不正常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值