2

I have multiple c functions on this format :

int function(const char* input, size_t len, char result[]) ;

where int is the return type;

result[] contains string which the function fill

what is the best to write such function as XS and expose it on perl to:

  1. get the return value of the function

  2. get the char result[] value on perl

I tried the below but the below only return the return value

int
my_function(a,b,c)
    const char *  a
    long            b
    const char *    c
    CODE:
    RETVAL =function(a,b,c)
    OUTPUT:
    RETVAL

Any help will be appreciated ?

friedo
  • 65,762
  • 16
  • 114
  • 184
smith
  • 3,232
  • 26
  • 55

3 Answers3

4

Create a new directory, and copy the following files into it:

./Example.xs

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"    
#include "const-c.inc"

int my_function(const char* input, size_t len, char result[])
{
    strcpy(result, "the answer");
    return 42;
}

MODULE = Acme::XS::Example        PACKAGE = Acme::XS::Example

INCLUDE: const-xs.inc
PROTOTYPES: DISABLE

void
my_xsub (input, len)
    char *input
    int len
PPCODE:
{
    char result[10];
    int got = my_function(input, len, result);

    /* create a new scalar from an int, and push onto stack */
    PUSHs( newSViv(got) );
    /* create a new scalar from a string, and push onto stack */
    PUSHs( newSVpv(result, 0) );

    XSRETURN(2);  /* two items returned */
}

./lib/Acme/XS/Example.pm

use 5.010001;
use strict;
use warnings;
use XSLoader ();

package Acme::XS::Example;
our $VERSION   = '0.001';
__PACKAGE__->XSLoader::load($VERSION);
1;

./t/basic.t

use strict;
use warnings;
use Test::More;

use_ok('Acme::XS::Example');

my @results = Acme::XS::Example::my_xsub("Hello world", 666);

is_deeply(
    \@results,
    [ 42, "the answer" ],
    "got expected results",
) or diag explain(\@results);

done_testing;

./Makefile.PL

use strict;
use Devel::PPPort;
use ExtUtils::MakeMaker 6.6303;
use ExtUtils::Constant;

Devel::PPPort::WriteFile();

ExtUtils::Constant::WriteConstants(
    NAME         => 'Acme::XS::Example',
    NAMES        => [],
    DEFAULT_TYPE => 'IV',
    C_FILE       => 'const-c.inc',
    XS_FILE      => 'const-xs.inc',
);

WriteMakefile(
    NAME       => 'Acme::XS::Example',
    DISTNAME   => 'Acme-XS-Example',
    VERSION    => '0.001',
    ABSTRACT   => 'an example XS thingy',
    AUTHOR     => ['Toby Inkster <tobyink@cpan.org>'],
    LICENSE    => 'perl_5',
    MIN_PERL_VERSION  => '5.010001',
    PREREQ_PM  => {
        'XSLoader'             => 0,
    },
    TEST_REQUIRES => {
        'Test::More'           => '0.96',
    },
    CONFIGURE_REQUIRES => {
        'Devel::PPPort'        => 0,
        'ExtUtils::Constant'   => 0,
        'ExtUtils::MakeMaker'  => '6.6303',
    },
    LIBS       => [''],
    DEFINE     => '',
    INC        => '-I.',
    test       => { TESTS => "t/*.t" },
    clean      => { FILES => 'const-c.inc const-xs.inc ppport.h' },
);

There's your skeleton to play around with. :-)

To build and test it:

perl Makefile.PL
make
make test
tobyink
  • 13,478
  • 1
  • 23
  • 35
1

The program h2xs can be used to create a perl/XS module which acts as a wrapper around your C code. I think that you'll want to create a header file that has your function prototypes.

Read the man pages for h2xs for details. Also, take a look here

Barton Chittenden
  • 4,238
  • 2
  • 27
  • 46
0

A perl function (also XS function) can return more then one value.
You will need to use PPCODE instead of CODE, and push multiple variables into the stack as results. see the perlxs docs for PPCODE for example.

Shmuel Fomberg
  • 546
  • 2
  • 11