Tricky STDERR issue under windows


P

philkime

I seem to have hit a rather tricky issue with STDERR redirection and libraries used via XS and wonder if anybody has any ideas.

I have an XS module which uses an external library. This library uses stdio, not PerlIO and can't be changed. I need to capture STDERR that this library outputs. This can't be done using PerlIO tricks like opening to an in memory scalar I realise. On non-windows, I can redirect STDERR to a file and read it in later when the library calls are finished. This works fine. On windows, it doesn't work because apparently, as soon as you re-open STDERR to a file, it decouples the library STDERR from perl's STDERR and the library continues to write to its own STDERR and it seems impossible to capture it.

Example below. On non-Windows, the STDERR from the library comes between the "|" characters as it should. On Windows, it comes after "||" as it's not captured. Any ideas on how to capture this?

#!/bin/perl
use Text::BibTeX;
use Capture::Tiny qw(capture);
my $stderr;

my $bib_entry = <<'END';
@BOOK{test1,
AUTHOR = {Arthur Author},
TITLE = {Arranging Arguments},,
YEAR = {1935}
}
END

my ($stdout, $stderr) = capture {
my $entry = new Text::BibTeX::Entry $bib_entry;
};

print "|$stderr|\n";

exit 0;
 
Ad

Advertisements

B

Bjoern Hoehrmann

* (e-mail address removed) wrote in comp.lang.perl.misc:
I have an XS module which uses an external library. This library uses
stdio, not PerlIO and can't be changed. I need to capture STDERR that
this library outputs. This can't be done using PerlIO tricks like
opening to an in memory scalar I realise. On non-windows, I can redirect
STDERR to a file and read it in later when the library calls are
finished. This works fine. On windows, it doesn't work because
apparently, as soon as you re-open STDERR to a file, it decouples the
library STDERR from perl's STDERR and the library continues to write to
its own STDERR and it seems impossible to capture it.

As I recall it, file handles are valid only within the same runtime. If
you are using MSVC++ and Perl was linked to one library and your XS code
to another one then they will have trouble exchanging file descriptors.
Using multiple processes would probably allow you to let cmd.exe do the
redirecting, have you tried that, redirecting via `perl example 2> err`?
 
P

philkime

Everything is gcc so there is no C runtime problem. It seems to be a Windows issue - this example shows the problem: even using Capture::Tiny it fails, but only on Windows:

#!/usr/bin/perl

use Capture::Tiny 'capture';
use File::Temp qw(tempfile);
use Inline C;

my ($stdout, $stderr) = capture { test_err() };

print "|$stderr|\n";

__END__
__C__
void test_err()
{
(void)fprintf (stderr, "ERROR");
}
 
P

philkime

Someone mailed me and pointed out that Windows doesn't slush STDERR like other OSES ... so with one more line, it works in windows:

#!/usr/bin/perl

use Capture::Tiny 'capture';
use File::Temp qw(tempfile);
use Inline C;

my ($stdout, $stderr) = capture { test_err() };

print "|$stderr|\n";

__END__
__C__
void test_err()
{
(void)fprintf (stderr, "ERROR");
(void)fflush(stderr);
}
 
Ad

Advertisements

P

philkime

I tested this and it does work with the external library if I add fflush() and recompile it. This library is compiled completely separately from the perl module (it's used by an XS module, it isn't part of it) so it uses utterly vanilla C stdio which perl doesn't/can't redefine.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top