Supportare più versioni incompatibili della libreria C ++
Domanda
scrissi Un'estensione di Ruby C ++ avvolgere Libreria di espressione regolare Re2 di Google ma a recente aggiornamento alla biblioteca ha modificato l'interfaccia del Match()
funzione da:
bool Match(const StringPiece& text,
int startpos,
Anchor anchor,
StringPiece *match,
int nmatch) const;
Per:
bool Match(const StringPiece& text,
int startpos,
int endpos,
Anchor anchor,
StringPiece *match,
int nmatch) const;
(Nota il nuovo int endpos
discussione.)
La mia domanda è: è possibile per me supportare entrambe le versioni di questa biblioteca in un'estensione nonostante il fatto che RE2 non sembri specificare alcun tipo di VERSION
costante che posso introspettare?
Idealmente, voglio essere in grado di provare la versione più recente (con 6 argomenti) e, fallendo, rientrare alla versione precedente (poiché sono in grado di riempire il endpos
argomento facilmente).
Al momento il mio codice è così:
matched = p->pattern->Match(text_as_string_piece, 0, (int)RSTRING_LEN(text), RE2::UNANCHORED, 0, 0);
Ma se hai la versione precedente di RE2, deve essere:
matched = p->pattern->Match(text_as_string_piece, 0, RE2::UNANCHORED, 0, 0);
Soluzione
La risposta tradizionale è generare a config.h
o qualsiasi altra cosa al momento dell'installazione.
Cioè, durante l'installazione rileverai quale versione di re2
è installato e quindi definire un simbolo in config.h
A seconda di questo:
// config.h
#ifndef CONFIG_H_INCLUDED
#define CONFIG_H_INCLUDED
#define RE2_MATCH_6_ARGS 1
#endif // CONFIG_H_INCLUDED
E poi, puoi usarlo:
#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
Questa è una soluzione stabile e dovrebbe funzionare bene.
Un'altra possibilità è quella di hackerare il sistema ...
Fornire una definizione di entrambi Match
Funzioni in una libreria wrapper:
Match5
lancia un errore (si prega di collegamento a RE2)Match6
in avanti aMatch5
.
Il fatto è (nel mondo di Unix ...), se un simbolo è già stato caricato, non sarà sovrascritto da una nuova definizione. Quindi fino a quando re2
viene caricato per primo finisci in uno di quei due scenari:
- vecchio
re2
: La tua libreria (wrapper) fornisce una definizione diMatch6
che inoltra alre2
Definizione fornita diMatch5
- nuovo
re2
: la chiamata va direttamente alla definizione diMatch6
Quellore2
fornito
Tanto più fragile. Richiede a Biblioteca wrapper intorno a re2
. È improbabile che funzioni con il collegamento statico (mai provato però ...). Ma non richiede un file ./configure
fare un passo.
Altri suggerimenti
Da quello che so, non puoi. Ciò richiederebbe di collegarti con le versioni vecchie e nuove di RE2, il che renderebbe le spazi dei nomi.
A meno che non esista una versione di questo metodo che riprende la vecchia versione, sei bloccato con la nuova versione.
Se vuoi essere in grado di farlo compilare La tua estensione per entrambe le versioni, quindi devi modificare i passaggi di compilazione per definire un po 'di flag voi controllo.
#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
Quindi per compilare il tuo codice, faresti qualcosa su queste righe:
make RE2_OLDFORMAT=1 all # compile for old version
make all # default target is for new version