arm linux 移植 Nginx

--- title: arm linux 移植 Nginx date: 2020-06-22 08:04:19 categories: tags: - Linux - arm - nginx - porting ---

背景

Nginx 在一些基于web的嵌入式产品上能够使用,所以本人也介绍一下有关的支持。

本人的有关博客:《Windows 编译安装 nginx 服务器 + rtmp 模块》、《Ubuntu 编译安装 nginx》、《Arm-Linux 移植 Nginx
Host平台   :Ubuntu 16.04
Arm平台   :3531d

rcre     : 8.30

zlib     :1.2.11

openssl   : 1.0.2t

nginx    : 1.17.6 (本文完全适用于 1.15版本的 nginx)

arm-gcc   :4.9.4

注意:

  • 这个和以往的交叉编译不一样,nginx的交叉编译依赖的库都是源码包,而不是最终的结果。
  • 由于nginx在嵌入式下的支持不是很好,所以在配置编译之前,需要手动修改工程中的某些项目。

主机准备

##
#    Copyright By Schips, All Rights Reserved
#    https://gitee.com/schips/

#    File Name:  make.sh
#    Created  :  Fri 22 Nov 2019 11:49:30 AM CST

##
#!/bin/sh
BASE=`pwd`
BUILD_HOST=arm-linux
ZLIB=zlib-1.2.11
OPENSSL=openssl-1.0.2t
PCRE=pcre-8.30
NGINX=nginx-1.17.6
FIN_INSTALL=/usr/${NGINX}

make_dirs() {
    cd ${BASE}
    mkdir  compressed  install  source -p

}

tget () { #try wget
    filename=`basename $1`
    echo "Downloading [${filename}]..."
    if [ ! -f ${filename} ];then
        wget $1
    fi

    echo "[OK] Downloaded [${filename}] "
}

download_package () {
    cd ${BASE}/compressed
    #下载包
    tget https://www.zlib.net/${ZLIB}.tar.gz
    tget https://www.openssl.org/source/${OPENSSL}.tar.gz
    # 注意地址
    tget https://jaist.dl.sourceforge.net/project/pcre/pcre/8.30/${PCRE}.tar.bz2
    tget http://mirrors.sohu.com/nginx/${NGINX}.tar.gz
}

tar_package () {
    cd ${BASE}/compressed
    ls * > /tmp/list.txt
    for TAR in `cat /tmp/list.txt`
    do
        tar -xf $TAR -C  ../source
    done
    rm -rf /tmp/list.txt
}


pre_configure_nginx () {
    cd ${BASE}/source/${NGINX}
    # auto/cc/name
    sed -r -i "/ngx_feature_run=yes/ s/.*/\tngx_feature_run=no/g" auto/cc/name
    sed -r -i "/exit 1/ s/.*//1" auto/cc/name

    # auto/types/sizeof
    sed -r -i "/ngx_size=`$NGX_AUTOTEST`/ s/.*/\tngx_size=4/g" auto/types/sizeof
    #
    sed -r -i "/PCRE_CONF_OPT=/ s/.*/PCRE_CONF_OPT=--host=${BUILD_HOST}/g" auto/options
}


configure_nginx () {
    cd ${BASE}/source/${NGINX}
    BUILD=`pwd`
    ./configure \
    --builddir=${BUILD} \
    --prefix=${FIN_INSTALL} \
    --with-http_mp4_module \
    --with-http_ssl_module \
    --without-http_upstream_zone_module \
    --with-openssl-opt=os/compiler:${BUILD_HOST}-gcc \
    --with-cc=${BUILD_HOST}-gcc \
    --with-cpp=${BUILD_HOST}-g++ \
    --with-ld-opt=-lpthread \
    --with-cc-opt='-D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64' \
    --with-pcre=${BASE}/source/${PCRE} \
    --with-openssl=${BASE}/source/${OPENSSL} \
    --with-zlib=${BASE}/source/${ZLIB} \
    --with-http_v2_module && echo "${FIN_INSTALL} with ${BUILD_HOST}" > ccinfo
}

