changeset 6383:85dea406e18f

Dynamic modules. The auto/module script is extended to understand ngx_module_link=DYNAMIC. When set, it links the module as a shared object rather than statically into nginx binary. The module can later be loaded using the "load_module" directive. New auto/module parameter ngx_module_order allows to define module loading order in complex cases. By default the order is set based on ngx_module_type. 3rd party modules can be compiled dynamically using the --add-dynamic-module configure option, which will preset ngx_module_link to "DYNAMIC" before calling the module config script. Win32 support is rudimentary, and only works when using MinGW gcc (which is able to handle exports/imports automatically). In collaboration with Ruslan Ermilov.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 04 Feb 2016 20:25:29 +0300
parents 392959224560
children e0d7c2f71851
files auto/cc/conf auto/cc/msvc auto/cc/sunc auto/init auto/install auto/lib/conf auto/lib/geoip/conf auto/lib/libgd/conf auto/lib/libxslt/conf auto/make auto/module auto/modules auto/options auto/os/darwin auto/os/win32 auto/summary src/core/nginx.c src/core/ngx_cycle.c src/core/ngx_cycle.h src/core/ngx_module.c src/core/ngx_module.h
diffstat 21 files changed, 1136 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/auto/cc/conf
+++ b/auto/cc/conf
@@ -5,12 +5,17 @@
 
 LINK="\$(CC)"
 
+MAIN_LINK=
+MODULE_LINK="-shared"
+
 ngx_include_opt="-I "
 ngx_compile_opt="-c"
+ngx_pic_opt="-fPIC"
 ngx_objout="-o "
 ngx_binout="-o "
 ngx_objext="o"
 ngx_binext=
+ngx_modext=".so"
 
 ngx_long_start=
 ngx_long_end=
@@ -45,6 +50,9 @@ if test -n "$CFLAGS"; then
 
         sunc)
 
+            MAIN_LINK=
+            MODULE_LINK="-G"
+
             case "$NGX_MACHINE" in
 
                 i86pc)
@@ -156,6 +164,20 @@ if [ "$NGX_PLATFORM" != win32 ]; then
     fi
 
 
+    ngx_feature="-Wl,-E switch"
+    ngx_feature_name=
+    ngx_feature_run=no
+    ngx_feature_incs=
+    ngx_feature_path=
+    ngx_feature_libs=-Wl,-E
+    ngx_feature_test=
+    . auto/feature
+
+    if [ $ngx_found = yes ]; then
+        MAIN_LINK="-Wl,-E"
+    fi
+
+
     ngx_feature="gcc builtin atomic operations"
     ngx_feature_name=NGX_HAVE_GCC_ATOMIC
     ngx_feature_run=yes
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -118,6 +118,12 @@ NGX_RCC="rc -fo$NGX_RES \$(CORE_INCS) $N
 CORE_LINK="$NGX_RES $CORE_LINK"
 
 
+# dynamic modules
+#MAIN_LINK="-link -def:$NGX_OBJS/nginx.def"
+#MODULE_LINK="-LD $NGX_OBJS/nginx.lib"
+
+
+ngx_pic_opt=
 ngx_objout="-Fo"
 ngx_binout="-Fe"
 ngx_objext="obj"
--- a/auto/cc/sunc
+++ b/auto/cc/sunc
@@ -57,6 +57,9 @@ case "$NGX_MACHINE" in
 
 esac
 
+MAIN_LINK=
+MODULE_LINK="-G"
+
 
 # optimizations
 
--- a/auto/init
+++ b/auto/init
@@ -5,6 +5,7 @@
 
 NGX_MAKEFILE=$NGX_OBJS/Makefile
 NGX_MODULES_C=$NGX_OBJS/ngx_modules.c
+NGX_MODULES=
 
 NGX_AUTO_HEADERS_H=$NGX_OBJS/ngx_auto_headers.h
 NGX_AUTO_CONFIG_H=$NGX_OBJS/ngx_auto_config.h
--- a/auto/install
+++ b/auto/install
@@ -26,6 +26,18 @@ case ".$NGX_SBIN_PATH" in
 esac
 
 
