问题
I am new to PERL XS and have a question about calling a shared library (.so) written in Ansi C. I can't seem to find any good examples showing exactly how to do this. I went though the tutorial to get started (Hello World and all that) located here:
http://www.lemoda.net/xs/perlxstut/
I would like to modify it to call a function named cpro_supported in a C shared libarary.
libpmap.so:
extern int cpro_supported(int);
Here are some basics:
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
);
Modified the LIBS parm with '-L path to .so file' but this didn't seem to help.
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);
When I run make test I receive the following error:
PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/test....
Can't load '/home/johnm/tmp/test/blib/arch/auto/test/test.so' for module test: /home/johnm/tmp/test/blib/arch/auto/test/test.so: undefined symbol: cpro_supported at /usr/lib/perl5/5.8.5/i386-linux-thread-multi/DynaLoader.pm line 230. at t/test.t line 9
Compilation failed in require at t/test.t line 9.
BEGIN failed--compilation aborted at t/test.t line 9. Looks like your test died before it could output anything. t/test....dubious Test returned status 255 (wstat 65280, 0xff00) DIED. FAILED tests 1-10 Failed 10/10 tests, 0.00% okay
Failed Test Stat Wstat Total Fail Failed List of Failed
t/test.t 255 65280 10 20 200.00% 1-10 Failed 1/1 test scripts, 0.00% okay. 10/10 subtests failed, 0.00% okay.
make: * [test_dynamic] Error 2
Any ideas on what is missing here??
Thx!!
回答1:
You haven't told it to link with the library that contains cpro_supported. (A -L option just tells the linker where it can find libraries; it doesn't actually tell it to link with any additional libraries. You need a -l option for that.)
MYEXTLIB is intended for C libraries that are built as part of the module's build process, not libraries installed on the system. Try this instead:
LIBS => ['-L/home/johnm/lib -lpmap -lmap -llang -ldispatch -led -lm -lncurses'],
回答2:
Looks like the answer was to add MYEXTLIB into 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
);
I was able to get past the original problem with the following error:
undefined symbol: cpro_supported
but dealing with another error:
/usr/include/curses.h:581:41: macro "instr" requires 2 arguments, but only 1 given make: *** [test.o] Error 1
I added the following to my .xs file to get rid of the following message but ended up with the message above:
#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.
which seems to be causing troubles with perl..Not sure yet what is going on here..
GOT IT!!
removed #include from .xs file and added -lncurses to LIBS parm and resolved the curses problem..
LIBS => ['-lm -lncurses'], # e.g., '-lm'
I've been taking cjm advise on completing a simple c program to call cpro_supported to help build parameters for Makefile.PM. The documentation for these parms is minimal and horrible if you ask me:
http://metacpan.org/pod/ExtUtils::MakeMaker
This is a slow, painful process..Argg!!!
UPDATE.....
Got it all working and can now call cpro_supported() which is in libpmap.so library. VICTORY!!!!
WAIT...Made changes recommended by cjm and everything works perfect now..See post by cjm.
来源:https://stackoverflow.com/questions/19569719/linking-to-a-c-shared-library-using-perl-xs