Questions about "perldoc perlembed"
- From: "jl_post@xxxxxxxxxxx" <jl_post@xxxxxxxxxxx>
- Date: Wed, 4 Jun 2008 14:02:24 -0700 (PDT)
Hi,
Ultimately I am trying to embed the ability to run Perl scripts on
a C++ program written in Visual Studio 2005 (on a Windows XP
machine). I have read "perldoc perlembed" and I have followed along
by running several of its examples on a Linux platform. While I can
get the sample programs to work on Linux, I am stumbling on getting
Perl to properly embed in my Win32 C++ program.
So I have a bunch of questions to ask about some of the concepts in
"perlembed". I'm hoping that with the answers to my questions I might
be able to resolve my issues.
Issue 1: "perlembed" gives the following warning:
If you have trouble compiling the scripts in this
documentation, you're not alone. The cardinal rule:
COMPILE THE PROGRAMS IN EXACTLY THE SAME
WAY THAT YOUR PERL WAS COMPILED. (Sorry for yelling.)
Now, I was able to compile Perl by downloading AP1003_source.zip from
ActiveState, unzipping it, cd-ing to perl/win32 and typing "nmake".
What confuses me is that this is not the same way I compile my main C+
+ program. In Visual Studio, I normally load a *.sln or *.vcproj file
and compile it from there, never using nmake or a Unix-like Makefile.
Therefore, I can't quite figure out how to compile both perl and my C+
+ program with the same options.
So question 1 is: How do I compile both Perl and my C++ program "in
exactly the same way"?
Issue 2: "perlembed" gives a wonderful example program that
demonstrates how to run/evaluate Perl statements from a C program
(header comments are mine):
/* From "perldoc perlembed" */
/* Compile on Unix with:
cc -o perl_eg1 perl_eg1.c `perl -MExtUtils::Embed -e ccopts -e
ldopts`
*/
#include <EXTERN.h>
#include <perl.h>
static PerlInterpreter *my_perl;
main (int argc, char **argv, char **env)
{
STRLEN n_a;
char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3(&argc,&argv,&env);
my_perl = perl_alloc();
perl_construct( my_perl );
perl_parse(my_perl, NULL, 3, embedding, NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
perl_run(my_perl);
/** Treat $a as an integer **/
eval_pv("$a = 3; $a **= 2", TRUE);
printf("a = %d\n", SvIV(get_sv("a", FALSE)));
/** Treat $a as a float **/
eval_pv("$a = 3.14; $a **= 2", TRUE);
printf("a = %f\n", SvNV(get_sv("a", FALSE)));
/** Treat $a as a string **/
eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = reverse($a);",
TRUE);
printf("a = %s\n", SvPV(get_sv("a", FALSE), n_a));
perl_destruct(my_perl);
perl_free(my_perl);
PERL_SYS_TERM();
}
I was curious to see how calls to eval_pv() knew which PerlInterpreter
to use, so I changed all instances of "my_perl" to "my__perl" (note
the double underscores). But when I tried to compile the program, I
got the following compiler error:
perl_eg1.c: In function `main':
perl_eg1.c:21: error: `my_perl' undeclared
I thought that was odd... Of course 'my_perl' is undeclared -- it's
'my__perl' that I want it to use. But for some reason, the
"PL_exit_flags |= PERL_EXIT_DESTRUCT_END;" line wants to use
'my_perl', whether it was declared or not. (Incidentally, I tried
commenting out that line to see what would happen, and the compiler
gave the same complaint for line 25, which is the ' eval_pv("$a = 3;
$a **= 2", TRUE);' line.)
So evidently, PL_exit_flags and eval_pv() want to use a
PerlInterpreter named "my_perl". But declaring a static/global
variable like in the given example won't work too well with threads,
if I ever have to run two (or more) scripts concurrently. So I
thought about how to get around this "my_perl" naming requirement.
Eventually I read the section "Maintaining multiple interpreter
instances" (also in "perlembed") which talks about
PERL_SET_CONTEXT(). It says that that call is "necessary to
initialize the global state that tracks which interpreter is the
'current' one on the particular process or thread that may be running
it."
Sounds good. It seems like I all have to do is call
PERL_SET_CONTEXT(my__perl) for the compiler to stop looking for
"my_perl". So I put "PERL_SET_CONTEXT(my__perl);" line right before
the perl_construct(), perl_parse(), PL_exit_flags, and all the
eval_pv() lines, but it doesn't appear to do any good. The compiler
still complains that "my_perl" in undeclared at the PL_exit_flags and
eval_pv() lines.
So question 2 is: Can calls to eval_pv() only be done when the
PerlInterpreter is specifically named "my_perl"? (And if not, how can
I specify a differently-named PerlInterpreter?)
Issue 3: I'm actually able to get a simple Perl program to run from
my C++ program with the following code:
void runPerlScript(char * script_filename)
{
char* argv[] = { "PROGRAM_NAME" };
int argc = sizeof(argv) / sizeof(char*);
PERL_SYS_INIT3(&argc, NULL, NULL);
PerlInterpreter *perlInterpreter = perl_alloc();
char* scriptArguments[] = { "PROGRAM_NAME",
"-ID:/perl/lib",
script_filename };
const int numArguments = sizeof(scriptArguments) / sizeof(char*);
PERL_SET_CONTEXT(perlInterpreter); // is this line needed?
PL_perl_destruct_level = 1;
perl_construct(perlInterpreter);
const int parseResult = perl_parse(perlInterpreter, NULL,
numArguments, scriptArguments, (char**) NULL);
if (parseResult == 0)
perl_run(perlInterpreter);
perl_destruct(perlInterpreter);
perl_free(perlInterpreter);
PERL_SYS_TERM();
}
With this code, I can run a simple script whose filename is passed in
as script_filename. However, it only succeeds once. The second time
this function is called, it crashes at the call to perl_parse().
I couldn't figure out what was causing this crash, but I read
something that seemed useful (again in "perlembed"), which said:
Even if you don't intend to run two or more interpreters
at the same time, but to run them sequentially, like
in the above example, it is recommended to build perl
with the -Dusemultiplicity option otherwise some
interpreter variables may not be initialized correctly
between consecutive runs and your application may
crash.
Sounds like my problem! So I go over to the perl/win32 directory and
have a look at its Makefile. Inside it I see the following lines:
#
# uncomment to enable multiple interpreters. This is need
# for fork() emulation and for thread support.
#
USE_MULTI = define
and the lines:
CFG_VARS = \
"INST_DRV=$(INST_DRV)" \
.
.
.
"usemultiplicity=$(USE_MULTI)" \
.
.
.
"optimize=$(OPTIMIZE:"=\")"
As far as I can tell, the "usemultiplicity" option is indeed being
used when compiling. Because of this, I can't figure out why the
second call to perl_parse() is crashing.
So Question 3 is: Why is my C++ program crashing the second time it
calls perl_parse()? (Is it because the -Dusemultiplicity option
wasn't set correctly, and if so, how do I set it correctly?)
Issue 4: I am able to "use" certain simple modules in my Perl scripts
that are run from the C++ program (like "warnigns" and "Time::Local"),
but not ones that have dynamic loading (like "Data::Dumper"). There
is a section in "perldoc perlembed" that addresses this very issue,
and it provides this sample solution for "use"ing the Socket module:
static void xs_init (pTHX);
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void boot_Socket (pTHX_ CV* cv);
EXTERN_C void
xs_init(pTHX)
{
char *file = __FILE__;
/* DynaLoader is a special case */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
newXS("Socket::bootstrap", boot_Socket, file);
}
So Question 4a is: That's nice for Socket, but how would I
incorporate a module name with "::" in it, like "Data::Dumper"? I
can't just add the line:
newXS("Data::Dumper::bootstrap", boot_Data::Dumper, file);
I would think that the "::" (outside of the string) would cause a
compiler error.
And Question 4b is: Do I have to hard-code the inclusion of every
dynamic module I would ever want to use? (Since the example does it
for the Socket module, it seems as though I would have to.)
Thanks in advance for any help.
-- Jean-Luc
.
- Follow-Ups:
- Re: Questions about "perldoc perlembed"
- From: jl_post@xxxxxxxxxxx
- Re: Questions about "perldoc perlembed"
- From: sisyphus
- Re: Questions about "perldoc perlembed"
- From: Ben Morrow
- Re: Questions about "perldoc perlembed"
- Prev by Date: Re: How to get the output from an ICQ clent
- Next by Date: Re: OT: SI units
- Previous by thread: FAQ 5.38 How do I select a random line from a file?
- Next by thread: Re: Questions about "perldoc perlembed"
- Index(es):
Relevant Pages
|