【发布时间】:2021-09-09 20:34:17
【问题描述】:
有一个用c编写的简单模块:
#include <stdio.h>
#include "apr_hash.h"
#include "ap_config.h"
#include "ap_provider.h"
#include "httpd.h"
#include "http_core.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static int example_handler(request_rec *r) {
if (!r->handler || strcmp(r->handler, "example-handler")){
return (DECLINED);
}
PyObject* py_io = PyImport_ImportModule("io");
Py_DECREF(py_io);
ap_set_content_type(r, "text/html");
ap_rprintf(r, "Filename: %s", r->filename);
return OK;
}
static void register_hooks(apr_pool_t *pool) {
ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST);
}
module AP_MODULE_DECLARE_DATA mod_example = {
STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, register_hooks
};
并在没有apxs 的情况下编译:
# Compile
gcc -D LINUX -D AMD64 \
$($(apxs -q APR_CONFIG) --cflags --includes) \
$(python3-config --cflags --includes) \
-fPIC -DSHARED_MODULE \
-I$(apxs -q INCLUDEDIR) $(apxs -q CFLAGS) \
-c mod_example.c;
# Link shared library
gcc -D LINUX -D AMD64 \
$($(apxs -q APR_CONFIG) --link-ld) \
$(python3-config --ldflags) \
-shared -o mod_example.so mod_example.o;
编译成功,没有错误或警告:
$ file build/mod_example.so
build/mod_example.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=10f64f7e7c6d0ec9301e07cb61fe5d0249653704, with debug_info, not stripped
但是当上传到安装了apache2的vm机器并启用模块并重新启动apache时,会说:
apache2:/etc/apache2/apache2.conf 第 146 行的语法错误:/etc/apache2/mods-enabled/mod_example.load 第 1 行的语法错误:无法加载 /usr/lib/apache2/modules/ mod_example.so 进入服务器:/usr/lib/apache2/modules/mod_example.so:未定义符号:PyImport_ImportModule
函数记录在这里:https://docs.python.org/3/c-api/import.html
为什么python.h中声明的python函数编译正确但没有在服务器上声明?,主机(ubuntu-desktop 20.04 lts)和vm机(ubuntu服务器)具有相同的python和apache版本(包括开发头文件) 20.04 升):
$ python3 --version
Python 3.8.5
$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 ...
$ find /usr/include -name "apr-*" | grep -o apr.*
apr-1.0
【问题讨论】:
-
问题是模块和
httpd都没有与Python库关联,你可能会使用libpython3.8.so的某个版本。这对适当的编译没有负面影响,并且可能链接器接受它是因为正在构建的对象是共享库,而不是程序。 Apxs 我也将提供有贡献的链接标志。 -
是的,在
/usr/lib/x86_64-linux-gnu/libpython3.8.so。您是说 apache 或模块在启动前需要预加载库吗? -
我在
/etc/apache2/envvars中写了完整路径:export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libpython3.8.so,并且工作正常:D。我可以在库级别做些什么来避免手动加载 python 库吗? -
您可以尝试将
$(python3-config --ldflags)移动到链接命令的末尾或将$(python3-config --libs)附加到链接命令。可能是任何一种替代方法。链接器对命令行参数的顺序很敏感。