分享
 
 
 

Delphi for Linux中应用共享对象库

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

本文用通俗易懂的语言介绍Linux平台上共享对象库(SO)的基本概念及主要优点,通过剖析在Delphi for Linux中应用SO与在Delphi for Windows中应用DLL的异同,以编程实例讲述了Linux平台的SO库文件的组成、SO库文件的函数重载、特殊编译指令、采用Delphi for Linux创建SO的编程规则、使用前的Linux系统设置,以及在Delphi for Linux中用隐式或显式链接方法装入和使用SO函数的基本方法、经验及技巧,并对应用SO可能出现的问题进行了探讨和分析。

共享对象库基本概念

Delphi for Linux是Borland公司推出的基于Linux平台的、面向对象的可视化开发工具,是目前Linux平台上很好的应用开发工具。Delphi for Linux也称Kylix。大家用Kylix开发Linux应用程序时,可能使用过Linux操作系统本身带的大量SO文件。SO是一种特殊的运行文件,包含若干方法、对象和资源,它不能直接运行,但可以被Kylix应用程序或其它可执行文件动态调用。SO文件扩展名为.so,编译前源文件扩展名为.dpr。本文所举例子均在Red Hat Linux 7.3及Kylix 3.0环境下调试编译通过,并可正常运行。

图1是Kylix主程序与SO库的层次关系图。从中可看出使用SO库有以下几个优点。

图1 Kylix主程序与SO库的层次关系图

◆ 多个Kylix程序或它的多个单元文件可通过接口共用一个SO库文件。另一方面,某一个Kylix程序,可通过多个接口使用多个SO库文件。这样,SO变成一种可共用的资源,实现真正的“资源共享”,大大缩小了Kylix应用程序的执行代码,增强了软件的可重用性。

◆ 将SO文件作为Kylix应用程序的公共调用模块设计时,由于其独立于应用程序,软件升级时只需修改SO库文件及编译SO,无需更改及重编译Kylix应用主程序。

◆ 不仅可使用Kylix编写SO库,还可使用C或C++等常用语言来编写,只要遵循特定的接口规范。

共享对象库的创建

1.SO库文件的构成

SO库文件和Kylix标准单元文件的内部结构基本相同,也有声明、实现及初始化部分。区别之一在于SO库只是其它程序可以调用的方法(包括函数及过程)集合。区别之二库程序以library关键字而非project开头启动其项目文件;库程序包含有exports语句,其列出要向外部提供的导出函数及过程。下面是SO库文件代码的简单例子,用以说明其构成。

library MyFirstSO;

uses

SysUtils, classes ; { Delphi for Windows 中引用类库为Windows }

function Add (A:Char;B:Char):Integer;cdecl;overload;

begin

Result := Ord (A) + Ord (B) ;

end;

function Add (A:Integer;B:Integer):Integer;cdecl;overload;

begin

Result := A + B ;

end;

function Double (N:Integer):Integer;cdecl

begin

Result := N * 2;

end;

exports

Add (A:Integer;B:Integer),

Add (A:Char;B:Char) name 'AddChar',

Double;

2.SO库文件中的函数重载

SO库也可以使用重载函数(即多个函数使用相同名称、不同参数),使用时需在重载的函数声明后标上overload指令。Kylix可以用原名称导出一个重载函数,在exports从句中表示其参数表。若要导出多个重载函数,则要在exports从句中用name字句指定不同名称,以区别重载。这可从上面的例子MyFirstSO中看出,Add是重载函数,为调用时区分,一个用原函数声明Add导出,另一个用AddChar导出。

3.SO库的特殊编译指令

编译后生成的SO库运行文件使用lib前缀和.so扩展名。考虑到实际命名规则与版本和支持符号链,Kylix在Object Pascal语言中引入了几个特殊编译指令,这些在Delphi中没有什么意义。库源文件MyFirstSO.dpr编译后产生的执行文件为libMyFirstSO.so。

◆ $SOPREFIX 改变名称前缀,默认为lib(正常库)或bpl(Kylix包)。用前缀区别两种库是因为Linux的库用单一扩展(.so)。

