7

改写的问题(虽然它已经解决了):

我在使用 dlopen(3) 在 linux 上加载共享对象库时遇到了麻烦。该库是我构建的库系统的一部分,这些库都在运行时由中央可执行文件加载。所有这些都被组织到 Code::Blocks 中的单个工作区中,每个项目在一个名为 Source 的目录中都有自己的文件夹,该文件夹将随程序一起提供。可执行文件的build目录是从自己的源代码倒过来的两个目录,这样可执行文件和Source文件夹在同一个目录下,库也和可执行文件build到同一个目录,所以我自然传递了库的名字我正在尝试打开,如图所示:

int main(int argc, char** argv) {
    void* hLibrary = dlopen("libLibrary.so", RTLD_NOW | RTLD_GLOBAL);
    if(hLibrary == NULL) {
        fprintf(stderr, "%s\n", dlerror());
        return 1;
    }

    return 0;
}

这在构建目录与源代码相同的时候起作用,直到我将源代码的目录更改为上述安排。此时的问题是 dlerror() 返回“无法打开 libLibrary.so:没有这样的文件或目录”,即使该文件明显存在并且与可执行文件位于同一目录中。然后我尝试传入“/libLibrary.so”,因为根据 dlopen(3) 上的手册页,添加 / 表示相对目录。这返回了相同的错误。

解决方案是需要一个“./” - 其中“.” 表示可执行文件的工作目录 - 并且需要在 Code::Blocks 中将工作目录更改为要构建可执行文件的位置。以下工作完美:

void* hLibrary = dlopen("./libLibrary.so", RTLD_NOW | RTLD_GLOBAL);

这并没有真正显示完整的解决方案,但以下基本上相当于我正在做的事情:

void* hLibrary = dlopen("./../../libLibrary.so", RTLD_NOW | RTLD_GLOBAL);

希望这能更好地解释这种情况。

4

2 回答 2

17

阅读dlopen(3)手册页(例如,通过man dlopen在您的机器上输入终端):

如果文件名包含斜杠(“/”),则将其解释为(相对或绝对)路径名。否则,动态链接器会按如下方式搜索库(有关详细信息,请参阅 ld.so(8)):

   o   (ELF only) If the executable file for the calling program
       contains a DT_RPATH tag, and does not contain a DT_RUNPATH tag,
       then the directories listed in the DT_RPATH tag are searched.

   o   If, at the time that the program was started, the environment
       variable LD_LIBRARY_PATH was defined to contain a colon-separated
       list of directories, then these are searched.  (As a security
       measure this variable is ignored for set-user-ID and set-group-ID
       programs.)

   o   (ELF only) If the executable file for the calling program
       contains a DT_RUNPATH tag, then the directories listed in that
       tag are searched.

   o   The cache file /etc/ld.so.cache (maintained by ldconfig(8)) is
       checked to see whether it contains an entry for filename.

   o   The directories /lib and /usr/lib are searched (in that order).

所以你需要调用dlopen("./libLibraryName.so", RTLD_NOW)- 不仅仅是dlopen("libLibraryName.so", RTLD_NOW)希望你的插件在你的$LD_LIBRARY_PATHon in/usr/lib/等.... - 或添加.到你的LD_LIBRARY_PATH(出于安全原因我不推荐)。

正如Jhonnash 回答的那样,您应该使用并显示dlerrorwhen dlopen(or dlsym) 失败的结果:

  void* dlh = dlopen("./libLibraryName.so", RTLD_NOW);
  if (!dlh) 
    { fprintf(stderr, "dlopen failed: %s\n", dlerror()); 
      exit(EXIT_FAILURE); };

您可能想阅读一些书籍,例如Advanced Linux Programming,以了解有关 Linux 系统编程的一般知识。

于 2013-07-18T06:56:14.533 回答
2

关于dlopen的定义;可以检查动态库 dlopen 错误。链接出现未定义符号错误

于 2013-07-18T06:21:44.570 回答