【问题标题】:Precompiled headers with GCC使用 GCC 预编译的头文件
【发布时间】:2010-09-08 16:48:17
【问题描述】:

任何人在使用 GCC 获得预编译头文件方面取得过任何成功吗?我的尝试没有运气,也没有看到很多关于如何设置它的好例子。我在 cygwin gcc 3.4.4 上试过,在 Ubuntu 上用过 4.0。

【问题讨论】:

  • 我试过了,我有预编译头文件的最佳用例,因为我的 c 源代码是编译器生成的,而不是用户编写的。 Sun Studio 尤其是 Visual Studio 大大缩短了构建时间。在 gcc 上,如果没有预编译头文件,情况会变得更糟。这是与 3.4 没有 testet 与 4.x 但速度和 gcc 是相互排斥的。
  • @Lothar 代码是什么?在一些大量模板化的代码上,我发现 g++ 比最近的 Visual Studio 编译器快 10 倍。
  • 我没有在我的 C++ 代码中使用模板。它只是 C + 异常处理 + 不错的 C++ 扩展。即使是在这个问题 6 年后的现在,VS2010 也快了一个数量级。但与此同时,我有 16 个内核,所以我可以忍受它。

标签: c++ gcc precompiled-headers


【解决方案1】:

我确实取得了成功。首先,我使用了以下代码:


#include <boost/xpressive/xpressive.hpp>
#include <iostream>

using namespace std;
using namespace boost::xpressive;

//A simple regex test
int main()
{
    std::string hello( "hello world!" );

    sregex rex = sregex::compile( "(\\w+) (\\w+)!" );
    smatch what;

    if( regex_match( hello, what, rex ) )
    {
        std::cout << what[0] << '\n'; // whole match
        std::cout << what[1] << '\n'; // first capture
        std::cout << what[2] << '\n'; // second capture
    }
    return 0;
}

这只是来自 Boost Xpressive 的一个问候世界(请参阅下面的链接)。首先,我使用 gcc 中的-H 选项进行编译。它显示了它使用的大量标题列表。然后,我查看了我的 IDE (code::blocks) 生成的编译标志,并看到了如下内容:

g++ -Wall -fexceptions -g -c main.cpp -o obj/Debug/main.o

所以我写了一个命令来编译带有完全相同标志的 Xpressive.hpp 文件:

sudo g++ -Wall -fexceptions -g /usr/local/include/boost/xpressive/xpressive.hpp

我用-H再次编译了原始代码并得到了这个输出:

g++ -Wall -fexceptions -H -g -c main.cpp -o obj/Debug/main.o ! /usr/local/include/boost/xpressive/xpressive.hpp.gch 主文件 . /usr/include/c++/4.4/iostream .. /usr/include/c++/4.4/x86_64-linux-gnu/bits/c++config.h .. /usr/include/c++/4.4/ostream .. /usr/include/c++/4.4/istream 主文件

!意味着编译器能够使用预编译的头文件。 x 表示它无法使用它。使用适当的编译器标志至关重要。我取下 -H 并进行了一些速度测试。预编译的标头从 14 秒提高到 11 秒。不错,但也不是很好。

注意:这是示例的链接:http://www.boost.org/doc/libs/1_43_0/doc/html/xpressive/user_s_guide.html#boost_xpressive.user_s_guide.examples 我无法在帖子中使用它。

顺便说一句:我正在使用以下 g++

g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3

