Calling C function from Perl within embedded C application
Asked Answered
E

1

14

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.

Eidolon answered 29/10, 2010 at 2:31 Comment(1)
The way to do it in Python is to create a FFI function in C and then add it to the dictionary of a virtual module that the Python script imports. Not sure if it's done the same way in Perl though.Monocoque
J
8

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.

Jaeger answered 29/10, 2010 at 2:43 Comment(3)
So does the first section that you pasted go into an .xs file?Eidolon
It's C code, so I'd want to put it in a .c file, but I doubt any proper C compiler cares about the extension of the files you ask it to compile :-)Jaeger
It all makes sense now; I was thinking that the newXS stuff was actually just talking about loading modules. Couldn't find much documentation about perl-xs; most appreciated sir!Eidolon

© 2022 - 2024 — McMap. All rights reserved.