关于在C ++中重新编译库的问题

时间:2010-02-21 01:17:08

标签: c++

假设我的班级依赖于其他图书馆。现在我需要修改一个应用程序的类。什么样的修改会迫使我重新编译 所有图书馆。重新编译所有库的规则是什么?

例如,我只知道案例2)是这样的。其他人怎么样?

1)添加构造函数

2)添加数据成员

3)将析构函数更改为虚拟

4)将具有默认值的参数添加到现有成员函数

5 个答案:

答案 0 :(得分:3)

你真的是说你要改变的班级取决于图书馆吗?您永远不必重新编译库,因为您已经更改了依赖于库的内容。如果更改了库所依赖的内容,则重新编译库。

答案是在C ++中,从技术上讲,所有这些都需要重新编译使用该类的任何东西。一个定义规则只允许在多个翻译单元中定义类,如果所有单元中的完全相同(我认为“完全”意味着预处理后相同的标记序列,在这种情况下甚至更改参数名称需要重新编译)。因此,如果不同的源文件共享一个标头,并且该标头中的类定义发生了变化,那么C ++不保证从这两个源文件编译的代码是否仍然是兼容的(如果只重建其中一个)。

但是,您的特定C ++实现将使用静态/动态库格式来放宽规则,并允许某些更改为“二进制兼容”。在你列出的东西中,只有(1)很有可能是二进制兼容的。你必须检查你的文档,但它可能没问题。通常(2)更改对象的大小和布局,(3)更改调用者销毁对象所需的代码,以及(4)更改函数的签名(默认值由调用代码插入,而不是被叫方)。

由于这个原因,通常值得避免使用默认参数。只需添加另一个重载。所以不要改变:

void foo(int a);

void foo(int a, int b = 0);

将其替换为:

void foo(int a) { foo(a, 0); }
void foo(int a, int b);

当然,如果用户正在使用指向函数foo的指针,那么前一个更改甚至不是源兼容的,更不用说二进制兼容了。后者是源兼容的,前提是解决了foo要使用的歧义。 C ++确实做了一些努力来帮助解决这个问题,初始化一个函数指针是一种罕见的(只有?)情况,其中context会影响表达式的值。

答案 1 :(得分:3)

您只需要重新编译依赖于您的班级的代码(如Nikolai所说),即您的班级居住在其他人使用的库中。 即便如此,只有在您的类:

时才需要重新编译相关代码
  1. 更改内存布局:
    • 您添加/删除成员;
    • 更改会员类型;
    • 您添加虚拟方法或将现有方法更改为虚拟方法(因此您添加了隐藏的vpointer成员);
  2. 更改方法签名(更准确地说,更改编译器用于名称修饰/修改的内容):
    • 改变他们的常数;
    • 改变他们的虚拟性;
    • 添加/更改默认参数值。
  3. 我很确定我错过了一些东西,但我会添加任何其他的东西(无论是评论还是我的记忆开始变得更好)。

答案 2 :(得分:0)

如果您只使用这些库,则没有什么会强迫您重新编译它们......

除了更改编译器/体系结构/操作系统或更改库的某些#define之外

答案 3 :(得分:0)

这个问题有点令人困惑,所以为了得到这个版本,你只需要重新编译依赖于你的类的代码。

那些依赖于你班级的事情:

  1. 向您的类添加构造函数会引入一个新函数,因此如果客户端代码不使用该构造函数,则不需要重新编译,
  2. 添加数据成员更改类的内存布局 - 需要重新编译,
  3. 将析构函数更改为虚拟更改/引入vtable布局和函数调度代码 - 需要重新编译,
  4. 使用默认值向现有成员函数添加参数会更改该函数的参数数量(在调用站点处替换默认参数) - 需要客户端代码重新编译。

答案 4 :(得分:0)

更改库所依赖的任何源代码或类应强制重新编译库。正确设置依赖关系的良好构建工具将在构建过程中自动处理此问题。