GCC使用预编译头文件

GCC使用预编译头文件

通常大型项目有许多头文件,每个源文件中都包含很多头文件。编译器一遍又一遍地处理这些头文件所花费的时间几乎可以占据构建项目的所有时间。为了使构建更快,GCC 允许您使用 预编译头文件

注意:,此文说的预编译头文件特指生成的 .gch文件,而不是相应的.h 文件。

要创建预编译的头文件,只需像编译任何其他文件一样编译它,如有必要,使用-x 选项将其视为 C 或 C++ 头文件。您可能希望使用构建工具,例如make确保当头文件发生更新时预编译的头文件也进行更新。

在编译过程中看,当发现中有#include 时,将搜索预编译的头文件。和搜索包含的文件一样(请参阅 C 预处理器中的搜索路径),编译器会在每个目录中查找预编译的标头,然后再在该目录中查找包含文件。搜索的名称是在 #include文件名称后附加中指定的名称.gch。如果无法使用此预编译头文件,则忽略它。

例如,如果您有 #include "all.h",并且您有 all.h.gch文件位于all.h同一目录中,则编译器尽可能使用预编译的头文件,否则使用原始头文件。

方案一,您可以决定将预编译的头文件放在一个目录中,并使用-I 确保在包含原始头的目录之前(或代替)搜索该目录。然后,如果要检查是否在一直使用预编译的头文件,则可以将与原始头文件同名的.h文件中增加#error ,并且将其放在包含命令的目录中。

注意:上述方案是指您生成.gch文件后,检查.gch文件是否生效的方法,如果.gch文件正确,会优先使用.gch,而忽视.h文件。当然这时您的Makefile不能自动在.h更新后生成.gch。

方案二,使用预编译头的另一种方法是用-include 编译选项。因此,对于没有考虑预编译头文件而设计的项目,可以简单地筛选项目使用的大部分头文件,在另一个头文件包含他们,并且预编译这个头文件,同时使用编译选项-include预编译头文件,如果头文件具有卫哨防止多重包含,则会跳过它们,因为它们已被包含(在预编译的头文件中)。

如果您需要为不同的语言、目标或编译器选项预编译相同的头文件,您可以改为创建一个名为all.h.gch目录, 并将每个预编译的头文件放在目录中,也许使用-o. 目录中的文件叫什么并不重要。目录中的每个预编译头文件都会被考虑,使用在该目录中遇到的对该编译有效的第一个预编译头文件;搜索没有特定的顺序。

注意:比如你要编译debug版本和release版本,有不同的编译参数。您可以生成多个.gch文件,比如all.h.debug.gch,all.h.release.gch 都放入all.h.gch 目录。gcc会自己寻找合适的。

当然还有许多其他可能性,仅受您的想法、良好的判断力和构建系统的限制。

只有满足下列这些条件时,编译器才能正确使用预编译头文件

  • 在特定编译中只能使用一个预编译头文件。

  • 一旦看到第一个 C 标记,就不能使用预编译头文件。您可以在预编译头文件之前使用预处理器指令;您不能在另一个头文件中包含预编译头文件。

  • 必须为与当前编译相同的语言生成预编译的头文件。您不能将 C 预编译头文件用于 C++ 编译。

  • 预编译的头文件必须由与当前编译使用的编译器(二进制)必须相同。

  • 在包含预编译头文件之前定义的任何宏必须和生成预编译头文件时有相同的方式定义,或者不得影响预编译头文件,这通常意味着它们根本不会出现在预编译头文件中。

    这-D选项是在包含预编译头文件之前定义宏的一种方法;使用 a#define也可以做到。还有一些隐式定义宏的选项,例如 -O和-Wdeprecated; 同样的规则适用于以这种方式定义的宏。

  • 如果您的编译构建需要调试信息,您使用-g或类似的选项,这时您编译预编译头文件时必须使用相同类型的调试选项(注:-g类型的选项必须相同,比如都是用-g,-ggdb等)。然而,即使您的编译构建不需要调试信息,您也可以使用-g构建的预编译头文件。

  • 通常必须使用相同-m选项在构建和使用预编译头文件。有关放宽此规则的任何情况, 请参见子模型选项。

  • 在构建和使用预编译头文件时,以下每个选项都必须相同:

    -fexceptions
    
  • 其他一些命令行选项以-f,-p, 或者-O,必须以与生成预编译头文件时相同的方式定义。目前,尚不清楚哪些选项可以安全更改,哪些不安全;最安全的选择是在生成和使用预编译头文件时使用完全相同的选项。已知以下是安全的:

    -fmessage-length=  -fpreprocessed  -fsched-interblock 
    -fsched-spec  -fsched-spec-load  -fsched-spec-load-dangerous 
    -fsched-verbose=number  -fschedule-insns  -fvisibility= 
    -pedantic-errors
    
  • 地址空间布局随机化 (ASLR) 可能导致不一致的的二进制 PCH 文件。如果您依赖稳定的 PCH 文件内容,请在生成 PCH 文件时禁用 ASLR。

所有这些,除了最后一个之外,如果不满足条件,编译器会自动忽略预编译的头文件。如果您发现一个选项组合不起作用并且不会导致预编译的标头被忽略,请考虑提交错误报告,请参阅错误

如果您在生成和使用预编译头文件时使用了不同的选项,则实际行为是选项行为的混合。例如,如果您使用-g要生成预编译头文件但在使用时不生成,您可能会或可能不会获得预编译头文件中例程的调试信息。

posted @ 2022-11-02 01:10  fullsail  阅读(981)  评论(0编辑  收藏  举报