pre_make_nginx () {
    cd ${BASE}/source/${NGINX}

    # 屏蔽nginx 的configure信息
    HEAD_FILE=`find . -name "ngx_auto_config.h"`
    DEL_LINE=`sed -n "/NGX_CONFIGURE/="  ${HEAD_FILE}`
        sed -i "${DEL_LINE}d" ${HEAD_FILE}
    echo "#undef NGX_CONFIGURE " >> ${HEAD_FILE}
    echo "#define NGX_CONFIGURE \"./configure\"" >> ${HEAD_FILE}
    
    echo "#ifndef NGX_SYS_NERR" >> ${HEAD_FILE}
    echo "#define NGX_SYS_NERR 132" >> ${HEAD_FILE}
    echo "#endif" >> ${HEAD_FILE}

    echo "#ifndef NGX_HAVE_SYSVSHM" >> ${HEAD_FILE}
    echo "#define NGX_HAVE_SYSVSHM 1" >> ${HEAD_FILE}
    echo "#endif" >> ${HEAD_FILE}

    # 删除makefile 多余的几行

        DEL_LINE=`sed -n "/build\:/="  Makefile  | awk 'END {print}'`
    # 因为是有 2 行,删除以后文件会发生变化
        sed -i "${DEL_LINE}d" Makefile
        sed -i "${DEL_LINE}d" Makefile

        DEL_LINE=`sed -n "/install\:/="  Makefile  | awk 'END {print}'`
        sed -i "${DEL_LINE}d" Makefile
        sed -i "${DEL_LINE}d" Makefile

        DEL_LINE=`sed -n "/modules\:/="  Makefile  | awk 'END {print}'`
        sed -i "${DEL_LINE}d" Makefile
        sed -i "${DEL_LINE}d" Makefile

}

make_nginx () {
    cd ${BASE}/source/${NGINX}
    make -j4 && sudo make install && sudo mv ccinfo ${FIN_INSTALL}/ccinfo
    cp ${FIN_INSTALL} ${BASE}/install/ -vr
    sudo rm ${FIN_INSTALL} -r
}
sudo ls
make_dirs
download_package
tar_package
pre_configure_nginx
configure_nginx
pre_make_nginx
make_nginx

这样应该就没有什么问题了。

arm板子准备

整个目录 拷贝 到板子,具体以prefix指定的路径为准上

添加nginx有关库和运行路径环境变量

完成nginx.conf的配置…(此步骤省略)

/usr/nginx/sbin/nginx -c /usr/nginx/conf/nginx.conf -p usr/nginx #启动nginx

编译nginx时指定外部模块

第三方模块下载地址:https://www.nginx.com/resources/wiki/modules/index.html

使第三方模块的生效方法: ./configure --add-module=模块的路径

例如:

/configure --prefix=/usr/local/nginx-1.4.1 \  
 --with-http_stub_status_module \  
 --with-http_ssl_module --with-http_realip_module \  
 --with-http_image_filter_module \  
 --add-module=../ngx_pagespeed-master  

附录:移植NGINX的中间过程

为了让读者能够搞清楚脚本中各命令的意义,本人保留了下文,以作为手动修改的参考依据。

nginx根目录下, 执行此脚本,再一步步排查错误。

    cd ${BASE}/source/${NGINX}
    echo ${BASE}/source/${NGINX}
    BUILD=`pwd`
    ./configure \
    --builddir=${BUILD} \
    --prefix=${BASE}/install/nginx \
    --with-http_mp4_module \
    --with-http_ssl_module \
    --without-http_upstream_zone_module \
    --with-openssl-opt=os/compiler:${BUILD_HOST}-gcc \
    --with-cc=${BUILD_HOST}-gcc \
    --with-cpp=${BUILD_HOST}-g++ \
    --with-ld-opt=-lpthread \
    --with-cc-opt='-D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64' \
    --with-pcre=${BASE}/source/${PCRE} \
    --with-openssl=${BASE}/source/${OPENSSL} \
    --with-zlib=${BASE}/source/${ZLIB} \
    --with-http_v2_module

