如何使用头文件正确设置动态库加载?

时间:2017-11-02 21:02:36

标签: android c++ c android-ndk

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

另一个团队开发了一个图书馆。他们发送头文件和*.so文件。头文件可供我们使用,我们可以将其包含在我们自己的代码中,并在我们希望的情况下使用它。但是,*.so随我们运行的平台一起提供。我们的软件在构建时无法访问此*.so。因此,我们也无法真正使用头文件,因为链接器会期望*.so在某些时候可用。

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

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

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

您可以按优先顺序选择一些选项:

  1. 从维护者处获取库。提供标题但不提供库(至少是我们对NDK中的库所做的存根库)只是不起作用。
  2. 构建您自己的存根库。如果你有一个要公开的符号列表,那就非常简单了。将int foo; void bar() {}放在C文件中,以获取需要公开的所有变量和函数,并将其构建为共享库。如果您在版本脚本中包含符号列表,则可以使用Android gen_stub_libs.py为您执行此操作。
  3. 在标头文件中标记__attribute__((weak))的所有符号。链接者不会抱怨他们失踪了。如果它们在运行时丢失,则库仍将加载,但每个函数的地址将为nullptr。在大多数情况下,实际上并不是您想要的,因为如果您对库的定义错误,则会将构建时失败转变为运行时失败,但在某些情况下,这可能很方便,因为使用{{更容易检查函数可用性1}}然后与if (foo) { foo(); }类似。
  4. dlsym添加到您的ldflags中。这甚至比3更差,因为它会影响您链接的所有库,但它不会要求您插入标题。