Question

I wrote a Ruby C++ extension to wrap Google's re2 regular expression library but a recent update to the library changed the interface of the Match() function from:

bool Match(const StringPiece& text,
           int startpos,
           Anchor anchor,
           StringPiece *match,
           int nmatch) const;

To:

bool Match(const StringPiece& text,
           int startpos,
           int endpos,
           Anchor anchor,
           StringPiece *match,
           int nmatch) const;

(Note the new int endpos argument.)

My question is: is it possible for me to support both versions of this library in one extension despite the fact that re2 does not seem to specify any kind of VERSION constant that I can introspect?

Ideally, I want to be able to try the newer version (with 6 arguments) and, failing that, fall back to the older version (as I am able to backfill the endpos argument easily).

At the moment my code is like this:

matched = p->pattern->Match(text_as_string_piece, 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, 0, 0);

But if you have the older version of re2, it needs to be:

matched = p->pattern->Match(text_as_string_piece, 0, RE2::UNANCHORED, 0, 0);
Was it helpful?

Solution

The traditional answer is to generate a config.h or whatever at installation time.

That is, at installation you will detect which version of re2 is installed, and then define a symbol in config.h depending on this:

// config.h
#ifndef CONFIG_H_INCLUDED
#define CONFIG_H_INCLUDED

#define RE2_MATCH_6_ARGS 1

#endif // CONFIG_H_INCLUDED

And then, you can use this:

#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

This is a stable solution, and should work well.


Another possibility is to hack the system...

Provide a definition of both Match functions in a wrapper library:

  • Match5 throws an error (please link to re2)
  • Match6 forwards to Match5.

The thing is (in the Unix world...), if a symbol has already been loaded, it will not be overwritten by a new definition. So as long as re2 is loaded first you end up in one of those two scenarios:

  • old re2: your (wrapper) library provides a definition of Match6 which forwards to the re2 provided definition of Match5
  • new re2: the call directly goes to the definition of Match6 that re2 provided

Much more brittle. Requires a wrapper library around re2. Unlikely to work with static linking (never tried though...). But does not require a ./configure step.

OTHER TIPS

From what I know, you can't. This would require you to link with both the old and the new versions of RE2, which would make namespaces collide.

Unless there exists a version of this method that ressembles the old version, you're stuck with the new version.

If you want to be able to compile your extension for both versions, then you have to modify your compiling steps to define some flag that you control.

#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

Then to compile your code, you'd do something along those lines:

make RE2_OLDFORMAT=1 all # compile for old version
make all # default target is for new version
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top