Соединение с разделяемой библиотекой 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.

Другие вопросы по тегам