Perl 对 C 的扩展接口(2)

来源:developerWorks 中国 作者:唐 明
  


编译 XS 文件

编译命令 h2xs

使用 h2xs 来编译并生成 XS 扩展接口所必要的系列文件。h2xs 用于根据 C 头文件 .h 生成相应的 Perl扩展,其扩展模块名字由 -n 参数指定,当没有 -n 参数时,则自动使用第一个 .h 头文件的名字,并将其首字母大写作为扩展模块的名字。


表 1. h2xs 常用参数
参数名 说明
-A --omit-autoload 忽略 autoload 机制
-O --overwrite-ok 允许覆盖已存在的扩展文件
-n --name=module_name 指定扩展模块的名字

更为详细和完整的参数列表可参阅相关文档 perldoc-h2xs。

生成的文件

当执行命令 “h2xs -A -n Mytest” 后,系统在当前目录下创建一个子目录 Mytest,并在其下生成一系列文件:MANIFEST,Makefile.PL,Mytest.pm,Mytest.xs,Mytest.t 和 Changes。

  1. MANIFEST

    MANIFEST 文件包含了在 Mytest 目录下创建的所有文件的名字。



    清单 11 .MANIFEST 文件内容
    				  
     Changes 
     Makefile.PL 
     MANIFEST 
     Mytest.xs 
     ppport.h 
     README 
     Mytest.t 
     lib/Mytest.pm 
     mylib/Makefile.PL 
     mylib/test.c 
     mylib/test.h 
    

  2. Changes

    Changes 文件记录了扩展接口的创建以及后续的修改动作。



    清单 12.Changes 文件内容
    				  
     Revision history for Perl extension Mytest. 
    
     0.01  Tue Jun  2 15:23:11 2009 
     - original version; created by h2xs 1.23 with options 
    	 -A -O -n Mytest ./Mytest/mylib/test.h 
    

  3. Makefile.PL

    Makefile.PL 文件是一个 Perl 脚本,用于自动生成 Makefile,以创建扩展接口。当执行 “Perl Makefile.PL” 命令后,系统生成相应的 Makfile,然后执行 “make” 会在当前目录下生成 blib 子目录,用于存放将要使用到的共享库文件 (shared library)。



    清单 13 . 一个简单的 Makefile.PL
    				  
    use ExtUtils::MakeMaker; 
     # See lib/ExtUtils/MakeMaker.pm for details of how to influence 
     # the contents of the Makefile that is written. 
     WriteMakefile( 
    	 NAME         => 'Mytest', 
    	 VERSION_FROM => 'Mytest.pm', # finds $VERSION 
    	 LIBS         => [''],   # e.g., '-lm'
    	 DEFINE       => '',     # e.g., '-DHAVE_SOMETHING'
    	 INC          => '',     # e.g., '-I/usr/include/other'
     ); 
    

  4. Mytest.pm

    Mytest.pm 文件是一个模块文件,定义了 Perl 如何加载该扩展接口。当在 Perl 代码中出现 “use Mytest;” 时,Perl 会在 @INC 数组中定义的目录列表里搜索 Mytest.pm 并加载。然后 Perl 代码就可以直接调用 Mytest.xs 扩展中定义的 C 函数。



    清单 14 .Mytest.pm 框架
    				  
     package Mytest; 
    
     use 5.008008; 
    
     use strict; 
     use warnings; 
    
     require Exporter; 
     our @ISA = qw(Exporter); 
     our %EXPORT_TAGS = ( 'all' => [ qw( 
     )]); 
    
     our $VERSION = '0.01'; 
     require XSLoader; 
     XSLoader::load('Mytest', $VERSION); 
    
     # Preloaded methods go here. 
     1; 	
     __END__ 
     # Below is the stub of documentation for your module. You better edit it! 
    

  5. Mytest.xs

    Mytest.xs 实现了 Perl 扩展接口,通过该接口 Perl 代码可以调用对应 C 文件中定义实现的函数。

  6. Mytest.t

    Mytest.t 文件是代码测试脚本,可以通过执行 “make test” 来测试扩展模块的编译是否正确。



    清单 15 .Mytest.t 框架
    				  
    use Test::More tests => 4; 
     BEGIN { use_ok('Mytest') }; 
    
     # Insert your test code below, the Test::More module is use()ed here so read 
     # its man page ( perldoc Test::More ) for help writing this test script. 
    

编译过程

通常一个 XS 扩展接口的编译过程为以下几步:


清单 16 . 编译步骤
				  
 perl Makefile.PL     
 make                   
 make test 
 make install 

首先运行 ”perl Makefile.PL” 在当前目录生成 Makefile;然后运行 ”make” 编译并创建所需的库文件;之后用 ”make test” 测试编译结果是否正确;最后运行 ”make install” 将库文件安装到系统目录,至此整个编译过程结束。





一个 XS 实例

  1. 在当前目录创建一个子目录 Mytest,在 Mytest 目录下创建子目录 mylib,并将已写好的 C 头文件和源代码放在 mylib 目录下。

    清单 17 . 头文件 test.h
    				  
     #define TESTVAL 	 3 
     extern double 	 add(int, long); 
     extern int    max(int, int); 
    



    清单 18 . 源文件 test1.c
    				  
     #include "./test.h"
     double add(int a, long b) 
     { 
     return (a + b + TESTVAL); 
     } 
    



    清单 19 . 源文件 test2.c
    				  
     #include "./test.h"
     int max(int a, int b) 
     { 
     return ((a>b)? a:b); 
     } 
    

  2. 在 Mytest/mylib 目录下创建 Makefile.PL 文件,以保证在 Mytest 目录运行 ”make” 时会自动调用该 Makefile.PL 并生成相应的 Makefile。

    清单 20 .Mytest/mylib 目录下的 Makefile.PL
    				  
    use ExtUtils::MakeMaker; 
     $Verbose = 1; 
     WriteMakefile( 
     NAME   => 'Mytest::mylib', 
     SKIP   => [qw(all static static_lib dynamic dynamic_lib)], 
     clean  => {'FILES' => 'libmylib$(LIB_EXT)'}, 
     ); 
    
     sub MY::top_targets { 
    '
     all :: static 
     pure_all :: static 
     static ::  libmylib$(LIB_EXT) 
     libmylib$(LIB_EXT): $(O_FILES) 
     $(AR) cr libmylib$(LIB_EXT) $(O_FILES) 
     $(RANLIB) libmylib$(LIB_EXT) 
    '; 
     } 
    

    在 MY::top_targets 中,通过 ar 将 mylib 子目录下的 test1.o 和 test2.o 编译为静态库 libmylib.a,并通过 ranlib 更新静态库 libmylib.a 的符号索引表。

    注意: $(AR) 和 $(RANLIB) 前面应该是 ‘ Tab ’ 而不是空格,否则 Make 会报 “missing separator” 错误并终止编译。


    时间:2009-08-07 09:15 来源:developerWorks 中国 作者:唐 明 原文链接

好文,顶一下
(2)
100%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量