Welcome

首页 / 软件开发 / Delphi / Delphi中的包(一):关于exe的编译、连接和执行

Delphi中的包(一):关于exe的编译、连接和执行2010-11-23首先把需要分析的问题列出来:

什么是包?什么是exe?它们在组成上有什么不同?包跟dcu是什么关系?dcp 是干什么的?这些文件在编译时是什么关系?又是怎么装载的?装载了以后怎么 样操作包?dll可以exports,但是为什么delphi帮助中不提包的exports,但是 有些代码却又在包中使用exprots?

首先来看看delphi的编译过程。delphi的工程中有两类:包和程序,前者的 后缀为dpk,后者为dpr。从简单的开始,先来搞dpr。根据delphi的帮助文档, 一个典型的dpr文件的结构如下:

1 program Editor;
2
3 uses
4 Forms, {change to QForms in Linux}
5 REAbout in "REAbout.pas" {AboutBox},
6 REMain in "REMain.pas" {MainForm};
7
8 {$R *.res}
9
10 begin
11 Application.Title := "Text Editor";
12 Application.CreateForm(TMainForm, MainForm);
13 Application.Run;
14 end.

其中10行到14行,begin…end很自然就是程序的执行入口。uses部分指明了 程序需要使用的一些Unit,这个就比较含糊了,为什么有的会用in指明源代码的 位置(这部分是自己向工程中添加的),有的如Forms这个部分,却又不需要? 那每个Unit又会uses其它Unit,这个问题似乎越来越复杂了。先看整个源代码的 结构:

编译器第一步首先遍历这张有向图,对每个Unit,如果有必要就对其进行编 译,生成对应的dcu。而这个“必要”问题,我开始以为是use这个Unit的语句是 带有in的,后来试验发现不对。因为在上面的情况下,Unit3并没有在Unit1的 Uses子句中指明路径,但是仍然正确产生了对应的dcu文件。后来使用filemon来 监视文件打开情况,发现过程是这样的:对于图中的每个节点,编译器按照当前 目录—project属性中的search path—IDE环境中的library path,这样的顺序 ,搜索节点对应的pas文件,没找到就再来一遍,但是这次搜索的是节点对应的 dcu文件。

现在编译搞定了,每个Unit(即pas文件)已经生成了对于的dcu文件,下面 的问题是连接。说到连接,问题就复杂了,连接有两种:静态和动态。静态连接 就是说把这些dcu全部合并到一起。这样,一个Unit对另一个Unit的调用,就成 了程序内部的事情了。这样的好处是快,而且简单,并发共享之类的问题都容易 处理。缺点是目标程序很大,而且如果现在要编写另一个程序,而Unit3可以重 用的话,则在连接时Unit3.dcu被再次拷贝。这样在两个程序同时运行时,内存 中会有两个Unit3的副本,比较浪费。动态连接就是说,两个程序在连接时,仅 仅只保留对Unit3的引用,而并不拷贝Unit3的内容。到运行时,把Unit3装入内 存,让两个程序公用。Dll和BPL都是动态连接的解决方案。问题在于,delphi中 关于连接的选项就只有project|Options|packages菜单中出现,“Build with runtime packages”这句话实在是太模糊了。所以还要再研究一下。