这件事困扰了我一段时间我试着在我的一个项目中将一个共享对象链接到一个可执行文件( struct 如下):

.
├── lib.c
├── lib.h
├── main.c
└── Makefile

...使用此生成文件:

CC != if command -v clang; then continue; elif command -v gcc; then continue; else echo c99; fi

.PHONY: build

build: main
    ./main

lib.so: lib.c
    $(CC)  -shared -fPIC -o lib.so lib.c

main: main.c lib.so
    $(info Building executable: "main")
    $(CC) -o main main.c lib.so

...但是我收到了这个错误:./main: error while loading shared libraries: lib.so: cannot open shared object file: No such file or directory

我确实找到了一些现有的解决方案,包括使用LD_LIBRARY_PATH变量或-Wl,-rpath=path/to/dir编译标志,但让我们说,我想用另一种方法来解决这个问题.

我知道,听我说完.我已经能够成功地运行链接到层次 struct 中的共享对象的二进制文件,如下所示:

.
├── bin/
│   └── main
├── lib/
│   └── lib.so
├── src/
│   ├── lib.c
│   ├── lib.h
│   └── main.c
└── Makefile

...而且我不需要使用这两种方法.在上面的示例中,我还对二进制文件使用了ldd:

$ ldd bin/main
    linux-vdso.so.1 (0x00007ffec55e7000)
    lib/lib.so (0x00007f3198a7f000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007f3198876000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f3198a8b000)

与麻烦的二进制代码相比:

$ ldd main
    linux-vdso.so.1 (0x00007ffc2de5f000)
    lib.so => not found
    libc.so.6 => /usr/lib/libc.so.6 (0x00007880524c3000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007880526d3000)

虽然我可能在这里做了一个假设,但我不会假装我还没有找到这个问题的答案.在我发布这个问题后不久,我将发布我自己的解决方案.

推荐答案

...但是我收到了这个错误:./main: error while loading shared libraries: lib.so: cannot open shared object file: No such file or directory

  1. 你应该把你的图书馆命名为notlib.so.将其命名为libfoo.so(其中foo表示库提供的功能.
  2. 你应该使用指向libfoo.so的路径not链接你的主可执行文件.
    $(CC) -o main main.c -L. -lfoo话这样做
  3. 为了使您的二进制文件在运行时找到libfoo.so,您需要编码到动态加载程序的二进制指令中,告诉它在哪里查找.

有几种常见的方法可用于(3):

  • 使用系统库目录.为此,您可以将libfoo.so复制到例如/usr/local/lib
  • 使用固定目录,例如当前位置.为此,请在链接行中添加-Wl,-rpath=$(pwd).请注意,将此命令添加到Makefile时,您需要转义$.

    这种方法有一个缺点:如果重命名目录,二进制文件将停止工作.
  • 使用目录relative到找到二进制文件本身的位置.为此,请加上-Wl,-rpath='$ORIGIN'.这种方法允许您自由地将{main,libfoo.so}复制到不同的目录并删除原始目录.只要mainlibfoo.so都在同一目录中,二进制文件就会继续工作.
  • 使用LD_LIBRARY_PATH.这样做的优点是,如果/当您移动项目目录时很容易更新,但缺点是您必须维护该变量,并且二进制文件将工作或不工作取决于它运行的环境.

Linux相关问答推荐

我想强调某些条件是否与Linux中的全部输出匹配

C++17/Linux:信号未解锁单独线程中被阻止的网络套接字调用

在同一目录中未检测到G++预编译头

如何更正我的CMakeLists.txt,使我的项目同时构建在Linux和Windows上?

Linux在所有多行中用新值替换整个列

如何使用 gdb 调试堆栈分段错误?

使用ansible配置Linux VM使用vmware_vm_shell模块时变成su?

CMake:处理静态库和共享库的正确方法

sed:用空格替换

中的换行符

linux shell获取多文件交集

BASEDIR 环境变量未正确定义

Bash 变量:是否区分大小写?

打印当前一周的星期一的日期(在 bash 中)

用于 Linux 的 Less 编译器

polkitd未注册身份验证代理的解释

Linux 配置/制作,--prefix?

使用sudo apt-get install build-essentials

使用 Bash 脚本查找文件中字符串的行号

Linux SCHED_OTHER、SCHED_FIFO 和 SCHED_RR - 区别

如何自动启动 Solr?