14

我对程序如何使用共享库有一些疑问。

当我构建一个共享库(使用 -shared -fPIC 开关)时,我会从外部程序中提供一些功能。通常我会做一个 dlopen() 来加载库,然后 dlsym() 将上述函数链接到一些函数指针。此方法不涉及包含任何 .h 文件。有没有办法避免做 dlopen() & dlsym() 并且只包括共享库的 .h ?

这可能是 c++ 程序如何使用存储在系统共享库中的代码。即只包括stdlib.h等。

4

5 回答 5

64

尼克,我认为所有其他答案实际上都是在回答您的问题,即您如何链接库,但是您提出问题的方式表明您对头文件和库之间的区别存在误解。它们是不相同的。你需要两者,他们做的不是同一件事。

构建可执行文件有两个主要阶段,编译(将您的源代码转换为中间形式,包含可执行的二进制指令,但不是可运行的程序)和链接(将这些中间文件组合成单个运行的可执行文件或库)。

当你这样做时gcc -c program.c,你正在编译,你生成program.o. 这一步是标题很重要的地方。您需要#include <stdlib.h>program.c例如)使用mallocand free。(类似地,您需要#include <dlfcn.h>and dlopendlsym)如果您不这样做,编译器会抱怨它不知道这些名称是什么,并因错误而停止。但是,如果您执行#include标头,编译器不会将您调用的函数的代码插入program.o. 它只是插入对它们的引用。原因是为了避免代码重复:程序的每个部分只需要访问一次代码,因此如果您需要更多文件 ( module1.c,module2.c等等),即使他们使用过malloc,您最终也只会引用malloc. 该单一副本以共享或静态形式(或)存在于标准中,但您的源代码中未引用这些副本,编译器也不知道它们。libc.solibc.a

链接器. 在你做的链接阶段gcc -o program program.o。然后,链接器将搜索您在命令行上传递的所有库,并找到您调用的所有未在您自己的代码中定义的函数的单一定义。这就是-l(正如其他人所解释的):告诉链接器您需要使用的库列表。它们的名称通常与您在上一步中使用的标题无关。例如,要使用dlsym您需要libdl.soor libdl.a,因此您的命令行将是gcc -o program program.o -ldl. 要使用头文件malloc中的大部分功能,std*.h您需要libc,但是因为每个C 程序都使用该库,所以它是自动使用的。链接(好像你已经完成了-lc)。

对不起,如果我要详细介绍,但如果你不知道你会想要的区别。如果不这样做,就很难理解 C 编译的工作原理。

最后一件事:dlopen并且dlsym不是正常的链接方法。它们用于特殊情况,您希望根据信息动态确定您想要的行为,无论出于何种原因,这些信息仅在运行时可用。如果您知道要在编译时调用哪些函数(在 99% 的情况下为真),则不需要使用这些dl*函数。

于 2009-07-27T07:10:13.937 回答
3

您可以链接共享库,例如静态库。然后在启动程序时搜索它们。事实上,默认情况下 -lXXX 会优先选择 libXXX.so 而不是 libXXX.a。

于 2009-07-24T08:42:04.567 回答
2

您需要为链接器提供正确的说明来链接您的共享库。

共享库名称类似于 libNAME.so,因此对于链接,您应该使用 -lNAME

将其命名为 libmysharedlib.so,然后将您的主程序链接为:

gcc -o myprogram myprogram.c -lmysharedlib 
于 2009-07-24T08:42:49.497 回答
1

如果你使用CMake来构建你的项目,你可以使用

TARGET_LINK_LIBRARIES(目标名称库名称)

如:

TARGET_LINK_LIBRARIES(我的程序我的图书馆)

要创建库“mylibrary”,您可以使用

ADD_LIBRARY(目标名称来源列表)

如:

ADD_LIBRARY(mylibrary ${mylibrary_SRCS})

此外,此方法是跨平台的(而简单地将标志传递给 gcc 则不是)。

于 2009-07-27T02:51:14.467 回答
0
  • 共享库 ( .so) 是存储函数/类/...的实际源代码的目标文件(以二进制形式)
  • 头文件 ( .h) 是指示(参考)编译器可以在哪里找到.so主代码所需的函数/类/... (in ) 的文件

因此,你需要他们两个。

于 2021-12-30T01:53:08.633 回答