+case ".$NGX_MODULES_PATH" in
+    ./*)
+    ;;
+
+    *)
+        NGX_MODULES_PATH=$NGX_PREFIX/$NGX_MODULES_PATH
+    ;;
+esac
+
+NGX_MODULES_PATH=`dirname $NGX_MODULES_PATH/.`
+
+
 case ".$NGX_CONF_PATH" in
     ./*)
     ;;
@@ -158,12 +170,24 @@ END
 fi
 
 
+if test -n "$NGX_MODULES"; then
+    cat << END                                                >> $NGX_MAKEFILE
+
+	test -d '\$(DESTDIR)$NGX_MODULES_PATH' \
+		|| mkdir -p '\$(DESTDIR)$NGX_MODULES_PATH'
+	cp $NGX_MODULES '\$(DESTDIR)$NGX_MODULES_PATH'
+END
+
+fi
+
+
 # create Makefile
 
 cat << END >> Makefile
 
 build:
 	\$(MAKE) -f $NGX_MAKEFILE
+	\$(MAKE) -f $NGX_MAKEFILE modules
 	\$(MAKE) -f $NGX_MAKEFILE manpage
 
 install:
--- a/auto/lib/conf
+++ b/auto/lib/conf
@@ -58,11 +58,11 @@ if [ $USE_ZLIB = YES ]; then
     . auto/lib/zlib/conf
 fi
 
-if [ $USE_LIBXSLT = YES ]; then
+if [ $USE_LIBXSLT != NO ]; then
     . auto/lib/libxslt/conf
 fi
 
-if [ $USE_LIBGD = YES ]; then
+if [ $USE_LIBGD != NO ]; then
     . auto/lib/libgd/conf
 fi
 
@@ -70,7 +70,7 @@ if [ $USE_PERL = YES ]; then
     . auto/lib/perl/conf
 fi
 
-if [ $HTTP_GEOIP = YES ]; then
+if [ $USE_GEOIP != NO ]; then
     . auto/lib/geoip/conf
 fi
 
--- a/auto/lib/geoip/conf
+++ b/auto/lib/geoip/conf
@@ -67,7 +67,12 @@ fi
 if [ $ngx_found = yes ]; then
 
     CORE_INCS="$CORE_INCS $ngx_feature_path"
-    CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+    if [ $USE_GEOIP = YES ]; then
+        CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+    fi
+
+    NGX_LIB_GEOIP=$ngx_feature_libs
 
     if [ $NGX_IPV6 = YES ]; then
         ngx_feature="GeoIP IPv6 support"
--- a/auto/lib/libgd/conf
+++ b/auto/lib/libgd/conf
@@ -67,7 +67,12 @@ fi
 if [ $ngx_found = yes ]; then
 
     CORE_INCS="$CORE_INCS $ngx_feature_path"
-    CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+    if [ $USE_LIBGD = YES ]; then
+        CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+    fi
+
+    NGX_LIB_LIBGD=$ngx_feature_libs
 
 else
 
--- a/auto/lib/libxslt/conf
+++ b/auto/lib/libxslt/conf
@@ -76,7 +76,12 @@ fi
 if [ $ngx_found = yes ]; then
 
     CORE_INCS="$CORE_INCS $ngx_feature_path"
-    CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+
+    if [ $USE_LIBXSLT = YES ]; then
+        CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+    fi
+
+    NGX_LIB_LIBXSLT=$ngx_feature_libs
 
 else
 
@@ -152,5 +157,9 @@ fi
 
 
 if [ $ngx_found = yes ]; then
-    CORE_LIBS="$CORE_LIBS -lexslt"
+    if [ $USE_LIBXSLT = YES ]; then
+        CORE_LIBS="$CORE_LIBS -lexslt"
+    fi
+
+    NGX_LIB_LIBXSLT="$NGX_LIB_LIBXSLT -lexslt"
 fi
--- a/auto/make
+++ b/auto/make
@@ -98,9 +98,11 @@ fi
 
 # the mail dependencies and include paths
 
-if [ $MAIL = YES ]; then
+if [ $MAIL != NO ]; then
 
-    ngx_all_srcs="$ngx_all_srcs $MAIL_SRCS"
+    if [ $MAIL = YES ]; then
+        ngx_all_srcs="$ngx_all_srcs $MAIL_SRCS"
+    fi
 
     ngx_deps=`echo $MAIL_DEPS \
         | sed -e "s/  *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
@@ -124,9 +126,11 @@ fi
 
 # the stream dependencies and include paths
 
-if [ $STREAM = YES ]; then
+if [ $STREAM != NO ]; then
 
-    ngx_all_srcs="$ngx_all_srcs $STREAM_SRCS"
+    if [ $STREAM = YES ]; then
+        ngx_all_srcs="$ngx_all_srcs $STREAM_SRCS"
+    fi
 
     ngx_deps=`echo $STREAM_DEPS \
         | sed -e "s/  *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
@@ -204,6 +208,7 @@ ngx_objs=`echo $ngx_all_objs $ngx_module
     | sed -e "s/  *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \
           -e "s/\//$ngx_regex_dirsep/g"`
 
+ngx_libs=
 if test -n "$NGX_LD_OPT$CORE_LIBS"; then
     ngx_libs=`echo $NGX_LD_OPT $CORE_LIBS \
         | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`
@@ -212,13 +217,18 @@ fi
 ngx_link=${CORE_LINK:+`echo $CORE_LINK \
     | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
 
+ngx_main_link=${MAIN_LINK:+`echo $MAIN_LINK \
+    | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
+
 
 cat << END                                                    >> $NGX_MAKEFILE
 
 $NGX_OBJS${ngx_dirsep}nginx${ngx_binext}:	$ngx_deps$ngx_spacer
-	\$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link
+	\$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
 	$ngx_rcc
 ${ngx_long_end}
+
+modules:
 END
 
 
@@ -472,3 +482,186 @@ if test -n "$NGX_PCH"; then
 END
 
 fi
+
+
+# dynamic modules
+
+if test -n "$NGX_PCH"; then
+    ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
+else
+    ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) \$(ALL_INCS)"
+fi
+
+ngx_obj_deps="\$(CORE_DEPS)"
+if [ $HTTP != NO ]; then
+    ngx_obj_deps="$ngx_obj_deps \$(HTTP_DEPS)"
+fi
+if [ $MAIL != NO ]; then
+    ngx_obj_deps="$ngx_obj_deps \$(MAIL_DEPS)"
+fi
+if [ $STREAM != NO ]; then
+    ngx_obj_deps="$ngx_obj_deps \$(STREAM_DEPS)"
+fi
+
+for ngx_module in $DYNAMIC_MODULES
+do
+    eval ngx_module_srcs="\$${ngx_module}_SRCS"
+    eval eval ngx_module_libs="\\\"\$${ngx_module}_LIBS\\\""
+
+    eval ngx_module_modules="\$${ngx_module}_MODULES"
+    eval ngx_module_order="\$${ngx_module}_ORDER"
+
+    ngx_modules_c=$NGX_OBJS/${ngx_module}_modules.c
+
+    cat << END                                    > $ngx_modules_c
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+END
+
+    for mod in $ngx_module_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 $ngx_module_modules
+    do
+        echo "    &$mod,"                         >> $ngx_modules_c
+    done
+
+    cat << END                                    >> $ngx_modules_c
+    NULL
+};
+
+END
+
+    echo 'char *ngx_module_names[] = {'           >> $ngx_modules_c
+
+    for mod in $ngx_module_modules
+    do
+        echo "    \"$mod\","                      >> $ngx_modules_c
+    done
+
+    cat << END                                    >> $ngx_modules_c
+    NULL
+};
+
+END
+
+    echo 'char *ngx_module_order[] = {'           >> $ngx_modules_c
+
+    for mod in $ngx_module_order
+    do
+        echo "    \"$mod\","                      >> $ngx_modules_c
+    done
+
+    cat << END                                    >> $ngx_modules_c
+    NULL
+};
+
+END
+
+    ngx_modules_c=`echo $ngx_modules_c | sed -e "s/\//$ngx_regex_dirsep/g"`
+
+    ngx_modules_obj=`echo $ngx_modules_c \
+        | sed -e "s/\(.*\.\)c/\1$ngx_objext/"`
+
+    ngx_module_objs=
+    for ngx_src in $ngx_module_srcs
+    do
+        case "$ngx_src" in
+            src/*)
+                ngx_obj=$ngx_src
+                ;;
+            *)
+                ngx_obj="addon/`basename \`dirname $ngx_src\``"
+                mkdir -p $NGX_OBJS/$ngx_obj
+                ngx_obj="$ngx_obj/`basename $ngx_src`"
+                ;;
+        esac
+
+        ngx_module_objs="$ngx_module_objs $ngx_obj"
+    done
+
+    ngx_module_objs=`echo $ngx_module_objs \
+        | sed -e "s#\([^ ]*\.\)cpp#$NGX_OBJS\/\1$ngx_objext#g" \
+              -e "s#\([^ ]*\.\)cc#$NGX_OBJS\/\1$ngx_objext#g" \
+              -e "s#\([^ ]*\.\)c#$NGX_OBJS\/\1$ngx_objext#g" \
+              -e "s#\([^ ]*\.\)S#$NGX_OBJS\/\1$ngx_objext#g"`
+
+    ngx_deps=`echo $ngx_module_objs $ngx_modules_obj $LINK_DEPS \
+        | sed -e "s/  *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
+              -e "s/\//$ngx_regex_dirsep/g"`
+
+    ngx_objs=`echo $ngx_module_objs $ngx_modules_obj \
+        | sed -e "s/  *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \
+              -e "s/\//$ngx_regex_dirsep/g"`
+
+    ngx_obj=$NGX_OBJS${ngx_dirsep}${ngx_module}${ngx_modext}
+
+    NGX_MODULES="$NGX_MODULES $ngx_obj"
+
+    if [ "$NGX_PLATFORM" = win32 ]; then
+        ngx_module_libs="$CORE_LIBS $ngx_module_libs"
+    fi
+
+    ngx_libs=
+    if test -n "$NGX_LD_OPT$ngx_module_libs"; then
+        ngx_libs=`echo $NGX_LD_OPT $ngx_module_libs \
+            | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`
+    fi
+
+    ngx_link=${CORE_LINK:+`echo $CORE_LINK \
+        | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
+
+    ngx_module_link=${MODULE_LINK:+`echo $MODULE_LINK \
+        | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
+
+
+    cat << END                                            >> $NGX_MAKEFILE
+
+modules:	$ngx_obj
+
+$ngx_obj:	$ngx_deps$ngx_spacer
+	\$(LINK) $ngx_long_start$ngx_binout$ngx_obj$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_module_link
+$ngx_long_end
+
+$ngx_modules_obj:	\$(CORE_DEPS)$ngx_cont$ngx_modules_c
+	$ngx_cc$ngx_tab$ngx_objout$ngx_modules_obj$ngx_tab$ngx_modules_c$NGX_AUX
+
+END
+
+    for ngx_src in $ngx_module_srcs
+    do
+        case "$ngx_src" in
+            src/*)
+                ngx_obj=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
+                ;;
+            *)
+                ngx_obj="addon/`basename \`dirname $ngx_src\``"
+                ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \
+                    | sed -e "s/\//$ngx_regex_dirsep/g"`
+                ;;
+        esac
+
+        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:	$ngx_obj_deps$ngx_cont$ngx_src
+	$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
+
+END
+
+    done
+done
--- a/auto/module
+++ b/auto/module
@@ -9,7 +9,58 @@ case $ngx_module_type in
 esac
 
 
-if [ "$ngx_module_link" = YES ]; then
+if [ "$ngx_module_link" = DYNAMIC ]; then
+
+    for ngx_module in $ngx_module_name; do
+        # extract the first name
+        break
+    done
+
+    DYNAMIC_MODULES="$DYNAMIC_MODULES $ngx_module"
+    eval ${ngx_module}_SRCS=\"$ngx_module_srcs\"
+
+    eval ${ngx_module}_MODULES=\"$ngx_module_name\"
+
+    if [ -z "$ngx_module_order" -a \
+         \( "$ngx_module_type" = "HTTP_FILTER" \
+         -o "$ngx_module_type" = "HTTP_AUX_FILTER" \) ]
+    then
+        eval ${ngx_module}_ORDER=\"$ngx_module_name \
+                                   ngx_http_copy_filter_module\"
+    else
+        eval ${ngx_module}_ORDER=\"$ngx_module_order\"
+    fi
+
+    if test -n "$ngx_module_incs"; then
+        CORE_INCS="$CORE_INCS $ngx_module_incs"
+    fi
+
+    libs=
+    for lib in $ngx_module_libs
+    do
+        case $lib in
+
+            LIBXSLT | LIBGD | GEOIP)
+                libs="$libs \$NGX_LIB_$lib"
+
+                if eval [ "\$USE_${lib}" = NO ] ; then
+                    eval USE_${lib}=DYNAMIC
+                fi
+            ;;
+
+            PCRE | OPENSSL | MD5 | SHA1 | ZLIB | PERL)
+                eval USE_${lib}=YES
+            ;;
+
+            *)
+                libs="$libs $lib"
+            ;;
+
+        esac
+    done
+    eval ${ngx_module}_LIBS=\'$libs\'
+
+elif [ "$ngx_module_link" = YES ]; then
 
     eval ${ngx_module_type}_MODULES=\"\$${ngx_module_type}_MODULES \
                                       $ngx_module_name\"
--- a/auto/modules
+++ b/auto/modules
@@ -159,6 +159,35 @@ fi
 ngx_module_type=HTTP_FILTER
 HTTP_FILTER_MODULES=
 
+ngx_module_order="ngx_http_static_module \
+                  ngx_http_gzip_static_module \
+                  ngx_http_dav_module \
+                  ngx_http_autoindex_module \
+                  ngx_http_index_module \
+                  ngx_http_random_index_module \
+                  ngx_http_access_module \
+                  ngx_http_realip_module \
+                  ngx_http_write_filter_module \
+                  ngx_http_header_filter_module \
+                  ngx_http_chunked_filter_module \
+                  ngx_http_v2_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_xslt_filter_module \
+                  ngx_http_image_filter_module \
+                  ngx_http_sub_filter_module \
+                  ngx_http_addition_filter_module \
+                  ngx_http_gunzip_filter_module \
+                  ngx_http_userid_filter_module \
+                  ngx_http_headers_filter_module \
+                  ngx_http_copy_filter_module \
+                  ngx_http_range_body_filter_module \
+                  ngx_http_not_modified_filter_module \
+                  ngx_http_slice_filter_module"
+
 if :; then
     ngx_module_name=ngx_http_write_filter_module
     ngx_module_incs=
@@ -263,7 +292,7 @@ if [ $HTTP_CHARSET = YES ]; then
     . auto/module
 fi
 
-if [ $HTTP_XSLT = YES ]; then
+if [ $HTTP_XSLT != NO ]; then
     ngx_module_name=ngx_http_xslt_filter_module
     ngx_module_incs=
     ngx_module_deps=
@@ -274,7 +303,7 @@ if [ $HTTP_XSLT = YES ]; then
     . auto/module
 fi
 
-if [ $HTTP_IMAGE_FILTER = YES ]; then
+if [ $HTTP_IMAGE_FILTER != NO ]; then
     ngx_module_name=ngx_http_image_filter_module
     ngx_module_incs=
     ngx_module_deps=
@@ -579,14 +608,14 @@ if [ $HTTP_GEO = YES ]; then
     . auto/module
 fi
 
-if [ $HTTP_GEOIP = YES ]; then
+if [ $HTTP_GEOIP != NO ]; then
     have=NGX_HTTP_X_FORWARDED_FOR . auto/have
 
     ngx_module_name=ngx_http_geoip_module
     ngx_module_incs=
     ngx_module_deps=
     ngx_module_srcs=src/http/modules/ngx_http_geoip_module.c
-    ngx_module_libs=
+    ngx_module_libs=GEOIP
     ngx_module_link=$HTTP_GEOIP
 
     . auto/module
@@ -864,7 +893,7 @@ if [ $HTTP_STUB_STATUS = YES ]; then
 fi
 
 
-if [ $MAIL == YES ]; then
+if [ $MAIL != NO ]; then
     MAIL_MODULES=
     MAIL_DEPS=
     MAIL_INCS=
@@ -873,6 +902,8 @@ if [ $MAIL == YES ]; then
     ngx_module_libs=
     ngx_module_link=YES
 
+    ngx_module_order=
+
     ngx_module_name="ngx_mail_module ngx_mail_core_module"
     ngx_module_incs="src/mail"
     ngx_module_deps="src/mail/ngx_mail.h"
@@ -937,7 +968,7 @@ if [ $MAIL == YES ]; then
 fi
 
 
-if [ $STREAM = YES ]; then
+if [ $STREAM != NO ]; then
     STREAM_MODULES=
     STREAM_DEPS=
     STREAM_INCS=
@@ -948,6 +979,8 @@ if [ $STREAM = YES ]; then
     ngx_module_libs=
     ngx_module_link=YES
 
+    ngx_module_order=
+
     ngx_module_name="ngx_stream_module \
                      ngx_stream_core_module \
                      ngx_stream_proxy_module \
@@ -1041,6 +1074,7 @@ if test -n "$NGX_ADDONS"; then
         ngx_module_deps=
         ngx_module_srcs=
         ngx_module_libs=
+        ngx_module_order=
         ngx_module_link=ADDON
 
         if test -f $ngx_addon_dir/config; then
@@ -1056,6 +1090,36 @@ if test -n "$NGX_ADDONS"; then
 fi
 
 
+if test -n "$DYNAMIC_ADDONS"; then
+
+    echo configuring additional dynamic modules
+
+    for ngx_addon_dir in $DYNAMIC_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=DYNAMIC
+
+        if test -f $ngx_addon_dir/config; then
+            . $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
+
+
 if [ $USE_OPENSSL = YES ]; then
     ngx_module_type=CORE
     ngx_module_name=ngx_openssl_module
@@ -1065,6 +1129,7 @@ if [ $USE_OPENSSL = YES ]; then
                      src/event/ngx_event_openssl_stapling.c"
     ngx_module_libs=
     ngx_module_link=YES
+    ngx_module_order=
 
     . auto/module
 fi
@@ -1078,6 +1143,7 @@ if [ $USE_PCRE = YES ]; then
     ngx_module_srcs=src/core/ngx_regex.c
     ngx_module_libs=
     ngx_module_link=YES
+    ngx_module_order=
 
     . auto/module
 fi
@@ -1100,14 +1166,42 @@ if [ $HTTP = YES ]; then
 fi
 
 
-if [ $MAIL = YES ]; then
-    modules="$modules $MAIL_MODULES"
+if [ $MAIL != NO ]; then
+
+    if [ $MAIL = YES ]; then
+        modules="$modules $MAIL_MODULES"
+
+    elif [ $MAIL = DYNAMIC ]; then
+        ngx_module_name=$MAIL_MODULES
+        ngx_module_incs=
+        ngx_module_deps=$MAIL_DEPS
+        ngx_module_srcs=$MAIL_SRCS
+        ngx_module_libs=
+        ngx_module_link=DYNAMIC
+
+        . auto/module
+    fi
+
     NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(MAIL_DEPS)"
 fi
 
 
-if [ $STREAM = YES ]; then
-    modules="$modules $STREAM_MODULES"
+if [ $STREAM != NO ]; then
+
+    if [ $STREAM = YES ]; then
+        modules="$modules $STREAM_MODULES"
+
+    elif [ $STREAM = DYNAMIC ]; then
+        ngx_module_name=$STREAM_MODULES
+        ngx_module_incs=
+        ngx_module_deps=$STREAM_DEPS
+        ngx_module_srcs=$STREAM_SRCS
+        ngx_module_libs=
+        ngx_module_link=DYNAMIC
+
+        . auto/module
+    fi
+
     NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(STREAM_DEPS)"
 fi
 
@@ -1167,3 +1261,16 @@ cat << END                              
 };
 
 END
+
+echo 'char *ngx_module_names[] = {'           >> $NGX_MODULES_C
+
+for mod in $modules
+do
+    echo "    \"$mod\","                      >> $NGX_MODULES_C
+done
+
+cat << END                                    >> $NGX_MODULES_C
+    NULL
+};
+
+END
--- a/auto/options
+++ b/auto/options
@@ -7,6 +7,7 @@ help=no
 
 NGX_PREFIX=
 NGX_SBIN_PATH=
+NGX_MODULES_PATH=
 NGX_CONF_PREFIX=
 NGX_CONF_PATH=
 NGX_ERROR_LOG_PATH=
@@ -120,7 +121,11 @@ STREAM_UPSTREAM_HASH=YES
 STREAM_UPSTREAM_LEAST_CONN=YES
 STREAM_UPSTREAM_ZONE=YES
 
+DYNAMIC_MODULES=
+
 NGX_ADDONS=
+NGX_ADDON_DEPS=
+DYNAMIC_ADDONS=
 
 USE_PCRE=NO
 PCRE=NONE
@@ -151,6 +156,7 @@ NGX_PERL=perl
 
 USE_LIBXSLT=NO
 USE_LIBGD=NO
+USE_GEOIP=NO
 
 NGX_GOOGLE_PERFTOOLS=NO
 NGX_CPP_TEST=NO
@@ -178,6 +184,7 @@ do
         --prefix=)                       NGX_PREFIX="!"             ;;
         --prefix=*)                      NGX_PREFIX="$value"        ;;
         --sbin-path=*)                   NGX_SBIN_PATH="$value"     ;;
+        --modules-path=*)                NGX_MODULES_PATH="$value"  ;;
         --conf-path=*)                   NGX_CONF_PATH="$value"     ;;
         --error-log-path=*)              NGX_ERROR_LOG_PATH="$value";;
         --pid-path=*)                    NGX_PID_PATH="$value"      ;;
@@ -215,8 +222,13 @@ do
         --with-http_realip_module)       HTTP_REALIP=YES            ;;
         --with-http_addition_module)     HTTP_ADDITION=YES          ;;
         --with-http_xslt_module)         HTTP_XSLT=YES              ;;
+        --with-http_xslt_module=dynamic) HTTP_XSLT=DYNAMIC          ;;
         --with-http_image_filter_module) HTTP_IMAGE_FILTER=YES      ;;
+        --with-http_image_filter_module=dynamic)
+                                         HTTP_IMAGE_FILTER=DYNAMIC  ;;
         --with-http_geoip_module)        HTTP_GEOIP=YES             ;;
+        --with-http_geoip_module=dynamic)
+                                         HTTP_GEOIP=DYNAMIC         ;;
         --with-http_sub_module)          HTTP_SUB=YES               ;;
         --with-http_dav_module)          HTTP_DAV=YES               ;;
         --with-http_flv_module)          HTTP_FLV=YES               ;;
@@ -266,6 +278,7 @@ do
         --with-http_stub_status_module)  HTTP_STUB_STATUS=YES       ;;
 
         --with-mail)                     MAIL=YES                   ;;
+        --with-mail=dynamic)             MAIL=DYNAMIC               ;;
         --with-mail_ssl_module)          MAIL_SSL=YES               ;;
         # STUB
         --with-imap)
@@ -285,6 +298,7 @@ use the \"--with-mail_ssl_module\" optio
         --without-mail_smtp_module)      MAIL_SMTP=NO               ;;
 
         --with-stream)                   STREAM=YES                 ;;
+        --with-stream=dynamic)           STREAM=DYNAMIC             ;;
         --with-stream_ssl_module)        STREAM_SSL=YES             ;;
         --without-stream_limit_conn_module)
                                          STREAM_LIMIT_CONN=NO       ;;
@@ -300,6 +314,7 @@ use the \"--with-mail_ssl_module\" optio
         --with-cpp_test_module)          NGX_CPP_TEST=YES           ;;
 
         --add-module=*)                  NGX_ADDONS="$NGX_ADDONS $value" ;;
+        --add-dynamic-module=*)          DYNAMIC_ADDONS="$DYNAMIC_ADDONS $value" ;;
 
         --with-cc=*)                     CC="$value"                ;;
         --with-cpp=*)                    CPP="$value"               ;;
@@ -356,6 +371,7 @@ cat << END
 
   --prefix=PATH                      set installation prefix
   --sbin-path=PATH                   set nginx binary pathname
+  --modules-path=PATH                set modules path
   --conf-path=PATH                   set nginx.conf pathname
   --error-log-path=PATH              set error log pathname
   --pid-path=PATH                    set nginx.pid pathname
@@ -384,8 +400,12 @@ cat << END
   --with-http_realip_module          enable ngx_http_realip_module
   --with-http_addition_module        enable ngx_http_addition_module
   --with-http_xslt_module            enable ngx_http_xslt_module
+  --with-http_xslt_module=dynamic    enable dynamic ngx_http_xslt_module
   --with-http_image_filter_module    enable ngx_http_image_filter_module
+  --with-http_image_filter_module=dynamic
+                                     enable dynamic ngx_http_image_filter_module
   --with-http_geoip_module           enable ngx_http_geoip_module
+  --with-http_geoip_module=dynamic   enable dynamic ngx_http_geoip_module
   --with-http_sub_module             enable ngx_http_sub_module
   --with-http_dav_module             enable ngx_http_dav_module
   --with-http_flv_module             enable ngx_http_flv_module
@@ -451,12 +471,14 @@ cat << END
   --without-http-cache               disable HTTP cache
 
   --with-mail                        enable POP3/IMAP4/SMTP proxy module
+  --with-mail=dynamic                enable dynamic POP3/IMAP4/SMTP proxy module
   --with-mail_ssl_module             enable ngx_mail_ssl_module
   --without-mail_pop3_module         disable ngx_mail_pop3_module
   --without-mail_imap_module         disable ngx_mail_imap_module
   --without-mail_smtp_module         disable ngx_mail_smtp_module
 
   --with-stream                      enable TCP proxy module
+  --with-stream=dynamic              enable dynamic TCP proxy module
   --with-stream_ssl_module           enable ngx_stream_ssl_module
   --without-stream_limit_conn_module disable ngx_stream_limit_conn_module
   --without-stream_access_module     disable ngx_stream_access_module
@@ -470,7 +492,8 @@ cat << END
   --with-google_perftools_module     enable ngx_google_perftools_module
   --with-cpp_test_module             enable ngx_cpp_test_module
 
-  --add-module=PATH                  enable an external module
+  --add-module=PATH                  enable external module
+  --add-dynamic-module=PATH          enable dynamic external module
 
   --with-cc=PATH                     set C compiler pathname
   --with-cpp=PATH                    set C preprocessor pathname
@@ -533,6 +556,7 @@ fi
 
 
 NGX_SBIN_PATH=${NGX_SBIN_PATH:-sbin/nginx}
+NGX_MODULES_PATH=${NGX_MODULES_PATH:-modules}
 NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf}
 NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH`
 NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid}
--- a/auto/os/darwin
+++ b/auto/os/darwin
@@ -14,6 +14,9 @@ CORE_SRCS="$UNIX_SRCS $DARWIN_SRCS"
 ngx_spacer='
 '
 
+MAIN_LINK=
+MODULE_LINK="-shared -Wl,-undefined,dynamic_lookup"
+
 # kqueue
 
 echo " + kqueue found"
--- a/auto/os/win32
+++ b/auto/os/win32
@@ -12,10 +12,15 @@ OS_CONFIG="$WIN32_CONFIG"
 NGX_ICONS="$NGX_WIN32_ICONS"
 SELECT_SRCS=$WIN32_SELECT_SRCS
 
+ngx_pic_opt=
+
 case "$NGX_CC_NAME" in
 
     gcc)
         CORE_LIBS="$CORE_LIBS -ladvapi32 -lws2_32"
+        MAIN_LINK="$MAIN_LINK -Wl,--export-all-symbols"
+        MAIN_LINK="$MAIN_LINK -Wl,--out-implib=$NGX_OBJS/libnginx.a"
+        MODULE_LINK="-shared -L $NGX_OBJS -lnginx"
     ;;
 
     *)
--- a/auto/summary
+++ b/auto/summary
@@ -60,6 +60,7 @@ echo
 cat << END
   nginx path prefix: "$NGX_PREFIX"
   nginx binary file: "$NGX_SBIN_PATH"
+  nginx modules path: "$NGX_MODULES_PATH"
   nginx configuration prefix: "$NGX_CONF_PREFIX"
   nginx configuration file: "$NGX_CONF_PATH"
   nginx pid file: "$NGX_PID_PATH"
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -24,6 +24,10 @@ static char *ngx_set_cpu_affinity(ngx_co
     void *conf);
 static char *ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+#if (NGX_HAVE_DLOPEN)
+static void ngx_unload_module(void *data);
+#endif
 
 
 static ngx_conf_enum_t  ngx_debug_points[] = {
@@ -133,6 +137,13 @@ static ngx_command_t  ngx_core_commands[
       0,
       NULL },
 
+    { ngx_string("load_module"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_load_module,
+      0,
+      0,
+      NULL },
+
       ngx_null_command
 };
 
@@ -1403,3 +1414,101 @@ ngx_set_worker_processes(ngx_conf_t *cf,
 
     return NGX_CONF_OK;
 }
+
+
+static char *
+ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+#if (NGX_HAVE_DLOPEN)
+    void                *handle;
+    char               **names, **order;
+    ngx_str_t           *value, file;
+    ngx_uint_t           i;
+    ngx_module_t        *module, **modules;
+    ngx_pool_cleanup_t  *cln;
+
+    if (cf->cycle->modules_used) {
+        return "is specified too late";
+    }
+
+    value = cf->args->elts;
+
+    file = value[1];
+
+    if (ngx_conf_full_name(cf->cycle, &file, 0) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    cln = ngx_pool_cleanup_add(cf->cycle->pool, 0);
+    if (cln == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    handle = ngx_dlopen(file.data);
+    if (handle == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           ngx_dlopen_n " \"%s\" failed (%s)",
+                           file.data, ngx_dlerror());
+        return NGX_CONF_ERROR;
+    }
+
+    cln->handler = ngx_unload_module;
+    cln->data = handle;
+
+    modules = ngx_dlsym(handle, "ngx_modules");
+    if (modules == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           ngx_dlsym_n " \"%V\", \"%s\" failed (%s)",
+                           &value[1], "ngx_modules", ngx_dlerror());
+        return NGX_CONF_ERROR;
+    }
+
+    names = ngx_dlsym(handle, "ngx_module_names");
+    if (names == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           ngx_dlsym_n " \"%V\", \"%s\" failed (%s)",
+                           &value[1], "ngx_module_names", ngx_dlerror());
+        return NGX_CONF_ERROR;
+    }
+
+    order = ngx_dlsym(handle, "ngx_module_order");
+
+    for (i = 0; modules[i]; i++) {
+        module = modules[i];
+        module->name = names[i];
+
+        if (ngx_add_module(cf, &file, module, order) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%i",
+                       module->name, module->index);
+    }
+
+    return NGX_CONF_OK;
+
+#else
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "\"load_module\" is not supported "
+                       "on this platform");
+    return NGX_CONF_ERROR;
+
+#endif
+}
+
+
+#if (NGX_HAVE_DLOPEN)
+
+static void
+ngx_unload_module(void *data)
+{
+    void  *handle = data;
+
+    if (ngx_dlclose(handle) != 0) {
+        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+                      ngx_dlclose_n " failed (%s)", ngx_dlerror());
+    }
+}
+
+#endif
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -212,7 +212,10 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
 
 
-    cycle->modules = ngx_modules;
+    if (ngx_cycle_modules(cycle) != NGX_OK) {
+        ngx_destroy_pool(pool);
+        return NULL;
+    }
 
 
     for (i = 0; cycle->modules[i]; i++) {
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -49,6 +49,8 @@ struct ngx_cycle_s {
     ngx_uint_t                free_connection_n;
 
     ngx_module_t            **modules;
+    ngx_uint_t                modules_n;
+    ngx_uint_t                modules_used;    /* unsigned  modules_used:1; */
 
     ngx_queue_t               reusable_connections_queue;
 
