Кросс-компиляция NGINX (для случая GCC)

Кросс-компиляция NGINX (для случая GCC)

NGINX — это HTTP-сервер и обратный прокси-сервер, почтовый прокси-сервер, а также TCP/UDP прокси-сервер общего назначения, изначально написанный Игорем Сысоевым. Уже длительное время он обслуживает серверы многих высоконагруженных сайтов.

Однако кросс-компиляция NGINX практически невозможна, поскольку разработанные Игорем Сысоевым скрипты конфигурирования исходного кода в большинстве случаев используют так называемую процедуру «Try Run».

Те кто знаком с утилитами Autoconf, Automake знают, что проверки необходимых параметров системы и кросс-компилятора осуществляются различными процедурами, которые, в свою очередь, могут применять попытки сборки исходного кода (Try compile), линковки объектных файлов (Try link) и, наконец, попытки запуска тестовых программ (Try Run).

Естественно, если речь идет о кросс-сборке, операции «Try Run» недопустимы, ведь мы не можем запустить программу, собранную под целевую архитектуру отличающуюся от архитектуры машины сборки на самой машине сборки.

В Autotools проблемы, связанные с невозможностью запуска целевых программ на сборочной машине в некоторых случаях решаютcя кешированием переменных, которые могу быть переопределены пользователем в файле --cache-file или заданы в командной строке вызова скрипта ./configure.

Скрипты Игоря Сысоева не предусматривают такого переопределения машинно-зависимых величин. Однако величин, которые необходимо задать во время конфигурирования исходных кодов NGINX достаточно много. К ним, в первую очередь, относятся размеры типов данных. Именно с них мы и начнем.

Размеры переменных различных типов проверяются с помощью скрипта auto/types/sizeof. Тестовые процедуры возвращают размер в байтах и предаются с помощью переменной ngx_size. В случае использования gcc для вычисления основных размеров данных, мы можем воспользоваться предопределенными macro С-компилятора, входящего в поставку GCC. Если мы добавим в каталог auto/types скрипт gcc-sizeof:

#!/bin/sh if [ "x$NGX_CC_NAME" = "x" -o "x$ngx_type" = "x" ] ; then echo "unknown" fi if [ "$ngx_type" = "int" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_INT__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" elif [ "$ngx_type" = "long" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_LONG__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" elif [ "$ngx_type" = "long long" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_LONG_LONG__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" elif [ "$ngx_type" = "size_t" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_SIZE_T__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" elif [ "$ngx_type" = "sig_atomic_t" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_INT__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" elif [ "$ngx_type" = "void *" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_POINTER__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" elif [ "$ngx_type" = "off_t" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_PTRDIFF_T__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" elif [ "$ngx_type" = "time_t" ] ; then size_from_cpp=`${CC} -dM -E - < /dev/null | grep __SIZEOF_PTRDIFF_T__ | cut -f3 -d' ' | sed 's,^[ \t]*,,' | sed 's,[ \t]*$,,'` echo "$size_from_cpp" fi

и поправим скрипт auto/types/sizeof так, чтобы в случае GCC, для вычисления размеров вызывался скрипт auto/types/gcc-sizeof, то на данном этапе конфигурирования мы сможем обеспечить правильную работу без запуска тестовых исполняемых файлов:

diff -b --unified -Nr nginx-1.20.2-orig/auto/types/sizeof nginx-1.20.2/auto/types/sizeof --- nginx-1.20.2-orig/auto/types/sizeof 2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/types/sizeof 2022-02-13 19:50:26.816530942 +0300 @@ -14,7 +14,8 @@ ngx_size= -cat << END > $NGX_AUTOTEST.c +if [ "$NGX_CC_NAME" != "gcc" ] ; then + cat << END > $NGX_AUTOTEST.c #include <sys/types.h> #include <sys/time.h> @@ -33,18 +34,21 @@ END -ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ + ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" -eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" + eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" -if [ -x $NGX_AUTOTEST ]; then + if [ -x $NGX_AUTOTEST ]; then ngx_size=`$NGX_AUTOTEST` echo " $ngx_size bytes" + fi +else + ngx_size=`ngx_type="$ngx_type" . auto/types/gcc-sizeof` + echo " $ngx_size bytes" fi - case $ngx_size in 4) ngx_max_value=2147483647

Для проверки big/little endian мы также можем воспользоваться предопределенными macro, добавив собственный скрипт gcc-endianness в каталог auto:

