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

Jok*_*oky 5 c++ templates shared-libraries android-ndk c++11

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

我有一个带有静态成员的模板类的标题.在运行时,静态成员的地址在库和客户端代码中使用.模板在库和客户端代码中都是隐式实例化的.它在Linux和OSX上工作正常,符号是重复的,但标记为"unqued",如nm所示(见下文).但是,当我为ARM(Android)编译时,符号在DSO和可执行文件中都标记为弱.加载器不统一,符号在运行时有效复制!

我读了这些: 静态成员的两个实例,怎么可能呢? 静态模板数据成员存储 ,尤其是这个答案:https: //stackoverflow.com/a/2505528/2077394 和:http: //gcc.gnu.org/wiki/Visibility

但我仍然有点困惑.我知道可见性的属性有助于优化,但我认为它应该默认工作.我知道C++标准并不关心共享库,但这是否意味着使用共享库会破坏标准?(或者至少这个实现不符合C++标准?)奖励:我该如何修复它?(而不是使用模板不是一个可接受的答案:))

标题:

template<class T>
struct TemplatedClassWithStatic {
    static int value;
};
template<class T>
int TemplatedClassWithStatic<T>::value = 0;
Run Code Online (Sandbox Code Playgroud)

shared.cpp:

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

main.cpp中:

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

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

并建立,看看符号定义:

生产.so:

 g++-4.8  -shared src/shared.cpp  -o libshared.so -I include/ -fPIC
Run Code Online (Sandbox Code Playgroud)

编译和链接主要:

 g++-4.8 src/main.cpp -I include/ -lshared -L.
Run Code Online (Sandbox Code Playgroud)

符号标记为"唯一":

nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value'
libshared.so:0000000000200a70 u TemplatedClassWithStatic<int>::value
a.out:00000000006012b0 u TemplatedClassWithStatic<int>::value
Run Code Online (Sandbox Code Playgroud)

生产.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
Run Code Online (Sandbox Code Playgroud)

编译和链接主要

~/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
Run Code Online (Sandbox Code Playgroud)

符号很弱!

nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value'
libshared.so:00002004 V TemplatedClassWithStatic<int>::value
a.out:00068000 V TemplatedClassWithStatic<int>::value
Run Code Online (Sandbox Code Playgroud)

编辑,注意上下文:我正在玩OOLua,一个帮助将C++绑定到Lua的库,当我开始定位Android时,我的单元测试失败了.我没有"拥有"代码,我宁愿深深地修改它.

编辑,在Android上运行它:

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
Run Code Online (Sandbox Code Playgroud)

n. *_* m. 5

Android 不支持唯一符号。它是 ELF 格式的 GNU 扩展,仅适用于 GLIBC 2.11 及更高版本。Android 根本不使用 GLIBC,它采用不同的 C 运行时,称为 Bionic。

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