CentOS7编译Python3.10启动mod_wsgi报GENERAL_NAME_free符号错误
问题背景
- 运行环境:CentOS 7系统,自行通过altinstall方式编译安装的Python 3.10位于
/usr/local/bin/python3.10路径,配套创建了独立Python虚拟环境,目标是将原有yum安装的Python 3.6 + mod_wsgi 4.7.0环境下运行的业务应用,升级到Python 3.10 + mod_wsgi 4.9.1版本 - 前期Python 3.10编译过程多次出问题,怀疑首次构建mod_wsgi时关联了早期有问题的Python 3.10版本,后续执行如下命令尝试重新基于最终编译完成的Python 3.10构建mod_wsgi,期间也试过仅带
--no-cache-dir参数的pip安装命令:
pip install --ignore-installed --no-cache-dir mod_wsgi==4.9.1 --no-binary mod_wsgi
- 执行
mod_wsgi-express setup-server命令可正常输出服务配置信息,执行命令与输出结果如下:
$ sudo LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/custom-openssl/lib /root/bin/init-mod_wsgi-express runningroutes sandbox.routes.loutilities.com routesmgr routesmgr 8002 Server URL : http://proxysvr.loutilities.com:8002/ Server Root : /etc/mod_wsgi-express/sandbox.routes.loutilities.com Server Conf : /etc/mod_wsgi-express/sandbox.routes.loutilities.com/httpd.conf Error Log File : /etc/mod_wsgi-express/sandbox.routes.loutilities.com/error_log (warn) Rewrite Rules : /etc/mod_wsgi-express/sandbox.routes.loutilities.com/rewrite.conf Environ Variables : /etc/mod_wsgi-express/sandbox.routes.loutilities.com/envvars Control Script : /etc/mod_wsgi-express/sandbox.routes.loutilities.com/apachectl Operating Mode : daemon Request Capacity : 5 (1 process * 5 threads) Request Timeout : 60 (seconds) Startup Timeout : 15 (seconds) Queue Backlog : 100 (connections) Queue Timeout : 45 (seconds) Server Capacity : 20 (event/worker), 20 (prefork) Server Backlog : 500 (connections) Locale Setting : en_US.UTF-8
- 调用的初始化脚本
/root/bin/init-mod_wsgi-express逻辑为激活目标虚拟环境后生成mod_wsgi服务配置,脚本内容如下:
$ sudo cat /root/bin/init-mod_wsgi-express #!/bin/bash if [[ $# -lt 5 ]] ; then echo "usage:" echo " init-mod_wsgi-express project servername user group port" exit 0 fi source /var/www/$2/venv/bin/activate mod_wsgi-express setup-server --server-name proxysvr.loutilities.com --port $5 --user $3 --group $4 /var/www/$2/$1/$1/$1.wsgi --working-directory /var/www/$2/$1/$1/ --server-root /etc/mod_wsgi-express/$2 deactivate
故障现象
尝试启动生成的apachectl控制脚本时触发语法错误,提示无法加载mod_wsgi动态库,具体报错如下:
$ sudo /etc/mod_wsgi-express/sandbox.routes.loutilities.com/apachectl start httpd (mod_wsgi-express): Syntax error on line 163 of /etc/mod_wsgi-express/sandbox.routes.loutilities.com/httpd.conf: Cannot load /var/www/sandbox.routes.loutilities.com/venv/lib/python3.10/site-packages/mod_wsgi/server/mod_wsgi-py310.cpython-310-x86_64-linux-gnu.so into server: /var/www/sandbox.routes.loutilities.com/venv/lib/python3.10/site-packages/mod_wsgi/server/mod_wsgi-py310.cpython-310-x86_64-linux-gnu.so: undefined symbol: GENERAL_NAME_free
已排查信息
- 在Python源码编译目录检索
GENERAL_NAME_free符号,确认该符号存在于编译生成的_ssl.o、python主程序、libpython3.10.a等二进制文件中,检索结果如下:
$ grep -R GENERAL_NAME_free . ./Modules/_ssl.c: sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); Binary file ./Modules/_ssl.o matches Binary file ./python matches Binary file ./libpython3.10.a matches Binary file ./Programs/_testembed matches
- 确认
libpython3.10.a存在于以下路径:
$ find /usr/local/lib -name libpython3.10.a /usr/local/lib/libpython3.10.a /usr/local/lib/python3.10/config-3.10-x86_64-linux-gnu/libpython3.10.a
- 初步判断问题大概率和Python安装配置、mod_wsgi与Python的关联绑定配置有关,需要明确虚拟环境中mod_wsgi正确查找依赖库文件的配置方法,获取可落地的排查方向与解决步骤。此前在mod_wsgi官方社区发帖咨询一周,暂未收到回复。
根因定位
报错核心是Apache加载mod_wsgi动态库时,找不到OpenSSL相关的GENERAL_NAME_free符号,本质是动态链接器加载mod_wsgi时没有优先加载自行编译的自定义版本OpenSSL,反而加载了CentOS 7自带的旧版OpenSSL(1.0.2版本),旧版OpenSSL没有导出这个符号。
- 生成配置时手动给
mod_wsgi-express setup-server命令加了自定义OpenSSL的LD_LIBRARY_PATH,但这个环境变量没有被写入生成的envvars配置和apachectl启动脚本,Apache启动时不会加载自定义OpenSSL路径 - 编译mod_wsgi时没有正确把Python、自定义OpenSSL的链接参数打进去,导致mod_wsgi没有记录正确的依赖库搜索路径
解决步骤
- 先彻底卸载旧的mod_wsgi,避免残留旧编译产物干扰
# 激活目标虚拟环境 source /var/www/sandbox.routes.loutilities.com/venv/bin/activate pip uninstall -y mod_wsgi # 清理系统里可能残留的yum安装版mod_wsgi yum remove -y mod_wsgi mod_wsgi-python3 - 带上正确的依赖路径重新编译安装mod_wsgi,确保编译阶段就能链接到自定义OpenSSL和正确的Python 3.10
# 把自定义OpenSSL、Python3.10的头文件、库路径加到当前编译环境变量 export CFLAGS="-I/usr/local/custom-openssl/include -I/usr/local/include/python3.10" export LDFLAGS="-L/usr/local/custom-openssl/lib -L/usr/local/lib -Wl,-rpath,/usr/local/custom-openssl/lib -Wl,-rpath,/usr/local/lib" export LD_LIBRARY_PATH=/usr/local/custom-openssl/lib:/usr/local/lib:$LD_LIBRARY_PATH # 重新编译安装mod_wsgi,强制不用预编译二进制包 pip install --no-cache-dir --force-reinstall --no-binary mod_wsgi mod_wsgi==4.9.1加
-Wl,-rpath参数的作用是把依赖库的搜索路径直接写进mod_wsgi动态库文件里,后续加载时不需要依赖外部LD_LIBRARY_PATH配置就能找到正确的库 - 验证mod_wsgi的依赖链接是否正确
输出里确认ldd /var/www/sandbox.routes.loutilities.com/venv/lib/python3.10/site-packages/mod_wsgi/server/mod_wsgi-py310.cpython-310-x86_64-linux-gnu.solibssl.so、libcrypto.so指向/usr/local/custom-openssl/lib下的自定义版本,不是系统/usr/lib64下的旧版本,同时确认libpython3.10.so指向/usr/local/lib下自行编译的版本即可。 - 调整初始化脚本,保证启动时环境变量不丢失
修改/root/bin/init-mod_wsgi-express脚本,提前设置全局库路径,同时增加参数让Apache启动时继承库路径配置:#!/bin/bash if [[ $# -lt 5 ]] ; then echo "usage:" echo " init-mod_wsgi-express project servername user group port" exit 0 fi # 提前设置库路径,保证生成配置和后续启动都能读取 export LD_LIBRARY_PATH=/usr/local/custom-openssl/lib:/usr/local/lib:$LD_LIBRARY_PATH source /var/www/$2/venv/bin/activate # 加--passenv LD_LIBRARY_PATH参数,让Apache启动时继承这个环境变量 mod_wsgi-express setup-server --server-name proxysvr.loutilities.com --port $5 --user $3 --group $4 --passenv LD_LIBRARY_PATH /var/www/$2/$1/$1/$1.wsgi --working-directory /var/www/$2/$1/$1/ --server-root /etc/mod_wsgi-express/$2 deactivate - 清理旧配置,重新生成并启动服务
rm -rf /etc/mod_wsgi-express/sandbox.routes.loutilities.com /root/bin/init-mod_wsgi-express runningroutes sandbox.routes.loutilities.com routesmgr routesmgr 8002 /etc/mod_wsgi-express/sandbox.routes.loutilities.com/apachectl start - 如果还是报错,直接编辑生成的
/etc/mod_wsgi-express/sandbox.routes.loutilities.com/envvars文件,在末尾加上库路径配置:
保存后重启服务即可。export LD_LIBRARY_PATH=/usr/local/custom-openssl/lib:/usr/local/lib:${LD_LIBRARY_PATH}
内容的提问来源于stack exchange,提问作者Lou K
相关产品推荐
相关产品推荐

