ActivePerl FAQ



NAME

perlwin32faq10 - Embedding and Extending


DESCRIPTION

Techniques for Embedding and Extending ActivePerl


How do I write an extension for ActivePerl?

Writing extensions in C or C++ for ActivePerl is identical to writing them for standard Perl. Consult the perlxstut document for complete information and pointers to other sources of information.

As a result of the oneperl effort, you now longer need to build ActivePerl from the source distribution to write or compile extensions. The Perl installation will detect your C compiler (currently, just Visual C++), and configure Perl to use it for compiling extensions.

Note that writing extensions in C or C++ is not easy. You need to have experience writing C programs for Windows platforms before you should even think about writing an extension.


How do I embed the Perl interpreter into my C/C++ program?

As of build 500, this is quite easy. ActivePerl exposes Perl's internals through a C++ object called PERL_OBJECT. Among other things, PERL_OBJECT simplifies the creation of multiple Perl interpreters within a single process.

To embed ActivePerl in your own application, you must have the following:

Before you can compile an application that embeds ActivePerl, you must compile Perl from source. This does not mean that you must install Perl from source - the reason that you must compile Perl from source is that the compilation process creates the DynaLoader.c source code file, which is required if you want to use any extensions in your application.

To compile Perl from source:

  1. Change directory to the win32 directory of your Perl source distribution and edit Makefile as necessary.

  2. Type nmake. This will compile all of Perl.

  3. Type nmake test. This ensures that Perl built correctly and passes all its tests.

  4. Perl is now compiled, and the DynaLoader.c file is created. If you did not install a binary release of Perl, you can issue the command make install, which will install Perl for you. This step is not necessary if you installed a binary release of Perl.

Once you have compiled Perl from source, you have a source tree that can be used to build an embedded version of Perl. Here is a simple program that includes an embedded Perl interpreter. It is actually quite a bit like perl.exe. You can use all the command-line switches that are supported by perl, and you can also include the name of a script to execute. If you supply no switches, it will read in a Perl program from standard input, and executes the program when end-of-file is encountered. Save this file as MyPerl.cpp on your computer (remember to outdent the source code):

    /*
        
        1) include perlhost.h. This header defines all the
           OS Interfaces that are used by the PERL_OBJECT.
        2) define the host data structure 'CPerlHost'
        3) call the CPerlHost member function PerlCreate,
           which calls perl_alloc and perl_construct
        4) call the CPerlHost member function PerlParse
        5) call the CPerlHost member function PerlRun
        6) when done, call the CPerlHost member function PerlDestroy,
           which calls perl_destruct and perl_free
        
        Including XSUB.h brings in the files that have macros to redefine
        the perl_* functions, to work with PERL_OBJECT. Note that these 
        macros may cause problems when there are name collisions. A common 
        problem is having a local variable that has the same name as a Perl 
        function. To track down these name collisions compile using '/P' 
        option with VC++ so that you can see what the preprocessor has done.
        
    */ 
    #include <EXTERN.h>
    #include <perl.h>
    #define NO_XSLOCKS
    
    // Bring in the macros that redefine perl_* functions to work with
    // PERL_OBJECT.
    //
    #include <XSUB.h>
    
    /* for Win32 */
    #include "win32iop.h"
    #include <fcntl.h>
    #include <perlhost.h>
    #include <stdio.h>
    
    // DynaLoader stuff.
    //
    char *staticlinkmodules[] = {
        "DynaLoader",
        NULL,
    };
    
    // More DynaLoader stuff.
    //
    EXTERN_C void boot_DynaLoader _((CV* cv _CPERLarg));
    
    static void
    xs_init(CPERLarg)
    {
        char *file = __FILE__;
        dXSUB_SYS;
        newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
    }
    
    CPerlObj *pPerl;  // The Perl object used by the host.
    
    int main (int argc, char **argv, char **env)
    {
        CPerlHost host;     // The Perl host
        host.PerlCreate();  // Create an instance of the Perl Interpreter
    
        printf("Welcome to my very own Perl!\n\n");
    
        // Read arguments from the command line.  If no script is named on the
        // command-line, and nothing is specified for -e, the interpreter will
        // read commands from standard input (just like Perl!).
        //
        host.PerlParse(xs_init, argc, argv, NULL);
    
        host.PerlRun();      // Run the interpreter.
        host.PerlDestroy();  // Destroy the interpreter.
        return 0;
    }

