这是为了补充@Horstling 的回答。
您可以创建静态库或动态库。当您创建静态链接库时,所有函数/对象的编译代码都将保存到一个文件中(在 Windows 中扩展名为 .lib)。在主项目(使用库的项目)的链接时,这些代码将与主项目代码一起链接到您的最终可执行文件中。所以最终的可执行文件不会有任何运行时依赖。
动态链接库将在运行时(而不是链接时)合并到主项目中。编译库时,您会得到一个 .dll 文件(其中包含实际编译的代码)和一个 .lib 文件(其中包含足够的数据供编译器/运行时在 .dll 文件中查找函数/对象)。在链接时,可执行文件将被配置为加载 .dll 并根据需要使用来自该 .dll 的编译代码。您需要将 .dll 文件与可执行文件一起分发才能运行它。
设计库时无需在静态或动态链接(或仅标头)之间进行选择,您可以创建多个项目/makefile,一个用于创建静态 .lib,另一个用于创建 .lib/.dll 对,然后分发两种版本,供用户选择。(您需要使用@Horstling 建议的预处理器宏)。
您不能将任何模板放入预编译库中,除非您使用一种称为Explicit Instantiation的技术,该技术会限制模板参数。
另请注意,现代编译器/链接器通常不尊重 inline 修饰符。他们可以内联一个函数,即使它没有被指定为内联,或者可以动态调用另一个具有内联修饰符的函数,因为他们认为合适。(无论如何,我会建议在适用的地方明确放置 inline 以获得最大的兼容性)。因此,如果您使用静态链接库而不是仅包含标头的库(并启用编译器/链接器优化,当然),不会有任何运行时性能损失。正如其他人所建议的那样,对于肯定会从内联调用中受益的非常小的函数,最好将它们放在头文件中,因此动态链接库也不会遭受任何重大的性能损失。(无论如何,内联函数只会影响经常调用的函数的性能,
#include "foo.cpp"
您可以更改 makefile/project 设置并将 foo.cpp 添加到要编译的源文件列表中,而不是将内联函数放入头文件(在您的头文件中)。这样,如果您更改任何函数实现,则无需重新编译整个项目,只会重新编译 foo.cpp。正如我之前提到的,优化编译器仍将内联您的小函数,您无需担心这一点。
如果您使用/设计预编译库,则应考虑使用与主项目不同的编译器版本编译库的情况。每个不同的编译器版本(甚至不同的配置,如 Debug 或 Release)都使用不同的 C 运行时(如 memcpy、printf、fopen 等)和 C++ 标准库运行时(如 std::vector<>、std::细绳, ...)。这些不同的库实现可能会使链接复杂化,甚至会产生运行时错误。
作为一般规则,请始终避免跨库共享编译器运行时对象(标准未定义的数据结构,如 FILE*),因为不兼容的数据结构会导致运行时错误。
链接项目时,C/C++ 运行时函数必须链接到库 .lib 或 .lib/.dll 或可执行文件 .exe。C/C++ 运行时本身可以链接为静态或动态库(您可以在 makefile/project 设置中进行设置)。
您会发现在库和主项目中动态链接到 C/C++ 运行时(即使您将库本身编译为静态库)避免了大多数链接问题(在多个运行时版本中存在重复的函数实现)。当然,您需要为所有使用的版本与您的可执行文件和库一起分发运行时 DLL。
有些场景需要静态链接到 C/C++ 运行时,在这些情况下,最好的方法是使用与主项目相同的编译器设置来编译库以避免链接问题。