文档章节

使用 GNU CC 的预编译头文件加快编译速度

AlphaJay
 AlphaJay
发布于 2010/11/23 14:35
字数 1101
阅读 674
收藏 3

既使用过 Microsoft® Visual C++® 又使用过 GNU CC 的网友一定会感受到两者编译速度的差异,尤其是对于 wxWidgets 这样头文件内容多的软件。Microsoft® Visual C++® 能够有很高编译效率的原因是其支持“预编译头文件” (Pre-Compiled Header, PCH)。当使用 Microsoft® Visual C++® 建立项目时,常常会建立文件 StdAfx.cpp 和 StdAfx.h。其中 StdAfx.h 包含了项目中所有实质 C/C++ 源文件所要用到的一些系统头文件,而 StdAfx.cpp 只包含了 StdAfx.h。这两个文件便是用来建立预编译头文件“项目名.pch”的。预编译头文件是将一些项目中普遍使用的头文件内容的词法分析、语法分析等结果缓存在一个特定格式的二进制文件中;当然编译实质 C/C++ 源文件时,就不必从头对这些头文件进行词法-语法分析,而只需要利用那些已经完成词法-语法分析的结果就可以了。

事实上,GNU CC 从 3.4.x 版和 4.x 版开始,也支持了这种提高编译效率的机制。只是由于 GNU CC 的手册中的《Using Precompiled Headers》一节对此介绍不多,也没有简单的自动项目管理工具支持这项功能,因而许多网友还不知道 GNU CC 的这项功能。

GNU CC 的手册中建议使用 make 管理预编译头文件,还指出 C 语言的预编译头文件和 C++ 语言的预编译头文件是不一样的。这里首先讲述项目中只有 C 语言源文件或只有 C++ 语言源文件的情形,再讲述项目中两种语言的源文件同时存在的情况。

项目中只有 C 或 C++ 一种语言的源文件时,只需建立一个预编译头文件。

  1. 建立一个头文件,例如命名为 inc.h。该文件供项目中所有的 C/C++ 源文件使用。将整个项目所需要的头文件都列在其中:
    /* $FreeBSD$ */
    #ifndef	_INC_H_
    #define	_INC_H_
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/uio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #endif /* ! _INC_H_ *
  2. 建立 Makefile,以维护预编译头文件。一方面要建立维护 GNU CC 的预编译头文件 inc.h.gch 的规则;另一方面,要在编译每个 C/C++ 源文件时检查 inc.h.gch,即让所有 .o 文件依赖于 inc.h.gch。
    # $FreeBSD$
    
    CC	=	gcc
    CFLAGS	=	-g -Wall
    
    CXX	=	gcc
    CXXFLAGS	=	-g -Wall
    
    LD	=	gcc
    LDFLAGS	=	-g -Wall
    
    EXE	=	testapp
    PCH_H	=	inc.h
    PCH	=	inc.h.gch
    SRCS	=	testapp.c
    OBJS	=	testapp.o
    LIBS	=			# System Libraries
    
    ECHO	=	echo
    CP	=	cp -v
    RM	=	rm -f
    
    .SUFFIXES:
    .SUFFIXES: .o .c .cxx
    
    # The meaning of "$<":
    #     BSD Pmake: the implied source
    #     GNU make: the first prerequisite
    
    .c.o:
    	$(CC) $(CFLAGS) -c $<
    .cxx.o:
    	$(CXX) $(CXXFLAGS) -c $<
    
    all:	$(EXE)
    
    #                  $>                    $^
    # BSD Pmake    all sources        not defined
    # GNU make     not defined        all prerequisites
    # Both interpret "$@" as target
    
    $(EXE):	$(OBJS) $(LIBBDD)
    	$(LD) $(LDFLAGS) -o $@ $> $^ $(LIBS)
    
    # Pre-compiled header
    $(OBJS): $(PCH)
    
    $(PCH): $(PCH_H)
    	$(CC) $(CFLAGS) $> $^
    
    clean:
    	$(RM) $(PCH) $(OBJS)
    # For Both UNIX-like OS and Microsoft Windows (MinGW/Cygwin)
    	$(RM) $(EXE) $(EXE).exe

如果项目既包含 C 语言源文件,也包含 C++ 语言源文件,就需要为两种语言分别维护一个预编译头文件。

  1. 再建立一个头文件,例如命名为 inc.hpp。inc.h 供 C 语言源文件使用,而 inc.hpp 供 C++ 语言文件使用。假如 inc.hpp 的内容与 inc.h 的相同,只需要简单的写上:
    /* $FreeBSD$ */
    #ifndef	_INC_HPP_
    #define	_INC_HPP_
    
    #include "inc.h"
    
    #endif /* ! _INC_HPP_ */
  2. 在 Makefile 里也要随之增加对 inc.hpp 的维护。一是要增加产生 inc.hpp.gch 的规则,此时执行 GNU CC 时要增加参数“-x c++-header”;二是要在 clean 一节中删除这个预编译头文件。
    # $FreeBSD$
    
    CC	=	gcc
    CFLAGS	=	-g -Wall
    
    CXX	=	gcc
    CXXFLAGS	=	-g -Wall
    
    LD	=	gcc
    LDFLAGS	=	-g -Wall
    
    EXE	=	testapp
    PCH_H	=	inc.h
    PCH	=	inc.h.gch
    PCH_X_H	=	inc.hpp
    PCH_X	=	inc.hpp.gch
    SRCS	=	testapp.c
    OBJS	=	testapp.o
    LIBS	=			# System Libraries
    
    ECHO	=	echo
    CP	=	cp -v
    RM	=	rm -f
    
    .SUFFIXES:
    .SUFFIXES: .o .c .cxx
    
    # The meaning of "$<":
    #     BSD Pmake: the implied source
    #     GNU make: the first prerequisite
    
    .c.o:
    	$(CC) $(CFLAGS) -c $<
    .cxx.o:
    	$(CXX) $(CXXFLAGS) -c $<
    
    all:	$(EXE)
    
    #                  $>                    $^
    # BSD Pmake    all sources        not defined
    # GNU make     not defined        all prerequisites
    # Both interpret "$@" as target
    
    $(EXE):	$(OBJS) $(LIBBDD)
    	$(LD) $(LDFLAGS) -o $@ $> $^ $(LIBS)
    
    # Pre-compiled header
    $(OBJS): $(PCH)
    
    $(PCH): $(PCH_H)
    	$(CC) $(CFLAGS) $> $^
    
    $(PCH_X): $(PCH_X_H)
    	$(CXX) $(CXXFLAGS) -x c++-header $> $^
    
    clean:
    	$(RM) $(PCH) $(PCH_X) $(OBJS)
    # For Both UNIX-like OS and Microsoft Windows (MinGW/Cygwin)
    	$(RM) $(EXE) $(EXE).exe

这是以上两种 Makefile 的比较:

@@ -12,6 +12,8 @@
 EXE	=	testapp
 PCH_H	=	inc.h
 PCH	=	inc.h.gch
+PCH_X_H	=	inc.hpp
+PCH_X	=	inc.hpp.gch
 SRCS	=	testapp.c
 OBJS	=	testapp.o
 LIBS	=			# System Libraries
@@ -48,7 +50,10 @@
 $(PCH): $(PCH_H)
 	$(CC) $(CFLAGS) $> $^
 
+$(PCH_X): $(PCH_X_H)
+	$(CXX) $(CXXFLAGS) -x c++-header $> $^
+
 clean:
-	$(RM) $(PCH) $(OBJS)
+	$(RM) $(PCH) $(PCH_X) $(OBJS)
 # For Both UNIX-like OS and Microsoft Windows (MinGW/Cygwin)
 	$(RM) $(EXE) $(EXE).exe

本文转载自:http://www.uml.org.cn/c++/200902105.asp

AlphaJay
粉丝 79
博文 284
码字总数 313790
作品 0
杭州
私信 提问
fatal error C1010: unexpected end of file while...

在编译VC++6.0是,出现fatal error C1010: unexpected end of file while looking for precompiled header directive 的错误. 解决方法: 1、如果发生错误的文件是由其他的C代码文件添加进入当...

Mr&Cheng
2013/01/20
35
0
分布式编译

通过本文,您将了解能够通过将编译过程分布到本地网络中的多台机器上,从而加快速度的开源工具选项。 减少基于 C/C++ 的系统的编译时间是所有发布和编译工程师所面对的主要挑战之一。本文研究...

红薯
2009/02/10
2.9K
0
【转】在VC空白项目里添加自定义的预编译头

在VC空白项目里添加自定义的预编译头 整篇只要看画出红线的部份就可以了,应该会节省你一些时间. 这里有个概念要先说明. 1>代码里面至少要有个CPP是用于创建预编绎头的. 2>其它CPP则都是选使用...

超能123
2012/12/27
75
0
Linux GCC 编译过程

目前Linux下最常用的C语言编译器是GCC(GNU Compiler Collection),它是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Object C等语言编写的程序.GCC不仅功能非常强大,结构也异常灵活....

鉴客
2011/11/23
1K
0
提高Qt Creator编译速度的5种方法,亲测可行(★firecat推荐★)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/libaineu2004/article/details/89352224 Qt Creator默认的编译方式太...

libaineu2004
04/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

vue vue-router beforeRouteEnter

本文转载于:专业的前端网站➬vue vue-router beforeRouteEnter beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `thi...

前端老手
47分钟前
4
0
Spring Boot 2 实战:结合 Docker 容器化

1. 前言 Docker 是啥?好处是啥? 什么现在如果作为一名开发你还不知道甚至没有用过我都感觉你落伍了。Docker 是一种虚拟化的容器技术,目的为了打造持续集成、版本控制、可移植性、隔离性和...

码农小胖哥
51分钟前
4
0
Linux 常用查询句柄的命令(Too many open files)

摘要 查询命令 进程占用的句柄总数 lsof -n | wc -l 查看哪一个进程占用的句柄最多 lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more 第一列 是 占用句柄数; 第二列 是 进程号 PID;...

liangxiao
51分钟前
5
0
JavaScript权威指南笔记5

第五章、语句 0、概述 JS程序是一系列可执行语句的集合。 通过控制语句来改变语句的默认执行顺序。 控制语句:条件、循环和跳转(如return、break和throw) 2、复合语句 当多条语句被当做一条语...

_Somuns
57分钟前
5
0
vmware安装ubuntu18.04总是 panic -not syncing:corrupted stack end detected inside schedule

Vmware 安装ubuntu 总是卡着不动, 提示panic -not synciong 网上提示很多办法,都试了效果不佳, 找到了完美解决办法 你的兼容模式重新选一下为6.0,兼容性对硬件有要求的 即可实现 成功安装...

dragon_tech
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部