To compile this program, you must use the following Makefile. Be sure to update LIBDIR to point to the CORE subdirectory of your Perl binary installation, and update SRCDIR to point to the src directory of the Perl source code that you compiled earlier. Save this file as Makefile (remember to outdent the contents):

    LIBDIR = C:\Perl\5.00500\lib\MSWin32-x86\CORE
    SRCDIR = C:\5.00500\src
    
    LIBS = oldnames.lib kernel32.lib user32.lib winspool.lib advapi32.lib \
           shell32.lib ole32.lib  oleaut32.lib netapi32.lib uuid.lib \
           wsock32.lib version.lib PerlCRT.lib $(LIBDIR)\PerlCore.lib
    CCFLAGS = -c -I$(LIBDIR) -Gf -W3 -DWIN32 -D_CONSOLE -DPERL_CORE \
              -O2 -MD -DNDEBUG -TP -GX -DPERL_OBJECT -UPERLDLL
    CCDYNA = $(CCFLAGS) -I$(SRCDIR)\ext\DynaLoader
    
    all:
        cl.exe $(CCFLAGS) -Fo.\MyPerl.obj MyPerl.cpp
        cl.exe $(CCFLAGS) -Fo.\win32.obj $(SRCDIR)\win32\win32.c
        cl.exe $(CCFLAGS) -Fo.\win32sck.obj $(SRCDIR)\win32\win32sck.c
        cl.exe $(CCFLAGS) -Fo.\DynaLoader.obj \
                          $(SRCDIR)\ext\DynaLoader\DynaLoader.c
        link.exe -nologo -nodefaultlib -release -machine:x86 $(LIBS) \
            -subsystem:console MyPerl.obj win32.obj win32sck.obj \
            DynaLoader.obj setargv.obj

Make sure that PerlCRT.lib has been installed properly. For more information, see How do I write an extension for ActivePerl?.

You can then compile MyPerl.cpp by typing nmake at the command line (make sure that both MyPerl.cpp and Makefile are in your current working directory). This will produce the file MyPerl.exe, which you can run at the command line as though it were perl.exe:

    C:\MyPerl>myperl -e "print qq[Hello, World\n];"
    Welcome to my very own Perl!
    
    Hello, World

or:

    C:\MyPerl>myperl
    Welcome to my very own Perl!
    
    print "Hello, world\n";
    ^Z
    Hello, world

If you want to use modules and extensions from your local Perl installation, you'll need to do one of two things. The simplest thing you can do is copy your executable to the same location as perl.exe.

If this is not an option, you need to tell your program where to find things. This can be accomplished by setting the PERL5LIB environment variable with something like:

    set PERL5LIB=C:\Perl\5.00500\lib;C:\Perl\site\5.00500\lib;C:\Perl\site\lib 

Then you can use modules and extensions from your local Perl installation:

    C:\MyPerl>MyPerl -MWin32::OLE -e "print $Win32::OLE::VERSION;"
    Welcome to my very own Perl!
    
    0.0807

