手把手教你nginx源码--auto/feature

微信公众号:Nginx源码分析
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!

回顾

来,看下图:
辅助脚本
图中还剩下auto/featureauto/include脚本没有分析,其他的几个辅助脚本已经分析完了。
那么本文就详细分析一下一个非常非常重要的脚本,auto/feature.

写在分析之前

为什么说auto/feature脚本非常重要呢?
因为该脚本对于不同的宿主系统,可以测试当前的宿主系统是否支持某个特性。nginx会根据测试结果选用不同的实现方式。
比如auto/feature可以测试当前系统是否支持epoll,如果支持,nginx就使用这种高效率的io多路复用机制。如果不支持,那么就可能选用select或者poll机制等。总之,无论如何,总会让你的机器能够成功的运行nginx.

auto/feature 脚本

测试宿主系统是否支持某个特性。

输入参数

ngx_feature: 要测试的特性名称,该参数主要用于向终端和NGX_AUTOCONF_ERR文件中输出日志,便于后面的分析。

ngx_feature_name: define的变量名

ngx_feature_run: 表示对编译之后文件的处理方式

ngx_feature_incs:包含c源文件所需的头文件。下面的ngx_feature_path参数是这些头文件所在的目录

ngx_feature_path:包含了编译程序时设置的头文件目录

ngx_feature_libs:编译源文件时依赖的库文件

ngx_feature_test:测试当前特性时要执行的代码

输出参数

ngx_found: 表示是否拥有该特性,如果为yes表示有该特性。
若为no,表示没有该特性。

功能

测试是否支持某个特性。

示例

我们以测试epoll特性的代码为例来说明auto/feature的用法。

# epoll, EPOLLET version

ngx_feature="epoll"
ngx_feature_name="NGX_HAVE_EPOLL"
ngx_feature_run=yes
ngx_feature_incs="#include <sys/epoll.h>"
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="int efd = 0, fd = 1, n;
                  struct epoll_event ee;
                  ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
                  ee.data.ptr = NULL;
                  efd = epoll_create(100);
                  if (efd == -1) return 1;"
. auto/feature

if [ $ngx_found = yes ]; then
    have=NGX_HAVE_CLEAR_EVENT . auto/have
    CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
    EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
    EVENT_FOUND=YES
fi
脚本内容
echo $ngx_n "checking for $ngx_feature ...$ngx_c"

cat << END >> $NGX_AUTOCONF_ERR

----------------------------------------
checking for $ngx_feature

END

ngx_found=no

if test -n "$ngx_feature_name"; then
    ngx_have_feature=`echo $ngx_feature_name \
                   | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
fi

if test -n "$ngx_feature_path"; then
    for ngx_temp in $ngx_feature_path; do
        ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
    done
fi

cat << END > $NGX_AUTOTEST.c

#include <sys/types.h>
$NGX_INCLUDE_UNISTD_H
$ngx_feature_incs

int main() {
    $ngx_feature_test;
    return 0;
}

END


ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \
          -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs"

ngx_feature_inc_path=

eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1"


if [ -x $NGX_AUTOTEST ]; then

    case "$ngx_feature_run" in

        yes)
            # /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"
                ngx_found=yes

                if test -n "$ngx_feature_name"; then
                    have=$ngx_have_feature . auto/have
                fi

            else
                echo " found but is not working"
            fi
        ;;

        value)
            # /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"
                ngx_found=yes

                cat << END >> $NGX_AUTO_CONFIG_H

#ifndef $ngx_feature_name
#define $ngx_feature_name  `$NGX_AUTOTEST`
#endif

END
            else
                echo " found but is not working"
            fi
        ;;

        bug)
            # /bin/sh is used to intercept "Killed" or "Abort trap" messages
            if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
                echo " not found"

            else
                echo " found"
                ngx_found=yes

                if test -n "$ngx_feature_name"; then
                    have=$ngx_have_feature . auto/have
                fi
            fi
        ;;

        *)
            echo " found"
            ngx_found=yes

            if test -n "$ngx_feature_name"; then
                have=$ngx_have_feature . auto/have
            fi
        ;;

    esac

else
    echo " not found"

    echo "----------"    >> $NGX_AUTOCONF_ERR
    cat $NGX_AUTOTEST.c  >> $NGX_AUTOCONF_ERR
    echo "----------"    >> $NGX_AUTOCONF_ERR
    echo $ngx_test       >> $NGX_AUTOCONF_ERR
    echo "----------"    >> $NGX_AUTOCONF_ERR
fi

rm $NGX_AUTOTEST*
脚本分析

我们以示例中测试epoll特性的代码分析这个脚本。

1).向终端和NGX_AUTOCONF_ERR中输出测试信息

echo $ngx_n "checking for $ngx_feature ...$ngx_c"

cat << END >> $NGX_AUTOCONF_ERR

----------------------------------------
checking for $ngx_feature

END

我们之前分析的几乎所有脚本文件的第一步都是这个功能。主要是方便查找错误使用。

2). 初始化一些变量

ngx_found=no

if test -n "$ngx_feature_name"; then
    ngx_have_feature=`echo $ngx_feature_name \
                   | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
