共享库和 .h 文件
我对程序如何使用共享库有一些疑问。
当我构建共享库(使用 -shared -fPIC
开关)时,我可以从外部程序使用一些函数。 通常我会使用 dlopen() 来加载库,然后使用 dlsym() 将上述函数链接到程序中的某些函数指针。 此方法不涉及包含任何 .h
文件。 有没有办法避免执行 dlopen()
& dlsym()
并且只包含共享库的 .h
?
我猜这可能是 C++ 程序如何使用存储在系统共享库中的代码,即 - 仅包括 stdlib.h 等。
I have some doubt about how do programs use shared library.
When I build a shared library ( with -shared -fPIC
switches) I make some functions available from an external program.
Usually I do a dlopen()
to load the library and then dlsym()
to link the said functions to some function pointers within my program.
This approach does not involve including any .h
file.
Is there a way to avoid doing dlopen()
& dlsym()
and just including the .h
of the shared library?
I guess this may be how C++ programs use code stored in system shared library, i.e - just including stdlib.h
etc.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
.so
) 是目标文件,其中存储函数/类/...的实际源代码(以二进制形式).h
) 是文件指示(引用)编译器可以在哪里找到主代码所需的函数/类/...(在.so
中)因此,您需要它们。
.so
) are object files where the actual source code of function/class/... are stored (in binary).h
) are files indicating (the reference) where the compiler can find function/class/... (in.so
) that are required by the main codeTherefore, you need both of them.
如果您使用 CMake 构建项目,则可以使用
如下所示:
要创建库“mylibrary”,您可以使用
As:
此外,此方法是跨平台的(而简单地将标志传递给 gcc 则不是)。
If you use CMake to build your project, you can use
As in:
To create the library "mylibrary", you can use
As in:
Additionally, this method is cross-platform (whereas simply passing flags to gcc is not).
您需要向链接器提供正确的指令来链接您的共享库。
共享库名称类似于 libNAME.so,因此为了链接,您应该使用 -lNAME
将其命名为 libmysharedlib.so,然后将主程序链接为:
You need to give the linker the proper instructions to link your shared library.
The shared library names are like libNAME.so, so for linking you should use -lNAME
Call it libmysharedlib.so and then link your main program as:
您可以像静态库一样链接共享库。 然后在启动程序时搜索它们。 事实上,默认情况下 -lXXX 会优先选择 libXXX.so 而不是 libXXX.a。
You can link shared libraries like static one. They are then searched for when launching the program. As a matter of fact, by default -lXXX will prefer libXXX.so to libXXX.a.
尼克,我认为所有其他答案实际上都在回答您的问题,这就是您链接库的方式,但是您表达问题的方式表明您对头文件和库之间的差异存在误解。 他们不一样。 你需要两者,但他们做的不是同一件事。
构建可执行文件有两个主要阶段:编译(将源代码转换为中间形式,包含可执行二进制指令,但不是可运行的程序)和链接(将这些中间文件组合成单个运行的可执行文件或库)。
当您执行
gcc -c program.c
时,您正在编译,并生成program.o
。 这一步是标题最重要的地方。 您需要在program.c
中添加#include
才能(例如)使用malloc
和free. (同样,对于
dlopen
和dlsym
,您需要#include
。)如果您不这样做,编译器会抱怨它不知道这些名称是什么,并因错误而停止。 但是,如果您#include
标头,编译器不会将您调用的函数的代码插入到program.o
中。 它只是插入对它们的引用。 原因是为了避免代码重复:程序的每个部分只需要访问代码一次,因此如果您需要更多文件(module1.c
、module2.c), c
等),即使它们全部使用了malloc
,您最终也只会得到对malloc
单个副本的许多引用>。 该单个副本以共享或静态形式(libc.so
或libc.a
)存在于标准库中,但这些不是在您的源代码中引用,并且编译器不知道它们。链接器是。 在链接阶段,您执行
gcc -o program program.o
。 然后,链接器将搜索您在命令行上传递给它的所有库,并找到您调用的所有函数的单个定义,这些函数未在您自己的代码中定义。 这就是-l
的作用(正如其他人所解释的):告诉链接器您需要使用的库列表。 它们的名称通常与您在上一步中使用的标头关系不大。 例如,要使用dlsym
,您需要libdl.so
或libdl.a
,因此您的命令行将是gcc - o 程序program.o -ldl
。 要使用malloc
或std*.h
标头中的大多数函数,您需要libc
,但因为该库由 使用每个 C 程序都会自动链接(就好像您已经完成了-lc
)。抱歉,如果我要讲很多细节,但如果您不知道其中的区别,您会想要了解的。 如果不这样做,就很难理解 C 编译的工作原理。
最后一件事:
dlopen
和dlsym
不是正常的链接方法。 它们用于特殊情况,在这种情况下,您希望根据无论出于何种原因仅在运行时可用的信息动态确定所需的行为。 如果您知道要在编译时调用哪些函数(99% 的情况下都是如此),则不需要使用 dl* 函数。Nick, I think all the other answers are actually answering your question, which is how you link libraries, but the way you phrase your question suggests you have a misunderstanding of the difference between headers files and libraries. They are not the same. You need both, and they are not doing the same thing.
Building an executable has two main phases, compilation (which turns your source into an intermediate form, containing executable binary instructions, but is not a runnable program), and linking (which combines these intermediate files into a single running executable or library).
When you do
gcc -c program.c
, you are compiling, and you generateprogram.o
. This step is where headers matter. You need to#include <stdlib.h>
inprogram.c
to (for example) usemalloc
andfree
. (Similarly you need#include <dlfcn.h>
fordlopen
anddlsym
.) If you don't do that the compiler will complain that it doesn't know what those names are, and halt with an error. But if you do#include
the header the compiler does not insert the code for the function you call intoprogram.o
. It merely inserts a reference to them. The reason is to avoid duplication of code: The code is only going to need to be accessed once by every part of your program, so if you needed further files (module1.c
,module2.c
and so on), even if they all usedmalloc
you would merely end up with many references to a single copy ofmalloc
. That single copy is present in the standard library in either it's shared or static form (libc.so
orlibc.a
) but these are not referenced in your source, and the compiler is not aware of them.The linker is. In the linking phase you do
gcc -o program program.o
. The linker will then search all libraries you pass it on the command line and find the single definition of all functions you've called which are not defined in your own code. That is what the-l
does (as the others have explained): tell the linker the list of libraries you need to use. Their names often have little to do with the headers you used in the previous step. For example to get use ofdlsym
you needlibdl.so
orlibdl.a
, so your command-line would begcc -o program program.o -ldl
. To usemalloc
or most of the functions in thestd*.h
headers you needlibc
, but because that library is used by every C program it is automatically linked (as if you had done-lc
).Sorry if I'm going into a lot of detail but if you don't know the difference you will want to. It's very hard to make sense of how C compilation works if you don't.
One last thing:
dlopen
anddlsym
are not the normal method of linking. They are used for special cases where you want to dynamically determine what behavior you want based on information that is, for whatever reason, only available at runtime. If you know what functions you want to call at compile time (true in 99% of the cases) you do not need to use thedl*
functions.