對於需要大量時間來建置的大型專案,您可以考慮建立自訂先行編譯的檔案。 Microsoft C 和 C++ 編譯器提供對任何 C 或 C++ 程式碼進行先行編譯的選項,包括內嵌程式碼。 使用此效能功能,您可以編譯穩定的程式碼主體、將程式碼的編譯狀態儲存在檔案中,並在後續編譯期間,將先行編譯的程式碼與仍在開發中的程式碼結合。 每個稍後的編譯速度較快,因為穩定程式碼不需要重新編譯。
您的套裝程式含多個模組,所有模組都使用一組標準 Include 檔案和相同的編譯選項。 在此情況下,所有 Include 檔案都可以先行編譯成一個先行編譯的標頭。 如需處理包含檔案之較新方式的詳細資訊,請參閱
比較標頭單位、模組和先行編譯標頭
。
第一個編譯 (建立先行編譯標頭檔) 比後續編譯還要長一點。 後續的編譯可以藉由包含先行編譯的程式碼,更快速地繼續進行。
您可以先行編譯 C 和 C++ 程式。 在 C++ 程式設計中,常見的做法是將類別介面資訊分成標頭檔。 這些標頭檔稍後可以包含在使用 類別的程式中。 藉由先行編譯這些標頭,您可以減少程式編譯所需的時間。
雖然每個來源檔案只能使用一個先行編譯標頭檔 ()
.pch
檔案,但您可以在專案中使用多個
.pch
檔案。
預先編譯器代碼的兩個選項
您可以先行編譯任何 C 或 C++ 程式碼;您不限於先行編譯標頭檔。
先行編譯需要規劃,但如果您預先編譯原始程式碼,而不是簡單的標頭檔,它會提供更快速的編譯。
當您知道原始程式檔使用一組通用標頭檔,或想要在先行編譯中包含原始程式碼時,先行編譯器代碼。
先行編譯標頭選項
(
/Yc
建立先行編譯標頭檔)
,
(
/Yu
使用先行編譯標頭檔)
。 用來
/Yc
建立先行編譯的標頭。 搭配選用
hdrstop
pragma 使用時,
/Yc
可讓您先行編譯標頭檔與原始程式碼。 選取
/Yu
以在現有的編譯中使用現有的先行編譯標頭。 您也可以搭配
/Yc
和
/Yu
選項使用
/Fp
,以提供先行編譯標頭的替代名稱。
的編譯器選項參考文章
/Yu
,並
/Yc
討論如何在開發環境中存取此功能。
因為 PCH 檔案包含電腦環境的相關資訊,以及程式的相關記憶體位址資訊,所以您應該只在建立程式的電腦上使用 PCH 檔案。
編譯
/Yu
程式選項可讓您指定要使用的 PCH 檔案。
當您使用 PCH 檔案時,除非另有指定,否則編譯器會假設在您建立 PCH 檔案時生效的相同編譯環境。 編譯環境包含編譯器選項、pragmas 等等。 如果編譯器偵測到不一致,它會發出警告,並盡可能識別不一致。 這類警告不一定表示 PCH 檔案發生問題;它們只會警告您可能發生的衝突。 下列各節將說明 PCH 檔案的一致性需求。
編譯器選項一致性
使用 PCH 檔案時,下列編譯器選項可能會觸發不一致的警告:
必須先使用 [產生流覽資訊]) (選項或 [排除區域變數
/Fr
(
/FR
) ] 選項來建立 PCH 檔案,然後使用 PCH 檔案的後續編譯可以使用這些選項。
C 7.0 相容 (
/Z7
)
如果此選項在建立 PCH 檔案時生效,則稍後使用 PCH 檔案的編譯可以使用偵錯資訊。
如果建立 PCH 檔案時,C 7.0 相容 (
/Z7
) 選項不會生效,則稍後會使用 PCH 檔案編譯並
/Z7
觸發警告。 偵錯資訊會放在目前的
.obj
檔案中,而 PCH 檔案中定義的本機符號則不適用於偵錯工具。
包含路徑一致性
PCH 檔案不包含標頭包含建立時生效之標頭包含路徑的相關資訊。 當您使用 PCH 檔案時,編譯器一律會使用目前編譯中指定的標頭 include 路徑。
來源檔案一致性
當您指定 [使用先行編譯標頭檔 ()
/Yu
] 選項時,編譯器會忽略所有預處理器指示詞, (包括出現在原始程式碼中且將會預先編譯的 pragmas) 。 這類預處理器指示詞指定的編譯必須與用於建立先行編譯標頭檔 ()
/Yc
選項的編譯相同。
Pragma 一致性
在建立 PCH 檔案期間處理的 Pragmas 通常會影響稍後使用 PCH 檔案的檔案。
comment
和
message
pragmas 不會影響編譯的其餘部分。
這些 pragmas 只會影響 PCH 檔案內的程式碼;它們不會影響稍後使用 PCH 檔案的程式碼:
comment
linesize
message
pagesize
subtitle
title
這些 pragmas 會保留為先行編譯標頭的一部分,並影響使用先行編譯標頭之編譯的其餘部分:
alloc_text
auto_inline
check_stack
code_seg
data_seg
function
include_alias
init_seg
inline_depth
inline_recursion
intrinsic
optimize
pointers_to_members
setlocale
vtordisp
warning
/Yc 和 /Yu 的一致性規則
當您使用 使用
/Yc
或
/Yu
建立的先行編譯標頭時,編譯器會將目前的編譯環境與建立 PCH 檔案時存在的編譯環境進行比較。 請務必使用一致的編譯器選項、pragmas 等) ,指定與前一個 (一致的環境。 如果編譯器偵測到不一致,它會發出警告,並盡可能識別不一致。 這類警告不一定表示 PCH 檔案發生問題;它們只會警告您可能發生的衝突。 下列各節說明先行編譯標頭的一致性需求。
編譯器選項一致性
下表列出使用先行編譯標頭時,可能會觸發不一致警告的編譯器選項:
/Fr
或
/FR
產生Microsoft來源瀏覽器資訊
若要讓
/Fr
和
/FR
選項具有 選項有效
/Yu
,它們也必須在建立先行編譯標頭時生效。 使用先行編譯標頭的後續編譯也會產生來源瀏覽器資訊。 瀏覽器資訊會放在單
.sbr
一檔案中,並以與 CodeView 資訊相同的方式由其他檔案參考。 您無法覆寫來源瀏覽器資訊的位置。
/GA
、
/GD
、
/GE
、
/Gw
或
/GW
Windows 通訊協定選項
在建立先行編譯標頭和目前編譯的編譯之間必須相同。 如果這些選項不同,編譯器就會發出警告。
產生完整的偵錯資訊
如果建立先行編譯標頭時,這個選項生效,則使用先行編譯的後續編譯可以使用該偵錯資訊。 如果在
/Zi
建立先行編譯標頭時沒有作用,則後續使用先行編譯的編譯和
/Zi
選項會觸發警告。 偵錯資訊會放在目前的物件檔中,而且偵錯工具無法使用先行編譯標頭中定義的本機符號。
上一節提供先行編譯標頭的概觀:/Yc 和 /Yu、/Fp 選項和
hdrstop
pragma。 本節描述在專案中使用手動先行編譯標頭選項的方法;其結尾為範例 makefile 及其所管理的程式碼。
如需在專案中使用手動先行編譯標頭選項的另一種方法,請研究位於 Visual Studio 預設設定期間所建立之目錄中的其中一個 makefiles
MFC\SRC
。 這些 Makefiles 採用與本節中所呈現的類似方法。 它們使用Microsoft程式維護公用程式 (NMAKE) 宏,並提供更大的建置程式控制權。
建置程式中的 PCH 檔案
軟體專案的程式碼基底通常包含在多個 C 或 C++ 原始程式檔、物件檔、程式庫和標頭檔中。 一般而言,makefile 會將這些專案的組合協調成可執行檔。 下圖顯示使用先行編譯標頭檔之 makefile 的結構。 此圖表中的 NMAKE 宏名稱和檔案名與
PCH 範例 makefile
中找到的範例程式碼一致,以及
PCH 的範例程式碼
。
此圖使用三個圖表裝置來顯示建置程式的流程。 具名矩形代表每個檔案或宏;這三個宏代表一或多個檔案。 陰影區域代表每個編譯或連結動作。 箭號會顯示編譯或連結程式期間合併的檔案和宏。
使用先行編譯標頭檔之 makefile 的結構
從圖表頂端開始,和
BOUNDRY
都是 NMAKE 宏,
STABLEHDRS
您可以在其中列出不需要重新編譯的檔案。 這些檔案是由命令字串編譯
CL /c /W3 /Yc$(BOUNDRY) applib.cpp myapp.cpp
只有在先行編譯標頭檔 ()
STABLE.pch
不存在,或是您對兩個宏中列出的檔案進行變更時。 不論是哪一種情況,先行編譯標頭檔只會包含宏中所列檔案的程式
STABLEHDRS
代碼。 列出您想要先行編譯宏的最後
BOUNDRY
一個檔案。
這些宏中所列的檔案可以是標頭檔或 C 或 C++ 原始程式檔。 (單一 PCH 檔案不能與 C 和 C++ sources.) 您可以使用
hdrstop
宏,在檔案內的
BOUNDRY
某個時間點停止先行編譯。 如需詳細資訊,請參閱
hdrstop
。
下圖的接下來,
APPLIB.obj
代表您最終應用程式中所使用的支援程式碼。 它是從
APPLIB.cpp
建立的、宏中列出的檔案,以及先行編譯標頭檔中
UNSTABLEHDRS
的先行編譯器代碼。
MYAPP.obj
代表您的最終應用程式。 它是從
MYAPP.cpp
建立的、宏中列出的檔案,以及先行編譯標頭檔中
UNSTABLEHDRS
的先行編譯器代碼。
最後,藉由連結宏
APPLIB.obj
(和
MYAPP.obj
) 中列出的
OBJS
檔案,建立可執行檔
MYAPP.EXE
() 。
PCH 的範例 makefile
下列 makefile 使用宏和
!IF
、
!ELSE
、
!ENDIF
控制流程命令結構,以簡化專案的調整。
# Makefile : Illustrates the effective use of precompiled
# headers in a project
# Usage: NMAKE option
# option: DEBUG=[0|1]
# (DEBUG not defined is equivalent to DEBUG=0)
OBJS = myapp.obj applib.obj
# List all stable header files in the STABLEHDRS macro.
STABLEHDRS = stable.h another.h
# List the final header file to be precompiled here:
BOUNDRY = stable.h
# List header files under development here:
UNSTABLEHDRS = unstable.h
# List all compiler options common to both debug and final
# versions of your code here:
CLFLAGS = /c /W3
# List all linker options common to both debug and final
# versions of your code here:
LINKFLAGS = /nologo
!IF "$(DEBUG)" == "1"
CLFLAGS = /D_DEBUG $(CLFLAGS) /Od /Zi
LINKFLAGS = $(LINKFLAGS) /COD
LIBS = slibce
!ELSE
CLFLAGS = $(CLFLAGS) /Oselg /Gs
LINKFLAGS = $(LINKFLAGS)
LIBS = slibce
!ENDIF
myapp.exe: $(OBJS)
link $(LINKFLAGS) @<<
$(OBJS), myapp, NUL, $(LIBS), NUL;
# Compile myapp
myapp.obj : myapp.cpp $(UNSTABLEHDRS) stable.pch
$(CPP) $(CLFLAGS) /Yu$(BOUNDRY) myapp.cpp
# Compile applib
applib.obj : applib.cpp $(UNSTABLEHDRS) stable.pch
$(CPP) $(CLFLAGS) /Yu$(BOUNDRY) applib.cpp
# Compile headers
stable.pch : $(STABLEHDRS)
$(CPP) $(CLFLAGS) /Yc$(BOUNDRY) applib.cpp myapp.cpp
STABLEHDRS
除了建置程式中 PCH 檔案中「使用先行編譯標頭檔之 Makefile 的結構」圖中顯示的 、 BOUNDRY
和 UNSTABLEHDRS
宏之外,這個 Makefile 還提供 CLFLAGS
宏和 LINKFLAGS
宏。 您必須使用這些宏來列出編譯器和連結器選項,這些選項適用于您建置偵錯或最終版本的應用程式可執行檔。 另外還有一個宏, LIBS
您可以在其中列出專案所需的程式庫。
makefile 也會使用 !IF
、 !ELSE
!ENDIF
來偵測您是否在 DEBUG
NMAKE 命令列上定義符號:
NMAKE DEBUG=[1|0]
這項功能可讓您在開發期間使用相同的 makefile,以及程式的最終版本。 DEBUG=0
用於最終版本。 下列命令列是相等的:
NMAKE
NMAKE DEBUG=0
如需 makefiles 的詳細資訊,請參閱 NMAKE 參考。 另請參閱 MSVC 編譯器選項 和 MSVC 連結器選項。
PCH 的範例程式碼
下列原始程式檔用於 PCH 檔案中所述的 makefile 和 PCH 的範例 makefile。 批註包含重要資訊。
原始程式檔 ANOTHER.H
:
// ANOTHER.H : Contains the interface to code that is not
// likely to change.
#ifndef __ANOTHER_H
#define __ANOTHER_H
#include<iostream>
void savemoretime( void );
#endif // __ANOTHER_H
原始程式檔 STABLE.H
:
// STABLE.H : Contains the interface to code that is not likely
// to change. List code that is likely to change
// in the makefile's STABLEHDRS macro.
#ifndef __STABLE_H
#define __STABLE_H
#include<iostream>
void savetime( void );
#endif // __STABLE_H
原始程式檔 UNSTABLE.H
:
// UNSTABLE.H : Contains the interface to code that is
// likely to change. As the code in a header
// file becomes stable, remove the header file
// from the makefile's UNSTABLEHDR macro and list
// it in the STABLEHDRS macro.
#ifndef __UNSTABLE_H
#define __UNSTABLE_H
#include<iostream>
void notstable( void );
#endif // __UNSTABLE_H
原始程式檔 APPLIB.CPP
:
// APPLIB.CPP : This file contains the code that implements
// the interface code declared in the header
// files STABLE.H, ANOTHER.H, and UNSTABLE.H.
#include"another.h"
#include"stable.h"
#include"unstable.h"
using namespace std;
// The following code represents code that is deemed stable and
// not likely to change. The associated interface code is
// precompiled. In this example, the header files STABLE.H and
// ANOTHER.H are precompiled.
void savetime( void )
{ cout << "Why recompile stable code?\n"; }
void savemoretime( void )
{ cout << "Why, indeed?\n\n"; }
// The following code represents code that is still under
// development. The associated header file is not precompiled.
void notstable( void )
{ cout << "Unstable code requires"
<< " frequent recompilation.\n";
原始程式檔 MYAPP.CPP
:
// MYAPP.CPP : Sample application
// All precompiled code other than the file listed
// in the makefile's BOUNDRY macro (stable.h in
// this example) must be included before the file
// listed in the BOUNDRY macro. Unstable code must
// be included after the precompiled code.
#include"another.h"
#include"stable.h"
#include"unstable.h"
int main( void )
savetime();
savemoretime();
notstable();
比較標頭單位、模組和先行編譯標頭
C/C++ 建置參考
MSVC 編譯器選項C++ 中的模組概觀
教學課程:使用模組匯入 C++ 標準程式庫
逐步解說:在 Visual C++ 專案中建置和匯入標頭單位
逐步解說:將 STL 程式庫匯入為標頭單位