2014-04-24 10 views
5

Bearbeiten: die Kommentare unter der angenommenen Antwort zeigen, dass es ein Problem mit dem Android Dynamic Loader sein könnte.Statische * Vorlage * Klassenmitglied über dynamische Bibliothek

Ich habe eine Überschrift für eine Vorlagenklasse mit einem statischen Mitglied. Zur Laufzeit wird die Adresse des statischen Members in der Bibliothek und im Client-Code verwendet. Die Vorlage wird implizit sowohl in der Bibliothek als auch im Client-Code instanziiert. Es funktioniert gut unter Linux und OSX, das Symbol ist dupliziert, aber markiert als "uniqued", wie durch nm angezeigt (siehe unten). Allerdings, wenn ich für ARM (Android) kompilieren, wird das Symbol sowohl im DSO als auch in der ausführbaren Datei als schwach markiert. Der Loader vereinheitlicht nicht und das Symbol wird zur Laufzeit effektiv dupliziert!

Ich lese diese: two instances of a static member, how could that be? Static template data members storage und vor allem diese Antwort: https://stackoverflow.com/a/2505528/2077394 und: http://gcc.gnu.org/wiki/Visibility

aber ich bin immer noch ein wenig verwirrt. Ich verstehe, dass die Attribute für die Sichtbarkeit zu optimieren helfen, aber ich dachte, es sollte standardmäßig funktionieren. Ich weiß, dass der C++ - Standard sich nicht um eine gemeinsam genutzte Bibliothek kümmert, aber bedeutet dies, dass die Verwendung von gemeinsam genutzten Bibliotheken den Standard bricht? (oder zumindest diese Implementierung ist nicht C++ Standard konform?) Bonus: Wie kann ich es beheben? (Und nicht die Vorlage ist keine akzeptable Antwort :))

Rubrik:

template<class T> 
struct TemplatedClassWithStatic { 
    static int value; 
}; 
template<class T> 
int TemplatedClassWithStatic<T>::value = 0; 

shared.cpp:

#include "TemplateWithStatic.hpp" 
int *addressFromShared() { 
    return &TemplatedClassWithStatic<int>::value; 
} 

main.cpp:

#include "TemplateWithStatic.hpp" 
#include <cstdio> 

int *addressFromShared(); 
int main() { 
    printf("%p %p\n", addressFromShared(), &TemplatedClassWithStatic<int>::value); 
} 

und Gebäude , Blick auf die Symbole Definitionen:

Herstellung .so:

g++-4.8 -shared src/shared.cpp -o libshared.so -I include/ -fPIC 

Kompilieren und Linken Haupt:

nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value' 
libshared.so:0000000000200a70 u TemplatedClassWithStatic<int>::value 
a.out:00000000006012b0 u TemplatedClassWithStatic<int>::value 

Herstellung .so

~/project/android-ndk-r9/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ -o libshared.so src/shared.cpp -I include/ --sysroot=/Users/amini/project/android-ndk-r9/platforms/android-14/arch-arm/ -shared 

:

g++-4.8 src/main.cpp -I include/ -lshared -L. 

Symbole als "einzigartig" gekennzeichnet sind, Kompilieren und Verknüpfen Haupt

~/project/android-ndk-r9/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ src/main.cpp libshared.so -I include/ --sysroot=${HOME}/project/android-ndk-r9/platforms/android-14/arch-arm/ -I ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/include -I ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include -I ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/include/backward -I ~/project/android-ndk-r9/platforms/android-14/arch-arm/usr/include ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/libgnustl_static.a -lgcc 

Symbole sind schwach!

nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value' 
libshared.so:00002004 V TemplatedClassWithStatic<int>::value 
a.out:00068000 V TemplatedClassWithStatic<int>::value 

bearbeiten, Note für den Kontext: Ich mit OOLua spielt, eine Bibliothek zu helfen Bindung C++ zu Lua und meine Unittests noch nicht bestehen, als ich begann Android Ziel. Ich "besitze" den Code nicht und würde ihn lieber tief modifizieren.