--- a/src/core/ngx_module.c
+++ b/src/core/ngx_module.c
@@ -10,7 +10,16 @@
 #include <ngx_core.h>
 
 
-ngx_uint_t  ngx_max_module;
+#define NGX_MAX_DYNAMIC_MODULES  128
+
+
+static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle);
+static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type,
+    ngx_uint_t index);
+
+
+ngx_uint_t         ngx_max_module;
+static ngx_uint_t  ngx_modules_n;
 
 
 ngx_int_t
@@ -20,9 +29,36 @@ ngx_preinit_modules()
 
     ngx_max_module = 0;
     for (i = 0; ngx_modules[i]; i++) {
-        ngx_modules[i]->index = ngx_max_module++;
+        ngx_modules[i]->index = i;
+        ngx_modules[i]->name = ngx_module_names[i];
     }
 
+    ngx_modules_n = i;
+    ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_cycle_modules(ngx_cycle_t *cycle)
+{
+    /*
+     * create a list of modules to be used for this cycle,
+     * copy static modules to it
+     */
+
+    cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1)
+                                              * sizeof(ngx_module_t *));
+    if (cycle->modules == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(cycle->modules, ngx_modules,
+               ngx_modules_n * sizeof(ngx_module_t *));
+
+    cycle->modules_n = ngx_modules_n;
+
     return NGX_OK;
 }
 
