在我学习C ++的过程中,我遇到了动态和静态库。
我通常会得到它们的要点:编译代码以包含在其他程序中。
但是,我想了解一些关于它们的事情:
main()
函数吗?.dylib
和.a
文件。我发现的与图书馆相关的所有内容似乎都针对那些已经知道如何使用它们的人。但是,我没有。 (但是想!)
谢谢!
(我还应该注意到我使用的是Mac OS X,虽然我更喜欢保持IDE中立或面向命令行,但我使用的是QtCreator / Netbeans)
答案 0 :(得分:18)
编写它们与普通的C ++程序有什么不同,减去main()函数吗?
没有
编译后的程序如何成为一个库?它显然不是可执行文件,所以如何转换,将'test.cpp'称为'test.dll'?
编译时传递-dynamiclib
标志。 (结果的名称仍默认为a.out
。在Mac OS X上,您应将动态库命名为lib***.dylib
,在Linux上命名为lib***.so
(共享对象))
一旦我了解它的格式,我该如何将它包含在另一个程序中?
首先,创建一个头文件,以便其他程序可以#include
知道你的dylib中可以使用哪些函数。
其次,链接到你的dylib。如果您的dylib被命名为libblah.dylib
,则会将-lblah
标记传递给gcc。
是否有标准的放置它们,所以无论编译器/链接器需要它们都可以轻松找到它们?
/usr/lib
或/usr/local/lib
。
动态库和静态库之间有什么区别(技术上和实际上)?
基本上,对于静态库,整个库都嵌入到它“链接”到的文件中。
我如何在我的代码中使用第三方库(我正在盯着MySql C ++连接器的.dylib和.a文件)
见第3个答案。
答案 1 :(得分:12)
除了图书馆为其他程序提供服务的明显区别外,通常(*)没有区别。
默认情况下导出gcc类/函数中的 * - 在VC ++中不是这种情况,您必须使用__declspec(export)
显式导出。
这取决于您的编译器。在Visual Studio中,您可以在项目配置中指定它。在gcc中创建静态库,您可以正常编译代码,然后使用ar
将其打包到存档中。要创建共享,首先编译(使用-fpic
标志以启用位置无关代码生成,共享库的要求),然后在目标文件上使用-shared
标志。更多信息可以在手册页中找到。
这再次依赖于编译器。在VS中,如果它是一个共享库,当包含你想要使用的类/函数时,它应该用__declspec(import)
标记(这通常用ifdefs完成),你必须指定共享的.lib文件连接库。对于静态库,您只需指定.lib文件(不需要导出/导入,因为代码最终会出现在您的可执行文件中)。
在gcc中,您只需使用-llibrary_name
指定要链接的库。
在这两种情况下,您都需要为您的客户端提供一些头文件,其中包含供公众使用的函数/类。
如果它是你自己的图书馆,那么这取决于你。通常,您可以指定要查看的链接器附加文件夹。我们的源代码树中有一个lib
文件夹,其中所有.lib
(或.a / .so)文件最终都会添加到该文件夹中要查看的其他文件夹。
如果你在UNIX上发布一个库,常见的地方通常是/usr/lib
(或/usr/local/lib
),这也是gcc默认搜索的地方。
当您将程序链接到静态库时,库的代码最终会出现在您的可执行文件中。实际上,这会使您的可执行文件变得更大,并且由于显而易见的原因而更难以更新/修复静态库(需要新版本的可执行文件)。
共享库与您的可执行文件是分开的,并且由您的程序引用,并且(通常)在需要时在运行时加载。
也可以加载共享库而无需链接它们。它需要更多的工作,因为您必须手动加载共享库和您想要使用的任何符号。在Windows上,这是使用LoadLibrary
/ GetProcAddress
和使用dlsym
/ dlopen
在POSIX系统上完成的。
这通常通过包含必要的头文件并链接到适当的库来实现。
与静态库foo
关联的简单示例如下所示:gcc main.cpp -o main.o -L/folder/where/foo.a/is/at -lfoo
。
大多数开源项目都有自述文件,提供更详细的说明,如果有的话,我建议你看一下。
答案 2 :(得分:4)
编写[libraries]与普通的C ++程序有什么不同,减去main()函数吗?
这取决于你对“不同”的定义。从语言的角度来看,你编写一个文件或文件集合,不要放入main()
并告诉编译器生成一个库而不是一个可执行文件。
但是,designing libraries is much harder因为您无法控制调用您的代码。与普通代码相比,库需要比失败更强大。你不一定有delete
指针有人传递给你的函数。你无法分辨哪些宏会破坏你的代码。您也不会意外污染全局命名空间(例如,不要将using namespace std
放在头文件的开头)。
编译后的程序如何成为一个库?它显然不是可执行文件,所以如何转换,将'test.cpp'称为'test.dll'?
这取决于编译器。在Visual C ++中,这是一个项目配置设置。在gcc中(从内存开始),它类似于gcc -c foo.c -shared
。
一旦我了解它的格式,我该如何将它包含在另一个程序中?
这取决于您的编译器和链接器。您可以确保通过项目设置或环境变量提供头文件,并确保通过不同的项目设置或编译器变量提供二进制文件。
是否有标准的放置它们,所以无论编译器/链接器需要它们都可以轻松找到它们?
这取决于操作系统。在UNIX中,您将把事情放在/usr/lib
,/usr/local/lib
等地方。在Windows上,人们常常将DLL放在像C:\WINDOWS
这样的地方,但不再允许这样做。而是将它放在程序目录中。
动态库和静态库之间有什么区别(技术上和实际上)?
静态库是更简单的原始模型。在编译时,链接器将库中的所有函数放入可执行文件中。您可以在没有库的情况下发送可执行文件,因为该库已被烘焙。
动态库(也称为共享库)涉及编译器在可执行文件中放入足够的信息,在运行时链接器将能够找到正确的库并调用其中的方法。这些库在使用它们的程序中在整个系统中共享。使用动态链接(dlsym()
等等)为图片添加了一些细节。
我如何在我的代码中使用第三方库(我正在盯着MySql C ++连接器的.dylib和.a文件)
这将取决于您的平台,不幸的是我无法告诉您更多有关.dylib文件的信息。 .a文件是静态库,您只需将它们添加到最终调用gcc(gcc main.c foo.a -o main
,如果您知道foo.a
在哪里,或gcc main.c -lfoo -o main
如果系统知道在哪里{{ 1}},foo.a
或foo.la
是)。通常,您确保编译器可以找到库并让链接器完成剩下的工作。
答案 3 :(得分:1)
静态库和动态库之间的区别在于,链接在编译时为静态库完成,将可执行代码嵌入到二进制文件中,而动态库链接在程序启动时动态完成。优点是图书馆可以单独分发,更新,代码(内存)可以在多个程序之间共享。
要使用库,只需为lib.a或lib.so
提供-l到g ++答案 4 :(得分:1)
我写这篇文章比技术上更正确更务实。这足以让你大致了解你所追求的目标。
编写它们与普通的C ++程序有什么不同,减去main()函数吗?
对于静态库,实际上差别不大。
对于动态库,您需要注意的最可能的区别是,您可能需要导出要在库外部使用的符号。基本上,您不导出的所有内容对您的库用户都是不可见的。确切地说,如何导出,以及默认情况下是否需要,取决于您的编译器。
对于动态库,您还需要解析所有符号,这意味着库不能依赖来自库外部的函数或变量。如果我的库使用一个名为foo()的函数,我需要在我的库中包含foo(),方法是自己编写或者链接到另一个提供它的库。我不能使用foo(),只是假设我的库的用户将提供它。链接器不知道如何调用尚不存在的foo()。
编译后的程序如何成为一个库?它显然不是可执行文件,所以如何转换,将'test.cpp'称为'test.dll'?
它类似于将test.cpp转换为test.exe的方式 - 编译和链接。您将选项传递给编译器,告诉它是创建可执行文件,静态库还是动态库。
一旦我了解它的格式,我该如何将它包含在另一个程序中?
在源代码中,包含使用库所必需的头文件,就像包含不在库中的代码的头文件一样。您还需要在链接行中包含该库,告诉链接器在哪里可以找到该库。对于许多系统,创建动态库会生成两个文件,即共享库和链接库。它是您在链接行中包含的链接库。
是否有标准的放置它们,所以无论编译器/链接器需要它们都可以轻松找到它们?
有一个环境变量告诉链接器在哪里查找库。该变量的名称因系统而异。您还可以告诉链接器有关其他要查找的位置。
动态库和静态库之间有什么区别(技术上和实际上)?
静态库被复制到链接到的东西中。可执行文件将包含静态库的副本,并且可以在另一台计算机上运行,而无需复制静态库。
动态库保留在单独的文件中。可执行文件在运行时加载分隔文件。您必须使用您的程序分发动态库的副本,否则它将无法运行。您也可以用新版本替换动态库,只要新库具有相同的接口,它仍将与旧的可执行文件一起运行。如果多个可执行文件使用相同的动态库,它也可以节省空间。实际上,动态库通常称为共享库。
我如何在我的代码中使用第三方库
与您自己创建的相同,如上所述。