使用perl XS链接到C共享库

时间:2013-10-24 15:08:09

标签: c linux perl makefile perl-xs

我是PERL XS的新手,对调用用Ansi C编写的共享库(.so)有疑问。我似乎找不到任何好的例子来说明如何做到这一点。我通过教程开始(Hello World和所有这些)位于此处:

http://www.lemoda.net/xs/perlxstut/

我想修改它以在C共享库中调用名为cpro_supported的函数。

libpmap.so:

extern  int cpro_supported(int);

以下是一些基础知识:

Makefile.PL:

use 5.008005;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
    NAME              => 'test',
    VERSION_FROM      => 'lib/test.pm', # finds $VERSION
    PREREQ_PM         => {}, # e.g., Module::Name => 1.1
    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
      (ABSTRACT_FROM  => 'lib/test.pm', # retrieve abstract from module
       AUTHOR         => 'A. U. Thor <johnm@localdomain>') : ()),
    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
);

使用'-L path to .so file'修改了LIBS parm,但这似乎没什么帮助。

test.xs:

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"


MODULE = test       PACKAGE = test      

int
cpro_it(monitor)
    int monitor
CODE:
    RETVAL = cpro_supported(monitor);
OUTPUT:
    RETVAL

void hello()
CODE:
printf("Hello, World!\n");

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

test.t:

# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl test.t'

#########################

# change 'tests => 1' to 'tests => last_test_to_print';

use Test::More tests => 10;
use test;
BEGIN { use_ok('test') };

#########################

# 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 (test::is_even(0), 1);
is (test::is_even(1), 0);
is (test::is_even(2), 1);
my $i;
$i = -1.5; test::round($i); is( $i, -2.0 );
$i = -1.1; test::round($i); is( $i, -1.0 );
$i = 0.0; test::round($i);  is( $i,  0.0 );
$i = 0.5; test::round($i);  is( $i,  1.0 );
$i = 1.2; test::round($i);  is( $i,  1.0 );
my $mon;
$mon = test::cpro_it(23); is($mon,1);

当我运行make test时,我收到以下错误:

PERL_DL_NONLAZY = 1 / usr / bin / perl“-MExtUtils :: Command :: MM”“ - e”“test_harness(0,'blib / lib','blib / arch')”t / *。t 吨/测试....

无法加载'/home/johnm/tmp/test/blib/arch/auto/test/test.so'进行模块测试:/ home / johnm / tmp / test / blib / arch / auto / test / test.so:未定义的符号:cpro_supported在/usr/lib/perl5/5.8.5/i386-linux-thread-multi/DynaLoader.pm第230行。  at t / test.t第9行

在t / test.t第9行的require中编译失败。

BEGIN失败 - 编译在t / test.t第9行中止。 看起来你的测试在输出任何东西之前就已经死了。 吨/测试....可疑         测试返回状态255(wstat 65280,0xff00) 死了。失败测试1-10         10/10测试失败,0.00%没关系

失败的测试统计Wstat总失败失败失败列表

t / test.t 255 65280 10 20 200.00%1-10 1/1测试脚本失败,0.00%没问题。 10/10分测试失败,0.00%没问题。

make: * [test_dynamic]错误2

关于这里缺少什么的任何想法?

THX !!

2 个答案:

答案 0 :(得分:4)

您尚未告知它与包含cpro_supported的库相关联。 (-L选项只是告诉链接器它可以在哪里找到库;它实际上并没有告诉它链接与任何其他库。你需要一个-l选项。)

MYEXTLIB适用于作为模块构建过程一部分构建的C库,而不是系统上安装的库。试试这个:

LIBS => ['-L/home/johnm/lib -lpmap -lmap -llang -ldispatch -led -lm -lncurses'],

答案 1 :(得分:1)

看起来答案是将MYEXTLIB添加到Makefile.PL:

use 5.008005;
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
    NAME              => 'test',
    VERSION_FROM      => 'lib/test.pm', # finds $VERSION
    PREREQ_PM         => {}, # e.g., Module::Name => 1.1
    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
      (ABSTRACT_FROM  => 'lib/test.pm', # retrieve abstract from module
       AUTHOR         => 'A. U. Thor <johnm@localdomain>') : ()),
    LIBS              => ['-lm'], # e.g., '-lm'
    DEFINE            => '', # e.g., '-DHAVE_SOMETHING'
    INC               => '-I.', # e.g., '-I. -I/usr/include/other'
    MYEXTLIB => '/home/johnm/lib/libpmap.so /home/johnm/lib/libmap.so /home/johnm/lib/liblang.so /home/johnm/lib/libdispatch.so /home/johnm/lib/libed.so',
# Un-comment this if you add C files to link with later:
    #OBJECT      => '$(O_FILES)' # link all the C files too
);

我能够通过以下错误解决原始问题:

undefined symbol: cpro_supported

但处理另一个错误:

/usr/include/curses.h:581:41: macro "instr" requires 2 arguments, but only 1 given make: *** [test.o] Error 1

我将以下内容添加到我的.xs文件中以删除以下消息但最终显示上述消息:

#include <curses.h>

Can't load '/home/johnm/tmp/test/blib/arch/auto/test/test.so' for module test: /home/johnm/dev/pmap-28-00/libso/bin/Linux/i686/libed.so: undefined symbol: stdscr at /usr/lib/perl5/5.8.5/i386-linux-thread-multi/DynaLoader.pm line 230.

这似乎引起了perl的麻烦......不确定这里发生了什么......

GOT IT !!

从.xs文件中删除#include并将-lncurses添加到LIBS parm并解决了curses问题..

LIBS              => ['-lm -lncurses'], # e.g., '-lm'

我一直在服用cjm建议完成一个简单的c程序来调用cpro_supported来帮助构建Makefile.PM的参数。如果你问我这些参与者的文件很少而且很可怕:

http://metacpan.org/pod/ExtUtils::MakeMaker

这是一个缓慢而痛苦的过程.Argg !!!

UPDATE .....

完成所有工作,现在可以调用libpmap.so库中的cpro_supported()。 VICTORY !!!!

等待...由cjm推荐的改变,现在一切都很完美。请查看cjm的帖子。