fi

上面首先初始化一个ngx_found,这个变量表示的是当前测试的特性是否存在。
接着,根据传进来的ngx_feature_name参数生成一个ngx_have_feature变量。
生成规则:把ngx_feature_name的小写字母全部换成大写字母。所以对于这个示例来说,最终的ngx_have_feature的值为NGX_HAVE_EPOLL

3).设置头文件目录

if test -n "$ngx_feature_path"; then
    for ngx_temp in $ngx_feature_path; do
        ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
    done

根据传进来的入参ngx_feature_path设置编译测试程序所需要的头文件。生成结果保存到ngx_feature_inc_path变量中。

4).生成自动测试程序
根据传进来的ngx_feature_test参数生成一个测试特性的c源文件。

cat << END > $NGX_AUTOTEST.c

#include <sys/types.h>
$NGX_INCLUDE_UNISTD_H
$ngx_feature_incs

int main() {
    $ngx_feature_test;
    return 0;
}

END

本例生成的c源文件代码如下:

#include <sys/types.h>
#include <unistd.h>
#include <sys/epoll.h>

int main() {
    int efd = 0, fd = 1, n;
    struct epoll_event ee;
    ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
    ee.data.ptr = NULL;
    efd = epoll_create(100);
    if (efd == -1) return 1;;
    return 0;
}

这个c源文件也是一个很简单的代码。

5).编译自动测试程序

ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \
          -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs"

ngx_feature_inc_path=

eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1"

上面的编译指令ngx_test的值如下:

gcc  -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -o objs/autotest objs/autotest.c

编译之后生成的目标文件是objs/autotest文件。

6).执行自动测试程序
我们先看一下如果没有编译成功的话,会执行什么东东。

echo " not found"

    echo "----------"    >> $NGX_AUTOCONF_ERR
    cat $NGX_AUTOTEST.c  >> $NGX_AUTOCONF_ERR
    echo "----------"    >> $NGX_AUTOCONF_ERR
    echo $ngx_test       >> $NGX_AUTOCONF_ERR
    echo "----------"    >> $NGX_AUTOCONF_ERR

其实这也是nginx惯用的手法,就是把这些测试信息保存到NGX_AUTOCONF_ERR错误日志文件中,便于查找错误原因。

7).如果编译成功了该咋办呢?
这部分代码也是比较长,我们分别讨论。
根据ngx_feature_run的值,可以分为如下几部分:

①.ngx_feature_run 的值为yes:

yes)
            if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
                echo " found"
                ngx_found=yes

                if test -n "$ngx_feature_name"; then
                    have=$ngx_have_feature . auto/have
                fi

            else
                echo " found but is not working"
            fi
        ;;