◆ $SOSUFFIX 在库名与扩展名之间增加文本,指定版本或其它信息。

◆ $SOVERSION 在扩展名之后增加版本号。

◆ $SONAME 表示相关符号链名,由编译器自动生成。

例如,下列代码生成库libsimple.so.2.0.1和符号链libsimple.so.2。

library simple ;

uses

SysUtils,Classes;

//函数定义省略

{$SOVERSION '2.0.1'}

{$SONAME 'libsimple.so.2'}

共享对象库的使用

Kylix应用程序使用SO库时,可以采用两种方式:一种是隐式链接(Implicit linking),也称静态装入;另一种是显式链接(Explicit Linking),也称动态装入。下面分别介绍这两种链接方式的使用方法、技巧及将窗体对象放入SO库的技术。

1.使用前的系统设置

自定义SO库建好后,Kylix应用程序调用时会报错,这是因为Kylix找不到新建库,必须对系统进行相关设置。这与在Delphi for Windows中使用DLL库不同,DLL库建好后只需将编译后的DLL文件放到Delphi主程序目录下即可使用。操作步骤如下:

◆ 将编译好的SO库文件放到Linux系统库目录/lib或/usr/lib下,或者在Linux系统库路径shell变量LD_LIBRARY_PATH中加入自定义SO库文件所在路径。

◆ 在根用户(root)下,用ldconfig命令刷新库缓冲区。

◆ 对Kylix执行文件使用ldd命令,查看该程序所关联的SO库。

2.隐式链接

隐式链接是指在应用程序开始执行时就将SO库文件加载到应用程序中。实现隐式链接并不难,只需在应用程序中加入库函数的声明语句及库的external定义从句,则库函数可以和一般局部函数一样使用。比如,要使用libMyFirstSO.so中的Add函数,则只要在应用程序中增加下面语句:

function Add (A:Integer;B:Integer):Integer;cdecl ;

external 'libMyFirstSO.so';

3.显式链接

显式链接是应用程序在执行过程中可根据实际需要随时加载SO库文件,也可以随时卸载SO库文件,还可在运行时进行SO库的切换。而这些是隐式链接无法做到的。与隐式链接相比,显式链接具有更大的灵活性。

在Kylix中,要动态装入库和调用导出函数可以用Delphi仿真代码或自然Linux方法。下面分别介绍这两种方法。

(1)用Delphi仿真代码动态装入

在Windows中动态装入DLL是用Windows API函数—LoadLibrary或Delphi提供的SafeLoadLibrary函数完成的。找到库后,程序调用Windows API函数—GetProcAddress搜索DLL导出函数。若找到匹配,则返回所请求函数指针,并将这个函数指针转换成适当类型和调用。使用完后调用FreeLibrary,从内存中释放库。

Kylix中使用Pascal RTL仿真函数实现SO库动态装入。下面的例子只列出Kylix应用程序中与动态链接相关部分,而非完整Kylix单元文件代码。

unit DynaForm;

interface

uses

SysUtils,Classes,Qcontrols,Qforms;

type

TForm1 = class(TForm)

Button1: TButton;

procedure Button1Click(Sender: TObject);

end;

var Form1:TForm1;

implementation

{$R *.XFM}

type TComputeInteger = function (x:Integer;y:Integer):Integer;cdecl;

//调用库函数接口类型定义

procedure TForm1.Button1Click(Sender:TObject);

var Handle :Thandle ;

Compute :TcomputeInteger;

begin

Handle:=LoadLibrary('libMyFirstSO.so');//动态装入库

if Handle<>0 then //找到库

begin