@@ -47,19 +83,279 @@ ngx_init_modules(ngx_cycle_t *cycle)
 ngx_int_t
 ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type)
 {
-    ngx_uint_t  i, max;
+    ngx_uint_t     i, next, max;
+    ngx_module_t  *module;
 
+    next = 0;
     max = 0;
 
     /* count appropriate modules, set up their indices */
 
     for (i = 0; cycle->modules[i]; i++) {
-        if (cycle->modules[i]->type != type) {
+        module = cycle->modules[i];
+
+        if (module->type != type) {
+            continue;
+        }
+
+        if (module->ctx_index != NGX_MODULE_UNSET_INDEX) {
+
+            /* if ctx_index was assigned, preserve it */
+
+            if (module->ctx_index > max) {
+                max = module->ctx_index;
+            }
+
+            if (module->ctx_index == next) {
+                next++;
+            }
+
             continue;
         }
 
-        cycle->modules[i]->ctx_index = max++;
+        /* search for some free index */
+
+        module->ctx_index = ngx_module_ctx_index(cycle, type, next);
+
+        if (module->ctx_index > max) {
+            max = module->ctx_index;
+        }
+
+        next = module->ctx_index + 1;
+    }
+
+    /*
+     * make sure the number returned is big enough for previous
+     * cycle as well, else there will be problems if the number
+     * will be stored in a global variable (as it's used to be)
+     * and we'll have to roll back to the previous cycle
+     */
+
+    if (cycle->old_cycle && cycle->old_cycle->modules) {
+
+        for (i = 0; cycle->old_cycle->modules[i]; i++) {
+            module = cycle->old_cycle->modules[i];
+
+            if (module->type != type) {
+                continue;
+            }
+
+            if (module->ctx_index > max) {
+                max = module->ctx_index;
+            }
+        }
+    }
+
+    /* prevent loading of additional modules */
+
+    cycle->modules_used = 1;
+
+    return max + 1;
+}
+
+
+ngx_int_t
+ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module,
+    char **order)
+{
+    void               *rv;
+    ngx_uint_t          i, m, before;
+    ngx_core_module_t  *core_module;
+
+    if (cf->cycle->modules_n >= ngx_max_module) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "too many modules loaded");
+        return NGX_ERROR;
+    }
+
+    if (module->version != nginx_version) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "module \"%V\" version %ui instead of %ui",
+                           file, module->version, nginx_version);
+        return NGX_ERROR;
+    }
+
+    if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "module \"%V\" is not binary compatible",
+                           file);
+        return NGX_ERROR;
+    }
+
+    for (m = 0; cf->cycle->modules[m]; m++) {
+        if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "module \"%s\" is already loaded",
+                               module->name);
+            return NGX_ERROR;
+        }
+    }
+
+    /*
+     * if the module wasn't previously loaded, assign an index
+     */
+
+    if (module->index == NGX_MODULE_UNSET_INDEX) {
+        module->index = ngx_module_index(cf->cycle);
+
+        if (module->index >= ngx_max_module) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "too many modules loaded");
+            return NGX_ERROR;
+        }
     }
 
