Кросс-компиляция 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/sizeof2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/types/sizeof2022-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/endianness2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/endianness2022-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/name2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/cc/name2022-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/feature2021-11-16 17:44:02.000000000 +0300 +++ nginx-1.20.2/auto/feature2022-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.pro/platform/branches/radix-1.8 

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

NO_CCACHE=1 make 

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

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

Мы постарались максимально использовать возможности NGINX для создания простого HTTP-сервера. Вы можете задать другие настройки, например отключив использование Legacy библиотеки GeoIP и/или ассинхронных файловых операций (—with-file-aio), о нюансах которых, в системе на базе ядра Linux, можно почитать в статье Делаем асинхронность асинхронной, разбираемся в планировщике Go, ругаем Linux.


ссылка на оригинал статьи https://habr.com/ru/post/651213/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *