使用 GNU CC 的預編譯頭文件加快編譯速度

既使用過 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++ 源文件時,就沒必要從頭對這些頭文件進行詞法-語法分析,而只須要利用那些已經完成詞法-語法分析的結果就能夠了。c++

事實上,GNU CC 從 3.4.x 版和 4.x 版開始,也支持了這種提升編譯效率的機制。只是因爲 GNU CC 的手冊中的《Using Precompiled Headers》一節對此介紹很少,也沒有簡單的自動項目管理工具支持這項功能,於是許多網友還不知道 GNU CC 的這項功能。緩存

GNU CC 的手冊中建議使用 make 管理預編譯頭文件,還指出 C 語言的預編譯頭文件和 C++ 語言的預編譯頭文件是不同的。這裏首先講述項目中只有 C 語言源文件或只有 C++ 語言源文件的情形,再講述項目中兩種語言的源文件同時存在的狀況。app

項目中只有 C 或 C++ 一種語言的源文件時,只需創建一個預編譯頭文件。socket

  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 的比較:ui

@@ -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
相關文章
相關標籤/搜索