diff mbox

Win32 stdio not working if SDL is enabled

Message ID 20150813120643.GF430@redhat.com
State New
Headers show

Commit Message

Daniel P. Berrangé Aug. 13, 2015, 12:06 p.m. UTC
When debugging some patches on Windows, I discovered that nothing printed
to stderr ever appears on the console. Eventually I discovered that if I
build with --disable-sdl, then stderr appears just fine.

Looking at the code in vl.c I see a hack for SDL introduced in

  commit 59a36a2f6728081050afc6ec97d0018467999f79
  Author: Stefan Weil <weil@mail.berlios.de>
  Date:   Thu Jun 18 20:11:03 2009 +0200

    Win32: Fix compilation with SDL.


If I mostly kill the hack from vl.c, and just leave a plain '#undef main'
then I get working console stderr once again.

eg I applied



FWIW, I'm building on Fedora 22 using


 # ./configure --cross-prefix=i686-w64-mingw32- \
           --prefix=$HOME/usr/qemu-git-win32 \
	   --target-list=x86_64-softmmu \
	   --disable-libusb --disable-usb-redir

Which has

  mingw32-SDL-1.2.15-5.fc21.noarch


To test I just run

  C:> qemu-system-x86_64 -object foobar
  qemu-system-x86_64: -object foobar: Parameter 'id' is missing

to get it to print an error about bad -object arg. The message
never appears unless I apply that patch above, though I lack any
explanation as to why this is happening, aside from "SDL black magic"

Regards,
Daniel

Comments

Pavel Fedin Aug. 13, 2015, 12:14 p.m. UTC | #1
Hello!

> Looking at the code in vl.c I see a hack for SDL introduced in
> 
>   commit 59a36a2f6728081050afc6ec97d0018467999f79
>   Author: Stefan Weil <weil@mail.berlios.de>
>   Date:   Thu Jun 18 20:11:03 2009 +0200
> 
>     Win32: Fix compilation with SDL.

 Just a hint which may have to do with this. Looks like SDL introduces its own entry point, but it's WinMain() instead of main(). In this case standard CRT setup is omitted. But it is very easy to recover in this case. Just call:

freopen("CONOUT$", "w", stderr);

 This performs the necessary setup and relinks CRT's stderr with Windows console stream. It is a well known hack.
 More info here: http://stackoverflow.com/questions/9020790/using-stdin-with-an-allocconsole

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Daniel P. Berrangé Aug. 13, 2015, 2:18 p.m. UTC | #2
On Thu, Aug 13, 2015 at 01:06:43PM +0100, Daniel P. Berrange wrote:
> When debugging some patches on Windows, I discovered that nothing printed
> to stderr ever appears on the console. Eventually I discovered that if I
> build with --disable-sdl, then stderr appears just fine.
> 
> Looking at the code in vl.c I see a hack for SDL introduced in
> 
>   commit 59a36a2f6728081050afc6ec97d0018467999f79
>   Author: Stefan Weil <weil@mail.berlios.de>
>   Date:   Thu Jun 18 20:11:03 2009 +0200
> 
>     Win32: Fix compilation with SDL.
> 
> 
> If I mostly kill the hack from vl.c, and just leave a plain '#undef main'
> then I get working console stderr once again.

[snip]

> to get it to print an error about bad -object arg. The message
> never appears unless I apply that patch above, though I lack any
> explanation as to why this is happening, aside from "SDL black magic"

So I figured out what's going on here

The sdl-config program is adding "-Dmain=SDL_main" to the compiler flags.
So when vl.c does this:

  #include <SDL.h>
  int qemu_main(int argc, char **argv, char **envp);
  int main(int argc, char **argv)
  {
      return qemu_main(argc, argv, NULL);
  }
  #undef main
  #define main qemu_main

We have an extra level of substitution going on. So we end up
the program starting in a

   main(int argc, char **argv)

that is provided by SDL.dll, which in turn calls this stub
we define at the top of vl.c:

  int main(int argc, char **argv)
  {
      return qemu_main(argc, argv, NULL);
  }

where 'main' is actually changed to 'SDL_main', and 'qemu_main'
is auctally the real 'main' at the bottom of vl.c

Looking in SDL sources, one of the things it does in its replacement
main() method is to kill off default stdout & stderr streams,
replacing them with a stream that writes data to stdout.txt and
stderr.txt in the current directory.

As well as breaking the ability to see error messages on stderr,
this stupid SDL redirection also breaks the ability to use the
monitor via '-monitor stdio'.

All this is done even if you are not actually using SDL as the
QEMU display output too.

By replacing that current hack:

  #include <SDL.h>
  int qemu_main(int argc, char **argv, char **envp);
  int main(int argc, char **argv)
  {
      return qemu_main(argc, argv, NULL);
  }
  #undef main
  #define main qemu_main

