Compiler construction 为什么支持预编译头的编译器通常只允许一个?

Compiler construction 为什么支持预编译头的编译器通常只允许一个?,compiler-construction,compiler-optimization,precompiled-headers,Compiler Construction,Compiler Optimization,Precompiled Headers,使用多个预编译头有潜在的好处。假设存在一个项目,其中有几个标题很少更改,并且在许多源代码文件中使用。这些头倾向于两个集群,A和B。当A中的一个头更改时,A中的其他头也可能更改,但B中的头更改的概率不受影响,反之亦然 在这种情况下使用两个预编译头可能是有益的,但大多数支持预编译头的编译器只支持一个预编译头 原因是什么?为什么会这样 注意:这个问题不是问是否存在支持多个预编译头的编译器,也不是问如何实现这一点 问题是什么使得允许多个预编译头在技术上具有挑战性或不切实际 >我感兴趣的编译器是GCC和

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

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

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

注意:这个问题不是问是否存在支持多个预编译头的编译器,也不是问如何实现这一点

问题是什么使得允许多个预编译头在技术上具有挑战性或不切实际


<> >我感兴趣的编译器是GCC和CLAN编译C++,但我的期望是,它不会改变答案。

< P>真正的问题,我认为是由源/头文件中条件数的组合而来的。 大多数头文件都充满了条件。“预编译”意味着条件已被解析。。。不幸的是,如果您选择将条件解析为true或false,并且您有20个条件,那么可能有~~ 1600万个配置。(我们甚至不计算标量而非布尔值的定义,或者参数化宏的定义)

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

有两种方法可以回避这个问题

“预编译”的大部分成本只是处理文本。如果编译器将头文件分解为一致性标记,并存储这些标记,那么即使每次仍对条件进行求值,也可以在很大程度上避免文本处理时间。我从来没有见过(但看起来并不十分)为C或C++编译器这样做。 另一种可能性是预编译和存储用户实际使用的每个组合,并存储它们,并按配置编制索引。然后查找将很容易找到“正确”的预编译头。我怀疑这将以一个适度的数量为单个用户提供最佳服务;谁有时间试验数百种配置

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

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

通常最好的解决方案是混合型的。我希望存储标记而不是文本,像上面那样分割条件,但留下一些带有未计算条件的文件,以便实际“处理”将产生非常有用的结果


唉,我将不得不把这些想法留给其他人来实现:-}

我熟悉的预编译头已经绑定到用于生成它们的编译器选项。宏不仅是已定义/未定义的,而且还可以扩展,因此尝试抢占所有可能的配置是不可能的,即使对于单个预编译头也是如此。这是用户的问题。是的,他们必须这样;编译器无法使用预编译头,除非它可以验证预编译头是使用同一组定义(包括参数化宏)处理的。否则,内容可能不正确。保存的任何预编译头文件都需要与其相关联的配置存储在一起进行检查。用于Windows和OS / 2的IBM C和C++编译器用于对您所使用的每个头文件进行预编译。这很快就产生了大量的文件。所以他们改变了。