仅标题库的好处
什么是只有头文件库的好处,你为什么要这样写反对将实现分为单独的文件?
在某些情况下,只有标题库是唯一的select,例如在处理模板时。
拥有仅包含标题的库也意味着您不必担心可能使用该库的不同平台。 分离实现时,通常会隐藏实现细节,并将该库作为头文件和库( lib
, dll
或.so
文件)的组合来分发。 这些当然必须为您提供支持的所有不同的操作系统/版本进行编译。
你也可以分发实现文件,但这意味着用户需要额外的步骤 – 在使用它之前编译你的库。
当然,这在个案的基础上适用。 例如,只有头文件的库有时会增加 代码大小& 编译时间。
仅标题库的好处:
- 简化构build过程。 您不需要构build库,并且在构build的链接步骤中不需要指定编译的库。 如果你有一个编译的库,你可能会想要构build它的多个版本:一个编译时启用了debugging,另一个启用了优化,可能还有另一个符号被删除。 对于多平台系统甚至可能更多。
仅标题库的缺点:
-
更大的对象文件。 源文件中使用的库中的每个内联方法也会在该源文件的编译对象文件中得到一个弱符号,外行定义。 这会降低编译器速度,也会降低链接器的速度。 编译器必须生成所有的膨胀,然后链接器必须将其过滤掉。
-
更长的编译。 除了上面提到的膨胀问题之外,编译将花费更长的时间,因为标题本身比标题库更大,而不是编译库。 那些大标题将需要为每个使用该库的源文件进行parsing。 另一个因素是头标库中的这些头文件必须包含内联定义所需的
#include
头文件以及库被构build为编译库时需要的头文件。 -
更纠结的汇编。 由于这些额外的
#include
需要一个只包含头文件的库,所以你会得到更多的依赖头文件的库。 更改库中一些关键函数的实现,您可能需要重新编译整个项目。 在编译库的源文件中进行更改,您只需重新编译一个库源文件,使用新的.o文件更新编译的库,然后重新链接应用程序。 -
较难让人阅读。 即使有最好的文档,图书馆的用户也往往不得不去读图书馆的标题。 只有头文件的库中的头文件被填充了实现细节,以便理解接口。 通过一个编译的库,你所看到的只是界面和一个关于实现的简单评论,这通常是你想要的。 这真是你应该想要的。 您不必知道实现细节知道如何使用库。
主要的“好处”是它需要你提供源代码,所以你最终会得到机器上的错误报告,以及你从来没有听说过的编译器。 当图书馆完全是模板时,你没有多lessselect,但是当你有select时,只有标题通常是一个糟糕的工程select。 (另一方面,头文件当然只意味着你不必logging任何整合程序。)
我知道这是一个旧的线程,但没有人提到过ABI接口或特定的编译器问题。 所以我想我会的。
这基本上是基于你的概念,要么写一个头部的库分发给人或重用自己与头上的一切。 如果您正在考虑重新使用头文件和源文件,并在每个项目中重新编译这些文件,那么这并不适用。
基本上,如果你编译你的C ++代码并用一个编译器build立一个库,那么用户试图使用不同的编译器或不同版本的相同编译器来使用这个库,那么由于二进制不兼容,你可能会得到链接器错误或奇怪的运行时行为。
例如,编译器供应商通常会在版本之间更改STL的实现。 如果你在一个接受std :: vector的函数库中有一个函数,那么它期望这个类中的字节按照编译库时的排列方式排列。 如果在一个新的编译器版本中,供应商已经提高了std :: vector的效率,那么用户的代码将会看到可能具有不同结构的新类,并将新结构传递到库中。 一切都从这里走下坡路……这就是为什么build议不要跨越库边界传递STL对象的原因。 这同样适用于C运行时(CRT)types。
在谈论CRT时,通常需要将库和用户的源代码链接到同一CRT上。 使用Visual Studio如果使用Multithreaded CRT构build库,但用户链接在Multithreaded Debug CRT上,则会出现链接问题,因为库可能找不到所需的符号。 我不记得它是哪个函数,但是对于Visual Studio 2015,Microsoft制作了一个CRT函数。 突然间,它在标题而不是CRT库,所以预期在链接时间find它的库不再可以这样做,这就产生了链接错误。 结果是这些库需要用Visual Studio 2015重新编译。
如果您使用Windows API,但是您使用不同的Unicode设置构build库用户,则还可能会出现链接错误或奇怪的行为。 这是因为Windows API具有使用Unicode或ASCIIstring的函数,而macros/定义了基于项目的Unicode设置自动使用正确types的函数。 如果你通过一个string跨越types错误的库边界,那么在运行时就会中断。 或者您可能会发现该程序不首先链接。
从其他第三方库(例如特征向量或GSLmatrix)跨库边界传递对象/types也是如此。 如果第三方库在编译你的库和你的用户编译他们的代码之间改变它们的头部,那么事情就会中断。
基本上是安全的,你可以通过图书馆边界的唯一的东西是build立在types和普通旧数据(POD)。 理想情况下,任何POD都应该在您自己的头文件中定义的结构中,而不要依赖任何第三方头文件。
如果你提供一个只有头文件的库,那么所有的代码都会使用相同的编译器设置和相同的头文件进行编译,所以这些问题会消失(提供第三部分库的版本,你和你的用户使用API是兼容的)。
然而,上面提到的负面因素,例如编译时间的增加。 你也可能正在运行一个业务,所以你可能不想把所有的源代码实现细节交给你的所有用户,以防其中一个窃取它。