如果执行成功的话,会把ngx_found设置为yes。这个变量在后面会用到。
然后调用auto/have脚本在NGX_AUTO_CONFIG_H文件中增加一个宏定义。

②.ngx_feature_run 的值为value:
在这种情况下,编译只有的源文件执行结果是一个数值。最终生成一个宏定义代表该数值。

value)
            # /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"
                ngx_found=yes

                cat << END >> $NGX_AUTO_CONFIG_H

#ifndef $ngx_feature_name
#define $ngx_feature_name  `$NGX_AUTOTEST`
#endif

END
            else
                echo " found but is not working"
            fi
        ;;

这种情况是计算一个结果,然后把结果通过宏的方式添加到NGX_AUTO_CONFIG_H文件中。

③.ngx_feature_run的值为bug.

 bug)
            # /bin/sh is used to intercept "Killed" or "Abort trap" messages
            if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
                echo " not found"

            else
                echo " found"
                ngx_found=yes

                if test -n "$ngx_feature_name"; then
                    have=$ngx_have_feature . auto/have
                fi
            fi
        ;;

这种情况的处理方式和yes的处理方式刚好相反。

④.ngx_feature_run为其他值。

*)
            echo " found"
            ngx_found=yes

            if test -n "$ngx_feature_name"; then
                have=$ngx_have_feature . auto/have
            fi
        ;;

只是简单的增加一个宏定义。

8). 删除临时文件

rm $NGX_AUTOTEST*

9).脚本执行完之后的工作
我们上面已经写到了,auto/feature输出了一个参数ngx_found,这个参数表示当前宿主系统是否含有此特性。
我们看一下当测试完epoll之后的处理。

if [ $ngx_found = yes ]; then
    have=NGX_HAVE_CLEAR_EVENT . auto/have
    CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
    EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
    EVENT_FOUND=YES
fi

这里就是一些特殊的处理,当宿主系统包含该特性之后的一些后续逻辑。

调试方法

由于在脚本中很多地方都调用了auto/feature脚本,如果我们想调试的话,不是特别方便,可以通过在源代码中添加下面的代码进行调试:

 if  test -n "$ngx_feature_name" ;then
 # 这里的NGX_SYS_NERR是我们想要调试的特性
 #我们可以在里层的if语句中完整各种功能进行调试
    if [ "$ngx_feature_name" = "NGX_SYS_NERR" ];then
        cat $NGX_AUTOTEST.c;
        echo `$NGX_AUTOTEST`;
    fi
fi

总结

我们详细的分析了auto/feature脚本的功能。这个脚本的作用就是测试在当前的宿主系统上面是否支持某个特性。

后面的文章我们会接着分析nginx的源码,敬请期待。顺便关注我的个公众号(Nginx源码分析)。

