delphilinux:Delphi for Linux中应用共享对象库

本文用通俗易懂语言介绍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应用执行代码增强了软件Software可重用性

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

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

共享对象库创建

1.SO库文件构成

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

library MyFirstSO;
uses
  SysUtils, es ; { 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
    SysUtilsClasses;
    //定义省略
    {$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;
erface
uses
SysUtilsClassesQcontrolsQforms;
type
  TForm1 = (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');//动态装入库
   Handle<>0 then //找到库
  begin
    Compute:=TcomputeInteger(GetProcAddress(Handle'Add');
//搜索库Add并返回指针
     Assigned(Compute) then
       ShowMessage(IntToStr(Compute(10,20));//使用库
    FreeLibrary(Handle);//释放库
  end
  
    ShowMessage('Library not found');
end;



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

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

procedure TForm1.Button1Click(Sender:TObject);
var Handle :Poer ;
   Compute :TcomputeInteger;
begin
  Handle:=dlopen('libMyFirstSO.so');//动态装入库
   Handle<>nil then //找到库
  begin
    Compute:=TcomputeInteger(dlsym(Handle'Add');
//搜索库Add并返回指针
     Assigned(Compute) then
       ShowMessage(IntToStr(Compute(10,20));//使用库
    dlclose(Handle);//释放库
  end
  
    ShowMessage('Library not found');
end;



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

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

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

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

unit ScrollF;
erface
uses
  SysUtils, Classes, QControls, QForms;
type
  TFormScroll = (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; //化颜色
       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图形类或CLXControl控件类对象建议最好使用软件Software包(Package)——种特殊共享库;而若库以非图形类处理为主如数值计算则用SO库更为方便

掌握并能熟练地使用共享对象库技术将有助于开发出功能更强、重用性更好、扩展更为灵活应用本文以例子方式通过SO和DLL比较介绍了共享对象库(SO)功能及使用思路方法希望通过本文读者能使用自己创建SO库来开发基于Linux应用 
Tags:  delphi对象 delphi面向对象 delphiforlinux delphilinux

延伸阅读

最新评论

发表评论