在上一篇文章中我说了 pymmseg-cpp 在 Windows 下无法正常工作的事情,经过一番折腾,现在终于能正常运行了。于是我发布了 1.0.1 版,并在 google code 申请了一个 project ,用于存放 release 包:pymmseg-cpp 在 google code 的项目主页 。
另外,在 github 上看到 nasi 将 rmmseg-cpp fork 了一下并对编译脚本针对 Mac OSX 进行了一点修改,便把补丁添加进来了。我身边也不好找 Mac 的机器,不过 ashchan 告诉我说打过这个补丁之后在 Mac 下挂起的问题解决掉了。于是我便顺便发布了一个 rmmseg-cpp 的新版本,没有其他改动,非 Mac 的用户不必升级。
再回过头来看看一开始 pymmseg-cpp 无法在 Windows 上工作的问题,有一个原因看起来是 C 和 C++ 之间的瓜葛,原来我写的 C 包装层大概像这个样子:
struct Token
{
Token(const char *text, int offset, int length)
:text(text), offset(offset), length(length) {}
const char *text;
int offset;
int length;
}
extern "C" {
/* ... snip... */
Token mmseg_next_token(rmmseg::Algorithm *algor)
{
/* ... snip ... */
return Token(/* ... */);
}
}
我在用 Microsoft 的编译器编译的时候它给了一个 Warning ,大致就是说 mmseg_next_token 函数有 C linkage ,但是返回值却是一个 C++ struct 。确实,C 的 struct 是没有构造函数的,然而我觉得这样的平凡对象也没有虚函数之类的,应该 C++ 和 C 也是一样才是啊。不过我把构造函数去掉,把 Token 的定义移动到 extern "C" 段里面去再编译,发现就可以正常运行了。但是我还是有些怀疑,于是又把代码改回原来的样子,再编译了一下,发现也正常。果然问题不在这里!不过我觉得还是把这个问题记下来,C 和 C++ 之间的关系确实有些微妙,这里虽然没有出问题,但是难保会碰到雷区呢,以后写这样的代码也还是小心些为妙。 :)
那最开始的那一堆错误又从何而来呢?这是因为我一开始一直是用 MinGW 的编译器在进行测试。也许 MinGW 生成的 shared library 比较奇怪吧,我写了一个只有一个空函数的 shared library 用 ctypes 调用了一下都会报错:尝试 cdll 会说 argument 太少了;尝试 windll 会说 argument 太多了。然而应该 cdll 才是正确的类型,因为某些函数还是可以正确调用的,我随便测试了一下,发现好像在返回值是一个 struct 的时候就会出现这个问题,例如:
extern "C" {
struct Token
{
const char *text;
int offset;
int length;
};
Token call_foo(Token *t)
{
return Token();
}
}
不过我暂时没有打算深究这个问题了,也许 MinGW + Python ctypes 本身就是一个比较奇怪的搭配吧,再加上 ctypes 在 Windows 下检查参数个数是否传递正确的方法本身就是比较 tricky 的,和 MinGW 不兼容似乎也是可以理解的啊。 ^_^bb
Comments (18)
你好,不用每次都加载辞典啊,程序刚启动的时候把辞典加载进来就可以了。不知道你说的是什么意思?难道是加载到 OS 的内存中,几个 mmseg 进程共享?这样大概没有 portable 的做法吧?
当然了,如果是批量做提取的话,就没这个问题了,像你说的一样,一次加载就可以了
你好,我知道你的意思了,不过这应该是 CGI 程序的通病吧,你也可以做一个后台 server ,前台的 CGI 程序将数据发送给 server ,server 分好词之后返回结果,或者用诸如 fastcgi 之类的,解决办法应该会有不少,但是我觉得还是不应该从 pymmseg 这边来改的。 :)
不过 boost 真是好大啊,每次一想到自己的程序如果要依赖于这样一个东西,就有点不寒而栗…… -.-bb
然而时间也真是过得好快,我还记得期盼 boost::asio 进入 boost 官方的遥遥无期的日子……
听上去不错阿,不过很久没有接触这些东西了,有机会再研究一下。
bcp ,有这种工具的?第一次听说,恩,看来以后可以放心大胆地用 boost 了,上次想用它的 hash 呢,纠结了很久还是自己实现了一个。 :-/
唔~ php5 我不会呢,不过 mmseg-cpp 本身是相对比较独立的一个模块,懂 php 的人的话,也许很容易弄出一个库来。
嗯,也对,想想这个东西做成php的extension恐怕不合适呢。需要加载很大的一个词表,做成一个服务让php调用可能更好一点。
Hi pluskid,
我是用MacBook Pro的,最新的rmmseg-cpp 0.2.6在我的10.5.5系统上可以正常的编译和安装,但是在运行时会抛出一个错误,大致是:
/Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundle: dlopen(/Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundle, 9): Symbol not found: ___gxx_personality_v0 (LoadError) Referenced from: /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundle Expected in: dynamic lookup - /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/../ext/rmmseg/rmmseg.bundlefrom /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `require' from /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/lib/rmmseg.rb:3 from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `gem_original_require' from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `require' from /Library/Ruby/Gems/1.8/gems/rmmseg-cpp-0.2.6/bin/rmmseg:4 from /usr/bin/rmmseg:19:in `load' from /usr/bin/rmmseg:19
这个可能是什么问题呢?
p.s. 再次感谢你的这个优秀的工具 :D
@Neo,
Hi, 我仔细检查了一下代码,发现有可能是因为我犯了一个低级错误。请你试一下把
ext/rmmseg/extconf.rb里面的CONFIG['LDShARED']那里的小写字母h改为大写的试试能否正常使用?