PyInstaller打包应用程序在控制台模式下工作正常,在窗口模式下崩溃

时间:2012-11-17 11:03:34

标签: python qt pyqt pyside pyinstaller

我正在使用Python和PySide构建一个相当复杂的应用程序。最后发布的那天即将到来,所以我想将这个应用程序构建为exe。

然而,我手上有一个奇怪的问题。我过去使用过PyInstaller(顺便使用版本2),从来没有发生过这种情况。

基本上,当我使用--console标志构建应用程序时,它可以正常工作 - 但它会打开控制台窗口。当我使用窗口标志(-w)构建应用程序时,它不能正常工作。它开始和一切,但有所有这些奇怪的故障。例如,加载文本文件通常会引发BadFileDescriptor错误(在控制台模式下不会发生),并且应用程序在执行某项任务后崩溃。更糟糕的是,任务是一个循环,并且第一次执行正常,但是当它再次开始工作时,它会崩溃。

当我查看minidump文件时,有一些关于QtGui4.dll文件的内存访问冲突的错误。同样,这不会在控制台模式下发生。

有人有什么想法吗?

1 个答案:

答案 0 :(得分:7)

BadFileDescriptor错误以及因此的内存访问冲突是由窗口模式下的stdout应用程序是固定大小的缓冲区引起的。 因此,如果您已经直接使用stdoutprint写信sys.stdout,那么在一段时间后您会看到这些错误。

您可以通过以下方式解决此问题:

  1. 删除/评论stdout
  2. 上的文字
  3. 使用logging代替打印到stdout
  4. 在应用程序执行开始时重定向stdout。这是一个需要更改代码的解决方案,即使我认为将调试语句移到logging也是更好的选择。
  5. 要重定向stdout,您可以使用此类代码:

    import sys
    import tempfile
    sys.stdout = tempfile.TemporaryFile()
    sys.stderr = tempfile.TemporaryFile()
    

    在执行程序之前。你也可以使用一些自定义对象将输出放在“日志”文件或其他任何东西,重要的是输出不应该填充固定大小的缓冲区。

    例如,您可以执行类似这样的操作,以便能够利用logging模块而无需更改太多代码:

    import sys
    import logging
    
    debug_logger = logging.getLogger('debug')
    debug_logger.write = debug_logger.debug    #consider all prints as debug information
    debug_logger.flush = lambda: None   # this may be called when printing
    #debug_logger.setLevel(logging.DEBUG)      #activate debug logger output
    sys.stdout = debug_logger
    

    这种方法的缺点是print为每一行执行了对stdout.write的更多调用:

    >>> print 'test'
    DEBUG:debug:test
    DEBUG:debug:
    

    如果你想要,你可以避免这种行为写一个真正的write函数,只用“实线”调用the_logger.debug

    无论如何,我认为这种解决方案应该只是暂时的,并且只能在将print移植到logging.debug的调用之前使用。

    (显然记录器应该写入文件而不是stdout以避免错误。)