【问题标题】:How do I source/link external functions in C or C++?如何在 C 或 C++ 中获取/链接外部函数?
【发布时间】:2009-01-06 19:57:43
【问题描述】:

编辑:我想我应该澄清一下,以防万一。我在 AIX Unix 机器上,所以我使用的是 VAC 编译器——没有 gnu 编译器。 结束编辑


我在 C/C++ 方面相当生疏,如果这是一个简单的问题,请原谅我。

我想从我的一些 C 程序中提取常用函数并将它们放入共享库或共享对象中。如果我在 perl 中执行此操作,我会将我的 subs 放在 perl 模块中,并在需要时使用该模块。

举个例子,假设我有这个功能:

int giveInteger()
{
    return 1034;
}

显然这不是一个真实世界的例子,但如果我想分享那个功能,我将如何进行?

我很确定我有两个选择:

  1. 将我的共享函数放在一个文件中,并让它在编译时与我的主程序一起编译。如果我对共享函数进行了更改,我将不得不重新编译我的主程序。
  2. 将我的共享函数放在一个文件中,并将其编译为共享库(如果我的条款正确的话),并将我的主程序链接到该共享库。我对共享库所做的任何更改(在编译后)都将在运行时集成到我的主程序中,而无需重新编译我的主程序。

我的想法正确吗?

如果是这样,我该如何完成这两种方法中的一种/两种?我进行了很多搜索,似乎找到了如何将自己的程序链接到其他人的共享库的信息,但没有找到如何创建自己的共享函数并以可以在自己的程序中使用它们的方式编译它们的信息.

非常感谢!

布赖恩


编辑:

结论

感谢大家的帮助!我想我会在这篇文章中添加对我有用的东西(对于 AIX 上的动态共享库),以便其他人可以受益:

我编译我的共享函数:

xlc -c sharedFunctions.c -o sharedFunctions.o

然后让它成为一个共享对象:

xlc -qmkshrobj -qexpfile=exportlist sharedFunctions.o
xlc -G -o libsharedFunctions.so sharedFunctions.o  -bE:exportlist

然后链接另一个程序:

xlc -brtl -o mainProgram mainProgram.c  -L. -lsharedFunctions

另一条评论帮助我找到了这个链接,这也有帮助: http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/topic/com.ibm.vacpp7a.doc/proguide/ref/compile_library.htm

再次感谢所有帮助过我的人!

【问题讨论】:

  • 您的命令仅对 C 源代码正确。对于 C++,您应该使用 xlC。在您的两个“使其成为共享对象”命令中,只有第二个实际上在做任何有用的事情(第一个链接 a.out,您忽略它)。

标签: c++ c shared-libraries


【解决方案1】:

是的,你是对的。第一个称为静态库,而第二个称为共享库,因为代码并没有在编译时绑定到可执行文件,而是每次在你的程序已加载。

静态库

如下编译你的库代码:

gcc -c *.c

-c 告诉程序不要链接目标文件,而只是为每个已编译的.c 文件留下目标文件。现在,将它们归档到一个静态库中:

ar rcs libmystuff.a *.o 

man ar 会告诉你 rcs 选项的含义。现在,libmystuff.a 是一个 archive 文件(您可以使用一些 zip 文件查看器打开它),其中包含这些目标文件以及每个目标文件的符号索引。您可以将其链接到您的程序:

gcc *.c libmystuff.a -o myprogram

现在,您的程序已准备就绪。请注意,静态库在命令中出现的顺序很重要。请参阅我的Link order 答案。

共享库

对于共享库,您将使用

创建您的库
gcc -shared -o libmystuff.so *.c

就是这样,libmystuff.so 现在是一个shared object 文件。如果要将程序链接到它,则必须将其放入/etc/ld.so.conf 文件中列出的目录中,或者由-L 切换到 GCC 给出的目录中,或者在 LD_LIBRARY_PATH 变量中列出的目录中。链接时,从您告诉 gcc 的库名称中删除 lib 前缀和 .so 后缀。

gcc -L. -lmystuff *.c -o myprogram

在内部,gcc 只会将您的参数传递给 GNU 链接器。您可以使用-### 选项查看它传递的参数:Gcc 将打印给每个子进程的确切参数。

有关链接过程的详细信息(一些事情是如何在内部完成的),请查看我的Linux GCC linker 答案。

【讨论】:

【解决方案2】:

您还有第三种选择。通常,您的 C++ 编译器应该能够链接 C 例程。必要的选项可能因编译器而异,因此 R 是您的好 M,但基本上,您应该能够使用 g++ 进行编译,如下所示:

$ g++ -o myapp myapp.cpp myfunc.c giveint.c

...或单独编译

$ gcc -c myfunc.c
$ gcc -c giveint.c
$ g++ -c myapp.cpp
$ g++ -o myapp myapp.o myfunc.o

您还需要包含函数声明;你在 C++ 中这样做

extern "C" {
    int myfunc(int,int);
    int giveInterger(void);
}

【讨论】:

  • 通常 .h 文件即使对于 c 也在 #ifdef CPP 中包含 extern "C" 位,仅针对这种情况。
  • 谢谢查理 - 我没有 gcc,所以我不确定这是否会有所不同 - 我刚刚编辑了我的帖子以说明我有 VAC 编译器......
  • 命令行有点不同,但差别不大。想法没有区别。
  • 是的,一些测试是否定义了 __cplusplus 并将 extern "C" 放在其声明周围。 c++ 编译器必须定义它。但其他一些库没有。
  • -o 和 -c 选项非常标准。 AT&T 的旧编译器使用它们,IBM 当前的 AIX 编译器使用它们 (publib.boulder.ibm.com/infocenter/comphelp/v7v91/…)。
【解决方案3】:

你需要区分重新编译和重新链接。

如果您将giveInteger() 放入单独的(存档)库中,然后稍后对其进行修改,您(显然)需要重新编译定义它的源文件,然后重新链接所有使用它的程序;但您不需要重新编译这样的程序 [1]。

对于共享库,您需要重新编译并重新链接该库;但您不必重新链接或重新编译任何使用它的程序。

过去在 AIX 上构建 C++ 共享库很复杂;您需要使用 makeC++SharedLib shell 脚本。但是有了 VAC 5.0 和 6.0,它变得非常容易。我相信您需要做的就是[2]:

xlC -G -o shr.o giveInteger.cc
xlC -o myapp main.cc shr.o

[1] 如果您编写正确的 Makefile(这是推荐的做法),所有这一切都会在您键入 make 时自动发生。

[2] AIX 的某个特性可能会使事情复杂化:默认情况下,共享库被加载到内存中,并“粘”在那里直到随后重新启动。因此,您可以重建 shr.o,重新运行程序,并观察正在执行的库的“旧”版本。为了防止这种情况发生,一种常见的做法是让 shr.o 不可读:

chmod 0750 shr.o

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-02
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    相关资源
    最近更新 更多