首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 包機制深度解析(一):EXE 編譯、鏈接、加載全流程與靜態/動態鏈接對比

     編輯:Delphi

問題清單

本系列旨在解答:包 vs EXE 結構差異?包 vs DCU 關係?DCP 作用?編譯/鏈接/加載流程?為何包中可用 exports 而幫助未提及?

一、 DPR 結構與編譯器遍歷

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.
  • uses 子句:聲明項目依賴的單元。in 'path' 指定源文件位置(專案私有單元);無路徑者(如 Forms)從搜索路徑查找。
  • 編譯器遍歷:構建單元依賴有向圖,對每個節點按序搜索:當前目錄 → Project Search Path → IDE Library Path。優先找 .pas 編譯生成 .dcu;找不到源則找 .dcu。

二、 鏈接階段:靜態 vs 動態

維度靜態鏈接 (默認,無運行時包)動態鏈接 (勾選 Build with Runtime Packages)
原理將所有 DCU 合併進 EXEEXE 僅保留對包單元的引用,運行時加載 BPL
優點運行快、部署簡單(單文件)、無版本衝突EXE 極小、多程序共享代碼節省內存、便於插件/模塊化
缺點EXE 大、多程序內存重複、升級需重發 EXE部署複雜(需帶 BPL)、版本地獄風險、啟動稍慢
實測體積356 KB (含所有 VCL/RTL 代碼)16 KB (僅含 Form、SysInit、DPR)
運行時模塊僅 EXEEXE + rtl.bpl + vcl.bpl (+ 其他勾選包)

三、 動態鏈接的單元劃分邏輯

「Build with Runtime Packages」列表中的包(如 vcl60, rtl60)決定哪些單元「外移」到 BPL。實測發現:

  • 列表僅含 vcl60 → 依然加載 rtl60 + vcl60(包間存在 requires 依賴)。
  • 列表僅含 rtl60 → 僅加載 rtl60,EXE 體積增大(VCL 單元被靜態鏈接回 EXE)。

推論:鏈接器根據包列表及包間依賴,將屬於這些包的單元從 EXE 排除,生成導入引用。未在列表(及其依賴閉包)中的單元,仍靜態鏈接進 EXE。

四、 加載階段:靜態(自動) vs 動態(手動)

  • 靜態加載:Delphi 生成啟動代碼,在 begin 前自動調用 LoadPackage 加載靜態鏈接列表中的 BPL。可通過 View -> Debug Windows -> Modules 觀察。
  • 動態加載:代碼中顯式調用 LoadPackage('MyPack.bpl'),靈活控制加載時機。

關鍵問題:什麼情況觸發自動加載?什麼情況可避免?下一章通過自建包實驗揭示。

五、 DCP 文件角色

.dcp (Delphi Compiled Package) 是包的符號信息文件,包含:

  • 包導出符號表(類、函數、變量)
  • 依賴包列表
  • 單元接口信息(供其他包/EXE 編譯期引用)

編譯使用包的項目時,鏈接器讀取 .dcp 而非 .dcu 獲取符號信息,.bpl 僅在運行時加載。這就是「編譯期用 DCP,運行期用 BPL」。

總結

Delphi 編譯鏈接加載流程:源碼遍歷 → DCU 生成 → (靜態: DCU合併入EXE | 動態: 符號導入DCP/引用BPL) → 運行時自動/手動加載 BPL。動態鏈接的核心是「集合運算」:EXE 單元集合 = 所有引用單元 - 運行時包單元集合。理解此流程,是掌握包機制、解決部署衝突的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved