利用pre-compiled headers技术以加速编译速度(一)
生活随笔
收集整理的這篇文章主要介紹了
利用pre-compiled headers技术以加速编译速度(一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
<初見pre-compiled headers技術>
????過去我們撰寫C/C++程序時,每個檔案都必須利用編譯器指令 #include 引入許多的系統標頭文件才能夠使程序順利編譯,接著經由連結產生執行檔。假如我們的Project(程序項目)存有兩個檔案a.cpp以及b.cpp,當我們在a.cpp里面用到getch()這個函式,我們就必須在使用a.cpp的開頭處寫著: #include <conio.h>
????否則編譯器一定告訴我們這個函式沒有定義。同樣地,即使b.cpp 這個檔案和a.cpp同屬一個Project之中,檔案里面只要有用到getch()這個函式,一樣得在b.cpp的開頭處寫著: #include <conio.h>
????當編譯器編譯a.cpp的時候,編譯器必須編譯conio.h一次,接著編譯b.cpp的時候,同樣必須重新編譯conio.h一次。因此,一旦a.cpp引入更多和b.cpp相同的標頭檔,也就代表編譯器將浪費許多時間在編譯同樣的標頭檔上。舉例來說,如果我們的Project里面有十個cpp檔同時引入相同的標頭檔,那幺就代表編譯的時間有9/10都因為被用來編譯相同的標頭檔而浪費掉了。因此BCB引進了pre-compiled headers技術,主要就是為了解決這個會使得編譯器做過多重復的編譯工作而導致編譯過程漫長的問題。
????所謂的pre-compiled headers技術,在筆者的記憶中是從BCB 3.0開始引進的概念,其實概念很簡單,就是”預先編譯標頭檔”的意思。以我們拿剛剛提到的例子來說,編譯器第一次編譯a.cpp的時候,就會因為使用pre-compiled headers技術,會先把conio.h的編譯結果先”cache”起來,然后等到待會編譯b.cpp的時候,編譯器會發現conio.h已經先被編譯過了,因此編譯器就直接把剛剛cache起來的conio.h編譯結果直接拿來使用,這樣一來就省掉了了大量的編譯時間,而程序設計師就可以從此向冗長的編譯過程說bye bye。
????在BCB之中,pre-compiled headers技術是透過編譯器指令#pragma hdrstop來達成,從BCB的help里面得知,出現在這個編譯器指令之前的標頭文件即代表告知編譯器要使用pre-compiled headers技術來加速編譯。但是事情并沒有我們想象的那幺單純,所以接下來筆者會花很長的篇幅來探討編譯器指令#pragma hdrstop對編譯效能所帶來的影響。
<pre-compiled headers技術對編譯速度的影響 - 1>
????首先,我們先按照<前置作業>所提到的方式,刪掉所有在編譯過程之中產生的所有檔案(*.exe 、 *.obj 、 *.tds ,請注意 , *.tds必須關掉整個Project之后才能刪除,也請大家先刪除BCB所在目錄的Lib子目錄里面的*.csm以及*.#??,『?』代表是一個0~9的數字)。
????接下來,我們做個簡單的測試,用干凈的程序原始碼(就是尚未編譯過的原始碼)來做編譯速度的測試,以下的數據以筆者的計算機輸出結果為基準,筆者的計算機配備為: Intel PIII 450 、 勝創PC100 128MB RAM 、華碩P2B主機板、操作系統是Windows 2000 Professional:
程序代碼1:
#include <iostream.h>
#include <vcl.h>
#pragma hdrstop
#pragma argsused
int main(int argc, char* argv[])
{
????cout << "Hello World" ;
????return 0;
}
測試結果1:
使用build 使用make
編譯次數 編譯行數 編譯時間 編譯次數 編譯行數 編譯時間
第一次 419266 7.90 第一次 419266 7.73
第二次以后 510638 8.48 第二次以后 0??0.14
程序代碼2:
#pragma hdrstop
#include <iostream.h>
#include <vcl.h>
#pragma argsused
int main(int argc, char* argv[])
{
????cout << "Hello World" ;
????return 0;
}
斜體字部分為與程序代碼1不同之處
測試結果2:
使用build 使用make
編譯次數 編譯行數 編譯時間 編譯次數 編譯行數 編譯時間
第一次 419266 5.60 第一次 419266 5.86
第二次以后 510638 4.42 第二次以后 0 0.15
????提醒讀者一點,空白行也算被編譯器在編譯行數中,所以大家的測試結果在編譯行數上可能會有些微的差距。
從上面的列表可以得到以下結論:
對這兩組測試程序而言,第一次編譯的時候不管用make或是build,其編譯速度幾乎沒差別。但是第二次以后的編譯,使用make的編譯速度壓倒性的快,而且快很多,原因請讀者參照一些介紹make的相關書籍。在這里筆者介紹O’Reilly (臺灣歐來禮) 出版的Managing Project with make,這本書在臺灣歐來禮的網站www.oreilly.com.tw似乎有看到會出現中文本的消息。
?????
把標頭文件放在編譯器指令 #pragma hdrstop之前在第一次編譯所花的時間要比把標頭文件放在編譯器指令 #pragma hdrstop之后要久。咦? 之前不是還提到利用pre-compiled headers技術會加快編譯速度,怎幺經過實驗之后發現竟然編譯速度變慢了呢? 要找尋原因,我們可以使用windows開始菜單里面的 搜尋/檔案或資料夾 功能,搜尋BCB所在目錄,將搜尋日期限定為您計算機上目前的日期,讀者就可以發現,一旦您把標頭文件放在編譯器指令 #pragma hdrstop之前,在BCB所在目錄下的Lib子目錄就會出現vcl50.#00以及vcl50.csm兩個檔案,而且檔案的size還蠻大的,但是如果把標頭文件放在編譯器指令 #pragma hdrstop之后,這兩個檔案并不會出現(如果讀者在測試的時候先測試程序代碼1,再測試程序代碼2,那幺這兩個檔案依舊會出現,因為這兩個檔案并不會因為重新打開Project或是重新開啟BCB而被刪除,因此讀者看到的可能是前次編譯所產生的vcl50.#00以及vcl50.csm)。
????如此一來,我們可以大膽地推測:之所以把標頭文件放在編譯器指令 #pragma hdrstop之前在第一次編譯所花的時間會比較長,是因為編譯器花了額外的功夫去產生這兩個檔案。因為編譯后所顯示的編譯時間并非只有單純的編譯時間,還包括了連結目的檔以產生執行檔所耗費的時間。精確的說,應該是『從開始編譯原始碼到產生最后的執行檔總共所花的時間』,所以前面的測試數據會給大家一種『使用pre-compiled headers技術反而會減慢編譯速度』的假象。
????讀者在前面所看到測試結果1所得的數據,是筆者每次測試過后,除了刪掉編譯時產生的*.obj 、 *.tds 、 *.exe檔之外,還外加刪掉vcl50.#00以及vcl50.csm兩個檔案所測得。如果在測試程序代碼1/使用make的時候,筆者沒有刪除測試程序代碼1/使用build的時候所產生vcl50.#00以及vcl50.csm這兩個檔案,則測試結果1的數據會變成:
測試結果3:
使用build 使用make
編譯次數 編譯行數 編譯時間 編譯次數 編譯行數 編譯時間
第一次 201723 13.57 第一次 17 1.87
第二次以后 201723 13.98 第二次以后 0 0.14
????是什幺原因導致結果有所差異呢? 因為筆者一開始先使用build指令測試編譯效能,然后關掉Project,刪掉編譯過程中產生的.obj 、 .tds 、 .exe檔,然后重新開啟Project,再使用make指令測試編譯效能,此時,由于之前build時所產生的vcl50.#00以及vcl50.csm這兩個檔案依舊留在硬盤中,所以make時編譯器就直接拿來用啦! 也因此我們看到編譯器只編譯了17行就結束。由此我們更可以證明, vcl50.#00以及vcl50.csm這兩個檔案就是我們所謂的cache檔,而它們的作用就是讓編譯器可以減少編譯的標頭文件數目以加速編譯。
????由以上所得到的結論告訴我們,如果接下來我們要做pre-compiled headers技術對編譯效能所產生影響之編譯效能評估,應該在第一次編譯的時候使用build指令,第二次以后都使用make指令,這樣才能精確地測出pre-compiled headers技術對編譯效能所帶來的改善,因為從數據中我們可以看出,build指令會讓編譯器從頭到尾重新編譯一次,所以只看build之后產生的結果是沒有意義的。
????不過,有時候重頭到尾重新編譯整個系統也是在所難免。比方說我們一旦把程序從debug版本變成release版本,或是把程序從release版本變成debug版本,之后的第一次編譯,即使我們使用make來編譯程序,編譯器所花的時間和使用build來編譯的結果是一樣的,都是重頭到尾重新編譯一次。我們還是可以利用pre-compiled headers技術讓這種從頭到尾的編譯可以更快,在本篇文章的后面會提到。
<pre-compiled headers技術對編譯速度的影響 -2>
前一段里面的測試程序只有一個單一的程序原始文件,接著我們來試試如果Project里面有多個程序原始文件的時候會有何種情形。為了避免情況復雜,我們只測試Project里頭有兩個程序原始文件的情況。首先,請使用 File/New新增一個Unit:
????并將檔案存成Unit2.cpp,此時我們Project之中就多出了兩個檔案,分別是Unit2.h以及Unit2.cpp,他們的內容如下:
程序代碼3:
Unit2.h
#ifndef Unit2H
#define Unit2H
void test(void) ;
#endif
Unit2.cpp
#include <vcl.h>
#include <stdio.h>
#pragma hdrstop
#include "Unit2.h"
void test(void)
{
????printf("test") ;
}
測試結果4:
編譯次數 編譯行數 編譯時間
第一次(build) 375564 10.03
第二次(make) 0 0.16
????我們觀察BCB所在目錄之下的Lib目錄,此時會發現之前的測試只有多兩個檔案,而這次的測試竟然又多了一個檔案,他們分別是: vcl50.csm、vcl50.#00、vcl50.#01。
????這樣的測試結果似乎沒有什幺結論,所以我們在第二次編譯之后,第三次編譯之前,把Unit2.cpp的內容修改如下:
程序代碼4:
#include <vcl.h>
#include <stdio.h>
#pragma hdrstop
#include "Unit2.h"
void test(void)
{
????printf("test") ;
????printf("test1") ;
}
則測試結果變成:
測試結果5(接測試結果4):
編譯次數 編譯行數 編譯時間
第三次(make) 30 1.19
????這跟我們預期的結果相同,pre-compiled headers技術完全發揮了縮短編譯時間的功能。
????后來筆者在Project多加了幾個Unit來測試,證明BCB除了會產生vcl50.csm之外,他會為每個Unit都產生一個vcl50.#??的檔案(這里的前提是:每個Unit所引入的標頭檔彼此都不同,如果相同的話,會有另外一種情況發生),如果我們有三個Unit,他就會在第一次build的時候產生vcl50.#00、vcl50.#01、vcl50.#02,然后加上原本一定會產生的vcl50.csm,總共就會有4個cache檔案,因此我們幾乎可以認定『編譯器會為每一個使用編譯器指令#pragma hdrstop的檔案產生一個cache文件,以加速編譯』這個我們所見的事實。也就是說,如果我們把Unit2.cpp里頭的編譯器指令#pragma hdrstop拿掉,那幺每次我們修改Unit2.cpp之后所測得的結果應該是:
測試結果6:
編譯次數 編譯行數 編譯時間
第三次(make) 173843 2.69
????而不是前面測試結果5的測試結果。因為沒有預先編譯好的cache檔,所以Unit2.cpp在修改程序后,必須從頭到尾從新編譯。
????筆者的另外一個測試,是先在Unit2.cpp中使用編譯器指令#pragma hdrstop,然后用make編譯執行檔,讓編譯器幫我們產生Unit2.cpp的cache檔,筆者并沒有刪除任何的vcl50.#??檔案。接著我將Unit2.cpp里頭的編譯器指令#pragma hdrstop拿掉,雖然每次原始碼的更改都會造成編譯行數多達173843上下,可是在make幾次之后,如果筆者重新將編譯器指令#pragma hdrstop放回Unit2.cpp之中原來的位置(也就是在#include <vcl.h>與#include <stdio.h>之下),則每次修改程序之后編譯的結果會比較接近測試結果5。
????在此我們暫且先把編譯器指令#pragma hdrstop之前所有引入的標頭檔檔名所構成的集合稱做『預先編譯標記』,我們大膽假設編譯器會幫我們把這個標記記錄在cache文件里頭,以方便下次編譯器在編譯其它檔案的時候作為辨識用。
????è我們根據上面的假設歸納了一個暫時的結論,就是:編譯器每次在編譯程序原始碼的時候,一般都是重新編譯所有的標頭檔。但是,如果程序原始文件中含有編譯器指令#pragma hdrstop,那幺編譯器就會去尋找Lib目錄底下的vcl50.#??,看看這些檔案是否符合目前的『預先編譯標記』,如果符合,那幺編譯器就直接引用之前編譯后留下的cache,因而省下許多重新編譯標頭檔的時間,如果沒有任何cache文件一個符合標記,那幺編譯器仍然會重頭開始編譯所有的標頭檔,并在編譯后自己產生一個和這個程序原始文件有相同『預先編譯標記』的cache文件,待下次有程序原始文件的預先編譯標記和這個cache文件的預先編譯標記相同時,編譯器就會直接引用這個cache檔。
????過去我們撰寫C/C++程序時,每個檔案都必須利用編譯器指令 #include 引入許多的系統標頭文件才能夠使程序順利編譯,接著經由連結產生執行檔。假如我們的Project(程序項目)存有兩個檔案a.cpp以及b.cpp,當我們在a.cpp里面用到getch()這個函式,我們就必須在使用a.cpp的開頭處寫著: #include <conio.h>
????否則編譯器一定告訴我們這個函式沒有定義。同樣地,即使b.cpp 這個檔案和a.cpp同屬一個Project之中,檔案里面只要有用到getch()這個函式,一樣得在b.cpp的開頭處寫著: #include <conio.h>
????當編譯器編譯a.cpp的時候,編譯器必須編譯conio.h一次,接著編譯b.cpp的時候,同樣必須重新編譯conio.h一次。因此,一旦a.cpp引入更多和b.cpp相同的標頭檔,也就代表編譯器將浪費許多時間在編譯同樣的標頭檔上。舉例來說,如果我們的Project里面有十個cpp檔同時引入相同的標頭檔,那幺就代表編譯的時間有9/10都因為被用來編譯相同的標頭檔而浪費掉了。因此BCB引進了pre-compiled headers技術,主要就是為了解決這個會使得編譯器做過多重復的編譯工作而導致編譯過程漫長的問題。
????所謂的pre-compiled headers技術,在筆者的記憶中是從BCB 3.0開始引進的概念,其實概念很簡單,就是”預先編譯標頭檔”的意思。以我們拿剛剛提到的例子來說,編譯器第一次編譯a.cpp的時候,就會因為使用pre-compiled headers技術,會先把conio.h的編譯結果先”cache”起來,然后等到待會編譯b.cpp的時候,編譯器會發現conio.h已經先被編譯過了,因此編譯器就直接把剛剛cache起來的conio.h編譯結果直接拿來使用,這樣一來就省掉了了大量的編譯時間,而程序設計師就可以從此向冗長的編譯過程說bye bye。
????在BCB之中,pre-compiled headers技術是透過編譯器指令#pragma hdrstop來達成,從BCB的help里面得知,出現在這個編譯器指令之前的標頭文件即代表告知編譯器要使用pre-compiled headers技術來加速編譯。但是事情并沒有我們想象的那幺單純,所以接下來筆者會花很長的篇幅來探討編譯器指令#pragma hdrstop對編譯效能所帶來的影響。
<pre-compiled headers技術對編譯速度的影響 - 1>
????首先,我們先按照<前置作業>所提到的方式,刪掉所有在編譯過程之中產生的所有檔案(*.exe 、 *.obj 、 *.tds ,請注意 , *.tds必須關掉整個Project之后才能刪除,也請大家先刪除BCB所在目錄的Lib子目錄里面的*.csm以及*.#??,『?』代表是一個0~9的數字)。
????接下來,我們做個簡單的測試,用干凈的程序原始碼(就是尚未編譯過的原始碼)來做編譯速度的測試,以下的數據以筆者的計算機輸出結果為基準,筆者的計算機配備為: Intel PIII 450 、 勝創PC100 128MB RAM 、華碩P2B主機板、操作系統是Windows 2000 Professional:
程序代碼1:
#include <iostream.h>
#include <vcl.h>
#pragma hdrstop
#pragma argsused
int main(int argc, char* argv[])
{
????cout << "Hello World" ;
????return 0;
}
測試結果1:
使用build 使用make
編譯次數 編譯行數 編譯時間 編譯次數 編譯行數 編譯時間
第一次 419266 7.90 第一次 419266 7.73
第二次以后 510638 8.48 第二次以后 0??0.14
程序代碼2:
#pragma hdrstop
#include <iostream.h>
#include <vcl.h>
#pragma argsused
int main(int argc, char* argv[])
{
????cout << "Hello World" ;
????return 0;
}
斜體字部分為與程序代碼1不同之處
測試結果2:
使用build 使用make
編譯次數 編譯行數 編譯時間 編譯次數 編譯行數 編譯時間
第一次 419266 5.60 第一次 419266 5.86
第二次以后 510638 4.42 第二次以后 0 0.15
????提醒讀者一點,空白行也算被編譯器在編譯行數中,所以大家的測試結果在編譯行數上可能會有些微的差距。
從上面的列表可以得到以下結論:
對這兩組測試程序而言,第一次編譯的時候不管用make或是build,其編譯速度幾乎沒差別。但是第二次以后的編譯,使用make的編譯速度壓倒性的快,而且快很多,原因請讀者參照一些介紹make的相關書籍。在這里筆者介紹O’Reilly (臺灣歐來禮) 出版的Managing Project with make,這本書在臺灣歐來禮的網站www.oreilly.com.tw似乎有看到會出現中文本的消息。
?????
把標頭文件放在編譯器指令 #pragma hdrstop之前在第一次編譯所花的時間要比把標頭文件放在編譯器指令 #pragma hdrstop之后要久。咦? 之前不是還提到利用pre-compiled headers技術會加快編譯速度,怎幺經過實驗之后發現竟然編譯速度變慢了呢? 要找尋原因,我們可以使用windows開始菜單里面的 搜尋/檔案或資料夾 功能,搜尋BCB所在目錄,將搜尋日期限定為您計算機上目前的日期,讀者就可以發現,一旦您把標頭文件放在編譯器指令 #pragma hdrstop之前,在BCB所在目錄下的Lib子目錄就會出現vcl50.#00以及vcl50.csm兩個檔案,而且檔案的size還蠻大的,但是如果把標頭文件放在編譯器指令 #pragma hdrstop之后,這兩個檔案并不會出現(如果讀者在測試的時候先測試程序代碼1,再測試程序代碼2,那幺這兩個檔案依舊會出現,因為這兩個檔案并不會因為重新打開Project或是重新開啟BCB而被刪除,因此讀者看到的可能是前次編譯所產生的vcl50.#00以及vcl50.csm)。
????如此一來,我們可以大膽地推測:之所以把標頭文件放在編譯器指令 #pragma hdrstop之前在第一次編譯所花的時間會比較長,是因為編譯器花了額外的功夫去產生這兩個檔案。因為編譯后所顯示的編譯時間并非只有單純的編譯時間,還包括了連結目的檔以產生執行檔所耗費的時間。精確的說,應該是『從開始編譯原始碼到產生最后的執行檔總共所花的時間』,所以前面的測試數據會給大家一種『使用pre-compiled headers技術反而會減慢編譯速度』的假象。
????讀者在前面所看到測試結果1所得的數據,是筆者每次測試過后,除了刪掉編譯時產生的*.obj 、 *.tds 、 *.exe檔之外,還外加刪掉vcl50.#00以及vcl50.csm兩個檔案所測得。如果在測試程序代碼1/使用make的時候,筆者沒有刪除測試程序代碼1/使用build的時候所產生vcl50.#00以及vcl50.csm這兩個檔案,則測試結果1的數據會變成:
測試結果3:
使用build 使用make
編譯次數 編譯行數 編譯時間 編譯次數 編譯行數 編譯時間
第一次 201723 13.57 第一次 17 1.87
第二次以后 201723 13.98 第二次以后 0 0.14
????是什幺原因導致結果有所差異呢? 因為筆者一開始先使用build指令測試編譯效能,然后關掉Project,刪掉編譯過程中產生的.obj 、 .tds 、 .exe檔,然后重新開啟Project,再使用make指令測試編譯效能,此時,由于之前build時所產生的vcl50.#00以及vcl50.csm這兩個檔案依舊留在硬盤中,所以make時編譯器就直接拿來用啦! 也因此我們看到編譯器只編譯了17行就結束。由此我們更可以證明, vcl50.#00以及vcl50.csm這兩個檔案就是我們所謂的cache檔,而它們的作用就是讓編譯器可以減少編譯的標頭文件數目以加速編譯。
????由以上所得到的結論告訴我們,如果接下來我們要做pre-compiled headers技術對編譯效能所產生影響之編譯效能評估,應該在第一次編譯的時候使用build指令,第二次以后都使用make指令,這樣才能精確地測出pre-compiled headers技術對編譯效能所帶來的改善,因為從數據中我們可以看出,build指令會讓編譯器從頭到尾重新編譯一次,所以只看build之后產生的結果是沒有意義的。
????不過,有時候重頭到尾重新編譯整個系統也是在所難免。比方說我們一旦把程序從debug版本變成release版本,或是把程序從release版本變成debug版本,之后的第一次編譯,即使我們使用make來編譯程序,編譯器所花的時間和使用build來編譯的結果是一樣的,都是重頭到尾重新編譯一次。我們還是可以利用pre-compiled headers技術讓這種從頭到尾的編譯可以更快,在本篇文章的后面會提到。
<pre-compiled headers技術對編譯速度的影響 -2>
前一段里面的測試程序只有一個單一的程序原始文件,接著我們來試試如果Project里面有多個程序原始文件的時候會有何種情形。為了避免情況復雜,我們只測試Project里頭有兩個程序原始文件的情況。首先,請使用 File/New新增一個Unit:
????并將檔案存成Unit2.cpp,此時我們Project之中就多出了兩個檔案,分別是Unit2.h以及Unit2.cpp,他們的內容如下:
程序代碼3:
Unit2.h
#ifndef Unit2H
#define Unit2H
void test(void) ;
#endif
Unit2.cpp
#include <vcl.h>
#include <stdio.h>
#pragma hdrstop
#include "Unit2.h"
void test(void)
{
????printf("test") ;
}
測試結果4:
編譯次數 編譯行數 編譯時間
第一次(build) 375564 10.03
第二次(make) 0 0.16
????我們觀察BCB所在目錄之下的Lib目錄,此時會發現之前的測試只有多兩個檔案,而這次的測試竟然又多了一個檔案,他們分別是: vcl50.csm、vcl50.#00、vcl50.#01。
????這樣的測試結果似乎沒有什幺結論,所以我們在第二次編譯之后,第三次編譯之前,把Unit2.cpp的內容修改如下:
程序代碼4:
#include <vcl.h>
#include <stdio.h>
#pragma hdrstop
#include "Unit2.h"
void test(void)
{
????printf("test") ;
????printf("test1") ;
}
則測試結果變成:
測試結果5(接測試結果4):
編譯次數 編譯行數 編譯時間
第三次(make) 30 1.19
????這跟我們預期的結果相同,pre-compiled headers技術完全發揮了縮短編譯時間的功能。
????后來筆者在Project多加了幾個Unit來測試,證明BCB除了會產生vcl50.csm之外,他會為每個Unit都產生一個vcl50.#??的檔案(這里的前提是:每個Unit所引入的標頭檔彼此都不同,如果相同的話,會有另外一種情況發生),如果我們有三個Unit,他就會在第一次build的時候產生vcl50.#00、vcl50.#01、vcl50.#02,然后加上原本一定會產生的vcl50.csm,總共就會有4個cache檔案,因此我們幾乎可以認定『編譯器會為每一個使用編譯器指令#pragma hdrstop的檔案產生一個cache文件,以加速編譯』這個我們所見的事實。也就是說,如果我們把Unit2.cpp里頭的編譯器指令#pragma hdrstop拿掉,那幺每次我們修改Unit2.cpp之后所測得的結果應該是:
測試結果6:
編譯次數 編譯行數 編譯時間
第三次(make) 173843 2.69
????而不是前面測試結果5的測試結果。因為沒有預先編譯好的cache檔,所以Unit2.cpp在修改程序后,必須從頭到尾從新編譯。
????筆者的另外一個測試,是先在Unit2.cpp中使用編譯器指令#pragma hdrstop,然后用make編譯執行檔,讓編譯器幫我們產生Unit2.cpp的cache檔,筆者并沒有刪除任何的vcl50.#??檔案。接著我將Unit2.cpp里頭的編譯器指令#pragma hdrstop拿掉,雖然每次原始碼的更改都會造成編譯行數多達173843上下,可是在make幾次之后,如果筆者重新將編譯器指令#pragma hdrstop放回Unit2.cpp之中原來的位置(也就是在#include <vcl.h>與#include <stdio.h>之下),則每次修改程序之后編譯的結果會比較接近測試結果5。
????在此我們暫且先把編譯器指令#pragma hdrstop之前所有引入的標頭檔檔名所構成的集合稱做『預先編譯標記』,我們大膽假設編譯器會幫我們把這個標記記錄在cache文件里頭,以方便下次編譯器在編譯其它檔案的時候作為辨識用。
????è我們根據上面的假設歸納了一個暫時的結論,就是:編譯器每次在編譯程序原始碼的時候,一般都是重新編譯所有的標頭檔。但是,如果程序原始文件中含有編譯器指令#pragma hdrstop,那幺編譯器就會去尋找Lib目錄底下的vcl50.#??,看看這些檔案是否符合目前的『預先編譯標記』,如果符合,那幺編譯器就直接引用之前編譯后留下的cache,因而省下許多重新編譯標頭檔的時間,如果沒有任何cache文件一個符合標記,那幺編譯器仍然會重頭開始編譯所有的標頭檔,并在編譯后自己產生一個和這個程序原始文件有相同『預先編譯標記』的cache文件,待下次有程序原始文件的預先編譯標記和這個cache文件的預先編譯標記相同時,編譯器就會直接引用這個cache檔。
總結
以上是生活随笔為你收集整理的利用pre-compiled headers技术以加速编译速度(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: redis常用命令getex_Redis
- 下一篇: 评论:北京“网店新规”将死在问题中