Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 跨动态库的静态*模板*类成员_C++_Templates_C++11_Android Ndk_Shared Libraries - Fatal编程技术网

C++ 跨动态库的静态*模板*类成员

C++ 跨动态库的静态*模板*类成员,c++,templates,c++11,android-ndk,shared-libraries,C++,Templates,C++11,Android Ndk,Shared Libraries,编辑:接受答案下面的评论表明这可能是Android动态加载程序的问题 我有一个带有静态成员的模板类的头。在运行时,静态成员的地址将在库和客户端代码中使用。模板在库和客户机代码中都隐式实例化。它在Linux和OSX上运行良好,符号是重复的,但标记为“uniqued”,如nm所示(见下文)。 然而,当我为ARM(Android)编译时,符号在DSO和可执行文件中都被标记为弱。加载程序不统一,符号在运行时被有效复制 我读到: 尤其是这个答案: 以及: 但我还是有点困惑。我知道可见性属性有助于优化,但

编辑:接受答案下面的评论表明这可能是Android动态加载程序的问题

我有一个带有静态成员的模板类的头。在运行时,静态成员的地址将在库和客户端代码中使用。模板在库和客户机代码中都隐式实例化。它在Linux和OSX上运行良好,符号是重复的,但标记为“uniqued”,如nm所示(见下文)。 然而,当我为ARM(Android)编译时,符号在DSO和可执行文件中都被标记为弱。加载程序不统一,符号在运行时被有效复制

我读到: 尤其是这个答案: 以及:

但我还是有点困惑。我知道可见性属性有助于优化,但我认为它在默认情况下应该可以工作。我知道C++标准不关心共享库,但这是否意味着使用共享库违反了标准?(或者至少这个实现不是C++标准符合?) 奖金:我怎样才能修好它?(不使用模板是不可接受的答案:))

标题:

template<class T>
struct TemplatedClassWithStatic {
    static int value;
};
template<class T>
int TemplatedClassWithStatic<T>::value = 0;
编辑和链接主要内容:

 g++-4.8 src/main.cpp -I include/ -lshared -L.
符号标记为“唯一”:

编译和链接main

~/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
符号很弱

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

您可以调整一些编译器/链接器设置来启用此功能(是否查看了
-fvisibility
标志?)

可能值得尝试使用GCC属性修饰符(在变量上显式设置
\uuuuuuu属性((可见性(“默认”))

如果做不到这一点,我唯一能建议的解决办法是:(所有这些都有点难看):

  • 显式实例化在共享库中创建的模板的所有形式,并在其实现中(而不是在标头中)提供初始值设定项。这可能有效,也可能无效
  • 与(1)类似,但使用shim函数作为共享变量的myers单例(下面的示例)
  • 基于rtti在映射中为类分配一个变量(这也可能会跨共享库边界失败)
  • e、 g


    可执行文件还必须提供用于实例化模板的任何类型的实现。

    Android不支持唯一符号。它是ELF格式的GNU扩展,仅适用于GLIBC2.11及更高版本。Android根本不使用GLIBC,它使用了另一种叫做仿生的C运行时


    (更新)如果弱符号不适用于您(结束更新),恐怕您必须修改代码,使其不依赖于静态数据。

    是的,我知道可能的解决方法,如果我要设计自己的库,我会这样做。但在这里,这是不可能的,因为我不“拥有”代码,我宁愿深入修改它。我和乌鲁阿有这个问题。现在我想知道我的测试用例是否应该按照标准工作。如果它应该工作,那么我可以认为它是一个GCC的错误!谢谢我应该得出结论,只要你开始使用共享库,Android工具链就不支持完全的C++标准吗?“只要你开始使用共享库,Android工具链就不支持完全的C++标准”---我自己对弱符号(Linux上)的实验表明,它们实际上是在共享库间工作的静态数据。也就是说,链接器将只强制使用一个弱符号,其他实例将被忽略。您是否尝试运行您的程序?是的,打印的地址不同(仅在Android上)。您是否使用
    dlopen
    打开共享库?当地址确实不同时就会出现这种情况。地址应该是相同的,在Linux上也是相同的。这意味着模板与此无关。这纯粹是安卓libc的问题。
     g++-4.8 src/main.cpp -I include/ -lshared -L.
    
    nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value'
    libshared.so:0000000000200a70 u TemplatedClassWithStatic<int>::value
    a.out:00000000006012b0 u TemplatedClassWithStatic<int>::value
    
    ~/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
    
    ~/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
    
    nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value'
    libshared.so:00002004 V TemplatedClassWithStatic<int>::value
    a.out:00068000 V TemplatedClassWithStatic<int>::value
    
    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
    
    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*);
    
    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;
    }