2013-07-03 21 views
14

Cosa (se presente) è un buon modo per gestire l'incoerenza ABI tra libC++ e stdlibC++ su Mac?Qual è un buon modo per gestire le differenze ABI tra libC++ e libstdC++ precedente?

Il problema: molte funzionalità di C++ 11 richiedono la nuova implementazione libC++ della libreria standard C++. Ma libC++ non è compatibile con ABI con il vecchio libstdC++, mentre attualmente la maggior parte del software in genere si collega a quest'ultimo. Ad esempio il compilatore di sistema usa ancora stdlibC++, il che significa che tutte le mie librerie installate con macports hanno un ABI diverso per le classi std come la stringa e non sono collegabili con progetti che fanno un uso pesante di C++ 11.

Il mio attuale hack-of-a-solution: mantieni due versioni di librerie in cui questo normalmente porta a un problema (boost, opencv ecc.) E link a quello appropriato.

Immagino che se volessi veramente usare libC++ dovrei eliminare il mio sistema da qualsiasi cosa usando stdlibC++ e fare in modo che qualsiasi cosa da macports (o da qualsiasi altra parte) si colleghi solo con libC++. Potresti vedere quanto scoraggiante possa sembrare questo compito.

Qualcuno ha elaborato un buon modo per relazionarsi a questo "tra-stdlib-limbo" in cui viviamo? :)

