我最近发现了 VTD-XML 解析 XML 方法的强大功能,主要是它的速度。 具体来说,我构建了 C 版本 2.10(也有 Java、C++ 和 C# 实现)。
我的目标很简单:我想使用 VTD-XML 进行解析,从 XML 中提取数据,并使用 Perl 处理数据。 最简单的方法可能是用我编写的 C 程序转储数据,然后通过管道将它们发送到 Perl 程序。也许不优雅,但它有效。
另一种不太简单的方法是由一个 Perl 程序组成,该程序使用 Inline::C 调用 C 数据收集器子例程。
所以我开始研究 Inline::C 并设法完成我需要使用 Perl C API 函数将数据从 C 子例程传回 Perl 的基本操作。 当我在 Inline::C 控制下的 C 源代码中编写 C 收集器子例程时,在编译阶段出现了问题。
存在像这样的符号冲突:bind() 在socket.h (Perl) 和autoPilot.h (VTD-XML) 中都定义。可以避免符号冲突将 VTD-XML 构建为具有显式导出映射的共享库( gcc -Wl,-version-script=foo.map )...这是正确的方法吗? 还有更好的方法吗?
最佳答案
我确实通过添加一个间接层达到了我的目标:糟糕,但在我看来它有效。
首先,我创建了一个包含 VTD-XML API 的共享库。构建这个共享对象时,我必须避免全局范围污染,仅导出所需的符号。
然后我构建了另一个共享库。第二个共享库隐藏了 VTD-XML API,应该通过 Inline::C 从 Perl 使用。在这个共享对象中,我使用 libvtd.so 部分公开的 API 编写了一些函数。
这个想法看起来像这样:
Perl -> Inline::C dynamic loader -> wrapper_API.so -> libvtd.so
主要问题来自共享库的运行时加载以及符号冲突/解析。
以下是我构建 libvtd.so 的方法,使所谓的wrapper_API.so 可以轻松使用它。
不幸的是,VTD-XML 没有构建 libvtd.so
共享对象,因此我必须自己构建它,用 gcc 将多个 .o 对象文件链接在一起:
gcc -shared -fPIC -Wl,-soname,libvtd.so.2.10 -Wl,--version-script=vtd-xml.map \
-o libvtd.so.2.10 libvtd.o arrayList.o fastIntBuffer.o fastLongBuffer.o \
contextBuffer.o vtdNav.o vtdGen.o autoPilot.o XMLChar.o XMLModifier.o intHash.o \
bookMark.o indexHandler.o transcoder.o elementFragmentNs.o
使用链接器选项-Wl,--version-script=vtd-xml.map
调整符号可见性,其中映射文件为:
{
global:
the_exception_context;
toString;
getText;
getCurrentIndex;
toNormalizedString;
toElement;
toElement2;
createVTDGen;
setDoc;
parse;
getNav;
freeVTDGen;
freeVTDNav;
getTokenCount;
local:
*;
};
全局(“导出”)符号位于 global:
部分下,而 local 下的包罗万象的 *
表示所有其他符号仅在本地已知。
所有对象模块均来自 VTD-XML 发行版,但 libvtd.o 除外:需要此自定义对象来解决异常处理库 cexept.h 的问题。 libvtd.c只有两行代码。
#include "customTypes.h"
struct exception_context the_exception_context[ 1 ];
在编译阶段,我必须调整 CFLAGS 来制作位置无关代码( gcc -fPIC
选项),以便制作共享对象。
readelf 工具对于检查符号可见性非常有用:
readelf --syms libvtd.so.2.10
Symbol table '.dynsym' contains 35 entries:
Num: Value Size Type Bind Vis Ndx Name
...
280: 000000000000d010 117 FUNC LOCAL DEFAULT 12 writeIndex
281: 000000000003c5d0 154 FUNC LOCAL DEFAULT 12 setCursorPosition
282: 000000000003c1f0 56 FUNC LOCAL DEFAULT 12 resetIntHash
...
331: 0000000000004f50 3545 FUNC GLOBAL DEFAULT 12 toElement
332: 00000000000071e0 224 FUNC GLOBAL DEFAULT 12 getText
333: 000000000000d420 114 FUNC GLOBAL DEFAULT 12 freeVTDGen
...
339: 000000000000b600 731 FUNC GLOBAL DEFAULT 12 toElement2
340: 000000000000e650 120 FUNC GLOBAL DEFAULT 12 getNav
341: 0000000000025750 70567 FUNC GLOBAL DEFAULT 12 parse
wrapperAPI.so 由多个使用 VTD-XML API 及其自定义类型的函数组成,但仅接受和返回标准 C 类型和/或结构。 该包装器直接来自以前的独立 C 程序。
关于c - 如何在 Perl 中通过 Inline::C 使用 VTD-XML?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6276626/