Соединение с разделяемой библиотекой C с использованием Perl XS
Я новичок в PERL XS и у меня есть вопрос о вызове разделяемой библиотеки (.so), написанной на языке Ansi C. Кажется, я не могу найти хороших примеров, показывающих, как именно это сделать. Я пошел, хотя учебник, чтобы начать (Hello World и все такое), расположенный здесь:
http://www.lemoda.net/xs/perlxstut/
Я хотел бы изменить его для вызова функции с именем cpro_supported в общей библиотеке C.
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
);
Изменен параметр LIBS с помощью '-L path to .so file', но это, похоже, не помогло.
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 / *. Tt / test....
Не удается загрузить /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. в строке t / test.t 9
Сбой компиляции в require в строке 9 t / test.t.
НАЧАЛО сбой - компиляция прервана в строке t / test.t 9. Похоже, ваш тест умер до того, как он мог что-либо вывести. t / test.... сомнительный Test возвратил статус 255 (wstat 65280, 0xff00) DIED. Неудачные тесты 1-10 Неудачные 10/10 тесты, 0,00% хорошо
Сбой теста Stat Wstat Total Fail Failed Список сбоев
t/test.t 255 65280 10 20 200,00% 1-10 Неудачные тестовые сценарии 1/1, 0,00% в порядке. 10/10 подтестов не удалось, 0,00% все в порядке.
make: * [test_dynamic] Ошибка 2
Любые идеи о том, что здесь не хватает??
Спасибо!!
2 ответа
Вы не сказали ему, чтобы связать с библиотекой, которая содержит cpro_supported
, (A -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.. Еще не уверен, что здесь происходит..
ПОНЯЛ!!
удалил #include из файла.xs и добавил -lncurses в LIBS parm и решил проблему с curses.
LIBS => ['-lm -lncurses'], # e.g., '-lm'
Я принимал совет cjm по завершению простой программы на c для вызова cpro_supported для помощи в сборке параметров для Makefile.PM. Документация по этим пармам минимальна и ужасна, если вы спросите меня:
http://metacpan.org/pod/ExtUtils::MakeMaker
Это медленный, болезненный процесс..Argg!!!
ОБНОВИТЬ.....
Все заработало и теперь можно вызывать cpro_supported(), который находится в библиотеке libpmap.so. ПОБЕДА!!!!
ПОДОЖДИТЕ... Внесены изменения, рекомендованные cjm, и теперь все работает идеально. См. Сообщение cjm.