22

在我学习 C++ 的过程中,我遇到了动态库和静态库。

我通常了解它们的要点:编译代码以包含到其他程序中。

但是,我想知道一些关于他们的事情:

  • 编写它们与普通的 C++ 程序有什么不同,减去main()函数?
  • 编译后的程序如何成为库?它显然不是一个可执行文件,那么我该如何将“test.cpp”变成“test.dll”?
  • 一旦我得到它的格式,我如何将它包含在另一个程序中?
  • 是否有放置它们的标准位置,以便任何需要它们的编译器/链接器都可以轻松找到它们?
  • 动态库和静态库之间有什么区别(技术上和实践上)?
  • 我将如何在我的代码中使用第三方库(我正在盯着MySql C++ 连接器的文件.dylib.a

我发现的所有与图书馆有关的东西似乎都是针对那些已经知道如何使用它们的人。然而,我不知道。(但愿意!)

谢谢!

(我还应该注意我使用的是 Mac OS X,虽然我更愿意保持 IDE 中立或面向命令行,但我使用 QtCreator/Netbeans)

4

5 回答 5

19

编写它们与普通的 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 文件)

见第三个答案。

于 2010-01-22T20:02:58.217 回答
12

编写它们与普通的 C++ 程序有什么不同,减去 main() 函数?

除了库提供服务供其他程序使用的明显区别外,通常(*)没有区别。

* 在 gcc 中的类/函数默认导出 - 在 VC++ 中不是这种情况,您必须使用__declspec(export).

编译后的程序如何成为库?它显然不是一个可执行文件,那么我该如何将“test.cpp”变成“test.dll”?

这取决于您的编译器。在 Visual Studio 中,您可以在项目配置中指定这一点。在 gcc 中创建一个静态库,你通常编译你的代码,然后使用ar. 要创建共享,您首先要编译(使用-fpic标志来启用与位置无关的代码生成,这是共享库的要求),然后-shared在目标文件上使用标志。更多信息可以在手册页中找到。

一旦我得到它的格式,我如何将它包含在另一个程序中?

同样,这有点依赖于编译器。在 VS 中,如果它是一个共享库,当包含您希望使用的类/函数时,应该用 a 标记__declspec(import)(这通常使用 ifdefs 完成)并且您必须指定共享库的 .lib 文件以进行链接。对于静态库,您只需要指定 .lib 文件(不需要导出/导入,因为代码最终会出现在您的可执行文件中)。

在 gcc 中,您只需要指定使用-llibrary_name.

在这两种情况下,您都需要为您的客户提供一些带有供公众使用的函数/类的头文件。

是否有放置它们的标准位置,以便任何需要它们的编译器/链接器都可以轻松找到它们?

如果它是您自己的图书馆,那么这取决于您。通常您可以指定要查看的链接器附加文件夹。我们lib在源代码树中有一个文件夹,所有.lib(或 .a/.so)文件都在其中结束,我们将该文件夹添加到要查看的附加文件夹中。

如果你在 UNIX 上发布一个库,常见的地方通常是/usr/lib(或/usr/local/lib),这也是 gcc 默认搜索的地方。

动态库和静态库之间有什么区别(技术上和实践上)?

当您将程序链接到静态库时,库的代码最终会出现在您的可执行文件中。实际上,这会使您的可执行文件更大,并且由于明显的原因(需要新版本的可执行文件)而更难更新/修复静态库。

共享库与您的可执行文件是分开的,由您的程序引用,并且(通常)在需要时在运行时加载。

也可以加载共享库而不链接到它们。它需要更多的工作,因为您必须手动加载共享库和您希望使用的任何符号。在 Windows 上,这是使用LoadLibrary/完成的GetProcAddress,而在 POSIX 系统上使用dlsym/完成dlopen

我将如何在我的代码中使用第三方库?

这通常通过包含必要的头文件并与适当的库链接来完成。

一个与静态库链接的简单示例foo如下所示gcc main.cpp -o main.o -L/folder/where/foo.a/is/at -lfoo

大多数开源项目都有一个自述文件,其中提供了更详细的说明,如果有的话,我建议您看一下。

于 2010-01-22T20:11:27.587 回答
4

编写 [库] 与普通 C++ 程序有什么不同,减去 main() 函数?

这取决于你对“不同”的定义。从语言的角度来看,您编写一个文件或文件集合,不要放入 amain()并且您告诉编译器生成一个库而不是可执行文件。

但是,设计库要困难得多,因为您无法控制调用您的代码。与普通代码相比,库需要更强大的抗故障能力。您不一定可以将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如果系统知道在哪里foo.afoo.la或在哪里foo.so)。通常,您确保编译器可以找到库并让链接器完成其余的工作。

于 2010-01-22T20:34:33.440 回答
1

静态库和动态库之间的区别在于,静态库的链接是在编译时完成的,将可执行代码嵌入到二进制文件中,而动态库的链接是在程序启动时动态完成的。优点是库可以单独分发、更新,代码(内存)可以在多个程序之间共享。

要使用库,您只需为 lib.a 或 lib.so 向 g++ 提供 -l

于 2010-01-22T20:06:19.860 回答
1

我写这篇文章是为了更务实而不是技术上正确。这足以让您大致了解您所追求的。

编写它们与普通的 C++ 程序有什么不同,减去 main() 函数?

对于静态库来说,其实差别不大。

对于动态库,您需要注意的最可能的区别是您可能需要导出您希望在库之外可用的符号。基本上,您不导出的所有内容对您图书馆的用户都是不可见的。究竟如何导出,甚至默认情况下是否需要,取决于您的编译器。

对于动态库,您还需要解析所有符号,这意味着库不能依赖于来自库外部的函数或变量。如果我的库使用名为 foo() 的函数,我需要通过自己编写或链接到提供它的另一个库来将 foo() 包含在我的库中。我不能使用 foo() 并且只是假设我的图书馆的用户会提供它。链接器不知道如何调用尚不存在的 foo()。

编译后的程序如何成为库?它显然不是一个可执行文件,那么我该如何将“test.cpp”变成“test.dll”?

这类似于将 test.cpp 转换为 test.exe - 编译和链接。您将选项传递给编译器以告诉它是创建可执行文件、静态库还是动态库。

一旦我得到它的格式,我如何将它包含在另一个程序中?

在您的源代码中,您包含使用库所需的头文件,就像您为不在库中的代码包含头文件一样。您还需要在链接行中包含库,告诉链接器在哪里可以找到库。对于许多系统,创建动态库会生成两个文件,共享库和链接库。它是您在链接行中包含的链接库。

是否有放置它们的标准位置,以便任何需要它们的编译器/链接器都可以轻松找到它们?

有一个环境变量告诉链接器在哪里寻找库。该变量的名称因系统而异。您还可以告诉链接器要查看的其他位置。

动态库和静态库之间有什么区别(技术上和实践上)?

静态库被复制到它所链接的东西中。可执行文件将包含静态库的副本,并且可以在另一台机器上运行而无需复制静态库。

动态库位于单独的文件中。可执行文件在运行时加载该单独的文件。您必须随程序分发动态库的副本,否则它将无法运行。您也可以将动态库替换为新版本,只要新库具有相同的界面,它仍然可以使用旧的可执行文件运行。如果多个可执行文件使用相同的动态库,它也可以节省空间。事实上,动态库通常被称为共享库。

我将如何在我的代码中使用第三方库

就像您使用自己创建的一样,如上所述。

于 2010-01-22T20:15:05.533 回答