提示:

checking for OS
 + Linux 4.15.0-65-generic x86_64
checking for C compiler ... found but is not working

./configure: error: C compiler arm-hisiv500-linux-gcc is not found

make: *** No rule to make target 'build', needed by 'default'.  Stop.

解决方法:

 修改 auto/cc/name

   ngx_feature_run=yes 👉 ngx_feature_run=no

   exit 1 👉 删掉或者注释

再次运行

./configure: error: can not detect int size

解决方法:

 vi auto/types/sizeof
 ngx_test中的 $CC 👉 gcc
 ngx_size=`$NGX_AUTOTEST` 👉  ngx_size=4

配置通过以后, 就可以开始make

checking whether we are cross compiling... configure: error: in `nginx-1.15.2/pcre-8.30':
configure: error: cannot run C compiled programs.
If you meant to cross compile, use `--host'.
See `config.log' for more details
Makefile:1282: recipe for target 'pcre-8.30/Makefile' failed
make: *** [pcre-8.30/Makefile] Error 1

解决方法

vi auto/options
 根据情况改成自己的交叉编译工具链
PCRE_CONF_OPT= 👉 PCRE_CONF_OPT=-–host=arm-hisiv600-linux

修改以后重新运行 ./make.sh以后再 make

src/os/unix/ngx_errno.c: In function ‘ngx_strerror’:
src/os/unix/ngx_errno.c:37:31: error: ‘NGX_SYS_NERR’ undeclared (first use in this function)
     msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]:
                               ^
src/os/unix/ngx_errno.c:37:31: note: each undeclared identifier is reported only once for each function it appears in
src/os/unix/ngx_errno.c: In function ‘ngx_strerror_init’:
src/os/unix/ngx_errno.c:58:11: error: ‘NGX_SYS_NERR’ undeclared (first use in this function)
     len = NGX_SYS_NERR * sizeof(ngx_str_t);
           ^
Makefile:693: recipe for target '/home/schips/arm/nginx/source/nginx-1.15.2/src/os/unix/ngx_errno.o' failed
make: *** [/home/linkpi/arm/nginx/source/nginx-1.15.2/src/os/unix/ngx_errno.o] Error 1
解决方法: 
    添加以下3行到 ngx_auto_config.h 中 (根据有关的源码可知, 这个宏和操作系统识别的错误个数有关)
  # ngx_auto_config.h 文件的位置和 $OBJ 变量有关
  

    #ifndef NGX_SYS_NERR
    #define NGX_SYS_NERR 132
    #endif

  // 注意: NGX_SYS_NERR不是在src里面的,而是编译的时候根据操作系统的不同而生成的不内容
  // 为了稳定,我们参考host端的结果,使用132作为值。

继续make

nginx-1.15.2/src/core/ngx_cycle.o: In function `ngx_init_cycle':
nginx-1.15.2/src/core/ngx_cycle.c:476: undefined reference to `ngx_shm_alloc'
nginx-1.15.2/src/core/ngx_cycle.c:685: undefined reference to `ngx_shm_free'
nginx-1.15.2/src/event/ngx_event.o: In function `ngx_event_module_init':
nginx-1.15.2/src/event/ngx_event.c:546: undefined reference to `ngx_shm_alloc'
collect2: error: ld returned 1 exit status
Makefile:247: recipe for target 'nginx-1.15.2/nginx' failed
make: *** [nginx-1.15.2/nginx] Error 1

解决方法:

由于,ngx_shm_free ngx_shm_alloc 这几个函数被条件宏NGX_HAVE_MAP_ANON,NGX_HAVE_SYSVSHM NGX_HAVE_MAP_DEVZERO,
3者选1,而nginx 的交叉编译不够友好,所以需要我们手动添加。

找到 ngx_auto_config.h  

添加以下3行

#ifndef NGX_HAVE_SYSVSHM
#define NGX_HAVE_SYSVSHM 1
#endif

make出现死循环(每次配置以后都需要执行)

