【问题标题】:How to properly setup dynamic library loading with header file?如何使用头文件正确设置动态库加载?
【发布时间】:2017-11-02 21:02:36
【问题描述】:

标题很难写好,所以让我解释一下我的情况:

另一个团队开发了一个库。他们提供一个头文件和一个*.so 文件。头文件可供我们使用,我们可以将其包含在我们自己的代码中并根据需要使用它。但是,*.so 是随我们运行的平台一起提供的。在构建我们的软件时,我们无权访问此 *.so。因此,我们也不能真正使用头文件,因为链接器会期望 *.so 在某个时候可用。

现在我要做的是创建一个包装类,它在运行时加载*.so 文件,然后使用dlsym() 按名称查找函数,并将它们映射到函数指针。

这是唯一的选择吗?有没有办法我可以使用头文件,但告诉链接器不要在构建时解析符号,而是在我们有机会加载 *.so 文件后尝试在运行时解析它们?

注意这里的真正平台是 Android(通过 NDK),但希望一般的 linux 建议在这种情况下也能正常工作,因为我们有可用的 POSIX API。

【问题讨论】:

    标签: android c++ c android-ndk


    【解决方案1】:

    您有几个选项,按优先顺序排列:

    1. 从维护者处获取库。提供标头而不提供库(至少是像我们为 NDK 中的库所做的那样的存根库)是行不通的。
    2. 构建您自己的存根库。如果您有要公开的符号列表,这非常简单。将int foo; void bar() {} 放入一个 C 文件中,以获取您需要公开并将其构建为共享库的所有变量和函数。如果您在版本脚本中有符号列表,则可以使用 Android 的 gen_stub_libs.py 为您完成。
    3. 在头文件中用__attribute__((weak))标记所有符号。链接器不会抱怨它们丢失了。如果它们在运行时丢失,库仍然会加载,但每个函数的地址都是nullptr。在大多数情况下并不是您真正想要的,因为如果您对库的定义是错误的,您会将构建时间故障转变为运行时故障,但在某些情况下这可能很方便,因为使用if (foo) { foo(); } 检查功能可用性然后执行类似于dlsym
    4. -Wl,--allow-shlib-undefined 添加到您的ldflags。这甚至比 3 更糟糕,因为它会影响您链接的所有库,但它不需要您干预标头。

    【讨论】:

    • 我最喜欢#1,缺点是现在我必须确保每次发布新版本时都获得最新的库,而不是“自动”获得固件版本在设备上。
    • 理想情况下,他们会在标题旁边提供给您。
    • 我的意思是,大多数时候公共接口不会改变,只是实现。那么我是否应该升级它,无论或以某种方式知道哪些版本会导致 ABI 不兼容并只升级那些版本?
    • 只要 ABI 不变,就不需要更新存根。每次都获取更新的内容可以保护您免受意外,但如果它确实发生了变化。
    【解决方案2】:

    在 Windows 上,这是通过要求链接器存在导出库 (.lib) 而不是真正的动态库 (.dll) 来解决的。我认为您可以尝试制作类似的东西,即制作一个假的 .so ,其中包含从真实 .so 导出的所有方法的存根并链接到它。这有望使链接器快乐,同时在运行时应用程序将加载真正的 .so。

    【讨论】:

    • 这是 NDK 对平台库 FWIW 所做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多