2

我最近发现了 VTD-XML 方法对 XML 解析的强大功能,主要是它的速度。具体来说,我已经构建了 C 版本 2.10(也有 Java、C++ 和 C# 实现)。

我的目标很简单:我想从 XML 中提取数据,使用 VTD-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 ) 的共享库...这是正确的方法吗?有没有更好的方法?

4

1 回答 1

4

我确实通过添加一层间接实现了我的目标:糟糕,在我看来它是有效的。

首先,我创建了一个包含 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共享对象,所以我必须自己构建它,将几个 .o 对象文件与 gcc 链接在一起:

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:
        *;  
};

全局(“exported”)符号位于该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 程序。

于 2011-06-09T14:40:50.737 回答