EDIT: Sto facendo una domanda di follow-up implicita più esplicita: Apple spedisce sia libC++ che libstdC++ con i loro sistemi. Supponendo che si attacchi il problema sottostante e si provi a passare a libC++ - only. Quale sarebbe il modo consigliato di passare da libstdC++ a libC++ dato che il 100% delle librerie attualmente installate sul sistema (alcune fornite con il sistema, la maggior parte tramite macports, alcune tramite compilazione manuale) sono collegate a libstdC++ (se c'è)? Qualcuno ha fatto questo ed è sopravvissuto?

+1

Tutto il codice collegati tra loro dovrebbe utilizzare la stessa implementazione libreria standard e la versione. Tutto il resto è chiamato incompatibile e non è mai stato progettato per funzionare. – PlasmaHH

+0

Sì fuori rotta. Questo è l'intero problema - che abbiamo simultaneamente due implementazioni di libreria standard incompatibili in circolazione. La mia domanda riguarda le strategie che le persone hanno adottato per affrontare questo problema. – kamjagin

+1

Questa è la strategia. Ci sono molte altre implementazioni di libreria standard, e sono incompatibili tra loro, e rimarranno così per sempre. – PlasmaHH

risposta

12

Escludendo gli usi "nascosti" dei tipi di libreria standard è perfettamente sicuro combinare libC++ e libstdC++ in un singolo programma, dove alcune TU (o librerie o moduli) usano libC++ e alcuni usano libstdC++. Finché le interfacce tra TU non usano i tipi incompatibili non dovrebbero esserci problemi.

libC++ utilizza gli spazi dei nomi in linea per garantire che i tipi incompatibili ABI non possano essere scambiati l'uno con l'altro; se un'interfaccia utilizza libC++ std::string direttamente una libreria in attesa di libstdC++ std::string non si collegherà all'interfaccia, poiché i simboli effettivi sono diversi: std::string rispetto a std::__1::string.

libC++ assicura inoltre che le caratteristiche di basso livello come eccezioni e allocazione dinamica della memoria sono ABI compatibile (supponendo che si costruisce libstdC++ e libC++ utilizzando la stessa libreria ABI), quindi è sicuro deallocare memoria in un TU che utilizza, per esempio, libC++ quando la memoria è stata allocata in una TU usando libstdC++, o per generare un'eccezione dalla creazione del codice su libC++ e catturarla nel codice usando libstdC++.

Può esserci un problema quando i tipi nelle interfacce nascondono i tipi di libreria standard; data un'interfaccia usando struct S { std::string s; }; la definizione del tipo S sarà diversa a seconda di ciò che la TU ritiene std::string, violando così la regola di una definizione.


Tuttavia suona come se il vero problema è con le biblioteche che fanno Utilizzare i tipi di libreria standard di interfacce.

Immagino che si potrebbe suggerire che se voglio davvero fare uso di libC++ dovrei eliminare il mio sistema di nulla usando stdlibC++, e fare in modo che qualsiasi cosa, da MacPorts (o in qualsiasi altro luogo) collega solo con libC++. Potresti vedere quanto scoraggiante possa sembrare questo compito.

È necessario solo accertarsi che le TU che utilizzano la libreria standard nelle interfacce utilizzino libC++. Non è necessario eliminare completamente libstdC++. Le librerie che non usano la libreria standard nella loro interfaccia possono continuare a collegarsi con libstdC++.

EDIT: Sto facendo una domanda di follow-up implicita più esplicita: Apple spedisce sia libC++ che libstdC++ con i loro sistemi. Supponendo che si attacchi il problema sottostante e si provi a passare a libC++ - only. Quale sarebbe il modo consigliato di passare da libstdC++ a libC++ dato che il 100% delle librerie attualmente installate sul sistema (alcune fornite con il sistema, la maggior parte tramite macports, alcune tramite compilazione manuale) sono collegate a libstdC++ (se c'è)? Qualcuno ha fatto questo ed è sopravvissuto?

Ricordare, importa solo quando la libreria standard viene utilizzata nelle interfacce. Speriamo che tali librerie stiano già passando a libC++ da soli quando costruiscono per OS X. In caso contrario, forse accetteranno le patch per farlo.

Costruire i propri binari utilizzando la libreria appropriata non è un 'trucco'; è la cosa giusta da fare a meno che il progetto upstream lo faccia per te. Se si utilizza coerentemente libC++ nel proprio codice, non sarà necessario creare più versioni di alcuna libreria; solo versioni di libC++.


di riferimento per la compatibilità ABI di libC++: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-September/024594.html

+0

Grazie - hai perfettamente ragione che ho sovrastimato i problemi con lo switch da libstdC++ a libC++. Dato che il boost riverito (filesystem) era uno dei colpevoli, ho assunto che molte librerie consolidate usassero anche la libreria standard nelle loro interfacce, il che non sembra essere il caso (a parte molti di essi sono solo c)). – kamjagin

+0

"Speriamo che tali librerie stiano già passando a libC++ da sole quando costruiscono per OS X. In caso contrario, forse accetteranno le patch per farlo." Dubito che accadrà prima che Apple cambi il valore predefinito del compilatore per l'opzione della libreria std C++ in Xcode da libstdC++ a libC++, perché in tal caso queste librerie introdurranno lo stesso problema con la lib di default std che correggono per una non predefinita. – Kaiserludi

+0

Qui vedo solo due opzioni per i provider di librerie di terze parti: - offre tutti i file binari in due versioni, una basata su libstdC++, l'altra su libC++ - elimina l'utilizzo di stdlib nella loro API (che sarebbe un'API di rottura modifica) – Kaiserludi

1

Non ti piacerà questo.

Semplicemente non è possibile avere un ABI che utilizza tipi le cui definizioni cambiano su sistemi diversi. Questo è quello che stai facendo quando hai un ABI che usa std::string (per esempio) e poi lo compilo usando diversi compilatori o su piattaforme diverse.

Nel risolvere questo problema, il mio approccio preferito - se possibile - sarebbe quello di eliminare tutto il materiale specifico del compilatore dall'ABI e sostituirlo con tipi nativi o tipi definiti dalla libreria. Questi tipi definiti dalla libreria devono, a loro volta, esporre solo elementi non compilatori nell'ABI.

A volte è possibile ottenere con una semplice sostituzione. Altre volte è necessario prendere provvedimenti più drastici. Un approccio potrebbe essere quello di fornire una sorta di classe bridge o wrapper attorno a cose come std::string. Forse qualcosa di simile:

class MyString 
{ 
public: 
    virtual const char* c_str() const = 0; 
    static MyString* Make(); 
    virtual MyString* Clone() const = 0; 
protected: 
    MyString(); 
}; 

E nella biblioteca stessa:

class MyStringImpl 
: 
    public MyString 
{ 
public: 
    const char* c_str() const 
    { 
    return mStr.c_str(); 
    } 

    MyString* Clone() const 
    { 
    return new MyStringImpl (*this); 
    } 

    MyStringImpl() 
    { 
    } 

    MyStringImple (const MyString& rhs) 
    : 
    mStr (rhs.c_str()) 
    { 
    } 
private: 
    std::string mStr; 
}; 

MyString* MyString::Make() 
{ 
    return new MyStringImpl; 
} 

Gross. Forse inefficiente. Un sacco di codice da scrivere. Ma questo è l'angolo in cui ti sei dipinto.

+0

"sarebbe quello di eliminare tutto il materiale specifico del compilatore da ABI e sostituirlo con entrambi i tipi nativi" si noti che anche le dimensioni di cose come int e long variano tra i compilatori, così come il layout effettivo dei POD pari. – PlasmaHH

+0

@PlasmaHH: punto giusto. In pratica userei tipi di dimensione fissa, come 'uint32_t' ecc. –

+0

Provenendo dal lato * nix sono un po 'rovinato avendo avuto lo stesso compilatore ABI dal 2004 (per gcc che è) e altri compilatori (come intel's e oracle forniscono in genere le modalità gnu-abi), mentre MSVC interrompe il suo ABI ogni due anni costringendo lo sviluppatore ad esplorare COM-heaven :). Anche così ho pensato che i POD sono disposti linearmente in memoria e hanno zero padding iniziale. L'incompatibilità ABI dei POD proviene da un indefinito tra-member-padding o c'è qualche punto aggiuntivo che è vagamente definito (o un-)? – kamjagin