#!/bin/sh if [ "x$NGX_CC_NAME" = "x" ] ; then exit 0 fi if `${CC} -dM -E - < /dev/null | grep " __BYTE_ORDER__ " | cut -f3 -d' ' | grep -q "_BIG_"` ; then exit 1 fi

и немного поправив оригинальный скрипт endianness:

diff -b --unified -Nr nginx-1.20.2-orig/auto/endianness nginx-1.20.2/auto/endianness --- nginx-1.20.2-orig/auto/endianness 2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/endianness 2022-02-13 19:50:26.816530942 +0300 @@ -13,7 +13,8 @@ END -cat << END > $NGX_AUTOTEST.c +if [ "$NGX_CC_NAME" != "gcc" ] ; then + cat << END > $NGX_AUTOTEST.c int main(void) { int i = 0x11223344; @@ -26,12 +27,12 @@ END -ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ + ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" -eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" + eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" -if [ -x $NGX_AUTOTEST ]; then + if [ -x $NGX_AUTOTEST ]; then if $NGX_AUTOTEST >/dev/null 2>&1; then echo " little endian" have=NGX_HAVE_LITTLE_ENDIAN . auto/have @@ -41,10 +42,18 @@ rm -rf $NGX_AUTOTEST* -else + else rm -rf $NGX_AUTOTEST* echo echo "$0: error: cannot detect system byte ordering" exit 1 + fi +else + if `. auto/gcc-endianness` ; then + echo " little endian" + have=NGX_HAVE_LITTLE_ENDIAN . auto/have + else + echo " big endian" + fi fi

Здесь надо учитывать то, что скрипт endianness ожидает нормального выхода из скрипта gcc-endianness в случае little-endian и аварийного завершения в случае big-endian.

Покончив с основными типами данных и ориентацией байтов, мы можем отменить проверку самого cross-компилятора, просто запретив выполнение тестовой процедуры в файле auto/cc/name:

diff -b --unified -Nr nginx-1.20.2-orig/auto/cc/name nginx-1.20.2/auto/cc/name --- nginx-1.20.2-orig/auto/cc/name 2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/cc/name 2022-02-13 19:50:26.816530942 +0300 @@ -7,7 +7,7 @@ ngx_feature="C compiler" ngx_feature_name= - ngx_feature_run=yes + ngx_feature_run= ngx_feature_incs= ngx_feature_path= ngx_feature_libs=

Однако это еще не все. Далее нам необходимо обеспечить проверки, осуществляемые с помощью скрипта auto/feature. Здесь вам будет необходимо, самостоятельно собрав и выполнив код некоторых тестовых программ, разобраться в том, какие из проверок вы сможете заменить на заготовленные вами ответы. Ответы передаются посредством переменной ngx_found. Если речь идет об обычном дистрибутиве на базе ядра Linux и GNU Libc, то вам будет достаточно следующих изменений файла auto/feature:

diff -b --unified -Nr nginx-1.20.2-orig/auto/feature nginx-1.20.2/auto/feature --- nginx-1.20.2-orig/auto/feature 2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/feature 2022-02-13 19:50:26.816530942 +0300 @@ -52,6 +52,85 @@ case "$ngx_feature_run" in yes) + + if [ "$ngx_feature_name" = "NGX_HAVE_GCC_ATOMIC" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_C99_VARIADIC_MACROS" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_GCC_VARIADIC_MACROS" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_EPOLL" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_SENDFILE" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_SENDFILE64" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_PR_SET_DUMPABLE" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_PR_SET_KEEPCAPS" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_MAP_ANON" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_MAP_DEVZERO" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + elif [ "$ngx_feature_name" = "NGX_HAVE_SYSVSHM" ] ; then + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + else # /bin/sh is used to intercept "Killed" or "Abort trap" messages if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then echo " found" @@ -64,6 +143,8 @@ else echo " found but is not working" fi + fi + ;; value)

Готовый patch для NGINX версии 1.20.2 можно получить следующим образом. Необходимо получить исходный код Radix cross Linux с помощью команды:

svn checkout svn://radix-linux.su/platform/branches/radix-1.9

Сменить каталог на radix-1.9/sources/packages/n/nginx и выполнить команду make:

NO_CCACHE=1 make

Таким образом вы получите исходный архив NGINX и необходимый для кросс-сборки patch в каталоге patches.

Весть процесс сборки NGINX можно видеть в каталоге radix-1.9/net/nginx/1.20.2. Здесь в Make-файле представлены основные параметры конфигурирования для различных архитектур.

Контакты:

Telegram: @rxlinux (Нажмите Leave a Comment под любым сообщением)

E-mail: Contact Us

Начать дискуссию