<think>好的,用户现在遇到了问题,执行`ls -l /root/nginx/nginx-1.26.3/sbin/nginx`时提示文件或目录不存在。之前他想要将Nginx的安装路径切换到新位置,但显然新路径下的nginx可执行文件不存在。我需要先确定可能的原因,然后一步步引导用户解决。 首先,用户可能没有正确安装或编译新版本的Nginx到指定目录。可能用户下载了源代码但未编译,或者编译后的安装路径不是预期的`/root/nginx/nginx-1.26.3`。需要确认用户是否执行了正确的安装步骤,比如解压、配置、编译和安装。 接下来,用户可能在之前的步骤中路径输入错误,或者目录结构不同。例如,Nginx默认安装路径可能是在`/usr/local/nginx`,而用户可能没有指定`--prefix`参数,导致安装到其他位置。需要检查用户是否在编译时指定了正确的安装目录。 另外,用户可能没有创建必要的目录结构。比如,`/root/nginx/nginx-1.26.3/sbin`目录可能不存在,导致即使编译成功,二进制文件也没有生成在正确的位置。这时候需要检查目录是否存在,并指导用户创建或调整安装参数。 还应该考虑权限问题,虽然之前的回答提到了权限,但这里的问题更基础,文件不存在,所以权限问题可能不是首要的。但需要确保用户有权限在`/root`下创建目录和文件,可能需要使用sudo或者在root用户下操作。 接下来,用户可能需要重新安装Nginx到正确的路径。应该提供详细的步骤,包括下载源代码、配置、编译和安装,并确保指定`--prefix=/root/nginx/nginx-1.26.3`。同时,提醒用户安装完成后验证sbin目录下是否存在nginx可执行文件。 如果用户已经尝试过安装但依然不存在,可能需要检查编译过程中是否有错误,或者是否安装过程被中断。建议用户查看编译日志,确认安装是否成功完成。 最后,如果用户只是移动了二进制文件而没有重新安装,可能会遇到依赖或库文件缺失的问题,这时候需要重新安装而不是简单移动文件。 总结来说,用户的问题核心在于新路径下的Nginx可执行文件不存在,需要引导用户正确安装或确认安装路径,并解决可能存在的目录创建、编译选项等问题。</think>根据你的错误提示,新Nginx路径下的二进制文件不存在。以下是完整的排查和解决方案: --- ### 一、错误原因分析 ```bash ls: cannot access /root/nginx/nginx-1.26.3/sbin/nginx: No such file or directory ``` 表示以下情况之一: 1. **未正确安装Nginx**到目标路径 2. **目录层级不匹配**(实际安装路径可能与预期不同) 3. **源码未编译**(仅有源码但未生成可执行文件) --- ### 二、完整解决流程 #### 步骤1:确认Nginx安装状态 ```bash # 检查目标路径是否存在 ls -l /root/nginx/nginx-1.26.3 # 检查编译痕迹 ls -l /root/nginx/nginx-1.26.3/objs/nginx ``` - 如果看到 `objs/nginx` 但无 `sbin/nginx`,说明编译成功但未执行 `make install` #### 步骤2:从源码重新安装(推荐方案) ```bash # 进入源码目录(假设源码在 /root/nginx/nginx-1.26.3) cd /root/nginx/nginx-1.26.3 # 清理旧编译痕迹(重要!) make clean # 配置安装路径(关键参数) ./configure --prefix=/root/nginx/nginx-1.26.3 \ --with-http_ssl_module \ --with-http_v2_module # 编译并安装 make && make install # 验证安装结果 ls -l /root/nginx/nginx-1.26.3/sbin/nginx ``` *注意:若需其他模块,可通过 `nginx -V` 查看旧版本编译参数* #### 步骤3:检查目录权限 ```bash # 确保目录树存在 mkdir -p /root/nginx/nginx-1.26.3/sbin # 修正所有权(根据实际运行用户) chown -R root:root /root/nginx ``` --- ### 三、常见问题处理 #### 问题1:`make install` 后仍无sbin/nginx **解决方案**: 1. 检查configure输出是否包含 `--prefix=/root/nginx/nginx-1.26.3` 2. 确认磁盘空间充足 `df -h /root` 3. 查看编译错误日志 `cat objs/autoconf.err` #### 问题2:缺少依赖库 ```bash # 安装基础编译依赖(CentOS示例) yum install -y gcc make openssl-devel pcre-devel zlib-devel ``` --- ### 四、安装验证 ```bash # 测试新nginx能否加载旧配置 /root/nginx/nginx-1.26.3/sbin/nginx -t -c /www/server/nginx/conf/nginx.conf # 预期输出 nginx: configuration file /www/server/nginx/conf/nginx.conf test is successful ``` --- ### 五、补充说明表 | 现象 | 解决方案 | |------------------------------|----------------------------| | `make: command not found` | 安装开发工具包 `yum groupinstall "Development Tools"` | | `objs/nginx` 存在但未安装 | 执行 `make install` | | 自定义模块缺失 | 在configure时添加 `--add-module=/path/to/module` | 完成上述步骤后,可继续按原切换方案修改systemd服务配置。建议通过编译安装确保路径可控性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值