如何使用.so文件运行C程序

12

我已经阅读了StackOverflow和Ask Ubuntu上的所有解决方案。

我有一个Go程序:

package main

import "C"

//export Getint
func Getint() int {
        return  2
}

func main() {}

我已经生成了一个名为t.so和头文件t.h.so文件。

现在我想在我的C程序中使用这个函数。
我已经编写了代码但不知道如何执行它。

#include <stdio.h>
#include <t.h>
int main()
{
int a;
a=Getint();
printf("number : %d",a);
return 0;
}

当我使用它执行时

gcc c.c t.so

它会生成 a.out 文件

但在运行 a.out 时,输入命令 ./a.out 会出现错误:

./a.out
Error while loading shared libraries: t.so: can not open shared object file: no such file or directory exists.

然后我尝试了以下方法:

gcc -c c.c -l t.so

因此它生成c.o文件,但该文件不可执行。


所有这些文件都在同一个位置。 - NIket
4个回答

11
你应该使用链接器选项 -rpath,这会告诉链接器在可执行程序中添加信息,以便找到运行时库,比如你的.so文件。
这可以通过GCC选项-Wl来完成,它指示GCC前端程序向链接器传递一个选项:
$ gcc c.c t.so -Wl,-rpath=$(pwd)

这将向链接器传递-rpath=$(pwd),而$(pwd)会导致shell调用pwd命令返回当前目录。只要不移动库文件,程序就应该能正常工作。
你可以使用环境变量 LD_LIBRARY_PATH ,但这样做 不被推荐

5

很可能您的加载器找不到该库。尝试在运行二进制文件之前将库所在目录的路径放入LD_LIBRARY_PATH中。

export LD_LIBRARY_PATH=/path/to/my/library
./a.out

在修改"LD_LIBRARY_PATH"时有一些问题需要注意,例如https://stackoverflow.com/a/36048246/5595995。 - undefined

3

.so文件是共享对象,也就是能够供需要它们的所有应用程序使用的对象,也就是共享的。由于这个特性,它们需要存储在一个众所周知的位置,并且需要被动态链接器索引。

例如,在Linux中,您通常会有一个名为/etc/ld.so.conf的文件,其中存储了自动从中读取共享对象的所有目录。

因此,您可以选择以下选项:

  • 将您的共享对象文件放入一个众所周知的位置
  • 将您的共享对象文件放在您选择的位置,并让动态链接器知道它:在Linux中,您可以修改ld.so.conf并运行ldconfig来更新ld索引
  • 如其他人建议的那样,在环境创建时将您的.so路径写入env变量LD_LIBRARY_PATH(由于动态链接器在运行应用程序之前读取该变量)。这必须在每个环境创建时完成
  • 如其他人建议的那样,在编译时使用-rpath。请注意,以这种方式编译后,您无法移动.so文件

个人而言,我更喜欢将.so文件安装在系统库路径中。


你能为“一个著名地方”添加信息吗? - undefined
1
如答案所述,“众所周知的地方”是指已经在文件/etc/ld.so.conf中索引的目录;通常/usr/lib是始终包含的通用路径,但请再次检查您的/etc/ld.so.conf。请注意,您可能在/etc/ld.so.conf中有一个指令,用于包含/etc/ld.so.conf.d/中存在的所有文件;在这种情况下,逐个打开它们并找到最适合您的路径。 - undefined
修改"/etc/ld.so.conf"文件有什么不利之处吗?我在这里找到了https://man7.org/linux/man-pages/man8/ldconfig.8.html,它似乎暗示手动编辑不被推荐。 - undefined
如果你知道你在做什么,并且你是唯一使用你的计算机的用户,我不认为有任何缺点。举个例子,你正在为一个共享库的项目1工作,同时也在为将使用该库的项目2工作。我会: 1)让项目1的输出文件命名为libprj1.so,放在target目录中。 2)在ld.so.conf中添加target的绝对路径。 3)每次重新创建libprj1.so后运行ldconfig命令。 4)使用-l prj1参数正常编译项目2。如果你更改了库文件,你不需要重新编译项目2(但每次都需要调用ldconfig命令)。 - undefined
谢谢分享这个案例。我正在寻找(手动)将生成的SO文件放置在适当的文件夹位置,以便在可执行文件运行时调用(而不是编译)。
  • 你提到的“众所周知”的位置似乎是一个不错的选择,但是没有可追溯性。
  • (手动)修改“/etc/ld.so.conf”听起来更加冒险。
  • 不推荐使用LD_LIBRARY_PATH(参考:https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html中的“rpath vs. LD_LIBRARY_PATH”)
  • “rpath”是在CPP代码编译期间使用的方法,而不是在可执行文件运行时。
- undefined
显示剩余2条评论

1
您应该使用LD_LIBRARY_PATH来让动态链接器在列表中找到您的共享库。语法类似于PATH,是由:分隔的目录列表。
在OSX上,这个环境变量被称为DYLD_LIBRARY_PATH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接