设为首页 收藏本站
查看: 726|回复: 0

[经验分享] PERL XS Tutorial

[复制链接]

尚未签到

发表于 2015-12-26 07:44:56 | 显示全部楼层 |阅读模式
XS: eXternal Subroutine, 也叫做xsub. 它是perl代码中调用c或者c++ 子例程的接口。
    在许多情形下,如一些CPU或内存密集型的任务,单纯使用PERL很难满足这些需求,这时,可以使用c或c++语言完成该任务,提供好接口后,通过XS接口可以直接被PERL 代码以module的形式调用。
  环境:
    OS :debian 5 lenny   PERL: This is perl, v5.10.0 built for i486-linux-gnu-thread-multi
  创建一个perl 扩展, 通过命令h2xs
  h2xs –A –n Mytest
    其中:-A 选项是 --omit-autoload , -n 选项用来指定新的module的名称,这里是Mytest。
  生成文件的列表:
  Changes: 记录新建扩展的修订日志。如果你使用版本管理工具,如cvs,svn,可以不关心这个文件。
  MANIFEST:
  Makefile.PL: 通过该文件可以生成Makefile。命令perl Makefile.PL
  use 5.010000;   
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      => 'lib/Mytest.pm', # finds $VERSION     
    PREREQ_PM         => {}, # e.g., Module::Name => 1.1     
    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005     
      (ABSTRACT_FROM  => 'lib/Mytest.pm', # retrieve abstract from module     
       AUTHOR         => 'root ') : ()),     
    LIBS              => ['-lm'], # e.g., '-lm'     
    DEFINE            => '', # e.g., '-DHAVE_SOMETHING'     
    INC               => '-I.', # e.g., '-I. -I/usr/include/other'     
    # Un-comment this if you add C files to link with later:     
    # OBJECT            => '$(O_FILES)', # link all the C files too     
);</ROOT@>
  Mytest.xs
  #include &quot;EXTERN.h&quot;   
#include &quot;perl.h&quot;     
#include &quot;XSUB.h&quot;
  #include &quot;ppport.h&quot;
  MODULE = Mytest         PACKAGE = Mytest
  /**Manually added functions in XS macro language**/
  void   
hello()     
    CODE:     
        printf(&quot;Hello, World!/n&quot;);
  int   
is_even(input)     
        int input     
    CODE:     
        RETVAL = (input % 2 == 0);     
    OUTPUT:     
        RETVAL
  void   
round(arg)     
        double arg     
    CODE:     
        if (arg > 0.0) {     
            arg = floor(arg + 0.5);     
        } else if (arg < 0.0) {     
            arg = ceil(arg - 0.5);     
        } else {     
            arg = 0.0 ;     
        }     
    OUTPUT:     
        arg
  ppport.h
  README
  t/ : 单元测试目录
  lib/: perl 扩展module的目录, PM文件。
  生成Makefile文件:
    perl Makefile.PL
  输出:
  Checking if your kit is complete...   
Looks good     
Writing Makefile for Mytest
  编译
    make
  输出:
  cp lib/Mytest.pm blib/lib/Mytest.pm   
/usr/bin/perl /usr/share/perl/5.10/ExtUtils/xsubpp  -typemap /usr/share/perl/5.10/ExtUtils/typemap  Mytest.xs > Mytest.xsc && mv Mytest.xsc Mytest.c     
Please specify prototyping behavior for Mytest.xs (see perlxs manual)     
cc -c  -I. -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g   -DVERSION=/&quot;0.01/&quot; -DXS_VERSION=/&quot;0.01/&quot; -fPIC &quot;-I/usr/lib/perl/5.10/CORE&quot;   Mytest.c     
Running Mkbootstrap for Mytest ()     
chmod 644 Mytest.bs     
rm -f blib/arch/auto/Mytest/Mytest.so     
cc  -shared -O2 -g -L/usr/local/lib Mytest.o  -o blib/arch/auto/Mytest/Mytest.so        /     
           -lm          /
  chmod 755 blib/arch/auto/Mytest/Mytest.so   
cp Mytest.bs blib/arch/auto/Mytest/Mytest.bs     
chmod 644 blib/arch/auto/Mytest/Mytest.bs     
Manifying blib/man3/Mytest.3pm
  编写Mytest Module 的单元测试文件 t/Mytest.t
    # Before `make install' is performed this script should be runnable with   
# `make test'. After `make install' it should work as `perl Mytest.t'
  #########################
  # change 'tests => 1' to 'tests => last_test_to_print';
  use Test::More tests => 9;   
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.     
is(&Mytest::is_even(0), 1);     
is(&Mytest::is_even(1), 0);     
is(&Mytest::is_even(2), 1);
  $i = -1.5 ; &Mytest::round($i); is($i, -2.0);   
