summaryrefslogtreecommitdiff
path: root/eclass/nginx-module.eclass
diff options
context:
space:
mode:
Diffstat (limited to 'eclass/nginx-module.eclass')
-rw-r--r--eclass/nginx-module.eclass809
1 files changed, 809 insertions, 0 deletions
diff --git a/eclass/nginx-module.eclass b/eclass/nginx-module.eclass
new file mode 100644
index 000000000000..55fa58e52133
--- /dev/null
+++ b/eclass/nginx-module.eclass
@@ -0,0 +1,809 @@
+# Copyright 1999-2025 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: nginx-module.eclass
+# @MAINTAINER:
+# Zurab Kvachadze <zurabid2016@gmail.com>
+# @AUTHOR:
+# Zurab Kvachadze <zurabid2016@gmail.com>
+# @SUPPORTED_EAPIS: 8
+# @BLURB: Provides a common set of functions for building NGINX's dynamic modules
+# @DESCRIPTION:
+# The nginx-module.eclass automates configuring, building and installing NGINX's
+# dynamic modules. Using this eclass is as simple as calling 'inherit nginx-module'.
+# This eclass automatically adds dependencies on www-servers/nginx. Henceforth,
+# the terms 'package' and 'module' will be used interchangeably to refer to a
+# consumer of nginx-module.eclass.
+#
+# If a part of package's functionality depends on NGINX configuration (e.g. HMAC
+# generation support depending on http_ssl module being present), the
+# corresponding module's 'config' code should be changed so that the functionality
+# in question is either (1) unconditionally enabled/disabled or (2) can be
+# toggled with a USE flag. That is, an ebuild author should deduce whether a
+# package actually depends on a particular module or on the underlying
+# libraries/APIs. In the example HMAC case, the module actually requires
+# libcrypto, not the http_ssl module, so the ebuild code reflects this by
+# patching the module's 'config' file and depending on dev-libs/openssl directly
+# using the ngx_mod_append_libs() function.
+#
+# If the module makes use of the ngx_devel_kit (NDK) or any other NGINX
+# module, there are two approaches.
+#
+# If these dependencies are not USE-conditional ones, they should be specified
+# in the NGINX_MOD_LINK_MODULES array before inheriting the eclass. This way,
+# the dependencies added to {,R}DEPEND variables. Additionally, the package is
+# linked to shared objects of the specified dependencies. See the variable
+# description for details.
+#
+# If the dependencies are USE-conditional, they should be specified as
+# usual in the relevant *DEPEND variable(s). Then, before
+# nginx-module_src_configure() is called, the dependencies should be linked to by
+# calling the ngx_mod_link_module() function. See the function description for
+# more information.
+#
+# nginx-module.eclass also supports tests provided by the Test::Nginx Perl
+# module. To enable them, set NGINX_MOD_OPENRESTY_TESTS to a non-empty value
+# prior to inheriting the eclass and, if necessary, populate the
+# NGINX_MOD_TEST_LOAD_ORDER variable. All the packages specified in
+# NGINX_MOD_TEST_LOAD_ORDER are added to BDEPEND.
+#
+# The code below presents one of the ways the nginx-module.eclass might be used.
+#
+# Example usage:
+# @CODE
+# # This module depends on ngx_devel_kit and ngx-lua-module.
+# NGINX_MOD_LINK_MODULES=(
+# www-nginx/ngx_devel_kit www-nginx/ngx-lua-module
+# )
+#
+# # Tests utilise Test::Nginx.
+# NGINX_MOD_OPENRESTY_TESTS=1
+# # We require ngx-lua-module and ngx-echo for tests, but ngx-echo should
+# # be loaded first. Otherwise, some tests break.
+# NGINX_MOD_TEST_LOAD_ORDER=(
+# www-nginx/ngx-echo
+# www-nginx/ngx-lua-module
+# )
+# inherit nginx-module
+#
+# IUSE="iconv"
+#
+# DEPEND="iconv? ( www-nginx/ngx-iconv )"
+# RDEPEND="${DEPEND}"
+#
+# src_configure() {
+# if use iconv; Then
+# ngx_mod_link_module "www-nginx/ngx-iconv"
+# ...
+# fi
+#
+# nginx-module_src_configure
+# }
+# @CODE
+
+case ${EAPI} in
+ 8) ;;
+ *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+if [[ -z ${_NGINX_MODULE_ECLASS} ]]; then
+_NGINX_MODULE_ECLASS=1
+
+inherit edo flag-o-matic toolchain-funcs
+
+#-----> Generic helper functions <-----
+
+# @FUNCTION: econf_ngx
+# @USAGE: [<args>...]
+# @DESCRIPTION:
+# Call ./configure, passing the supplied arguments.
+# The NGINX's build system consists of many helper scripts, which are executed
+# relative to the working directory. Therefore, the function only supports
+# executing the configure script from the current working directory. This
+# function also checks whether the script is executable. If any of the above
+# conditions are not satisfied, the function aborts the build process with
+# 'die'. It also fails if the script itself exits with a non-zero exit code,
+# unless the function is called with 'nonfatal'.
+# If running ./configure is required, this function should be called.
+econf_ngx() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ [[ ! -x ./configure ]] &&
+ die "./configure is not present in the current working directory or is not executable"
+ nonfatal edo ./configure "$@"
+ # For some reason, NGINX's ./configure returns 1 if it is used with the
+ # '--help' argument.
+ if [[ $? -ne 0 && "$1" != --help ]]; then
+ die -n "./configure ${*@Q} failed"
+ fi
+}
+
+# @FUNCTION: ngx_mod_pkg_to_sonames
+# @USAGE: <package name>
+# @RETURN: Null-delimited list of basenames of shared objects corresponding to the supplied package.
+# @DESCRIPTION:
+# Takes one argument and prints a null-delimited list of basenames of shared
+# objects corresponding to the supplied package.
+#
+# The mapping between a package and shared objects goes as follows.
+#
+# 1. The package is stripped of category, yielding a plain
+# package name.
+#
+# 2. The plain package name is then used to lookup into the internal
+# associative array NGX_MOD_TO_SONAME. If the lookup fails, the build is
+# aborted with 'die'. 'nonfatal' might be used to make the error to find
+# shared objects non-fatal.
+#
+# 3. The obtained shared objects are printed to the stdout as a
+# null-delimited list.
+#
+# Example usage:
+# @CODE
+# # Obtain shared objects provided by www-nginx/ngx-lua-module.
+# mypkg=www-nginx/ngx-lua-module
+# mapfile -d '' lua-sonames < <(ngx_mod_pkg_to_sonames "${mypkg}")
+# @CODE
+ngx_mod_pkg_to_sonames() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ [[ $# -ne 1 ]] && die "${FUNCNAME[0]} must receive exactly one argument"
+
+ local pkg="$1"
+ local dep_sonames
+
+ # Strip '${CATEGORY}/' from '${CATEGORY}/${PN}'.
+ local entry="${pkg#*/}"
+
+ # Obtain the name of the shared object of the package with PN '${entry}' by
+ # looking at the corresponding subscript of the NGX_MOD_TO_SONAME array.
+ #
+ # For example, entry=ngx-lua-module yields
+ # entry="${NGX_MOD_TO_SONAME[ngx-lua-module]}"
+ # which yields
+ # entry="ngx_http_lua_module"
+ entry="${NGX_MOD_TO_SONAME[${entry}]}"
+ [[ -z ${entry} ]] &&
+ die -n "No shared objects found for the dependency ${pkg}. Please file a bug"
+
+ # Read comma-separated shared object names into the 'dep_sonames' array.
+ IFS=, read -ra dep_sonames <<< "${entry}"
+ # Append '.so' to the end of each array member.
+ dep_sonames=( "${dep_sonames[@]/%/.so}" )
+
+ # Print null-delimited list of shared objects' basenames to stdout.
+ printf "%s\0" "${dep_sonames[@]}"
+}
+
+# @FUNCTION: ngx_mod_append_libs
+# @USAGE: [<linker flags>...]
+# @DESCRIPTION:
+# Adds the passed arguments to the list of flags used for the linking the
+# module's shared objects. Flags may be of any form accepted by linker.
+# See the nginx_src_install() function in nginx.eclass for more details.
+#
+# This function has no effect after nginx-module_src_configure() has been
+# called.
+#
+# Example usage:
+# @CODE
+# ngx_mod_append_libs "-L/usr/$(get_libdir)/nginx/modules" \
+# "$("$(tc-getPKG_CONFIG)" --libs luajit)"
+# @CODE
+ngx_mod_append_libs() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ [[ $# -eq 0 ]] && return 0
+
+ export _NGINX_GENTOO_MOD_LIBS="${_NGINX_GENTOO_MOD_LIBS} $*"
+}
+
+# @FUNCTION: ngx_mod_setup_link_modules
+# @DESCRIPTION:
+# Adds necessary linker arguments for linking to other NGINX modules' share
+# objects installed in /usr/$(get_libdir)/nginx/modules by calling
+# ngx_mod_append_libs(). This function takes no arguments.
+#
+# This function is called internally by the ngx_mod_link_module() function.
+# ngx_mod_setup_link_modules() keeps track whether it has already been called,
+# doing nothing if it is called again after the first execution.
+ngx_mod_setup_link_modules() {
+ debug-print-function "${FUNCNAME[0]}"
+
+ # Check whether this function has already been called.
+ [[ -n ${_NGX_MOD_SETUP_LINK_CALLED} ]] && return 0
+ declare -g -r _NGX_MOD_SETUP_LINK_CALLED=1
+
+ local moddir
+ moddir="${EPREFIX}/usr/$(get_libdir)/nginx/modules"
+ # Add 'moddir' to the list of directories search by linker.
+ ngx_mod_append_libs "-L${moddir}"
+
+ # The string passed to ngx_mod_append_libs undergoes the following
+ # transformations by NGINX build system (the str variable denotes the
+ # original string and 'modname' represents the name of the current module):
+ # 0. Given the value of 'str':
+ # $ echo "${str}"
+ # -Wl,-rpath,'\''\$\${ORIGIN}'\''
+ #
+ # 1. In auto/module, line 93:
+ # eval ${modname}_libs=\'$str\'.
+ # yields
+ # modname_libs='-Wl,-rpath,'\''\$\${ORIGIN}'\'''
+ # which can be logically separated into
+ # (a) '-Wl,-rpath,'
+ # ^
+ # |
+ # The first original single quote (\'$str\')
+ # ^
+ # |
+ # This one
+ # (b) \' (backslash-escaped semicolon)
+ # (c) '\$\${ORIGIN}'
+ # (d) \'
+ # (e) ''
+ # ^
+ # |
+ # The last original single quote (\'$str\')
+ # ^
+ # |
+ # This one
+ # To preserve the string we add literal ' and \' so that the
+ # ORIGIN part does not get expanded.
+ # - (a) expands to
+ # -Wl,-rpath
+ # - (b) expands to
+ # '
+ # - (c) expands to
+ # \$\${ORIGIN}
+ # - (d) expands to
+ # '
+ # - (e) expands to nothing
+ # Thus, after evaluating, the value of modname_libs is the
+ # following.
+ # $ echo "${modname_libs}"
+ # -Wl,-rpath,'\$\${ORIGIN}'
+ #
+ # 2. In auto/make, line 507:
+ # eval eval ngx_module_libs="\\\"\$${modname}_libs\\\"".
+ # The expansion of parameters and double quotes produces the
+ # following.
+ # \"$modname_libs\"
+ # The first outermost eval obtains the contents of the
+ # ${modname}_libs variable and encloses them in double quotes,
+ # yielding:
+ # eval ngx_module_libs="-Wl,-rpath,'\$\${ORIGIN}'"
+ # The second innermost eval expands the double-quoted string,
+ # produced by the first eval, stripping backslashes from '$'. The
+ # value of 'ngx_module_libs' is therefore:
+ # $ echo "${ngx_module_libs}"
+ # -Wl,-rpath,'$${ORIGIN}'
+ #
+ # 3. ngx_module_libs's contents are added to the Makefile. make
+ # expands $var variable references, double dollar is used to
+ # suppress the expanding. Thus, the following is passed to the
+ # shell:
+ # -Wl,-rpath,'${ORIGIN}'
+ #
+ # 4. Finally, shell expands the single quotes, yielding literal:
+ # -Wl,-rpath,${ORIGIN}
+ ngx_mod_append_libs "-Wl,-rpath,'\''"'\$\${ORIGIN}'"'\''"
+}
+
+# @FUNCTION: ngx_mod_link_module
+# @USAGE: <package name>
+# @DESCRIPTION:
+# Add the required linker flags to link to the shared objects provided by the
+# package passed as the argument. This function automatically calls
+# ngx_mod_setup_link_modules(), if it has not been called. If the specified
+# package provides more than one shared object, all of the shared objects are
+# linked to. As ngx_mod_append_libs(), this function has no effect after
+# nginx-module_src_configure has been called.
+#
+# This function uses the ngx_mod_pkg_to_sonames() function under the hood to map
+# package names to shared objects. If there are no predefined mappings for the
+# selected package, the NGX_MOD_TO_SONAME associative array may be changed
+# manually, as presented in the following code excerpt.
+#
+# @CODE
+# NGX_MOD_TO_SONAME+=(
+# [www-nginx/ngx-pkg-name]="the_corresponding_soname_without_dot_so_suffix"
+# )
+# @CODE
+#
+# See the default value of NGX_MOD_TO_SONAME for examples.
+#
+# This function might be used to implement USE-conditional dependency on another
+# NGINX module. See the code snipped below for an example of such usage.
+#
+# Example usage:
+# @CODE
+# inherit nginx-module
+#
+# DEPEND="iconv? ( www-nginx/ngx-iconv )"
+# RDEPEND="${DEPEND}"
+#
+# src_configure() {
+# if use iconv; then
+# ngx_mod_link_module "www-nginx/ngx-iconv"
+# ...
+# fi
+#
+# nginx-module_src_configure
+# }
+# @CODE
+ngx_mod_link_module() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ [[ $# -ne 1 ]] && die "${FUNCNAME[0]} must receive exactly one argument"
+
+ [[ -z ${_NGX_MOD_SETUP_LINK_CALLED} ]] && ngx_mod_setup_link_modules
+
+ # Obtain the shared objects names of the module we want to link to (yes,
+ # there might be more than one shared object for a given NGINX module).
+ local -a sonames
+ mapfile -d '' sonames < <(ngx_mod_pkg_to_sonames "$1")
+
+ # Prepend '-l:' to each shared object name. The colon instructs the linker
+ # to link to the given name literally; i.e. '-lmylib' will look for
+ # 'libmylib.so', while '-l:mylib' will look for 'mylib'.
+ ngx_mod_append_libs "${sonames[@]/#/-l:}"
+}
+
+#-----> ebuild-defined variables <-----
+
+# @ECLASS_VARIABLE: NGINX_MOD_S
+# @DESCRIPTION:
+# Holds the path to the module sources directory, used in the
+# nginx-module_src_configure() phase function. If unset at the time of inherit,
+# defaults to ${S}.
+: "${NGINX_MOD_S=${S}}"
+
+# The ${S} variable is set to the path of the directory where the actual build
+# will be performed. In this directory, symbolic links to NGINX's build system
+# and NGINX's headers are created by the nginx-module_src_unpack() phase
+# function.
+S="${WORKDIR}/nginx"
+
+# @ECLASS_VARIABLE: NGINX_MOD_SHARED_OBJECTS
+# @OUTPUT_VARIABLE
+# @DESCRIPTION:
+# An array containing the basenames of all compiled shared objects (with the
+# extension ".so"). For some modules, may consist of more than one shared
+# object.
+#
+# This variable is set in the nginx-module_src_compile() function. Its contents
+# are undefined before that.
+#
+# Example value:
+# @CODE
+# ngx_http_lua_module.so
+# @CODE
+
+# @ECLASS_VARIABLE: NGX_MOD_TO_SONAME
+# @DESCRIPTION:
+# An associative array that maps NGINX module package names to their shared
+# object names. For example, 'ngx-lua-module' is mapped to
+# 'ngx_http_lua_module'. The shared objects are specified without the '.so'
+# suffix. May be changed/appended to at any time by an ebuild to override/add
+# shared object mappings.
+declare -g -A NGX_MOD_TO_SONAME+=(
+ [ngx_devel_kit]=ndk_http_module
+ [ngx-lua-module]=ngx_http_lua_module
+ [ngx-xss]=ngx_http_xss_filter_module
+ [ngx-echo]=ngx_http_echo_module
+ [ngx-memc]=ngx_http_memc_module
+ [ngx-eval]=ngx_http_eval_module
+ [ngx-set-misc]=ngx_http_set_misc_module
+ [ngx-headers-more]=ngx_http_headers_more_filter_module
+ [ngx-iconv]=ngx_http_iconv_module
+ [ngx-srcache]=ngx_http_srcache_filter_module
+ [ngx-lua-upstream]=ngx_http_lua_upstream_module
+)
+
+# @ECLASS_VARIABLE: NGINX_MOD_LINK_MODULES
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Set to package names of the NGINX module dependencies of this module. This
+# array must be set prior to inheriting the eclass.
+#
+# All the modules specified in this array are added to DEPEND and RDEPEND. This
+# might be disabled by setting NGINX_MOD_OVERRIDE_LINK_DEPEND to a non-empty
+# value. Additionally, the listed modules are added to the NEEDED sections of
+# the current module's shared objects, i.e. the current module is dynamically
+# linked to the shared objects corresponding to packages specified in
+# NGINX_MOD_LINK_MODULES.
+#
+# Each element of the array specifies a dependency of an ebuild. An entry
+# consists of a category followed by a package name: ${CATEGORY}/${PN}.
+#
+# To determine the shared object corresponding to an entry, the eclass looks up
+# the respective mapping, specified in the NGX_MOD_TO_SONAME array (see the
+# array description for more information). If no match is found, the build is
+# aborted with 'die'.
+#
+# Example usage:
+# @CODE
+# # This module depends on both NDK and ngx-lua-module.
+# NGINX_MOD_LINK_MODULES=(
+# www-nginx/ngx_devel_kit
+# www-nginx/ngx-lua-module
+# )
+# inherit nginx-module
+# @CODE
+
+# @ECLASS_VARIABLE: NGINX_MOD_OVERRIDE_LINK_DEPEND
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Set to a non-empty value prior to inheriting the eclass so that the modules
+# listed in NGINX_MOD_LINK_MODULES are not automatically added to DEPEND and
+# RDEPEND.
+
+# @ECLASS_VARIABLE: NGINX_MOD_OPENRESTY_TESTS
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Set to non-empty value to enable prior to inheriting the eclass to enable the
+# tests via the Test::Nginx (dev-perl/Test-Nginx) testing scaffold. See the
+# description of the NGINX_MOD_TEST_LOAD_ORDER variable for more details.
+
+# @ECLASS_VARIABLE: NGINX_MOD_TEST_DIR
+# @DESCRIPTION:
+# Set to directory containing tests relative to NGINX_MOD_S. If
+# NGINX_MOD_OPENRESTY_TESTS is not set, has no effect. Defaults to "t".
+: "${NGINX_MOD_TEST_DIR:=t}"
+
+# @ECLASS_VARIABLE: NGINX_MOD_TEST_LOAD_ORDER
+# @PRE_INHERIT
+# @DESCRIPTION:
+# If NGINX_MOD_OPENRESTY_TESTS is set to a non-empty value, this array specifies
+# simultaneously the test dependencies of the current module and, since NGINX is
+# sensitive to the order of module loading, their load order. As a special
+# workaround, the current module could also be specified as an entry in order to
+# force a specific load order. If the current module is not listed in this
+# array, it is loaded first, before its test dependencies.
+#
+# All the modules specified in this array, barring the current module, are added
+# to test BDEPEND. This behaviour may be disabled by setting the
+# NGINX_MOD_OVERRIDE_TEST_BDEPEND variable to a non-empty value.
+#
+# The format of each entry is the same as in the NGINX_MOD_LINK_MODULES
+# variable. See its description for details.
+#
+# The shared object names obtained from each entry are then used to populate the
+# TEST_NGINX_LOAD_MODULES environment variable. TEST_NGINX_LOAD_MODULES
+# instructs Test::Nginx in what order and which shared objects should be loaded
+# during tests.
+#
+# This array must be set prior to inheriting the eclass. If
+# NGINX_MOD_OPENRESTY_TESTS is not set, this variable has no effect.
+#
+# Example:
+# @CODE
+# NGINX_MOD_OPENRESTY_TESTS=1
+# NGINX_MOD_TEST_LOAD_ORDER=(
+# www-nginx/ngx-lua-module www-nginx/ngx-eval
+# www-nginx/{my-cool-module,my-another-module}
+# )
+# @CODE
+
+# @ECLASS_VARIABLE: NGINX_MOD_OVERRIDE_TEST_BDEPEND
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Set to a non-empty value prior to inheriting the eclass so that the modules
+# listed in NGINX_MOD_TEST_LOAD_ORDER are not automatically added to BDEPEND.
+# Has no effect if either NGINX_MOD_OPENRESTY_TESTS or NGINX_MOD_TEST_LOAD_ORDER
+# are not set.
+
+#-----> *DEPEND stuff <-----
+
+# As per upstream documentation, modules must be rebuilt with each NGINX
+# upgrade.
+DEPEND="
+ www-servers/nginx:=[modules(-)]
+"
+BDEPEND="${DEPEND}"
+RDEPEND="${DEPEND}"
+
+if [[ -z ${NGINX_MOD_OVERRIDE_LINK_DEPEND} &&
+ ${#NGINX_MOD_LINK_MODULES[@]} -gt 0 ]];
+then
+ DEPEND+=" ${NGINX_MOD_LINK_MODULES[*]}"
+ RDEPEND+=" ${NGINX_MOD_LINK_MODULES[*]}"
+fi
+
+#-----> Tests setup <-----
+
+# @FUNCTION: _ngx_mod_set_test_env
+# @INTERNAL
+# @DESCRIPTION:
+# Sets global variables like IUSE and BDEPEND for tests.
+_ngx_mod_set_test_env() {
+ IUSE="test"
+ RESTRICT="!test? ( test )"
+ BDEPEND+=" test? (
+ dev-perl/Test-Nginx
+ virtual/perl-Test-Harness
+ )
+ "
+
+ if [[ -z ${NGINX_MOD_OVERRIDE_TEST_BDEPEND} &&
+ ${#NGINX_MOD_TEST_LOAD_ORDER[@]} -gt 0 ]];
+ then
+ local entry
+ local -a moddep=
+ for entry in "${NGINX_MOD_TEST_LOAD_ORDER[@]}"; do
+ # If the current entry is equal to the current package, do not add
+ # it to BDEPEND.
+ [[ ${entry} == "${CATEGORY}/${PN}" ]] && continue
+
+ moddep+=( "${entry}" )
+ done
+ if [[ ${#moddep[@]} -gt 0 ]]; then
+ BDEPEND+="
+ test? (
+ ${moddep[*]}
+ )
+ "
+ fi
+ fi
+}
+
+[[ -n ${NGINX_MOD_OPENRESTY_TESTS} ]] && _ngx_mod_set_test_env
+
+unset -f _ngx_mod_set_test_env
+
+#-----> Phase functions <-----
+
+# @FUNCTION: nginx-module_src_unpack
+# @DESCRIPTION:
+# Unpacks the sources and sets up the build directory in S=${WORKDIR}/nginx.
+# Creates the following symbolic links (to not copy the files over):
+# - '${S}/src' -> '/usr/include/nginx',
+# - '${S}/auto' -> '/usr/src/nginx/auto',
+# - '${S}/configure' -> '/usr/src/nginx/configure'.
+# For additional information, see the nginx.eclass source, namely the
+# nginx_src_install() function.
+nginx-module_src_unpack() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ default_src_unpack
+ mkdir nginx || die "mkdir failed"
+ ln -s "${BROOT}/usr/src/nginx/configure" nginx/configure || die "ln failed"
+ ln -s "${BROOT}/usr/src/nginx/auto" nginx/auto || die "ln failed"
+ ln -s "${ESYSROOT}/usr/include/nginx" nginx/src || die "ln failed"
+}
+
+# @FUNCTION: nginx-module_src_prepare
+# @DESCRIPTION:
+# Patches module's initialisation code so that any module's preprocessor
+# definitions appear in the separate '__ngx_gentoo_mod_config.h' file inside the
+# 'build' directory. This function also makes module's "config" script clear
+# whatever content build/ngx_auto_config.h may have at the time of invocation.
+# Then, default_src_prepare() is called.
+nginx-module_src_prepare() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ pushd "${NGINX_MOD_S}" >/dev/null || die "pushd failed"
+ # Since NGINX does not guarantee ABI or API stability, we utilise
+ # preprocessor macros that were used to compile NGINX itself, to build third
+ # party modules. As such, we do not want for the dummy preprocessor macros
+ # produced by NGINX build system during module compilation to leak into the
+ # building environment. However, we do need to "capture" preprocessor macros
+ # set by the module itself, so we are required to somehow get these
+ # separately.
+ #
+ # To achieve that, the following sed script inserts ': >
+ # build/ngx_auto_config.h' line at the start of a module's 'config' shell
+ # script which gets sourced by NGINX build system midway during
+ # configuration. It has an effect of truncating the file containing NGINX
+ # preprocessor macros. This results in the file containing only module's
+ # macros at the end of the module's configuration.
+ #
+ # The following command renames the file with module's preprocessor macros
+ # to __ngx_gentoo_mod_config.h to be later merged with the system NGINX
+ # header into the actual header used during compilation. Due to the fact
+ # that executing the config shell script is not the last thing that NGINX
+ # build system does during configuration, we can not simply rename the
+ # header after the whole configuration, as it may contain other preprocessor
+ # macros than only the module's ones.
+ sed -i -e '1i\' -e ': > build/ngx_auto_config.h' config ||
+ die "sed failed"
+ echo 'mv build/ngx_auto_config.h build/__ngx_gentoo_mod_config.h' \
+ >> config || die "echo failed"
+ default_src_prepare
+ popd >/dev/null || die "popd failed"
+}
+
+# @FUNCTION: nginx-module_src_configure
+# @DESCRIPTION:
+# Configures the dynamic module by calling NGINX's ./configure script.
+# Custom flags can be supplied as arguments to the function, taking precedence
+# over eclass's flags.
+# This assembles ngx_auto_config.h from the system ngx_auto_config.h and
+# __ngx_gentoo_mod_config.h (see nginx-module_src_prepare()), and
+# ngx_auto_headers.h from the system ngx_auto_headers.h.
+# Also, sets environment variables and appends necessary libraries if
+# NGINX_MOD_LINK_MODULES is set.
+nginx-module_src_configure() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ local ngx_mod_flags
+ ngx_mod_flags=(
+ --with-cc="$(tc-getCC)"
+ --with-cpp="$(tc-getCPP)"
+ # The '-isystem' flag is used instead of '-I', so as for the installed
+ # (system) modules' headers to be of lower priority than the headers of
+ # the currently built module. This only affects the modules that both
+ # come with and install their own headers, e.g. ngx_devel_kit.
+ --with-cc-opt="-isystem src/modules"
+ --with-ld-opt="${LDFLAGS}"
+ --builddir=build
+ --add-dynamic-module="${NGINX_MOD_S}"
+ )
+
+ # NGINX build system adds directories under src/ to the include path based
+ # on the specified configuration flags. Since nginx.eclass does not
+ # save/restore the configuration flags, we have to add the directories to
+ # the include path manually.
+ # The src/os is added automatically by the auto/unix script and the
+ # src/modules directory is included by the '--with-cc-opt' configuration
+ # flag.
+ append-cflags "$(find -H src -mindepth 1 -type d \! \( \( -path 'src/os' -o \
+ -path 'src/modules' \) -prune \) -printf '-I %p ')"
+
+ # Some NGINX modules that depend on ngx_devel_kit (NDK) check whether the
+ # NDK_SRCS variable is non-empty and error out if it is empty or not
+ # defined. ngx_devel_kit sets this variable during its build but due to the
+ # fact that we build modules separately, i.e. the dependant module is not
+ # build alongside NDK, the variable is not exported in the environment and
+ # the module halts the build.
+ #
+ # For all the modules that I have seen, the ones that inspect this variable
+ # only check whether NDK_SRCS is non-empty, they do not compare its contents
+ # nor alter the variable in any way. Therefore, setting NDK_SRCS to a dummy
+ # value works around the build failures for the plugins that do check the
+ # variable and, subsequently, has no effect on the modules that do not
+ # depend on NDK at all or do not check the variable.
+ #
+ # This variable is mainly checked by modules developed by OpenResty.
+ export NDK_SRCS="ndk.c"
+
+ # Add the required linking flags required for the modules specified in the
+ # NGINX_MOD_LINK_MODULES array.
+ if [[ ${#NGINX_MOD_LINK_MODULES[@]} -gt 0 ]]; then
+ local mod
+ for mod in "${NGINX_MOD_LINK_MODULES[@]}"; do
+ ngx_mod_link_module "${mod}"
+ done
+ fi
+
+ eval "local -a EXTRA_ECONF=( ${EXTRA_ECONF} )"
+
+ # Setting the required environment variable to skip the unnecessary
+ # execution of certain scripts (see nginx_src_install() in nginx.eclass).
+ _NGINX_GENTOO_SKIP_PHASES=1 econf_ngx \
+ "${ngx_mod_flags[@]}" \
+ "$@" \
+ "${EXTRA_ECONF[@]}"
+
+ cat "${ESYSROOT}/usr/include/nginx/ngx_auto_config.h" \
+ build/__ngx_gentoo_mod_config.h > build/ngx_auto_config.h ||
+ die "cat failed"
+ cp "${ESYSROOT}/usr/include/nginx/ngx_auto_headers.h" build ||
+ die "cp failed"
+}
+
+# @FUNCTION: nginx-module_src_compile
+# @DESCRIPTION:
+# Compiles the module(s) by calling "make modules" and fills the
+# NGINX_MOD_SHARED_OBJECTS array.
+nginx-module_src_compile() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ emake modules
+ # Save the basenames of all the compiled modules into the
+ # NGINX_MOD_SHARED_OBJECTS array.
+ mapfile -d '' NGINX_MOD_SHARED_OBJECTS < \
+ <(find -H "${S}/build" -maxdepth 1 -type f -name '*.so' -printf '%P\0')
+}
+
+# @FUNCTION: nginx-module_src_test
+# @DESCRIPTION:
+# If NGINX_MOD_OPENRESTY_TESTS is set to a non-empty value, tests the compiled
+# module using Test::Nginx (dev-perl/Test-Nginx).
+nginx-module_src_test() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ [[ -z ${NGINX_MOD_OPENRESTY_TESTS} ]] && return 0
+
+ # The TEST_NGINX_LOAD_MODULES variable holds the space-separated paths of
+ # modules that should be loaded during testing. The variable is set (in
+ # order) to the shared object names of the built modules and, then, to
+ # shared objects of the dependant modules. Doing this the other way around
+ # introduces some test failures for modules like ngx-eval.
+ local -x TEST_NGINX_LOAD_MODULES=
+ local -a dep_sonames pkg_sonames
+ local cur_pkg_in_load_order=
+
+ # The system module directory.
+ local moddir
+ moddir="${BROOT}/usr/$(get_libdir)/nginx/modules"
+
+ [[ ${#NGINX_MOD_SHARED_OBJECTS[@]} -eq 0 ]] &&
+ die "No shared objects found for the currently built module"
+ # Prepend each member of the NGINX_MOD_SHARED_OBJECTS array with
+ # '${S}/build/' and save the array into pkg_sonames.
+ pkg_sonames=( "${NGINX_MOD_SHARED_OBJECTS[@]/#/${S}/build/}" )
+
+ local pkg
+ for pkg in "${NGINX_MOD_TEST_LOAD_ORDER[@]}"; do
+ # If the entry is the current package, use the shared objects saved in
+ # '${pkg_sonames[@]}' and set the 'cur_pkg_in_load_order' variable.
+ if [[ ${pkg} == "${CATEGORY}/${PN}" ]]; then
+ TEST_NGINX_LOAD_MODULES+=" ${pkg_sonames[*]}"
+ cur_pkg_in_load_order=1
+ continue
+ fi
+
+ # Save the shared objects names into the dep_sonames array.
+ mapfile -d '' dep_sonames < <(ngx_mod_pkg_to_sonames "${pkg}")
+
+ # Prepend each array member with '${moddir}/' (see above) to obtain the
+ # absolute path to the shared object.
+ dep_sonames=( "${dep_sonames[@]/#/${moddir}/}" )
+
+ # Add the shared objects' paths to the TEST_NGINX_LOAD_MODULES
+ # environment variable.
+ TEST_NGINX_LOAD_MODULES+=" ${dep_sonames[*]}"
+ done
+ unset pkg
+
+ # If the current package is not specified in NGINX_MOD_TEST_LOAD_ORDER, load
+ # it before its test dependencies.
+ if [[ -z ${cur_pkg_in_load_order} ]]; then
+ TEST_NGINX_LOAD_MODULES="${pkg_sonames[*]} ${TEST_NGINX_LOAD_MODULES}"
+ fi
+
+ pushd "${NGINX_MOD_S}" >/dev/null || die "pushd failed"
+
+ # If NGINX_MOD_LINK_MODULES is non-empty, meaning the current module is
+ # linked to another module in moddir, set LD_LIBRARY_PATH to the module's
+ # directory so that the dynamic loader can find shared objects we depend on.
+ [[ ${#NGINX_MOD_LINK_MODULES[@]} -gt 0 ]] &&
+ local -x LD_LIBRARY_PATH="${moddir}"
+
+ # Tests break when run in parallel.
+ TEST_NGINX_SERVROOT="${T}/servroot" \
+ edo prove -j1 -I. -r ./"${NGINX_MOD_TEST_DIR}"
+
+ popd >/dev/null || die "popd failed"
+}
+
+# @FUNCTION: nginx-module_src_install
+# @DESCRIPTION:
+# Installs the compiled module(s) into /usr/${libdir}/nginx/modules.
+nginx-module_src_install() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ insinto "/usr/$(get_libdir)/nginx/modules"
+ doins build/*.so
+}
+
+# @FUNCTION: nginx-module_pkg_postinst
+# @DESCRIPTION:
+# Shows the instructions on how to enable and use the just-compiled module.
+nginx-module_pkg_postinst() {
+ debug-print-function "${FUNCNAME[0]}" "$@"
+ # ngx_devel_kit is an SDK, it does not need to be enabled manually.
+ [[ ${PN} == ngx_devel_kit ]] && return 0
+
+ local mod
+
+ elog "${PN} has been compiled."
+ elog ""
+ elog "To utilise the module, add the following line(s) to your NGINX"
+ elog "configuration file, which by default is \"${EROOT}/etc/nginx/nginx.conf\"."
+ elog ""
+ for mod in "${NGINX_MOD_SHARED_OBJECTS[@]}"; do
+ elog " load_module modules/${mod};"
+ done
+}
+
+fi
+
+EXPORT_FUNCTIONS src_unpack src_prepare src_configure src_compile src_test \
+ src_install pkg_postinst