我写了a Ruby C++ extension以包裹Google's re2 regular expression library,但recent update to the library更改了Match()
函数的界面:
bool Match(const StringPiece& text,
int startpos,
Anchor anchor,
StringPiece *match,
int nmatch) const;
要:
bool Match(const StringPiece& text,
int startpos,
int endpos,
Anchor anchor,
StringPiece *match,
int nmatch) const;
(注意新的int endpos
参数。)
我的问题是:我是否有可能在一个扩展中支持这个库的两个版本,尽管re2似乎没有指定任何我可以反省的VERSION
常量?
理想情况下,我希望能够尝试更新的版本(带有6个参数),如果失败,则回退到旧版本(因为我能够轻松地回填endpos
参数)。
目前我的代码是这样的:
matched = p->pattern->Match(text_as_string_piece, 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, 0, 0);
但是如果您有旧版本的re2,则需要:
matched = p->pattern->Match(text_as_string_piece, 0, RE2::UNANCHORED, 0, 0);
答案 0 :(得分:0)
据我所知,你做不到。这将要求您链接RE2的旧版本和新版本,这将使命名空间发生冲突。
除非存在重新使用旧版本的此方法的版本,否则您将无法使用新版本。
如果您希望能够编译两个版本的扩展,那么您必须修改编译步骤以定义您控制的一些标记。
#ifdef RE2_ODLFORMAT
matched = p->pattern->Match(text_as_string_piece, 0, RE2::UNANCHORED, 0, 0);
#else
matched = p->pattern->Match(text_as_string_piece, 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, 0, 0);
#endif
然后要编译代码,你可以按照以下方式做点什么:
make RE2_OLDFORMAT=1 all # compile for old version
make all # default target is for new version
答案 1 :(得分:0)
传统的答案是在安装时生成config.h
或其他任何内容。
也就是说,在安装时,您将检测安装了re2
的版本,然后在config.h
中定义符号,具体取决于:
// config.h
#ifndef CONFIG_H_INCLUDED
#define CONFIG_H_INCLUDED
#define RE2_MATCH_6_ARGS 1
#endif // CONFIG_H_INCLUDED
然后,你可以使用它:
#if defined(RE2_MATCH_6_ARGS) && RE2_MATCH_6_ARGS == 1
matched = p->pattern->Match(text_as_string_piece, 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, 0, 0);
#else
matched = p->pattern->Match(text_as_string_piece, 0, RE2::UNANCHORED, 0, 0);
#endif
这是一个稳定的解决方案,应该可以正常使用。
另一种可能性就是攻击系统......
在包装器库中提供Match
个函数的定义:
Match5
会抛出错误(请链接到re2)Match6
转发至Match5
。事情是(在Unix世界中......),如果已经加载了符号,它将不会被新定义覆盖。因此,只要首先加载re2
,您就会进入以下两种情况之一:
re2
:您的(包装)库提供Match6
的定义,该定义转发re2
提供的Match5
定义re2
:来电直接转到Match6
提供的re2
定义 很多更脆弱。需要re2
周围的包装器库。不太可能使用静态链接(从未尝试过......)。但不需要./configure
步骤。