我对程序如何使用共享库存有疑问。
当我构建一个共享库(带有-shared -fPIC开关)时,我从外部程序中提供了一些函数。 通常我会执行dlopen()来加载库,然后使用dlsym()将所述函数链接到某些函数指针。 此方法不涉及任何.h文件。 有没有办法避免做dlopen()& dlsym(),只包括共享库的.h?
我猜测这可能是c ++程序如何使用存储在系统共享库中的代码。即仅包括stdlib.h等。
答案 0 :(得分:46)
尼克,我认为所有其他答案实际上都在回答您的问题,这就是您链接库的方式,但您对问题的表达方式表明您对标题文件和库之间的差异存在误解。他们不一样。你需要两个,他们没有做同样的事情。
构建可执行文件有两个主要阶段,编译(将源转换为中间形式,包含可执行二进制指令,但不是可运行程序)和链接(将这些中间文件组合成一个正在运行的可执行文件或库) )。
执行gcc -c program.c
时,您正在编译,并生成program.o
。此步骤是标题的重要部分。您需要#include <stdlib.h>
program.c
中的malloc
(例如)使用free
和#include <dlfcn.h>
。 (同样,dlopen
和dlsym
需要#include
。)如果你不这样做,编译器会抱怨它不知道这些名字是什么,并且因错误而停止。但是,如果您执行program.o
标头,编译器不将您调用的函数的代码插入module1.c
。它只是向它们插入引用。原因是避免重复代码:代码只需要程序的每个部分都需要访问一次,因此如果您需要更多文件(module2.c
,malloc
等),即使他们所有使用malloc
,您最终也会得到许多对libc.so
的单个副本的引用。该单个副本以共享或静态形式(libc.a
或gcc -o program program.o
)存在于标准库中,但这些未在您的源中引用,并且编译器不是了解他们。
链接器是。在链接阶段,您执行-l
。然后链接器将在命令行中搜索您传递它的所有库,并找到您调用的所有函数的单定义,这些函数未在您自己的代码中定义。这就是dlsym
的作用(正如其他人所解释的那样):告诉链接器你需要使用的库列表。它们的名称通常与您在上一步中使用的标题几乎没有关系。例如,要使用libdl.so
,您需要libdl.a
或gcc -o program program.o -ldl
,因此您的命令行将为malloc
。要使用std*.h
标题中的libc
或大多数函数,您需要-lc
,但由于每个 C程序都使用该库,因此它是自动链接(就像您已完成dlopen
)。
很抱歉,如果我要详细介绍,但如果你不知道你想要的差异。如果不这样做,很难理解C编译的工作原理。
最后一件事:dlsym
和dl*
不是正常的关联方法。它们用于特殊情况,您希望根据无论何种原因仅在运行时可用的信息动态确定所需的行为。如果您知道在编译时要调用哪些函数(在99%的情况下都是如此),则不需要使用{{1}}函数。
答案 1 :(得分:3)
您可以链接共享库,例如静态库。然后在启动程序时搜索它们。事实上,默认情况下-lXXX更喜欢libXXX.so到libXXX.a。
答案 2 :(得分:2)
您需要为链接器提供链接共享库的正确说明。
共享库名称类似于libNAME.so,因此对于链接,您应该使用-lNAME
将其命名为libmysharedlib.so,然后将您的主程序链接为:
gcc -o myprogram myprogram.c -lmysharedlib
答案 3 :(得分:1)
如果您使用CMake构建项目,则可以使用
TARGET_LINK_LIBRARIES(targetname libraryname)
如:
TARGET_LINK_LIBRARIES(myprogram mylibrary)
要创建库“mylibrary”,您可以使用
ADD_LIBRARY(targetname sourceslist)
如:
ADD_LIBRARY(mylibrary ${mylibrary_SRCS})
此外,这种方法是跨平台的(而只是简单地将标志传递给gcc)。