如何在Unix/Linux系统中生成lxml的静态版本?

1 投票
2 回答
2000 浏览
提问于 2025-04-28 15:54

我现在有两个Unix系统,一个用来提供服务,另一个用来构建(这个构建的环境比较老旧)。我需要在服务机器上使用Python的lxml库。我尝试了以下命令:

python setup.py build --static-deps

或者

CFLAGS="-g -O2 -fPIC"
python setup.py build --static-deps

但是结果是:

ld: fatal: relocations remain against allocatable but non-writable sections
collect2: ld returned 1 exit status
error: command '/usr/lib/python2.6/pycc' failed with exit status 1

我在想,怎样才能做一个静态构建,这样我就可以轻松地部署到我的服务机器上?

另外,如果我

python setup.py build

没有错误,但如果我:

Python 2.6.4 (r264:75706, Apr 17 2011, 11:24:50) [C] on sunos5
Type "help", "copyright", "credits" or "license" for more information.
>>> from lxml import etree
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: ld.so.1: isapython2.6: fatal: relocation error: file /usr/lib/python2.6/site-packages/lxml/etree.so: symbol __xmlStructuredErrorContext: referenced symbol not found

我搜索了一下:导入lxml.etree到Python时出错,似乎没有好的答案。我认为这是链接的问题,所以我觉得做一个静态链接应该是更好的解决方案。

但我主要的目标是减少部署时的工作量,所以我会接受任何简单的方法。

请帮帮我。提前谢谢!

暂无标签

2 个回答

0

在Android上使用libxml

使用以下命令来设置和编译:

./configure --enable-static --disable-shared

然后运行:

make libxml2.la

4

问题看起来是你在尝试构建一个没有静态依赖的静态库。

静态库,比如说 libxml2.a,其实就是一堆对象文件(.o 文件)的集合。当你链接这个库时,链接器会把你调用的函数的代码从这些对象文件中复制到你的目标文件里。这样,最终生成的目标文件就可以独立运行,不需要 libxml2.a;因为当你调用 libxml2 的函数时,相关的代码已经在你的库里了。

而共享库,比如 libxml2.so,基本上就是一个可执行文件。当你链接这个库时,链接器会创建一些重定位条目,这样当你的目标文件和 libxml2.so 同时加载到内存时,你调用的 libxml2 的函数就能正常工作,因为相关的代码就在 libxml2.so 里。

你想做的其实是构建一个混合体:一个共享库(这样可以作为模块加载),它可能动态链接到 libpython.so(也许还有其他操作系统自带的库),但同时又静态链接 libxml2libxslt2 的代码。

现代的链接器完全可以做到这一点,但它需要 libxml2 的静态库才能实现。

所以,你需要先安装 libxml2.a(还有 libxslt2.a,甚至可能需要 libz.a),才能构建你想要的东西。


我这里简化了一些。在某些平台上,.so 文件实际上只是一个共享对象的前端,基本上是重定位表加上指向真实文件的链接。在其他平台上,代码可以从 .so 文件中提取出来并进行“重定位”,而 .a 文件也可以只是共享对象的类似前端。而且有些平台与 ELF 的差异如此之大,以至于这些术语可能会让人感到困惑。

如果你想了解更多,可以从 这个问题开始,看看相关的问题。

如果你不想了解那么多,只需相信你需要 .a 文件来进行静态链接。


如果你查看 安装 文档,你会注意到:

在 Linux(以及大多数其他正常工作的操作系统)上,只要 libxml2libxslt 正确安装,包括开发包(即头文件等),pip 就能成功构建源代码分发。如果构建失败,可以使用你的包管理工具查找像 libxml2-devlibxslt-devel 这样的包,并确保它们已安装。另外,设置 STATIC_DEPS=true 会自动下载并构建这两个库。

所以,如果你根本没有这些库,构建 lxml 会自动下载依赖,帮你构建 .a 文件并链接。

但如果你 这些库,那么 (a) pkg-config 和/或 xml2-config 会找到它们并使用,(b) 即使没有找到,lxml 也可能会用 -lxml2 来构建,而不是指向 libxml2.a 的绝对路径,这样就可能链接错误的库。

那怎么解决这个问题呢?你可能会想会有一个简单的标志来告诉它不要这样做,但据我所知,并没有。所以,你的选择包括:

  • 在一个不包含 libxml2libxslt2 的假根目录下构建。这在 构建 Debian 包 的文档中有提到。
  • 手动构建仅静态的 libxml2libxslt2,并将生成的 xml2-configxslt2-config 的绝对路径传递给 setup.py,具体说明见 构建源代码
  • 临时修改 xml2-configxslt2-config(或者如果没有这些,可以修改 pkg-config 使用的 .pc 文件),让它们在 LDFLAGS 中使用 .a 文件的绝对路径,而不是 -L-l 标志。
  • 在构建 lxml 时,临时将 .so 文件从你的库路径中移除(可以通过重命名、设置不同的路径等方式)。
  • 假设版本号与已安装的 .so 文件不同(或可以不同),你可以按照 Mac 构建说明 指定明确的版本号。你可能需要手动下载压缩包,但不需要自己构建。

如果这一切听起来有点麻烦,像是应该很简单的事情……那么,记住你在做什么。Linux 是围绕为你的特定系统构建源代码分发的最佳方式而设计的。如果你的系统有 xml2 和 xslt2 的共享库,所有的设置都是为了尝试使用它们。如果你想构建的代码要部署到没有这些库的系统上,你的开发系统也应该没有这些库;如果有,你就得知道怎么解决这个问题。

撰写回答