【讨论】:

  • 添加 -Winvalid-pch 将帮助您调试在使用 PCH 时是否以及为什么出现问题。
  • “不错但不是很好”预编译的头文件在您有许多相互重新链接的头文件时很有用,因此它们将减少使用大型库或许多库的非常大的项目的编译时间。跨度>
  • “不错但不是很好”:使用 gcc 4.4.7,136 个 .cpp 文件总大小为 35.5 Mb,148 个 .h 文件总大小为 5.5 Mb,.gch 文件为 48 Mb,调试构建需要 2'20" (vs 2'14" non-pch),-O2 优化构建需要 4'30" (vs 5'33" non-pch) 在调试构建附近可以预期效果,但这只是优化构建从预编译中获利....不知道为什么。预编译在 Windows 上更具戏剧性!
  • (cont'd) 对应的 pch/non-pch 输出文件的大小字节大小完全相同,这很好。重复构建时,上述时间似乎有所不同,例如 -O2 non-pch 在 3'45" 和 5'33" 之间变化,所以这不是精确的科学,可能是由于在 VMware 中运行。无论如何,gcc pch 在我看来根本没有用。将其与 Windows VS2012(x64,单线程编译)上的相同代码库进行比较:调试 46" pch,2'50" non-pch,release 2'13" pch,5'02" non-pch。当然,在启用多处理器时速度会更快......
  • @AndreasVergison - 您是否尝试过使用-Winvalid-pch 来确保正确使用预编译的标头?我们注意到使用 pch 进行调试构建有了很大的改进,所以我想知道您的设置是否存在问题。
【解决方案2】:

Firstly, see the documentation here.

您像编译任何其他文件一样编译头文件,但您将输出放在后缀为.gch 的文件中。

因此,例如,如果您预编译 stdafx.h,您将有一个预编译的标头,只要您包含 stdafx.h,就会自动搜索名为 stdafx.h.gch 的预编译标头

例子:

stdafx.h:

#include <string>
#include <stdio.h>

a.cpp:

#include "stdafx.h"
int main(int argc, char**argv)
{
  std::string s = "Hi";
  return 0;
}

然后编译为:

&gt; g++ -c stdafx.h -o stdafx.h.gch
&gt; g++ a.cpp
&gt; ./a.out

即使您在第 1 步后删除 stdafx.h,您的编译也将正常工作。

【讨论】:

    【解决方案3】:

    调用 gcc 的方式与为源文件调用它的方式相同,但使用头文件。

    例如

    g++ $(CPPFLAGS) test.h
    

    这会生成一个名为 test.h.gch 的文件

    每次 gcc 搜索 test.h 时,它首先查找 test.h.gch,如果找到它会自动使用它。

    更多信息可以在GCC Precompiled Headers找到

    【讨论】:

    • 我正在使用 gcc 3.4 并且行 g++ stdafx.h 将无法编译,您会收到错误“g++: 头文件编译请求”,但这会编译,不确定这是否是我想要的虽然:“g++ -c -x c++ stdafx.h -o stdafx.h.pch”
    【解决方案4】:

    C++ 预编译头文件的-x 说明符是-x c++-header,而不是-x c++。下面是 PCH 的用法示例。

    pch.h:

    // Put your common include files here: Boost, STL as well as your project's headers.
    

    main.cpp:

    #include "pch.h"
    // Use the PCH here.
    

    像这样生成 PCH:

    $ g++ -x c++-header -o pch.h.gch -c pch.h
    

    pch.h.gch必须和pch.h在同一目录下才能使用,所以请确保从pch.h所在的目录执行上述命令。

    【讨论】:

    • 这应该是 -c pch.h ,而不是 -c pch.cpp ?
    【解决方案5】:

    过去我曾设法让预编译的头文件在 gcc 下工作,我记得当时也遇到了问题。需要记住的是,如果不满足某些条件,gcc 将忽略文件(header.h.gch 或类似文件),可以在gcc precompiled header documentation page 上找到其列表。

    通常,最安全的做法是让您的构建系统首先编译 .gch 文件,并使用与其他源代码相同的命令行选项和可执行文件。这样可以确保文件是最新的并且没有细微的差异。

    首先让它与一个人为的示例一起工作可能也是一个好主意,只是为了消除您的问题特定于您项目中的源代码的可能性。

    【讨论】:

      【解决方案6】:

      确保-include your_header.h

      这就是我预编译和使用bits/stdc++.h 集合的方式。

      代码

      #include <bits/stdc++.h>
      

      然后我通过使用 -H 编译我的文件并查看输出来找到 lib

      g++ sol.cpp -H -O3 -pthread -lm -std=c++14 -o executable
      

      我看到的地方

      . /usr/include/x86_64-linux-gnu/c++/7/bits/stdc++.h
      

      所以我在当前目录中创建了一个新目录bits,并从那里复制了stdc++.h

      然后我跑了

      g++ bits/stdc++.h -O3 -std=c++14  -pthread
      

      生成bits/stdc++.gch

      通常我通过以下方式编译我的代码

      g++ sol.cpp -O3 -pthread -lm -std=c++14 -o executable
      

      ,但我不得不将其修改为

      g++ sol.cpp -include bits/stdc++.h -O3 -pthread -lm -std=c++14 -o executable
      

      因为它只解析为.gch 文件而不是.h-include bits/stdc++.h 这对我来说很关键。要记住的另一件事是,您必须使用与编译*.cpp 几乎相同的参数来编译*.h 头文件。当我没有包含 -O3-pthread 时,它忽略了 *.gch 预编译头。

      要检查一切是否正确,您可以通过比较结果来测量时差

      time g++ sol.cpp ...
      

      或运行

      g++ sol.cpp -H -O3 -pthread -lm -std=c++14 -o executable
      

      再次查找头文件路径,例如,如果您现在在库路径之前获得!

      ! ./bits/stdc++.h.gch
      ....
      

      【讨论】:

      • 非常感谢这个答案,我已经为此扯了两天的头发了:)
      【解决方案7】:

      关于文件扩展名的一个微妙提示让我感到困惑,因为我没有足够关注:.gch 扩展名被添加到预编译文件的全名中,它不会替换 .h。如果你弄错了,编译器将找不到它并且默默地不起作用。

      precomp.h => precomp.h.gch

      不是:

      precomp.h => precomp.gch

      使用 gcc -H 检查它是否正在查找/使用它。

      【讨论】:

        猜你喜欢
        • 2012-09-08
        • 2012-06-13
        • 1970-01-01
        • 1970-01-01
        • 2017-03-29
        • 1970-01-01
        • 2016-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多