Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling C function from Perl within embedded C application

Tags:

c

perl

perl-xs

Ok, this is a very interesting question and there may not be any easy way to do this but figured I would throw this out there before deciding that modifying Perl is my underlying answer.

So I've got a C application that calls Perl scripts in an embedded fashion. This all works fine and dandy and it's pretty awesome that I can pass information in and get information back out. HOWEVER, now onto my next conquest; I need to allow my embedded script(s) to be able to call some functions within the C application that ORIGINALLY CALLED IT.

This is important because XSUB would require it to be an external library; but I don't want it to be an external library I want it to be a direct call to the C function(s). Now maybe this can be done via XSUB and I've just been reading and understanding it wrong.

Application -(run)-> Perl

Application <-(function_x())- Perl

Application -(returnfunction_x)-> Perl

The reason this cannot be an external library is because I am relying on data that is solely created/stored within the application.

like image 876
Suroot Avatar asked Oct 29 '10 02:10

Suroot


1 Answers

XSUBs actually don't require there to be an external library. They merely provide the ability to call to a c function from perl space, and provide some convenience in mapping the calling conventions between C and Perl.

All you need to do is register XSUBs you compiled into the embedding application with the perl interpreter you're embedding.

#include "XSUB.h"

XS(XS_some_func);
XS(XS_some_func)
{
    dXSARGS;
    char *str_from_perl, *str_from_c;

    /* get SV*s from the stack usign ST(x) and friends, do stuff to them */
    str_from_perl = SvPV_nolen(ST(0));

    /* do your c thing calling back to your application, or whatever */
    str_from_c = some_c_func(str_from_perl);

    /* pack up the c retval into an sv again and return it on the stack */
    mXPUSHp(c_str);
    XSRETURN(1);
}

/* register the above XSUB with the perl interpreter after creating it */
newXS("Some::Perl::function", XS_some_func, __FILE__);

When embedding perl, this sort of thing is usually done in the xs_init function you pass to parse_perl.

EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);

static void
xs_init (pTHX)
{
    newXS("Some::Perl::function", XS_some_func, __FILE__);
    /* possibly also boot DynaLoader and friends. perlembed has more
     * details on this, and ExtUtils::Embed helps as well. */
    newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
}

perl_parse(my_perl, xs_init, argc, my_argv, NULL);

After that you'll be able to call to the XSUB as Some::Perl::function from perl space, and that XSUB in turn is free to call back to your application in any way it wants to.

like image 151
rafl Avatar answered Nov 15 '22 11:11

rafl