【问题标题】:Why do compilers that support precompiled headers typically only allow one?为什么支持预编译头文件的编译器通常只允许一个?
【发布时间】:2014-12-09 22:08:44
【问题描述】:

使用多个预编译头文件有潜在的好处。假设有一个项目,其中有几个不经常更改并在许多源代码文件中使用的标头。这些标头倾向于两个簇,A 和 B。当 A 中的一个标头发生变化时,A 中的其他标头也可能发生变化,但 B 中的标头发生变化的概率不受影响,反之亦然。

在这种情况下使用两个预编译头文件可能是有益的,但大多数支持预编译头文件的编译器只支持一个预编译头文件。

这是什么原因,为什么会这样?

注意:这个问题不是问是否存在支持多个预编译头文件的编译器或如何实现。

问题是关于允许多个预编译头文件在技术上具有挑战性或不切实际的原因。

我感兴趣的特定编译器是 gcc 和 clang 编译 C++,但我的期望是这不会改变答案。

【问题讨论】:

  • 用于 Windows 和 OS/2 的 IBM C 和 C++ 编译器用于预编译您曾经使用过的每个头文件。这很快就产生了大量的文件。所以他们改变了它。

标签: compiler-construction compiler-optimization precompiled-headers


【解决方案1】:

我认为真正的问题是源文件/头文件中条件句的数量引起的组合。

大多数头文件都充满了条件。 “预编译”意味着条件句已被解析......不幸的是,如果您选择将条件句解析为真或假,并且您有 20 个条件句,则有 ~1600 万种可能的配置。 (我们甚至没有计算标量而非布尔值或参数化宏的定义)。

如果使用需要一种配置,您可以使用一个预编译的头文件。有趣的是,对于个人开发人员来说,这似乎很常见,这是对“只有一个”的一种解释。但是如果配置变化很快,要么需要大量的预编译头文件,这有其自身的成本(想象一下“预编译”1600万个预配置头文件),要么必须按需生成它们(哎呀,这就是我们希望的情况避免)。

人们可能会以两种方式避开这两种方式。

“预编译”的大部分成本只是处理文本。如果编译器将头文件分解为组成标记并存储标记,则可以在很大程度上避免文本处理时间,即使每次仍然评估条件。我从未见过(但看起来不是很难)有这样的 C 或 C++ 编译器。

另一种可能性是预编译和存储用户实际使用的每个组合,并按配置索引存储它们。然后查找将很容易找到“正确”的预编译头文件。我怀疑这对于数量不多的单个用户来说会达到顶峰。谁有时间试验数百种配置?

一种遥远的想法是象征性地评估条件。虽然许多条件是独立的,但一些条件控制其他条件的配置,因此在条件之间存在一组复杂的约束......可以预先计算这些组合,然后预先计算可能的配置。在实践中,有用的组合可能会少很多。

更实用的方法可能是隔离相互关联的条件句组。本质上,您会得到许多较小的头文件,每个头文件的条件较少。如果它们变得足够小,您实际上可以预先计算较小文件的选择空间,然后简单地选择正确的文件。您必须为每个附加一个预处理器配置说明。

通常最好的解决方案是混合解决方案。我希望存储标记而不是文本,如上所述拆分条件,但留下一些具有 some 未评估条件的文件,以实际“处理”会产生非常有用的结果。

唉,我将不得不把这些想法留给其他人的热情去实施:-}

【讨论】:

  • 我熟悉的预编译头文件已经绑定到用于生成它们的编译器选项。宏不仅是定义/未定义的,而且还可以扩展,因此尝试抢占所有可能的配置是不可能的,即使对于单个预编译头文件也是如此。那是用户的问题。
  • 是的,他们必须是;编译器不能使用预编译头文件,除非它可以验证预编译头文件是使用相同的定义集(包括参数化宏)处理的。否则内容可能不正确。任何保存的预编译头文件都需要与其关联的配置一起存储以进行此类检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 2020-08-04
  • 1970-01-01
  • 2010-11-20
  • 1970-01-01
  • 2023-03-06
相关资源
最近更新 更多