【问题标题】:Android NDK - 'extern' functions in library not found when app startsAndroid NDK - 应用程序启动时未找到库中的“外部”函数
【发布时间】:2014-07-12 00:15:06
【问题描述】:

我使用 NDK 构建了我的共享库,其中几乎没有其他库。我的库几乎没有定义“外部”函数。由于它是一个库,因此这些“外部”函数随后在项目 (.cpp) 文件中声明。我有一个问题,应用程序构建得很好,并在设备上崩溃并出现以下错误:

07-12 00:45:03.680: E/dalvikvm(2161): dlopen("/data/app-lib/org.libsdl.app-16/libRTEngine.so") 失败:dlopen 失败:找不到“libRTEngine.so”引用的符号“RTEngineSetup”...

这个 RTEngineSetup 函数在我的库中定义为:extern "C" void RTEngineSetup(); 然后我的应用程序将其声明为: void RTEngineSetup() { ... }

似乎无法将它们链接在一起。该系统在台式机上运行良好。

这是我的代码设计图: http://s14.postimg.org/s0r83u801/my_code.png

这是我如何构建我的库(第一部分)和我的应用程序(包括我的库)(第二部分): http://ann-tech.com/lib_Android.txt

如果有人知道为什么'extern' 定义 () 没有与它在应用程序的 .cpp 文件中的声明链接,请告诉我。现在浪费了 2 天。

感谢您的宝贵时间。

【问题讨论】:

    标签: android android-ndk shared-libraries shared extern


    【解决方案1】:

    首先,不要在您的 Android.mk 中允许 LOCAL_ALLOW_UNDEFINED_SYMBOLS。然后您的问题将在链接步骤中可见。

    哪个 .cpp 文件定义了 RTEngineSetup?它是否包含将其声明为 extern "C" 的头文件?

    在 NDK 工具链中有一个 nm 实用程序,它可以显示在每个 .so 中定义的符号列表,以及外部引用。

    很遗憾,Android 动态加载器无法解析循环依赖。您可以将 libRTApp 拆分为两部分(一个仅提供 RTEngineSetup() 和她的亲属以供 libRTEngine.so 链接,另一个 - 取决于 RTEngine 和所有其他库),或者在 libRTEngine 中使用 dlsym()在运行时找到对 RTEngineSetup()` 及其亲属的引用,例如

    pRTEngineSetup = dlsym(RTLD_DEFAULT, "RTEngineSetup");
    

    ..等等

    【讨论】:

    • 感谢您的回复。
    • 感谢您的回复。这种结构在其他平台上工作得很好。 Libs ==> MyEngine(有 5 个外部“C”定义)==> 应用程序(使用 MyEngine 并声明这 5 个外部函数)如果我在构建 MyEngine 库时不使用 LOCAL_ALLOW_UNDEFINED_SYMBOLS,我会收到以下错误:pastebin.com/rfmqB5cJ 如果我将该标志设置为true,它构建MyEngine Lib,并使用此Lib构建应用程序,但随后说我的extern“C”函数没有在任何地方声明,即使它们在我的应用程序中,使用这个lib。有什么想法吗?
    • 这是另一张图片,希望能更好地解释我的工作:s14.postimg.org/4t3vl5ds1/my_stuff.png 问题是,我的引擎似乎不像 Lib(在 NDK 上)那样构建,否则它会知道一些它的功能是在它之外声明的。
    • 那么,RTEngineSetup 和其他人是从libRTApp.so 导出的?您应该在libRTApp.so 之后链接libRTEngine.so。依赖项由LOCAL_SHARED_LIBRARIES 控制。
    • 可能觉得crazy linker很有用。
    【解决方案2】:

    亚历克斯!

    这太棒了!非常感谢你。我是 NDK 和 Android 编码的新手,所以不得不连续破解 3 天。当您说要使用 dlsym() 时,我不知道它是什么。但我已经想通了,现在一切都很完美。

    解决方案: 如果您的库有 C++ 函数(定义)为 extern - extern void Update(); 例如, 并且您正在尝试将此库链接到您的应用程序,您想要(声明)这些函数,例如:void Update() { ... },您必须在您的库 C++ 代码中添加以下代码:

    //Library file pointer
    void *handle;
    handle = dlopen( "lib/libRTApp.so", RTLD_LOCAL | RTLD_LAZY );
    
    // New names for functions you are linking to
    void ( *RTUpdate )( void ), ( *RTClose )( void );
    
    // Assigning function to a pointer
    *( void ** ) ( &RTUpdate ) = dlsym( handle, "RTAppUpdate" );
    *( void ** ) ( &RTClose ) = dlsym( handle, "RTAppClose" );
    
    // Free the memory!
    dlclose( handle );  
    

    非常感谢亚历克斯·科恩!你救了我。

    【讨论】:

    • 我相信你不需要dlopen(),但是dlsym(RTLD_DEFAULT, name)就足够了。要验证吗?
    • 是的,亚历克斯,你是对的。这样就更容易了 :) 非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2011-10-17
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 2013-12-22
    相关资源
    最近更新 更多