使用C ++库时如何避免包含相同的代码?

时间:2012-12-31 01:53:49

标签: c++ linker include static-libraries

编辑:我知道包含警卫,但包含文件这里的问题。我正在讨论实际编译和已链接的代码,这些代码将被编入静态库。

我正在用C ++为自己创建一个通用的实用程序库。

我正在创建的其中一项功能printFile需要stringcout以及标准库的其他此类成员。

我担心在编译库时,然后链接到另一个也使用stringcout的项目时,stringcout的代码将会重复:它将在程序与之链接的库二进制文件中预先链接,并且它将再次与使用它们的项目链接。

图书馆的结构如下:

  1. 有一个libname.hpp文件,使用该库的程序员应该在他的项目中#include
  2. 对于fname中声明的每个函数libname.hpp,都有一个文件fname.cpp来实现它。
  3. 所有fname.cpp个文件也#include "libname.hpp"
  4. 图书馆本身会编译为libname.a,并将其复制到/usr/lib/
  5. 这会发生吗?
    如果是的话,这是一个问题吗?
    如果是,那我该如何避免呢?

4 个答案:

答案 0 :(得分:3)

  

我担心在编译库时,然后链接到另一个也使用string和cout的项目时,string和cout的代码将被复制

不要担心:没有现代编译系统会这样做。模板函数的代码被发送到目标文件中,但链接器会丢弃重复的条目。

答案 1 :(得分:3)

标准C ++库的库定义不会显示在您自己的静态库中,除非您在那里明确地包含它们(即,您从标准C ++库中提取目标文件并将它们包含到您的库中)。静态库根本没有链接,只是对其他库有未定义的引用。静态库只是定义库提供的符号的目标文件的集合。来自标题的定义,例如内联函数和模板实例,将以多个翻译单元中的多个定义不会冲突的方式定义。如果代码实际上没有内联,它将定义“弱”符号,这会导致在链接时忽略或删除重复项。

唯一真正关心的是链接到可执行文件的库需要使用兼容的库定义。由于大量代码驻留在头文件中,因此对C ++头文件进行相对频繁的更改,包括标准C ++库头(相对于包含少得多代码的C库头)。

答案 2 :(得分:0)

是的,标准库事物的代码将被复制。例如,如果您返回一个std :: string或在其中一个方法中将一个作为参数,则可能会出现问题。它在标准库实现中的布局可能与用户的布局不同。

答案 3 :(得分:0)

这在实践中很少成为问题。

对于static函数和头文件中定义的内联模板化函数,没有什么可担心的:每个编译单元都有自己的副本(例如在.a库中可能已有许多匿名副本) 。这没关系,因为这些定义不会被导出,所以链接器不需要担心它们。

对于使用非静态链接声明的函数,是否存在问题取决于链接.a库的方式。

构建库时,通常在标准C ++库中链接。创建的库将包含对标准C ++库的未定义引用。必须在构建最终可执行二进制文件之前解决这些问这通常在以默认方式链接最终二进制文件时自动完成(取决于编译器)。

有些时候人们会将标准C ++库链接到静态库中。如果您要链接多个静态库,每个静态库都嵌入另一个库(如标准C ++库),那么如果这些嵌入式库中存在任何差异,则会出现问题。幸运的是,这是一个罕见的问题,至少使用gcc工具链。这是微软工具的more frequent problem

在某些情况下,解决方法是将一个或多个冲突的静态库转换为动态库。这样,每个动态库都可以静态链接自己的有问题库的副本。只要动态库不从有问题的库中导出符号并且没有内存布局不兼容,通常就没有任何问题。