With just

 #include <SDL.h>
 #undef main

we get rid of SDL.dll's replacement main() method entirely and execution
directly starts in QEMU's main() from vl.c. This avoids the stupid
console output redirection SDL does, and AFAICT, the SDL UI still works
after this, so the other setup things SDL.dll does don't seem to be too
critical

Regards,
Daniel
Stefan Weil Aug. 13, 2015, 5:48 p.m. UTC | #3
Am 13.08.2015 um 14:06 schrieb Daniel P. Berrange:
> When debugging some patches on Windows, I discovered that nothing printed
> to stderr ever appears on the console. Eventually I discovered that if I
> build with --disable-sdl, then stderr appears just fine.
> 
> Looking at the code in vl.c I see a hack for SDL introduced in
> 
>   commit 59a36a2f6728081050afc6ec97d0018467999f79
>   Author: Stefan Weil <weil@mail.berlios.de>
>   Date:   Thu Jun 18 20:11:03 2009 +0200
> 
>     Win32: Fix compilation with SDL.
> 
> 
> If I mostly kill the hack from vl.c, and just leave a plain '#undef main'
> then I get working console stderr once again.
> 

Hi Daniel,

that's a feature of SDL 1.2: stdout and stderr are by default
redirected to files stdout.txt and stderr.txt in the executable's
directory.

This redirection can be disabled by an environment variable
(SDL_STDIO_REDIRECT="no"). On my Linux machines, I always
set this variable, so when I run QEMU for Windows with
wine32 or wine64, stdout and stderr work.

Printing to stdout / stderr on Windows can be an adventure:
depending on your shell (command.exe, cmd.exe, MinGW shell,
MinGW rxvt, Cygwin shell, ...) it works different, and I also
had application crashes when a GUI application which was
not started from a shell tried to print to stdout.

From a user's point of view, maybe a better solution than
the current one would be a GTK console window which displays
any output to stdout / stderr.

Regards
Stefan
Daniel P. Berrangé Aug. 14, 2015, 11:14 a.m. UTC | #4
On Thu, Aug 13, 2015 at 07:48:47PM +0200, Stefan Weil wrote:
> Am 13.08.2015 um 14:06 schrieb Daniel P. Berrange:
> > When debugging some patches on Windows, I discovered that nothing printed
> > to stderr ever appears on the console. Eventually I discovered that if I
> > build with --disable-sdl, then stderr appears just fine.
> > 
> > Looking at the code in vl.c I see a hack for SDL introduced in
> > 
> >   commit 59a36a2f6728081050afc6ec97d0018467999f79
> >   Author: Stefan Weil <weil@mail.berlios.de>
> >   Date:   Thu Jun 18 20:11:03 2009 +0200
> > 
> >     Win32: Fix compilation with SDL.
> > 
> > 
> > If I mostly kill the hack from vl.c, and just leave a plain '#undef main'
> > then I get working console stderr once again.
> > 
> 
> Hi Daniel,
> 
> that's a feature of SDL 1.2: stdout and stderr are by default
> redirected to files stdout.txt and stderr.txt in the executable's
> directory.
> 
> This redirection can be disabled by an environment variable
> (SDL_STDIO_REDIRECT="no"). On my Linux machines, I always
> set this variable, so when I run QEMU for Windows with
> wine32 or wine64, stdout and stderr work.
> 
> Printing to stdout / stderr on Windows can be an adventure:
> depending on your shell (command.exe, cmd.exe, MinGW shell,
> MinGW rxvt, Cygwin shell, ...) it works different, and I also
> had application crashes when a GUI application which was
> not started from a shell tried to print to stdout.

I see it is something intentional done by SDL, but I don't think it is
desirable in general.  I rather doubt it would crash as that would imply
that code is checking the return value of fprintf() and taking some action
on error. Instead we exclusive ignore fprintf() return values, so if the
OS is reporting an I/O error we'll be ignoring it. In any case, it is
possible to build QEMU on Win32 without SDL, or set that env variable,
at which point QEMU will be printing to stdio anyway. So in the unlikely
case there is a crash scenario, we need to fix that regardless.

IMHO we should be disabling this bogus behaviour of SDL so QEMU does not
have different behaviour wrt stdio depending on what libraries you happen
to build against, or what platform you choose. Expecting people to know
about a magic env variable to make QEMU work as it does everywhere else
is just broken.