$i = -1.1 ; &Mytest::round($i); is($i, -1.0);     
$i = 0.0 ; &Mytest::round($i); is($i, 0.0);     
$i = 0.5 ; &Mytest::round($i); is($i, 1.0);     
$i = 1.2 ; &Mytest::round($i); is($i, 1.0);
  执行测试:
  make test
  输出:
  PERL_DL_NONLAZY=1 /usr/bin/perl &quot;-MExtUtils::Command::MM&quot; &quot;-e&quot; &quot;test_harness(0, 'blib/lib', 'blib/arch')&quot; t/*.t   
t/Mytest....ok     
All tests successful.     
Files=1, Tests=9,  0 wallclock secs ( 0.02 cusr +  0.01 csys =  0.03 CPU)
  最后:
  make install 来安装perl 扩展
  根据c lib 的header file创建perl module
    新建的module名称为Mytest3 建立目录结构
  mkdir Mytest3
  cd Mytest3
  mkdir testlib
  cd testlib
  Mytest3完成后的目录结构:
  Mytest3   
   ---> testlib
  在testlib 下 创建你的testlib库,这里仅创建一个简单test.c 和它的header test.h, 如下:
  test.c
  #include &quot;test.h&quot;   
#include
  int   
foo(int a, int b)     
{     
    printf(&quot;in foo(int, int)/n&quot;);     
    return a + b;     
}
  test.h
  #ifndef TEST_H   
#define TEST_H
  extern int foo(int , int );   
#endif
  在testlib目录下创建一个Makefile.PL, 如下:
  use ExtUtils::MakeMaker;
  $Verbose = 1;   
WriteMakefile(     
    NAME => 'Mytest3::testlib',     
    SKIP => [qw(all static static_lib dynamic dynamic_lib)],     
    clean => {FILES => 'libtestlib$(LIB_EXT)'},     
);
  sub MY::top_targets {   
'     
all :: static
  pure_all :: static
  static :: libtestlib$(LIB_EXT)
  libtestlib$(LIB_EXT) : $(O_FILES)   
        $(AR) cr libtestlib$(LIB_EXT) $(O_FILES)     
        $(RANLIB) libtestlib$(LIB_EXT)     
';     
}
  perl Makefile.PL; make 生成libtestlib.a archive文件。
  使用h2xs 生成perl module 框架:
  cd到Mytest3的父目录,执行h2xs –O –n Mytest3 Mytest2/testlib/test.h,其中-O选项表示覆盖已经存在的extension 目录
  完成后cd到Mytest3目录, 编辑刚刚自动生成的Makefile.PL :
  use 5.010000;   
use ExtUtils::MakeMaker;     
# See lib/ExtUtils/MakeMaker.pm for details of how to influence     
# the contents of the Makefile that is written.     
WriteMakefile(     
    NAME              => 'Mytest3',     
    VERSION_FROM      => 'lib/Mytest3.pm', # finds $VERSION     
    PREREQ_PM         => {}, # e.g., Module::Name => 1.1     
    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005     
      (ABSTRACT_FROM  => 'lib/Mytest3.pm', # retrieve abstract from module     
       AUTHOR         => 'root ') : ()),     
    LIBS              => [''], # e.g., '-lm'     
    DEFINE            => '', # e.g., '-DHAVE_SOMETHING'     
    INC               => '-I.', # e.g., '-I. -I/usr/include/other'     
        # Un-comment this if you add C files to link with later:     
    # OBJECT            => '$(O_FILES)', # link all the C files too     
MYEXTLIB          => 'testlib/libtestlib$(LIB_EXT)',     
);     
if  (eval {require ExtUtils::Constant; 1}) {     
  # If you edit these definitions to change the constants used by this module,     
  # you will need to use the generated const-c.inc and const-xs.inc     
  # files to replace their &quot;fallback&quot; counterparts before distributing your     
  # changes.     
  my @names = (qw());     
  ExtUtils::Constant::WriteConstants(     
                                     NAME         => 'Mytest3',     
                                     NAMES        => /@names,     
                                     DEFAULT_TYPE => 'IV',     
                                     C_FILE       => 'const-c.inc',     
                                     XS_FILE      => 'const-xs.inc',     
                                  ); </ROOT@>
  }   
else {     
  use File::Copy;     
  use File::Spec;     
  foreach my $file ('const-c.inc', 'const-xs.inc') {     
    my $fallback = File::Spec->catfile('fallback', $file);     
    copy ($fallback, $file) or die &quot;Can't copy $fallback to $file: $!&quot;;     
  }     
}
  sub MY::postamble {   
'     
$(MYEXTLIB) : testlib/Makefile     
        cd testlib && $(MAKE) $(PASSTHRU)     
'     
}
  其中, 增加MYEXTLIB使得h2xs生成的Makefile.PL 可以找到这里的c lib: testlib
  修改生成的Mytest3.xs 文件:
  #include &quot;EXTERN.h&quot;   
#include &quot;perl.h&quot;     
#include &quot;XSUB.h&quot;
  #include &quot;ppport.h&quot;
  #include &quot;testlib/test.h&quot; //using the relative directory
  #include &quot;const-c.inc&quot;
  MODULE = Mytest3                PACKAGE = Mytest3
  INCLUDE: const-xs.inc
  int   
foo(a, b)     
    int a     
    int b     
OUTPUT:     
    RETVAL
  定义PERL的xs接口,使得perl code可以调用testlib的foo函数。
  .xs 代码文件的结构
    如Mytest3.xs所示:
  MODULE = Mytest3                PACKAGE = Mytest3 注意这一行。
  在该行之前的代码片段将被xsubpp保存直接输出到最终的c source code当中。
  在该行之后会被xsubpp根据perl API convention翻译成c souce code。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-156375-1-1.html 上篇帖子: 弥补php上传的缺陷,这么多 perl upload程序,我们选哪个? 下篇帖子: perl文件操作
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表