问题
I just realized, that the PerlIO layer seems to do something more than just (more or less) easily wrap the stdio.h-functions.
If I try to use a file-descriptor resolved via PerlIO_stdout()
and PerlIO_fileno()
with functions from stdio.h, this fails.
For example:
PerlIO* perlStdErr = PerlIO_stderr();
fdStdErrOriginal = PerlIO_fileno(perlStdErr);
relocatedStdErr = dup(fdStdOutOriginal);
_write(relocatedStdErr, "something", 8); //<-- this fails
I've tried this with VC10. The embedded perl program is executed from a different context - so it's not possible to use PerlIO from the context where the write to the relocatedStdErr is performed.
For the curious: I need to execute a perl script and forward the output of the script's stdout/stderr to a log whilst keeping the ability to write on stdout for myself. Moreover this should work platform independent (linux, windows console application, win32 desktop application). Just to forward the stdout/stderr doesn't work in Win32 desktop applications since there is none ;) - you need to use the perl's stdout/stderr.
Needed solution: Be able to write on a filehandle (or descriptor) derived from perlio NOT using the PerlIO stack.
EDIT - my solution:
As Story Teller was pointing to PerlIO_findFILE, this did the trick. So here an excerpt of the code - see the comments inside for descriptions:
FILE* stdErrFILE = PerlIO_findFILE(PerlIO_stderr()); //convert to Perl's stderr to stdio FILE handle
fdStdErrOriginal = _fileno(stdErrFILE); //get descriptor using MSVC
if (fdStdErrOriginal >= 0)
{
relocatedStdErr = _dup(fdStdErrOriginal); //relocate stdErr for external writing using MSVC
if (relocatedStdErr >= 0)
{
if (pipe(fdPipeStdErr) == 0) //create pipe for forwarding stdErr - USE PERL's IO since win32subsystem(non-console) "_pipe" doesn't work
{
if (dup2(fdPipeStdErr[1], fdStdErrOriginal) >= 0) //hang pipe on stdErr - USE PERL's IO (since it's created by perl)
{
close(fdPipeStdErr[1]); //close the now duplicated writer on stdErr for further usage - USE PERL's IO (since it's created by perl)
//"StreamForwarder" creates a thread that catches/reads the pipe's input and forwards it to the processStdErrOutput function (using the PerlIO)
stdErrForwarder = new StreamForwarder(fdPipeStdErr[0], &processStdErrOutput, PerlIO_stderr());
return relocatedStdErr; //return the relocated stdErr to be able to '_write' onto it
}
}
}
}
...
...
_write(relocatedStdErr, "Hello Stackoverflow!", 20); //that works :)
One interesting thing that I actually don't understand is, that the perl documentation says that is't necessary to #define PERLIO_NOT_STDIO 0
to be able to use PerlIO_findFILE()
. But for me, that works fine without it and further I like to use PerlIO and the stdio together anyway. That's a point I didn't figured out what is going on.
来源:https://stackoverflow.com/questions/41549508/embedded-perl-in-c-perlapio-interoperability-with-stdio