-    return max;
+    /*
+     * put the module into the cycle->modules array
+     */
+
+    before = cf->cycle->modules_n;
+
+    if (order) {
+        for (i = 0; order[i]; i++) {
+            if (ngx_strcmp(order[i], module->name) == 0) {
+                i++;
+                break;
+            }
+        }
+
+        for ( /* void */ ; order[i]; i++) {
+
+#if 0
+            ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0,
+                           "module: %s before %s",
+                           module->name, order[i]);
+#endif
+
+            for (m = 0; m < before; m++) {
+                if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) {
+
+                    ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0,
+                                   "module: %s before %s:%i",
+                                   module->name, order[i], m);
+
+                    before = m;
+                    break;
+                }
+            }
+        }
+    }
+
+    /* put the module before modules[before] */
+
+    if (before != cf->cycle->modules_n) {
+        ngx_memmove(&cf->cycle->modules[before + 1],
+                    &cf->cycle->modules[before],
+                    (cf->cycle->modules_n - before) * sizeof(ngx_module_t *));
+    }
+
+    cf->cycle->modules[before] = module;
+    cf->cycle->modules_n++;
+
+    if (module->type == NGX_CORE_MODULE) {
+
+        /*
+         * we are smart enough to initialize core modules;
+         * other modules are expected to be loaded before
+         * initialization - e.g., http modules must be loaded
+         * before http{} block
+         */
+
+        core_module = module->ctx;
+
+        if (core_module->create_conf) {
+            rv = core_module->create_conf(cf->cycle);
+            if (rv == NULL) {
+                return NGX_ERROR;
+            }
+
+            cf->cycle->conf_ctx[module->index] = rv;
+        }
+    }
+
+    return NGX_OK;
 }
