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


  

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


  
  多个Kylix程序或它的多个单元文件可通过接口共用一个SO库文件。另一方面,某一个Kylix程序,可通过多个接口使用多个SO库文件。这样,SO变 成一种可共用的资源,实现真正的资源共享,大大缩小了Kylix应用程序的执行代码,增强了软件的可重用性。
  
  SO文件作为Kylix应用程序的公共调用模块设计时,由于其独立于应用程序,软件升级时只需修改SO库文件及编译SO,无需更改及重编译Kylix应用主程序。
  
  不仅可使用Kylix编写SO库,还可使用CC++等常用语言来编写,只要遵循特定的接口规范。
  
  共享对象库的创建
  1.SO库文件的构成
  
   SO库文件和Kylix标准单元文件的内部结构基本相同,也有声明、实现及初始化部分。区别之一在于SO库只是其它程序可以调用的方法(包括函数及过 程)集合。区别之二库程序以library关键字而非project开头启动其项目文件;库程序包含有exports语句,其列出要向外部提供的导出函数 及过程。下面是SO库文件代码的简单例子,用以说明其构成。
  
  library MyFirstSO
  uses
   SysUtils, classes { Delphi for Windows 中引用类库为Windows }
  function Add (ACharBChar)Integercdecloverload
  begin
   Result := Ord (A) + Ord (B)
  end
  function Add (AIntegerBInteger)Integercdecloverload
  begin
   Result := A + B
  end
  function Double (NInteger)Integercdecl
  begin
   Result := N * 2
  end;
  exports
   Add (AIntegerBInteger)
   Add (ACharBChar) name 'AddChar'
   Double
  
  2.SO库文件中的函数重载
  
   SO库也可以使用重载函数(即多个函数使用相同名称、不同参数),使用时需在重载的函数声明后标上overload指令。Kylix可以用原名称导出一 个重载函数,在exports从句中表示其参数表。若要导出多个重载函数,则要在exports从句中用name字句指定不同名称,以区别重载。这可从上 面的例子MyFirstSO中看出,Add是重载函数,为调用时区分,一个用原函数声明Add导出,另一个用AddChar导出。
  
  3.SO库的特殊编译指令
  
   编译后生成的SO库运行文件使用lib前缀和.so扩展名。考虑到实际命名规则与版本和支持符号链,KylixObject Pascal语言中引入了几个特殊编译指令,这些在Delphi中没有什么意义。库源文件MyFirstSO.dpr编译后产生的执行文件为 libMyFirstSO.so
  
  ◆ $SOPREFIX 改变名称前缀,默认为lib(正常库)或bplKylix包)。用前缀区别两种库是因为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 (AIntegerBInteger)Integercdecl
  
  external 'libMyFirstSO.so'
  
  3.显式链接

显式链接是应用程序在执行过程中可根据实际需要随时加载SO库文件,也可以随时卸载SO库文件,还可在运行时进行SO库的切换。而这些是隐式链接无法做到的。与隐式链接相比,显式链接具有更大的灵活性。
  
  在Kylix中,要动态装入库和调用导出函数可以用Delphi仿真代码或自然Linux方法。下面分别介绍这两种方法。
  
  (1)Delphi仿真代码动态装入
  
   在Windows中动态装入DLL是用Windows API函数—LoadLibraryDelphi提供的SafeLoadLibrary函数完成的。找到库后,程序调用Windows API函数—GetProcAddress搜索DLL导出函数。若找到匹配,则返回所请求函数指针,并将这个函数指针转换成适当类型和调用。使用完后调用 FreeLibrary,从内存中释放库。
  
  Kylix中使用Pascal RTL仿真函数实现SO库动态装入。下面的例子只列出Kylix应用程序中与动态链接相关部分,而非完整Kylix单元文件代码。
  
  unit DynaForm;
  interface
  uses
  SysUtilsClassesQcontrolsQforms
  type
   TForm1 = class(TForm)
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
  end;
  var Form1TForm1
  implementation
  {$R *.XFM}
  type TComputeInteger = function (xIntegeryInteger)Integercdecl
  //调用库函数接口类型定义
  procedure TForm1.Button1Click(SenderTObject)
  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(SenderTObject)
  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建立的窗体放在共享对象中,这可以是对话框或其它窗体。
  
  生成新的库对象之后,只要在库源文件的声明部分增加对窗体单元文件。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值