bearbeiten, es auf Android laufen:

adb push libshared.so data/local/tmp/ 
adb push a.out data/local/tmp/ 
adb shell "cd data/local/tmp/ ; LD_LIBRARY_PATH=./ ./a.out" 
0xb6fd7004 0xb004 

Antwort

4

Android unterstützt keine eindeutige Symbole. Es ist eine GNU-Erweiterung des ELF-Formats, die nur mit GLIBC 2.11 und höher funktioniert. Android verwendet GLIBC überhaupt nicht, es verwendet eine andere C-Laufzeit namens Bionic.

(Update) Wenn schwache Symbole funktionieren nicht für Sie (Ende update) Ich fürchte, Sie den Code so ändern würde, dass es nicht auf statische Daten angewiesen ist.

+0

Danke. Sollte ich zu dem Schluss kommen, dass die Android-Toolchain den vollständigen C++ - Standard nicht unterstützt, solange Sie Shared Libraries verwenden? – Joky

+0

"Die Android-Toolchain unterstützt den C++ - Standard nicht vollständig, solange Sie Shared Libraries verwenden" - Eigene Experimente mit schwachen Symbolen (unter Linux) deuten darauf hin, dass sie tatsächlich für statische Daten in gemeinsam genutzten Bibliotheken funktionieren. Das heißt, der Linker wird nur eines der schwachen Symbole verwenden, die anderen werden ignoriert. Hast du versucht, dein Programm zu starten? –

+0

Ja, die gedruckte Adresse ist anders (nur für Android) – Joky

1

Es kann einige Compiler/Linker-Einstellungen, die Sie optimieren können, um dies zu ermöglichen (haben Sie an der -fvisibility Flagge sah?).

Möglicherweise ein GCC Attribut Modifikator einen Versuch wert sein kann (Set explizit __attribute__ ((visibility ("default"))) auf der Variable).

dass Failing, die einzigen Abhilfen konnte ich vorschlagen, sind: (alle etwas hässlich sind):

  1. Explizit alle Formen der Vorlage instanziiert, die in der gemeinsam genutzten Bibliothek erstellt werden und die Initialisierungen in ihrer Umsetzung zur Verfügung stellen (nicht im Header). Dies kann oder kann nicht funktionieren.
  2. Wie (1), aber eine Shimfunktion als myers Singletons für den gemeinsam benutzten Variable (Beispiel unten) verwenden.
  3. Ordnen Sie eine Variable in einer Karte für die Klasse basiert auf rtti (die auch über eine gemeinsam genutzte Bibliothek Grenze scheitern könnte).

z.B.

template<class T> 
struct TemplatedClassWithStatic { 
    static int& getValue() { return TemplatedClassWithStatic_getValue((T const*)0); } 
}; 
// types used by the shared library.. can be forward declarations here but you run the risk of violating ODR. 
int& TemplatedClassWithStatic_getValue(TypeA*); 
int& TemplatedClassWithStatic_getValue(TypeB*); 
int& TemplatedClassWithStatic_getValue(TypeC*); 

shared.cpp

int& TemplatedClassWithStatic_getValue(TypeA*) { 
    static int v = 0; 
    return v; 
} 
int& TemplatedClassWithStatic_getValue(TypeB*) { 
    static int v = 0; 
    return v; 
} 
int& TemplatedClassWithStatic_getValue(TypeC*) { 
    static int v = 0; 
    return v; 
} 

Die ausführbare Datei auch Implementierungen bieten für alle Typen, die es um die Vorlage zu instanziieren verwendet würde.

+0

Ja, ich kenne die mögliche Problemumgehung, und ich würde das tun, wenn ich meine eigene Bibliothek entwerfen würde. Aber hier ist es nicht möglich, da ich den Code nicht "besitze" und ich würde ihn lieber tief modifizieren. Ich habe dieses Problem mit OOLUA. Jetzt frage ich mich, ob mein Testfall nach dem Standard funktionieren soll oder nicht. Wenn es funktionieren sollte, kann ich es als GCC-Fehler betrachten! – Joky

Verwandte Themen