本系列旨在解答:包 vs EXE 結構差異?包 vs DCU 關係?DCP 作用?編譯/鏈接/加載流程?為何包中可用 exports 而幫助未提及?
program Editor;
uses Forms, REAbout in 'REAbout.pas' {AboutBox}, REMain in 'REMain.pas' {MainForm};
{$R *.res}
begin Application.Title := 'Text Editor'; Application.CreateForm(TMainForm, MainForm); Application.Run; end.
in 'path' 指定源文件位置(專案私有單元);無路徑者(如 Forms)從搜索路徑查找。.pas 編譯生成 .dcu;找不到源則找 .dcu。| 維度 | 靜態鏈接 (默認,無運行時包) | 動態鏈接 (勾選 Build with Runtime Packages) |
|---|---|---|
| 原理 | 將所有 DCU 合併進 EXE | EXE 僅保留對包單元的引用,運行時加載 BPL |
| 優點 | 運行快、部署簡單(單文件)、無版本衝突 | EXE 極小、多程序共享代碼節省內存、便於插件/模塊化 |
| 缺點 | EXE 大、多程序內存重複、升級需重發 EXE | 部署複雜(需帶 BPL)、版本地獄風險、啟動稍慢 |
| 實測體積 | 356 KB (含所有 VCL/RTL 代碼) | 16 KB (僅含 Form、SysInit、DPR) |
| 運行時模塊 | 僅 EXE | EXE + rtl.bpl + vcl.bpl (+ 其他勾選包) |
「Build with Runtime Packages」列表中的包(如 vcl60, rtl60)決定哪些單元「外移」到 BPL。實測發現:
vcl60 → 依然加載 rtl60 + vcl60(包間存在 requires 依賴)。rtl60 → 僅加載 rtl60,EXE 體積增大(VCL 單元被靜態鏈接回 EXE)。推論:鏈接器根據包列表及包間依賴,將屬於這些包的單元從 EXE 排除,生成導入引用。未在列表(及其依賴閉包)中的單元,仍靜態鏈接進 EXE。
begin 前自動調用 LoadPackage 加載靜態鏈接列表中的 BPL。可通過 View -> Debug Windows -> Modules 觀察。LoadPackage('MyPack.bpl'),靈活控制加載時機。關鍵問題:什麼情況觸發自動加載?什麼情況可避免?下一章通過自建包實驗揭示。
.dcp (Delphi Compiled Package) 是包的符號信息文件,包含:
編譯使用包的項目時,鏈接器讀取 .dcp 而非 .dcu 獲取符號信息,.bpl 僅在運行時加載。這就是「編譯期用 DCP,運行期用 BPL」。
Delphi 編譯鏈接加載流程:源碼遍歷 → DCU 生成 → (靜態: DCU合併入EXE | 動態: 符號導入DCP/引用BPL) → 運行時自動/手動加載 BPL。動態鏈接的核心是「集合運算」:EXE 單元集合 = 所有引用單元 - 運行時包單元集合。理解此流程,是掌握包機制、解決部署衝突的基石。