[英]linking to a C shared library using 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);
以下是一些基础知识:
生成文件.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参数,但这似乎没有帮助。
测试.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
测试.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/*.tt/test.. ..
无法为模块测试加载“/home/johnm/tmp/test/blib/arch/auto/test/test.so”:/home/johnm/tmp/test/blib/arch/auto/test/test.so :未定义符号:cpro_supported at /usr/lib/perl5/5.8.5/i386-linux-thread-multi/DynaLoader.pm line 230. at t/test.t line 9
在 t/test.t 第 9 行的 require 中编译失败。
BEGIN 失败——编译在 t/test.t 第 9 行中止。看起来你的测试在它可以输出任何东西之前就死了。 t/test....dubious 测试返回状态 255 (wstat 65280, 0xff00) DIED。 FAILED 测试 1-10 失败 10/10 测试,0.00% 正常
t/test.t 255 65280 10 20 200.00% 1-10 1/1 测试脚本失败,0.00% 正常。 10/10 子测试失败,0.00% 没问题。
制作: * [test_dynamic] 错误 2
关于这里缺少什么的任何想法?
谢谢!!
您还没有告诉它与包含cpro_supported
的库链接。 ( -L
选项只是告诉链接器它可以在哪里找到库;它实际上并没有告诉它链接任何其他库。为此您需要一个-l
选项。)
MYEXTLIB
用于作为模块构建过程的一部分构建的 C 库,而不是安装在系统上的库。 试试这个:
LIBS => ['-L/home/johnm/lib -lpmap -lmap -llang -ldispatch -led -lm -lncurses'],
看起来答案是将 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 带来了麻烦..不确定这里发生了什么..
知道了!!
从 .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!!!
更新.....
一切正常,现在可以调用 libpmap.so 库中的 cpro_supported()。 胜利!!!!
等待...进行了 cjm 推荐的更改,现在一切正常。请参阅 cjm 的帖子。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.