2015-05-28 4 views
6

Ich bin dabei, CPU-Versand basierend auf Prozessor-Features zu verwenden, um die Implementierung eines komplizierten numerischen Algorithmus zu wechseln. Ich möchte die beiden Versionen (eine Version von sse2 und sse3 aus Gründen des Arguments) einbeziehen. Ich kompiliere in derselben dynamischen Bibliothek.Vermeidung von doppeltem Symbol beim Kompilieren mit mehreren Befehlssätzen

Der bisherige Ansatz besteht darin, den gesamten architekturspezifischen Code in einen Namespace einzubetten, z. namespace sse2 und namespace sse3 und vermeiden damit doppelte Symbolnamen beim Verknüpfen mit der endgültigen dynamischen Bibliothek.

Was passiert jedoch, wenn ich einen Code außerhalb meiner Kontrolle (z. B. eine std::vector<int>) in der sse2 und ss3-Version verwenden. Soweit ich sehen kann, wird die std::vector Implementierung in den Objektdateien sse2 und sse3 vorhanden sein, könnte aber theoretisch je nach den Optimierungen, die vom Compiler ausgeführt werden, unterschiedliche Anweisungen enthalten. Wenn ich diese Objektdateien in die dynamische Bibliothek einbinde, wird eine davon verwendet, und ich riskiere möglicherweise, eine sse3-Anweisung auf einer CPU auszuführen, die nur sse2 unterstützt.

Abgesehen von der Kompilierung in zwei separate dynamische Bibliotheken, was kann getan werden, um dieses Problem zu umgehen? Ich brauche eine Lösung, die sowohl mit Visual Studio als auch mit Windows, Mac OS X und Linux funktioniert.

+0

'std :: vector' wird entweder in einer dynamischen Bibliothek oder einer statischen Bibliothek implementiert, die mit Ihrem eigenen Objekt verknüpft ist (z. B. in glibc). Ihre Objektdateien sollten nur die Deklaration von 'std :: vector' und nicht die Implementierung/Definition enthalten. Was ist das Problem? –

+0

Zunächst war std :: vector nur ein Beispiel. Ich spreche auch über andere Bibliotheken von Drittanbietern, die nur Header sein können. Zweitens ist std :: vector eine Vorlage, so dass der Code in meinen eigenen Objektdateien vorhanden ist. –

+0

[Das könnte Sie interessieren] (https://stackoverflow.com/questions/30320369/aliass-of-a-function-template). Wenn Sie eine Bibliothek aus einer Headerdatei verwenden, stellen Sie sicher, dass alle Funktionen statisch inline sind. Das ist, was ich tue. –

Antwort

0

Ein Ansatz wäre es, auf der Shared-Library-Ebene anstelle der Objektdateiebene zu versenden. Dies würde erfordern, dass die gesamte Bibliothek mehrere Male mit unterschiedlicher Befehlssatzunterstützung kompiliert wird und dann zur Laufzeit auf der Grundlage der von Ihnen erkannten CPU-Fähigkeiten zur entsprechenden gemeinsam genutzten Bibliothek gesendet wird. Ich erkläre einen Ansatz, der dafür unter OS X und Linux in this previous answer funktionieren kann. Ich habe jedoch (noch) nicht versucht, dies unter Windows zu implementieren.

+0

Es ist sicherlich eine interessante Lösung, die Sie in der anderen Antwort geschrieben haben. Wie ich jedoch in der Frage gesagt habe, würde ich es lieber mit nur einer einzigen dynamischen Bibliothek machen. Ich weiß, wie man es mit mehreren Bibliotheken macht, wenn auch in weniger kluger Weise, als Sie vorschlagen, –

-3

Dieses Szenario wird vollständig in der Sprache unterstützt und sollte keine explizite Behandlung erfordern. Ihr dynamisches Dispatch-Szenario hat nicht viel damit zu tun - es ist sehr typisch für ein Projekt, std :: vector in mehreren Übersetzungseinheiten zu instanziieren, und trotzdem wird ODR nicht verletzt. Im Allgemeinen sind Inline-Funktionen - und insbesondere Template-Instanziierungen - für den Linker einfach nicht sichtbar (d. H. Erscheinen in den Obj-Dateitabellen nicht als "External").

Wenn Sie aus bestimmten exotischen Gründen diesen Verknüpfungstyp explizit steuern müssen, müssen Sie auf Compiler-spezifische Geräte zurückgreifen. Das MSVC-Gerät ist selectany, gcc hat some other devices. Ich weiß nicht, ob es klirrt - aber der Punkt ist, dass es dir schwerfällt, einen Grund zu finden, einen von ihnen zu benutzen.

+0

Das Problem, auf das sich das OP bezieht, ist nicht ODR-bezogen. Das Problem ist, dass die verschiedenen Instanziierungen von "std :: vector " zum Beispiel in seinem Szenario nicht austauschbar sind, da sie mit unterschiedlicher Befehlssatzunterstützung kompiliert werden.Es gibt keine Garantie dafür, dass Template-Instanziierungen inline sind, sodass der Linker die verschiedenen Instanziierungen eines bestimmten Symbols deduplizieren muss. Im Fall des OP gibt es keine Möglichkeit für den Linker zu wissen, welche der verschiedenen Instanziierungen für die Verwendung akzeptabel wäre, daher das Problem. –

+0

Genau, JasonR. Es scheint, dass, wenn ich mich mit den Objektdateien/Bibliothek des kleinsten Befehlssatzes verlinke, zuerst diejenigen Implementierungen ausgewählt werden, die zumindest das Problem des Versuchs, einen nicht unterstützten Befehl auszuführen, entfernen. Das entfernt jedoch jeden Leistungsvorteil von diesem Teil des Codes. –