Regards,
Daniel
Daniel P. Berrangé Aug. 14, 2015, 12:15 p.m. UTC | #5
On Fri, Aug 14, 2015 at 12:14:15PM +0100, Daniel P. Berrange wrote:
> On Thu, Aug 13, 2015 at 07:48:47PM +0200, Stefan Weil wrote:
> > Am 13.08.2015 um 14:06 schrieb Daniel P. Berrange:
> > > When debugging some patches on Windows, I discovered that nothing printed
> > > to stderr ever appears on the console. Eventually I discovered that if I
> > > build with --disable-sdl, then stderr appears just fine.
> > > 
> > > Looking at the code in vl.c I see a hack for SDL introduced in
> > > 
> > >   commit 59a36a2f6728081050afc6ec97d0018467999f79
> > >   Author: Stefan Weil <weil@mail.berlios.de>
> > >   Date:   Thu Jun 18 20:11:03 2009 +0200
> > > 
> > >     Win32: Fix compilation with SDL.
> > > 
> > > 
> > > If I mostly kill the hack from vl.c, and just leave a plain '#undef main'
> > > then I get working console stderr once again.
> > > 
> > 
> > Hi Daniel,
> > 
> > that's a feature of SDL 1.2: stdout and stderr are by default
> > redirected to files stdout.txt and stderr.txt in the executable's
> > directory.
> > 
> > This redirection can be disabled by an environment variable
> > (SDL_STDIO_REDIRECT="no"). On my Linux machines, I always
> > set this variable, so when I run QEMU for Windows with
> > wine32 or wine64, stdout and stderr work.
> > 
> > Printing to stdout / stderr on Windows can be an adventure:
> > depending on your shell (command.exe, cmd.exe, MinGW shell,
> > MinGW rxvt, Cygwin shell, ...) it works different, and I also
> > had application crashes when a GUI application which was
> > not started from a shell tried to print to stdout.
> 
> I see it is something intentional done by SDL, but I don't think it is
> desirable in general.  I rather doubt it would crash as that would imply
> that code is checking the return value of fprintf() and taking some action
> on error. Instead we exclusive ignore fprintf() return values, so if the
> OS is reporting an I/O error we'll be ignoring it. In any case, it is
> possible to build QEMU on Win32 without SDL, or set that env variable,
> at which point QEMU will be printing to stdio anyway. So in the unlikely
> case there is a crash scenario, we need to fix that regardless.
> 
> IMHO we should be disabling this bogus behaviour of SDL so QEMU does not
> have different behaviour wrt stdio depending on what libraries you happen
> to build against, or what platform you choose. Expecting people to know
> about a magic env variable to make QEMU work as it does everywhere else
> is just broken.

A thought occurs to me - on Windows we actually build two copies of
the emulator

 - qemu-system-x86_64.exe - linked to the "console" subsystem
 - qemu-system-x86_64w.exe - linked to the "windows" subsystem [1]

With the 'windows' subsystem build it is reasonable to believe that the
user will not have any console generally available to view stderr/out.

So how about we make it such that when linked to the 'console' subsystem
we have stdout/stderr open by default, and when linked to the 'windows'
subsystem we have stdout/stderr redirected to a file (as SDL does). Except
that we make this redirection to a file happen in QEMU code, so it has
consistent behaviour even in non-SDL builds on Windows.

Regards,
Daniel

[1] '-mwindows'
     This option is available for Cygwin and MinGW targets.  It
     specifies that a GUI application is to be generated by instructing
     the linker to set the PE header subsystem type appropriately.
Liviu Ionescu Aug. 14, 2015, 2:59 p.m. UTC | #6
> On 14 Aug 2015, at 15:15, Daniel P. Berrange <berrange@redhat.com> wrote:
> 
> On Fri, Aug 14, 2015 at 12:14:15PM +0100, Daniel P. Berrange wrote:
>> On Thu, Aug 13, 2015 at 07:48:47PM +0200, Stefan Weil wrote:
>>> ... that's a feature of SDL 1.2: stdout and stderr are by default
>>> redirected to files stdout.txt and stderr.txt in the executable's
>>> directory.
>>> 
>>> This redirection can be disabled by an environment variable
>>> (SDL_STDIO_REDIRECT="no"). On my Linux machines, I always
>>> set this variable, so when I run QEMU for Windows with
>>> wine32 or wine64, stdout and stderr work.

in GNU ARM Eclipse QEMU I build SDL with '--disable-stdio-redirect' to prevent this annoying behaviour.

regards,

Liviu
diff mbox

Patch

diff --git a/vl.c b/vl.c
index 0adbbd6..8e1481b 100644
--- a/vl.c
+++ b/vl.c
@@ -39,16 +39,8 @@ 
 #endif
 
 #ifdef CONFIG_SDL
-#if defined(__APPLE__) || defined(main)
 #include <SDL.h>
-int qemu_main(int argc, char **argv, char **envp);
-int main(int argc, char **argv)
-{
-    return qemu_main(argc, argv, NULL);
-}
 #undef main
-#define main qemu_main
-#endif
 #endif /* CONFIG_SDL */
 
 #ifdef CONFIG_COCOA