既使用過 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
/* $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_ *
# $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++ 語言源文件,就須要爲兩種語言分別維護一個預編譯頭文件。工具
/* $FreeBSD$ */ #ifndef _INC_HPP_ #define _INC_HPP_ #include "inc.h" #endif /* ! _INC_HPP_ */
# $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