The following example is based on the PerlPower example from Doug MacEachern and Jon Orwant's perlembed document (this is part of Perl, and you should have a copy included with ActivePerl). You should save the following program as PerlPower.cpp:

    /*
        To show how to embed Perl with PERL_OBJECT defined, we will show the
        changes needed for the PerlPower sample that is in perlembed.pod.
        
        1) include perlhost.h. This header defines all the
           OS Interfaces that are used by the PERL_OBJECT.
        2) define the host data structure 'CPerlHost'
        3) call the CPerlHost member function PerlCreate,
           which calls perl_alloc and perl_construct
        4) call the CPerlHost member function PerlParse
        5) call the CPerlHost member function PerlRun
        6) call any of the perl_call_* functions
        7) when done, call the CPerlHost member function PerlDestroy,
           which calls perl_destruct and perl_free
        
        Including XSUB.h brings in the files that have macros to redefine the
        perl_* functions, to work with PERL_OBJECT. Note that these macros may
        cause problems when there are name collisions. A common problem is
        having a local variable that has the same name as a Perl function. To
        track down these name collisions compile using '/P' option with VC++ so
        that you can see what the preprocessor has done.
        
    */
    
    #include <EXTERN.h>
    #include <perl.h>
    
    #define NO_XSLOCKS
    
    // Bring in the macros that redefine perl_* functions to work with
    // PERL_OBJECT.
    //
    #include <XSUB.h>
    
    /* for Win32 */
    #include "win32iop.h"
    #include <fcntl.h>
    #include <perlhost.h>
    
    // DynaLoader stuff.
    //
    char *staticlinkmodules[] = {
        "DynaLoader",
        NULL,
    };
    
    // More DynaLoader stuff.
    //
    EXTERN_C void boot_DynaLoader _((CV* cv _CPERLarg));
    static void
    xs_init(CPERLarg)
    {
        char *file = __FILE__;
        dXSUB_SYS;
        newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
    }
    
    CPerlObj *pPerl;
    
    static void
    PerlPower(int a, int b)
    {
        dSP;                            /* initialize stack pointer      */
        ENTER;                          /* everything created after here */
        SAVETMPS;                       /* ...is a temporary variable.   */
        PUSHMARK(SP);                   /* remember the stack pointer    */
        XPUSHs(sv_2mortal(newSViv(a))); /* push the base onto the stack  */
        XPUSHs(sv_2mortal(newSViv(b))); /* push the exponent onto stack  */
        PUTBACK;                        /* make local stack pointer global */
        perl_call_pv("expo", G_SCALAR); /* call the function             */
        SPAGAIN;                        /* refresh stack pointer         */
                                        /* pop the return value from stack */
    
        printf ("%d to the %dth power is %d.\n", a, b, POPi);
        PUTBACK;
        FREETMPS;                       /* free that return value        */
        LEAVE;                          /* ...and the XPUSHed "mortal" args.*/
    }
    
    int main (int argc, char **argv, char **env)
    {
        CPerlHost host;
    
        host.PerlCreate();
    
        // Don't use argv or argc for embedding.  Instead, we'll pretend that
        // we gave it the arguments "-e 0".
        //
        char *embedding[] = { "", "-e", "0" };
        host.PerlParse(xs_init, 3, embedding, NULL);
    
        // Define the expo() function.
        //
        perl_eval_pv("sub expo { my($a, $b) = @_; return $a ** $b; }", TRUE);
    
        host.PerlRun();
    
        PerlPower(3, 4);                      /*** Compute 3 ** 4 ***/
    
        host.PerlDestroy();
        return 0;
    }

The following Makefile can be used to compile PerlPower.cpp:

    LIBDIR = C:\Perl\5.00468\lib\MSWin32-x86\CORE
    SRCDIR = C:\betab9\src
    
    LIBS = oldnames.lib kernel32.lib user32.lib winspool.lib advapi32.lib \
           shell32.lib ole32.lib  oleaut32.lib netapi32.lib uuid.lib \
           wsock32.lib version.lib PerlCRT.lib $(LIBDIR)\PerlCore.lib
    
    CCFLAGS = -c -I$(LIBDIR) -Gf -W3 -DWIN32 -D_CONSOLE -DPERL_CORE \
              -O2 -MD -DNDEBUG -TP -GX -DPERL_OBJECT -UPERLDLL
    CCDYNA = $(CCFLAGS) -I$(SRCDIR)\ext\DynaLoader
    
    all:
        cl.exe $(CCFLAGS) -Fo.\PerlPower.obj PerlPower.cpp
        cl.exe $(CCFLAGS) -Fo.\win32.obj $(SRCDIR)\win32\win32.c
        cl.exe $(CCFLAGS) -Fo.\win32sck.obj $(SRCDIR)\win32\win32sck.c
        cl.exe $(CCFLAGS) -Fo.\DynaLoader.obj \
                          $(SRCDIR)\ext\DynaLoader\DynaLoader.c
        link.exe -nologo -nodefaultlib -release -machine:x86 $(LIBS) \
            -subsystem:console PerlPower.obj win32.obj win32sck.obj \
            DynaLoader.obj setargv.obj

As with the MyPerl.cpp example Makefile, be sure that SRCDIR and LIBDIR point to the correct directories. You can compile PerlPower.cpp by typing nmake at the command line (make sure that both PerlPower.cpp and Makefile are in your current working directory). This will produce the file PerlPower.exe, which you can run at the command line:

    C:\PerlPower>PerlPower
    3 to the 4th power is 81.

You should definitely read the perlembed document in its entirety to get an overview of the issues involved with embedding Perl. Then, you can use the MyPerl.cpp and PerlPower.cpp as guides for embedding ActivePerl.


I have a program with perl embedded from the standard distribution. Why won't it compile with ActivePerl?

ActivePerl exposes the Perl interpreter in a slightly different fashion than standard Perl. For information on how to embed using ActivePerl, see How do I embed the Perl interpreter into my C/C++ program?.


AUTHOR AND COPYRIGHT

 

This FAQ was originally assembled and maintained by Evangelo Prodromou. It has been revised and updated by Brian Jepson of O'Reilly & Associates, David Grove, David Dmytryshyn, and David Sparks of ActiveState.

This FAQ is in the public domain. If you use it, however, please ensure that you give credit to the original authors.

 ActivePerl FAQ