1

问题:与Linux 的这个问题类似,我在OSError: PortAudio library not found打包我的应用程序pyinstaller并执行.exe. (注意,当我通过 shell 运行我的未打包应用程序时,我没有遇到任何问题。这只发生在我使用 pyinstaller 打包它时)。

尽管portaudio通过包管理器安装似乎适用于 Linux,但这似乎不是 Windows 的选项,因为sounddevice 文档说,“如果您使用的是 Mac OS X 或 Windows,该库将使用 pip 自动安装”和只做一个pip search portaudio返回包装器

问题 我需要做什么才能sounddevice在我的 Windows 环境中工作?为什么它可以在我的 shell 中工作,但在打包应用程序后却不行?

完全错误:

(venv) λ my-app.exe
Traceback (most recent call last):
  File "site-packages\sounddevice.py", line 71, in <module>
OSError: PortAudio library not found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "point-of-service-recorder.py", line 11, in <module>
    import sounddevice as sd
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "c:\path\to\my\app\venv\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\sounddevice.py", line 83, in <module>
OSError: cannot load library 'C:\Users\TYLER~1.HIT\AppData\Local\Temp\_MEI250242\_sounddevice_data\portaudio-binaries\libportaudio32bit.dll': error 0x7e
[23156] Failed to execute script point-of-service-recorder

构建输出

  • 运行 pyinstaller 构建的选定输出:
[...]

22251 INFO: Looking for dynamic libraries
22260 INFO: Cannot get manifest resource from non-PE file c:\users\path\to\app\venv\lib\site-packages\_soundfile_data\COPYING
22262 WARNING: Can not get binary dependencies for file: c:\users\path\to\app\venv\lib\site-packages\_soundfile_data\COPYING
22262 WARNING:   Reason: 'DOS Header magic not found.'

安装包

  • 请注意,cffi根据要求,存在 、 和sounddevice。未列出,但我认为它包含在 中,就像文档说 (?)setuptoolsportaudiosounddevice
(venv) λ pip list            
Package        Version       
-------------- ---------     
altgraph       0.16.1              
certifi        2019.6.16     
cffi           1.12.3        
chardet        3.0.4         
Click          7.0           
Flask          1.1.1         
Flask-WTF      0.14.2        
future         0.17.1        
idna           2.8           
itsdangerous   1.1.0         
Jinja2         2.10.1        
MarkupSafe     1.1.1         
numpy          1.17.0        
pefile         2019.4.18     
pip            19.2.2        
pycparser      2.19          
pydub          0.23.1        
PyInstaller    3.5           
pywin32-ctypes 0.2.0         
requests       2.22.0        
setuptools     41.0.1        
sounddevice    0.3.13        
SoundFile      0.10.2        
urllib3        1.25.3        
waitress       1.3.0         
Werkzeug       0.15.5        
wheel          0.33.4        
WTForms        2.2.1         
4

3 回答 3

2

我设法解决了这个问题,而无需对 sounddevice 源代码进行任何更改。这对我很有用,所以我不必记住我的 sounddevice 源代码被黑了。

我使用了 sounddevice 0.4.3,它正在几个不同的位置寻找 DLL。

我能够通过以不同的名称和文件夹复制 dll 来欺骗它找到 DLL,如下所示:

from pathlib import Path
import shutil    

# copy the sounddevice dll under a different name and path
infile = Path('../pyenv/Lib/site-packages/_sounddevice_data/portaudio-binaries/libportaudio64bit.dll')
outfile = Path('dist/bin/libportaudio-2.dll')
outfile.parent.mkdir()
shutil.copy(infile,outfile)
于 2021-11-24T13:39:50.327 回答
1

对此有些尴尬,但我没有在构建中包含所需的端口音频 .dll。将它们复制到env\site-packages并更新sounddevice.py以指向正确.dll的对我有用


编辑

可以在以下位置找到预构建的 dll:https ://github.com/spatialaudio/portaudio-binaries

我将它们添加到/bin目录并更新sounddevice.py以使用它们(下面的代码)


这是我sounddevice.py从 v0.3.13 更新的(手动更改以 #! 标记)

import atexit as _atexit
import os as _os
import platform as _platform
import sys as _sys
from ctypes.util import find_library as _find_library
from _sounddevice import ffi as _ffi


#! built path to my dlls (in my `bin` dir)
#! use _platform.architecture to infer whether to use 32 or 64-bit dll
try:
    _libname = 'libportaudio' + _platform.architecture()[0] + '.dll'
    _libname = _os.path.join('bin', _libname)
    _lib = _ffi.dlopen(_libname)
except OSError:
    if _platform.system() == 'Windows':  #! use Windows, not default 'Darwin'
        _libname = 'libportaudio' + _platform.architecture()[0] + '.dll'
    else:
        #! custom error
        raise OSError('PortAudio library not found! Make sure the system is Windows 64 or 32 bit and you have the '
                      'correct libportaudio dll saved in  site-packages')

#! keep rest the same

在设置我的开发环境时,我运行这个 bat 脚本以sounddevice.py使用我的自定义环境更新虚拟环境中的默认值:

echo Updating sounddevice.py ...
copy .\sounddevice.py .\venv\Lib\site-packages\sounddevice.py /y
copy .\libportaudio32bit.dll .\venv\Lib\site-packages\libportaudio32bit.dll /y
copy .\libportaudio64bit.dll .\venv\Lib\site-packages\libportaudio64bit.dll /y


提示:确保您锁定 sounddevice 版本(requirements.txt例如),以便将来的版本不会破坏此 hack

于 2019-08-12T18:46:57.957 回答
0

我将 libportaudio32bit.dll 打包到我的 exe 文件中,并删除了这些代码:

# import _sounddevice_data
# _libname = _os.path.join(
#     next(iter(_sounddevice_data.__path__)), 'portaudio-binaries', _libname)
_lib = _ffi.dlopen(_libname)

在 sounddevice.py 中,现在它正在工作。

于 2019-10-08T08:39:20.183 回答