nginx-1.15.2/Makefile:1374: recipe for target 'build' failed
make[650]: *** [build] Interrupt
nginx-1.15.2/Makefile:1374: recipe for target 'build' failed
make[649]: *** [build] Interrupt
nginx-1.15.2/Makefile:1374: recipe for target 'build' failed
make[648]: *** [build] Interrupt
nginx-1.15.2/Makefile:1374: recipe for target 'build' failed
make[647]: *** [build] Interrupt
nginx-1.15.2/Makefile:1374: recipe for target 'build' failed
make[646]: *** [build] Interrupt

解决方法:

删除nginx根目录图中这几行(位于1377行左右)

   7 build:
   6     $(MAKE) -f /home/schips/arm/nginx/source/nginx-1.15.2/Makefile
   5
   4 install:
   3     $(MAKE) -f /home/schips/arm/nginx/source/nginx-1.15.2/Makefile install
   2
   1 modules:
1380     $(MAKE) -f /home/schips/arm/nginx/source/nginx-1.15.2/Makefile modules

再次编译:

由于每次配置(configure)会使ngx_auto_config.h重置。为了方便维护,我们将有关的改动做成脚本。

##
#    Copyright By Schips, All Rights Reserved
BUILD=.
./configure \
--builddir=${BUILD} \
--prefix='/home/schips/arm/nginx/install/nginx' \
--with-http_mp4_module \
--with-http_ssl_module \
--without-http_upstream_zone_module \
--with-pcre=./pcre-8.30 \
--with-openssl=./openssl-1.0.2t \
--with-zlib=./zlib-1.2.11 \
--with-cc=arm-hisiv500-linux-gcc \
--with-cpp=arm-hisiv500-linux-g++ \
--with-ld-opt=-lpthread \
--with-cc-opt='-D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64' \
--with-openssl-opt=os/compiler:arm-hisiv500-linux-gcc \
--with-http_v2_module || exit 1


echo "// schips add"               >> ngx_auto_config.h
echo "#ifndef NGX_SYS_NERR"        >> ngx_auto_config.h
echo "#define NGX_SYS_NERR 132"    >> ngx_auto_config.h
echo "#endif"                      >> ngx_auto_config.h
echo ""                            >> ngx_auto_config.h
echo "#ifndef NGX_HAVE_SYSVSHM"    >> ngx_auto_config.h
echo "#define NGX_HAVE_SYSVSHM 1"  >> ngx_auto_config.h
echo "#endif"                      >> ngx_auto_config.h
echo "Need edit Makefile" && exit 1
make CC=arm-hisiv500-linux-gcc
make install

使用已经编译好的 openssl库以加快编译速度(在本文中未启用)
--with-openssl 参数虽然可以指定 OpenSSL 路径,但只支持 OpenSSL 的源代码,不支持已编译好的 OpenSSL。

每回更新 nginx 都要重新编译 OpenSSL 肯定很麻烦,网上找到一个方案,觉得很好,记录下来。

1.1 首先使用交叉编译Openssl:

CC=arm-linux-gnueabi-gcc ./config no-asm shared --prefix=/app/my_lib

1.2 修改nginx的Mkaefile代码:

把
 31#CORE_INCS="$CORE_INCS $OPENSSL/.openssl/include"
 32#CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h"
 33#CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a"
 34#CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a"
 35#CORE_LIBS="$CORE_LIBS $NGX_LIBDL"
 改为:
 37CORE_INCS="$CORE_INCS $OPENSSL/include"
 38CORE_DEPS="$CORE_DEPS $OPENSSL/include/openssl/ssl.h"
 39CORE_LIBS="$CORE_LIBS $OPENSSL/libssl.a"
 40CORE_LIBS="$CORE_LIBS $OPENSSL/libcrypto.a"
 41CORE_LIBS="$CORE_LIBS $NGX_LIBDL"
 41CORE_LIBS="$CORE_LIBS $NGX_LIBDL"
posted @ 2019-11-01 02:42  schips  阅读(7094)  评论(4编辑  收藏  举报