您的位置:首页 > 编程语言 > Delphi

Delphi中的包(二):关于bpl

2005-09-16 10:06 204 查看
------摘自:http://blog.csdn.net/soobey/archive/2005/08/29/467732.aspx
现在我们不得不写自己的dpk工程,以更改地检测我们的猜想。我们首先建立一个project group,包含三个工程:

program ProjectEXE;
uses
Forms,
Windows,
UnitFormMain in 'UnitFormMain.pas' {FormMain};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TFormMain, FormMain);
Application.Run;
end.
unit UnitFormMain;
interface
uses
Windows, StdCtrls, Forms, Classes, Controls;
type
TFormMain = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormMain: TFormMain;
implementation
{$R *.dfm}
procedure TFormMain.Button1Click(Sender: TObject);
var
LForm:TForm2;
begin
LForm:=TForm2.Create(Application);
LForm.ShowModal;
LForm.Free;
end;
end.

package Package1;
requires
vcl,
rtl;
contains
UnitFormAnother in 'UnitFormAnother.pas' {FormAnother},
UnitForm1 in 'UnitForm1.pas' {Form1};
end.
unit UnitFormAnother;
interface
uses
Forms;
type
TFormAnother = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{$R *.dfm}
end.
unit UnitForm1;
interface
uses
UnitFormAnother;
type
TForm1 = class(TFormAnother)
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{$R *.dfm}
end.

package Package2;
requires
rtl,
vcl;
contains
UnitForm2 in 'UnitForm2.pas' {Form2};
end.
unit UnitForm2;
interface
uses
UnitFormAnother;
type
TForm2 = class(TFormAnother)
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{$R *.dfm}
end.

小技巧:delphi对project group的编译是按照列表顺序从上到下进行的,因此在有些时候,被require或者use的文件如果在下面,那么可能会提示找不到文件。因此最好用文本编辑器调整一下bpg文件中的列表顺序。
现在我们看到,package工程的入口dpr文件结构中没有uses子句,但是取而代之的是contains子句。从字面上说,这好像是指明这个包将会由哪些Unit组成。这些Unit再去use别的unit,这样就又形成了一张有向图。是这样的吗?我们将Package1的contain部分改成
contains
UnitForm1 in 'UnitForm1.pas' {Form1};
这样仅包含UnitForm1。而UnitForm1中因为存在继承关系,必然要use UnitFormAnother。于是自然package1中必须包含三个Unit:Package1.dpk、UnitFormAnother.pas、UnitForm1.pas。然后编译,结果报警说:隐式地引入了UnitFormAnother。先不管这个警告,然后改exe工程:把FormMain的button1Click改成
procedure TFormMain.Button1Click(Sender: TObject);
var
LForm:TForm1;
begin
LForm:=TForm1.Create(Application);
LForm.ShowModal;
LForm.Free;
end;
当然,还要在FormMain的Uses里面加上UnitForm1,然后修改runtime package列表,加上package1。然后编译,调试,检查Module情况。结果发现ProjectExe里面包含FormMain,而Package1.pbl里面包含我们所推测的三个Unit。另一个试验是,如果在编译exe的时候,去掉列表中的package1,并且恰好能让编译器找到FormAnother和Form1(源文件也好,dcu也好),也可以成功编译。但是此时三个Form都跑到exe中间去了。
类似地,验证package2,发现:package2也可以编译过,前提是它能够找到FormAnother,此时package2中包含两个Form;如果把package2的require部分改成只依赖package1,那么最终编译出来的package2中则只含Form2。如果两个package都包含FormAnother,而exe同时使用两个package的话,那么会产生编译错误。(是啊,两个package同时加载一个类,当我要使用的时候,到底是谁提供服务呢?)这种情况很容易发生,因为一方面FormAnother是Form1和Form2的公共基类;另一方面,在Contain子句里面很容易不小心漏掉FormAnother。所以编译器的提示还是很不错的,写程序还是按规矩办事,把contain写完整比较好。
因此,现在基本可以得到结论:
由dpr文件的runtime library(或者dpk文件的requires子句)出发,再继续搜索这些bpl require的bpl,直到获得所需的所有bpl文件。设这些bpl中包含的Unit组成集合A。然后从dpr文件的uses子句(或dpk文件的contains子句)出发,生成工程所需Unit的集合B。则最后编译目标仅包含B-A。其情况如下图



集合B中的Unit,如果存在于集合A中,则在连接时不需要对应的dcu文件,有bpl和bpc就好了。而B-A部分,要么必须有pas文件,要么需要有dcu文件。
现在,编译和连接的问题基本解决了,现在来研究加载。加载有两种,一种是自动的,由delphi控制;一种是手动的,在程序中写LoadPackage。先来搞清楚什么情况下会自动加载library。
测试是这样的,ProjectExe use UnitForm1, Package2 contains UnitForm2 requires package1,package1 contains UnitForm1和UnitFormAnother。在ProjectExe的Package list里面仅有package2。运行结果是:加载的包有rtl、vcl和package1,package2并没有出现。也就是说,自动装入内存的包是那些存在于A集合中,且跟B集合有交集的包。所有想要完全手工加载包,还必须要注意一些问题,起码它不能直接和间接地被require,包中的Unit也不能在Use里面出现。换句话说,调用者完全不知道被调用包的情况下才能避免自动装载。
既然调用者完全不知道被调用的包的信息,凭什么去调用呢?Delphi里面似乎没有头文件之类的东西。怎么获取这个包的接口呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: