阅读这篇不错的文章(预编译头文件),我对这些如何在现实生活中实际工作有一些疑问.更具体地说,我怎么知道我需要在以下场景中触发预编译头的重建:
After reading this nice article (The Care and Feeding of Pre-Compiled Headers), I have some doubts regarding how these can actually work in real life. More specifically, how can I know that I need to trigger the rebuild of the pre-compiled header in the following scenarios:
#define
改变预处理器解释一些已经包含在我的预编译头文件中的头文件的方式#define
是一个特定的预处理器指令,它改变了预处理器解释已包含在预编译头文件中的头文件的方式#include
其他标头#define
something in one of my .cpp files that alters the way the pre-processor interprets some headers that are already included in my pre-compiled header#define
s a specific pre-processor directive that alters the way the pre-processor interprets a header already included in the precompiled header#include
other headers预编译头文件的使用是否应该强制执行某种限制性编码风格,例如将 .cpp 文件中包含的头文件数量限制为一个,并且永远不要在 .cpp 文件中#define
添加内容?
Should the usage of pre-compiled headers enforce a certain restrictive coding style like limiting the number of headers included in .cpp files to one and never #define
ing stuff in a .cpp file?
虽然微软的编译器可能在预编译头文件方面做得不错(通过应用一些特定于 MS 的伏都教),因为据我所知,它提供了 /Yc
和 /Yu
应该完成所有管道的选项,对于 GCC,这个功能似乎需要在 Makefile 中进行大量手动工作和创造力,我无法找到一个应该解决所有问题的模板使用预编译头文件的陷阱.
While Microsoft's compiler probably does a decent job with pre-compiled headers (by applying some MS-specific voodoo) because, as far as I know, it provides the /Yc
and /Yu
options that are supposed to do all the plumbing, for GCC it seems that this functionality requires a lot of manual work and creativity in the Makefile and I wasn't able to find a template that is supposed to address all the pitfalls of using pre-compiled headers.
例如,如果我有一个构建多个库的项目,为了在每次更改后不重建所有库,我必须使用一些非常可爱的sed
技巧 在 Makefile 中检测当前库的头文件 #include
d 是否是已修改(或 #include
修改后的标头).我什至不敢去想预先构建的标头实际上意味着什么,以便构建脚本在每次需要时重建它们.
For example, if I have a project which builds several libraries, in order not to rebuild all of them after each change, I have to use some really cute sed
tricks in the Makefile to detect if one of the headers #include
d by the current library was modified (or it #include
s a modified header). I fear to even think of the complications that pre-built headers would actually imply in order for the build script to rebuild them each time it is necessary.
当前的 GCC(即 4.7)及其以前的版本与 预编译头 仅当您的应用程序具有单个公共头,并且该单个头(依次包括所有系统的,以及应用程序所需的库特定的)是 #include
-d(作为您的源的第一个非注释词素)被您的每个来源申请.
Current GCC (i.e. 4.7) and previous versions of it works nicely with precompiled headers only when you have a single common header to your application, and when that single header (which includes in turn all the system ones, and the library specific ones, required by the application) is #include
-d (as the first non-comment lexeme of your sources) by every source of your application.
所以你应该有一个 single yourapp.h
并且有 yourapp
starting 的每个源文件(即每个编译单元) 与 #include yourapp.h"
具有相同的预处理选项(即 -D
或 -I
或 -U
) 在命令行上.youapp.h
头文件通常是 #include
-ing 许多其他的,例如系统标头(或 GTK 或 Qt 标头),如
或
或 [在 C++ 中] ;
或
或
等
So you should have a single yourapp.h
and have every source file (i.e. every compilation unit) of yourapp
starting with #include "yourapp.h"
with the same preprocessing options (i.e. -D
or -I
or -U
) on the command line. That youapp.h
header file is usually #include
-ing many others, e.g. system headers (or GTK or Qt ones) like <stdlib.h>
or <sys/poll.h>
or [in C++] <algorithm>
or <gtk/gtk.h>
or <QtGui>
etc.
回想一下,-H
是让 gcc
告诉您包含的内容的有用选项.
Recall that -H
is a useful option to get gcc
tell you what is included.
如果需要,您的源文件可能有一些额外的 #include
after #include yourapp.h"
.
在 GCC 包含 [单个] 预编译头文件后,您当然可以使用 #define
宏、#include
一些非预编译头文件,进行条件编译#ifdef
等,但该预处理不会被预编译"!
After a [single] precompiled header has been included by GCC, you may of course #define
macros, #include
some non-precompiled header, do conditional compilation with #ifdef
, etc. But that preprocessing won't be "pre-compiled"!
这可能不符合您的需求或习惯.
This may not fit your needs or habits.
有些人(特别是来自 Google,特别是 Diego Novillo)正在开发 PreParsed Header (pph) 分支 改善这种情况,但目前的 GCC 主干还没有得到那个工作.
Some people (notably from Google, notably Diego Novillo) are working on the PreParsed Header (pph) branch to improve the situation, but the current GCC trunk has not got that work yet.
关于 GCC 行为的解释是预处理头本质上是整个 GCC 堆的持久序列化检查点(相关于 GCC 内的内存管理通过 Ggc 和 GTY 以及 gengtype
).只有当 gcc
处于其初始空状态时,才能加载该检查点堆.一旦 gcc
(实际上是 cc1
或 cc1plus
)知道某些东西,它就不能再加载任何预编译头文件 *.h.gch
并将恢复解析文本头文件 *.h
.
The explanation about that behavior of GCC is that a preprocessed header is essentially a persistent serialized checkpoint of the entire GCC heap (related to memory management inside GCC thru Ggc and GTY and gengtype
). That checkpointed heap can be loaded only when gcc
is in its initial empty state. As soon as something is known to gcc
(actually cc1
or cc1plus
) it cannot load any more any precompiled header file *.h.gch
and will revert to parsing the textual header file *.h
.
即使 GCC 4.9 也需要一个预编译头.Diego Novillo 等人的预解析头文件.已被废弃.
Even GCC 4.9 wants a single precompiled header. The pre-parsed header effort by Diego Novillo et al. has been abandoned.
C++ 标准的未来版本(发布 C++14)可能定义了一个模块机制.见例如n4047 提案和 C++20 标准.
Future versions (post C++14) of the C++ standard might define a module mechanism. See e.g. n4047 proposal and the C++20 standard.
(附加附录,2020 年夏季)这仍然适用于 GCC-10 其中存在多个 静态分析器 选项.另请参阅 Clang 静态分析器 和 这份报告草案.考虑使用 Frama-C.
(additional addenda, summer 2020) This still holds for GCC-10 where several static analyzer options exist. See also the Clang static analyzer and this draft report. Consider using Frama-C.
这篇关于GCC 和预编译头文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!