+
+
+static ngx_uint_t
+ngx_module_index(ngx_cycle_t *cycle)
+{
+    ngx_uint_t     i, index;
+    ngx_module_t  *module;
+
+    index = 0;
+
+again:
+
+    /* find an unused index */
+
+    for (i = 0; cycle->modules[i]; i++) {
+        module = cycle->modules[i];
+
+        if (module->index == index) {
+            index++;
+            goto again;
+        }
+    }
+
+    /* check previous cycle */
+
+    if (cycle->old_cycle && cycle->old_cycle->modules) {
+
+        for (i = 0; cycle->old_cycle->modules[i]; i++) {
+            module = cycle->old_cycle->modules[i];
+
+            if (module->index == index) {
+                index++;
+                goto again;
+            }
+        }
+    }
+
+    return index;
+}
+
+
+static ngx_uint_t
+ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index)
+{
+    ngx_uint_t     i;
+    ngx_module_t  *module;
+
+again:
+
+    /* find an unused ctx_index */
+
+    for (i = 0; cycle->modules[i]; i++) {
+        module = cycle->modules[i];
+
+        if (module->type != type) {
+            continue;
+        }
+
+        if (module->ctx_index == index) {
+            index++;
+            goto again;
+        }
+    }
+
+    /* check previous cycle */
+
+    if (cycle->old_cycle && cycle->old_cycle->modules) {
+
+        for (i = 0; cycle->old_cycle->modules[i]; i++) {
+            module = cycle->old_cycle->modules[i];
+
+            if (module->type != type) {
+                continue;
+            }
+
+            if (module->ctx_index == index) {
+                index++;
+                goto again;
+            }
+        }
+    }
+
+    return index;
+}
--- a/src/core/ngx_module.h
+++ b/src/core/ngx_module.h
@@ -12,9 +12,234 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <nginx.h>
+
+
+#define NGX_MODULE_UNSET_INDEX  (ngx_uint_t) -1
 
 
-#define NGX_MODULE_V1          0, 0, 0, 0, 0, 0, 1
+#define NGX_MODULE_SIGNATURE_0                                                \
+    ngx_value(NGX_PTR_SIZE) ","                                               \
+    ngx_value(NGX_SIG_ATOMIC_T_SIZE) ","                                      \
+    ngx_value(NGX_TIME_T_SIZE) ","
+
+#if (NGX_HAVE_KQUEUE)
+#define NGX_MODULE_SIGNATURE_1   "1"
+#else
+#define NGX_MODULE_SIGNATURE_1   "0"
+#endif
+
+#if (NGX_HAVE_IOCP)
+#define NGX_MODULE_SIGNATURE_2   "1"
+#else
+#define NGX_MODULE_SIGNATURE_2   "0"
+#endif
+
+#if (NGX_HAVE_FILE_AIO)
+#define NGX_MODULE_SIGNATURE_3   "1"
+#else
+#define NGX_MODULE_SIGNATURE_3   "0"
+#endif
+
+#if (NGX_HAVE_AIO_SENDFILE)
+#define NGX_MODULE_SIGNATURE_4   "1"
+#else
+#define NGX_MODULE_SIGNATURE_4   "0"
+#endif
+
+#if (NGX_HAVE_EVENTFD)
+#define NGX_MODULE_SIGNATURE_5   "1"
+#else
+#define NGX_MODULE_SIGNATURE_5   "0"
+#endif
+
+#if (NGX_HAVE_EPOLL)
+#define NGX_MODULE_SIGNATURE_6   "1"
+#else
+#define NGX_MODULE_SIGNATURE_6   "0"
+#endif
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+#define NGX_MODULE_SIGNATURE_7   "1"
+#else
+#define NGX_MODULE_SIGNATURE_7   "0"
+#endif
+
+#if (NGX_HAVE_INET6)
+#define NGX_MODULE_SIGNATURE_8   "1"
+#else
+#define NGX_MODULE_SIGNATURE_8   "0"
+#endif
+
+#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
+#define NGX_MODULE_SIGNATURE_9   "1"
+#else
+#define NGX_MODULE_SIGNATURE_9   "0"
+#endif
+
+#if (NGX_HAVE_REUSEPORT)
+#define NGX_MODULE_SIGNATURE_10  "1"
+#else
+#define NGX_MODULE_SIGNATURE_10  "0"
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+#define NGX_MODULE_SIGNATURE_11  "1"
+#else
+#define NGX_MODULE_SIGNATURE_11  "0"
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+#define NGX_MODULE_SIGNATURE_12  "1"
+#else
+#define NGX_MODULE_SIGNATURE_12  "0"
+#endif
+
+#if (NGX_HAVE_SETFIB)
+#define NGX_MODULE_SIGNATURE_13  "1"
+#else
+#define NGX_MODULE_SIGNATURE_13  "0"
+#endif
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+#define NGX_MODULE_SIGNATURE_14  "1"
+#else
+#define NGX_MODULE_SIGNATURE_14  "0"
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+#define NGX_MODULE_SIGNATURE_15  "1"
+#else
+#define NGX_MODULE_SIGNATURE_15  "0"
+#endif
+
+#if (NGX_HAVE_VARIADIC_MACROS)
+#define NGX_MODULE_SIGNATURE_16  "1"
+#else
+#define NGX_MODULE_SIGNATURE_16  "0"
+#endif
+
+#if (NGX_HAVE_MD5)
+#define NGX_MODULE_SIGNATURE_17  "1"
+#else
+#define NGX_MODULE_SIGNATURE_17  "0"
+#endif
+
+#if (NGX_HAVE_SHA1)
+#define NGX_MODULE_SIGNATURE_18  "1"
+#else
+#define NGX_MODULE_SIGNATURE_18  "0"
+#endif
+
+#if (NGX_HAVE_OPENAT)
+#define NGX_MODULE_SIGNATURE_19  "1"
+#else
+#define NGX_MODULE_SIGNATURE_19  "0"
+#endif
+
+#if (NGX_HAVE_ATOMIC_OPS)
+#define NGX_MODULE_SIGNATURE_20  "1"
+#else
+#define NGX_MODULE_SIGNATURE_20  "0"
+#endif
+
+#if (NGX_HAVE_POSIX_SEM)
+#define NGX_MODULE_SIGNATURE_21  "1"
+#else
+#define NGX_MODULE_SIGNATURE_21  "0"
+#endif
+
+#if (NGX_THREADS)
+#define NGX_MODULE_SIGNATURE_22  "1"
+#else
+#define NGX_MODULE_SIGNATURE_22  "0"
+#endif
+
+#if (NGX_PCRE)
+#define NGX_MODULE_SIGNATURE_23  "1"
+#else
+#define NGX_MODULE_SIGNATURE_23  "0"
+#endif
+
+#if (NGX_HTTP_SSL)
+#define NGX_MODULE_SIGNATURE_24  "1"
+#else
+#define NGX_MODULE_SIGNATURE_24  "0"
+#endif
+
+#if (NGX_HTTP_V2)
+#define NGX_MODULE_SIGNATURE_25  "1"
+#else
+#define NGX_MODULE_SIGNATURE_25  "0"
+#endif
+
+#if (NGX_HTTP_GZIP)
+#define NGX_MODULE_SIGNATURE_26  "1"
+#else
+#define NGX_MODULE_SIGNATURE_26  "0"
+#endif
+
+#if (NGX_HTTP_DEGRADATION)
+#define NGX_MODULE_SIGNATURE_27  "1"
+#else
+#define NGX_MODULE_SIGNATURE_27  "0"
+#endif
+
+#if (NGX_HTTP_X_FORWARDED_FOR)
+#define NGX_MODULE_SIGNATURE_28  "1"
+#else
+#define NGX_MODULE_SIGNATURE_28  "0"
+#endif
+
+#if (NGX_HTTP_REALIP)
+#define NGX_MODULE_SIGNATURE_29  "1"
+#else
+#define NGX_MODULE_SIGNATURE_29  "0"
+#endif
+
+#if (NGX_HTTP_HEADERS)
+#define NGX_MODULE_SIGNATURE_30  "1"
+#else
+#define NGX_MODULE_SIGNATURE_30  "0"
+#endif
+
+#if (NGX_HTTP_DAV)
+#define NGX_MODULE_SIGNATURE_31  "1"
+#else
+#define NGX_MODULE_SIGNATURE_31  "0"
+#endif
+
+#if (NGX_HTTP_CACHE)
+#define NGX_MODULE_SIGNATURE_32  "1"
+#else
+#define NGX_MODULE_SIGNATURE_32  "0"
+#endif
+
+#if (NGX_HTTP_UPSTREAM_ZONE)
+#define NGX_MODULE_SIGNATURE_33  "1"
+#else
+#define NGX_MODULE_SIGNATURE_33  "0"
+#endif
+
+#define NGX_MODULE_SIGNATURE                                                  \
+    NGX_MODULE_SIGNATURE_0 NGX_MODULE_SIGNATURE_1 NGX_MODULE_SIGNATURE_2      \
+    NGX_MODULE_SIGNATURE_3 NGX_MODULE_SIGNATURE_4 NGX_MODULE_SIGNATURE_5      \
+    NGX_MODULE_SIGNATURE_6 NGX_MODULE_SIGNATURE_7 NGX_MODULE_SIGNATURE_8      \
+    NGX_MODULE_SIGNATURE_9 NGX_MODULE_SIGNATURE_10 NGX_MODULE_SIGNATURE_11    \
+    NGX_MODULE_SIGNATURE_12 NGX_MODULE_SIGNATURE_13 NGX_MODULE_SIGNATURE_14   \
+    NGX_MODULE_SIGNATURE_15 NGX_MODULE_SIGNATURE_16 NGX_MODULE_SIGNATURE_17   \
+    NGX_MODULE_SIGNATURE_18 NGX_MODULE_SIGNATURE_19 NGX_MODULE_SIGNATURE_20   \
+    NGX_MODULE_SIGNATURE_21 NGX_MODULE_SIGNATURE_22 NGX_MODULE_SIGNATURE_23   \
+    NGX_MODULE_SIGNATURE_24 NGX_MODULE_SIGNATURE_25 NGX_MODULE_SIGNATURE_26   \
+    NGX_MODULE_SIGNATURE_27 NGX_MODULE_SIGNATURE_28 NGX_MODULE_SIGNATURE_29   \
+    NGX_MODULE_SIGNATURE_30 NGX_MODULE_SIGNATURE_31 NGX_MODULE_SIGNATURE_32   \
+    NGX_MODULE_SIGNATURE_33
+
+
+#define NGX_MODULE_V1                                                         \
+    NGX_MODULE_UNSET_INDEX, NGX_MODULE_UNSET_INDEX,                           \
+    NULL, 0, 0, nginx_version, NGX_MODULE_SIGNATURE
+
 #define NGX_MODULE_V1_PADDING  0, 0, 0, 0, 0, 0, 0, 0
 
 
@@ -22,12 +247,13 @@ struct ngx_module_s {
     ngx_uint_t            ctx_index;
     ngx_uint_t            index;
 
+    char                 *name;
+
     ngx_uint_t            spare0;
     ngx_uint_t            spare1;
-    ngx_uint_t            spare2;
-    ngx_uint_t            spare3;
 
     ngx_uint_t            version;
+    char                 *signature;
 
     void                 *ctx;
     ngx_command_t        *commands;
@@ -63,12 +289,19 @@ typedef struct {
 
 
 ngx_int_t ngx_preinit_modules();
+ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle);
 ngx_int_t ngx_init_modules(ngx_cycle_t *cycle);
 ngx_int_t ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type);
 
 
+ngx_int_t ngx_add_module(ngx_conf_t *cf, ngx_str_t *file,
+    ngx_module_t *module, char **order);
+
+
 extern ngx_module_t  *ngx_modules[];
 extern ngx_uint_t     ngx_max_module;
 
+extern char          *ngx_module_names[];
+
 
 #endif /* _NGX_MODULE_H_INCLUDED_ */