http://www.perlmonks.org?node_id=356182

monks,

The issues with embedding perl, distibuting perl apps without a perl install, perl runtime environments, perl plugins etc etc are well-covered here at the monastery.

I am not a C programmer and do not enjoy compiling code-bases like Perl, but as a perl coder the idea of embedding is appealing to me. PAR fulfills this to a certain extent, but real easy embedding could do a lot more than just application packaging.

As a proof-of-concept, I took the minimal C i knew and hacked together a surprisingly small .h file that can be used to link up to a precompiled perl library - perl58.dll or libperl.so.
The code in its current state is trivial and limited, but it has been tested on Mandrake 9.1 and Windows and works AOK running a fairly large, pure-perl web-app from the command line.
#include "perlembed.h" int main(int argc, char** argv, char** env) { perlembed_setup("perl58.dll"); perlembed_run(argc, argv, env); perlembed_teardown(); return 0; }
Thats the API as it stands now, effectively miniperlmain.c with cross-platform library loading...

I would appreciate any opinions from the real C coders amongst us on the viability and limits of this approach, and whether this is worth pursuing further. Of course ideas/improvements from anyone are welcome.

edit: removed link to tarball, see below for the basic gist
cheers

Replies are listed 'Best First'.
Re: poor mans embedding
by BUU (Prior) on May 25, 2004 at 22:22 UTC
    Perhaps I'm just stupid and can't see this, but I have a few questions:
    1. What are you trying to accomplish?
    2. Whats the difference between your script and the regular perl.exe that links against the libraries anyways?
    3. Why not use miniperl or par?
      Whats the difference between your script and the regular perl.exe that links against the libraries anyways?

      Nothing as it stands - except that this doesn't rely on the Perl source and is compilable by the C/make-challenged such as myself ;-)
      Given the amount of general interest in distributing standalone perl-apps and responses to tools such as tinyperl (including yours!)...i thought this might be good news for some people - especially seeing as the code is portable to some extent.

      Why not use miniperl or par?

      Like i tried to say above...packaging apps is fine as it is, im not trying to make another perl2exe or PAR.

      I guess what my meditation was; how far could you conceivably get just manually poking at the library without #including perl.h?


      edit: layout and grammer



      time was, I could move my arms like a bird and...
Re: poor mans embedding
by Ctrl-z (Friar) on May 31, 2004 at 11:15 UTC

    ...and whether this is worth pursuing further

    hmm, I'll take that as a resounding "No!". Fair enough.

    For completeness, heres what worked/sucked:

    • on Linux, only the original code worked - all other calls into the API seg faulted. Just dont know enough C/Perl/Linux to continue with this...
    • on Windows, I had reached scalar/array creation and manipulation, call_argv and eval_pv - tested and working. Using only the base SV type and a couple of #defines seemed to provide most of what youd likely need in terms of variable manipulation from C; assuming your not diotalevi ;-)
    • Getting DynaLoader working this way remains a mystery...
    • no stack manipulation...

    Ive included the basic source that compiled on both platforms, as I will be removing the link in the OP. Maybe at least, this will be of some use to windows users that dont have MSVC... you may also be interested in these:

    275516 - BrowserUks results compiling perl with bcc32
    sieperl - binary perl builds with GPL/Artistic licensing.

    #ifndef perlembed_h #define perlembed_h /* ** compilation examples for bcc32 and gcc linux ** bcc32 -DEMBED_WIN32 ** gcc -ldl -lpthread -DEMBED_LINUX ** ** int main(int argc, char** argv, char** env) ** { ** perlembed_setup("/path/to/libperl.so/or/perl58.dll"); ** perlembed_main(argc, argv, env); ** perlembed_teardown(); ** return 0; ** } **/ #ifdef EMBED_WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> #endif #ifdef EMBED_LINUX #include <dlfcn.h> #endif int perlembed_setup(char* DllPath); void perlembed_main(int argc, char** argv, char** env); void perlembed_teardown(); void* perlembed_loadLibrary(char* DllPath); void* perlembed_getProcAddress(char* symbol); void perlembed_freeLibrary(void* perlDll); static struct { void* interpreter ; void* dll ; int loadedOK ; void* (*alloc) (); void (*construct) (void*); void (*parse) (void*, void*, int, char**, char**); void (*destruct) (void*); void (*free) (void*); void (*run) (void*); } perlembed; /* ** dynamically links to the appropriate perl library */ int perlembed_setup( char* DllPath ) { if(perlembed.loadedOK ) return 1; perlembed.dll = perlembed_loadLibrary(DllPath); if(perlembed.dll) { perlembed.alloc = perlembed_getProcAddress("perl_alloc"); perlembed.construct = perlembed_getProcAddress("perl_construct"); perlembed.parse = perlembed_getProcAddress("perl_parse"); perlembed.destruct = perlembed_getProcAddress("perl_destruct"); perlembed.free = perlembed_getProcAddress("perl_free"); perlembed.run = perlembed_getProcAddress("perl_run"); perlembed.interpreter= perlembed.alloc(); perlembed.construct( perlembed.interpreter ); perlembed.loadedOK = 1; return 0; } return 1; } /* ** frees the interpreter */ void perlembed_teardown() { if( !perlembed.loadedOK ) return; perlembed.free(perlembed.interpreter); perlembed.destruct(perlembed.interpreter); perlembed.loadedOK = 0; perlembed_freeLibrary( perlembed.dll ); } /* ** runs as perl with the given commandline */ void perlembed_main(int argc, char** argv, char** env) { if( !perlembed.loadedOK ) return; perlembed.parse(perlembed.interpreter, 0, argc, argv, env); perlembed.run(perlembed.interpreter); } void* perlembed_getProcAddress(char* symbol) { #ifdef EMBED_WIN32 return GetProcAddress( perlembed.dll, symbol ); #endif #ifdef EMBED_LINUX return dlsym(perlembed.dll, symbol); #endif } void* perlembed_loadLibrary(char* DllPath) { #ifdef EMBED_WIN32 return LoadLibrary(DllPath); #endif #ifdef EMBED_LINUX return dlopen(DllPath, RTLD_LAZY|RTLD_GLOBAL); #endif } void perlembed_freeLibrary(void* perlDll) { #ifdef EMBED_WIN32 FreeLibrary( perlDll ); #endif #ifdef EMBED_LINUX dlclose(perlDll); #endif } #endif



    time was, I could move my arms like a bird and...