Compute:=TcomputeInteger(GetProcAddress(Handle,'Add');

//搜索库函数Add,并返回函数指针

if Assigned(Compute) then

ShowMessage(IntToStr(Compute(10,20));//使用库函数

FreeLibrary(Handle);//释放库

end

else

ShowMessage('Library not found');

end;

(2)用Linux自然代码动态装入

也可以使用Libc系统单元中的低级Linux函数,这样可使用更多参数、更好地控制系统。使用的Linux函数分别为dlopen(打开并装入库函数)、dlsym(搜索库函数)、dlclose(释放库)。因此,上例中调用库的代码变为:

procedure TForm1.Button1Click(Sender:TObject);

var Handle :Pointer ;

Compute :TcomputeInteger;

begin

Handle:=dlopen('libMyFirstSO.so');//动态装入库

if Handle<>nil then //找到库

begin

Compute:=TcomputeInteger(dlsym(Handle,'Add');

//搜索库函数Add,并返回函数指针

if Assigned(Compute) then

ShowMessage(IntToStr(Compute(10,20));//使用库函数

dlclose(Handle);//释放库

end

else

ShowMessage('Library not found');

end;

(3)SO库中窗体对象的使用

除了包含函数和过程的库之外,还可以将Kylix建立的窗体放在共享对象中,这可以是对话框或其它窗体。

生成新的库对象之后,只要在库源文件的声明部分增加对窗体单元文件的引用,然后在窗体单元文件中编写生成和使用窗体的导出函数。下面的例子实现Kylix主程序通过调用SO库窗体处理函数,来激活模态对话框以选择颜色,并更新应用主窗体颜色。步骤如下:

◆ 创建具有特定功能的窗体单元文件ScrollF,窗体对象为FormScroll。下面代码仅用于说明,并非完整的程序。

unit ScrollF;

interface

uses

SysUtils, Classes, QControls, QForms;

type

TFormScroll = class(TForm) //对象及方法定义省略

end;

var FormScroll:TformScroll;

◆ 在窗体单元文件ScrollF的实现部分编写使用窗体FormScroll的导出函数GetColor。其功能是激活对话框对象FormScroll以选择颜色,并将颜色值返回。代码如下:

function GetColor (Col: LongInt):LongInt;cdecl;

var

FormScroll:TformScroll;

begin

Result := Col; //函数返回缺省值

try

FormScroll := TFormScroll.Create (Application);

try

FormScroll.SelectedColor := Col; //初始化颜色

if FormScroll.ShowModal = mrOK then //显示对话框

Result := FormScroll.SelectedColor; //返回颜色值

finally

FormScroll.Free;

end;

except

on E: Exception do

MessageDlg ('Error in FormDLL: ' +E.Message, mtError, [mbOK], 0);

end;

end;

◆ 在窗体文件ScrollF的定义部分增加导出函数GetColor的声明。代码如下:

function GetColor (Col:LongInt):LongInt;cdecl;

◆ 在库源文件FormSO.dpr的定义部分增加对窗体单元ScrollF的引用。代码如下:

library FormSO;

uses

ScrollF in 'ScrollF.pas' {FormScroll};

exports

GetColor;

end.

◆ 编译库文件FormSO.dpr,生成SO库执行文件libFormSO.so。

现在,就可以在Kylix应用程序中以隐式或动态方法来调用库libFormSO.so中的窗体类函数GetColor。

应注意的问题

尽管SO库为开发者带来诸多好处,但由于其与一般Kylix程序的差异,如果把它当作后者一样使用可能会带来一些问题。下面列出使用中可能出现的几个问题:

(1)在SO库中大量引用CLX图形类库,将对SO库带来不良影响。

(2)如果编译库和主执行文件而不运行库,则会得到CLX代码和数据的两个拷贝。例如,可能得到两个不同的全局Application对象,库中的Application对象不能正确初始化。

(3)如果库中需要大量调用CLX图形类或CLX控件类对象,建议最好使用软件包(Package)——一种特殊的共享库;而若库以非图形类处理为主,如数值计算,则用SO库更为方便。

掌握并能熟练地使用共享对象库技术,将有助于开发出功能更强、重用性更好、扩展更为灵活的应用程序。本文以实例方式,通过SO与DLL的比较介绍了共享对象库(SO)的功能及使用方法。希望通过本文,读者能使用自己创建的SO库来开发基于Linux的应用程序。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有