Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Portaudio Bundled but location is my local install? #7816

Open
msj121 opened this issue Aug 2, 2023 · 5 comments
Open

Portaudio Bundled but location is my local install? #7816

msj121 opened this issue Aug 2, 2023 · 5 comments
Labels
triage Please triage and relabel this issue

Comments

@msj121
Copy link

msj121 commented Aug 2, 2023

Hi, my code works, and bundling works.

However when I add the need for portaudio in my code it appears that the hook runs and loads the correct bundles into the onefile locations, but when running the application it looks for the portaudio in another location (my local install).

To be clear:
Console error:

Library Validation failed: Rejecting '/opt/homebrew/Cellar/portaudio/19.7.0/lib/libportaudio.2.dylib' (Team ID: none, platform: no) for process 'pypy(12758)' (Team ID: N12B3X14HN, platform: no), reason: mapped file has no Team ID and is not a platform binary (signed with custom identity or adhoc?)

The issue is NOT codesigning, I manually sign everything fine, the issue is that it is attempting to load a local copy of portaudio and NOT the one bundled (which is signed).

Any idea what to do or how to track down? I looked in warn log but didn't see this mentioned.

My spec is pretty standard, thanks for any help!:

block_cipher = None


a = Analysis(
    ['pypy.py'],
    pathex=[],
    binaries=[],
    datas=[],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    [],
    exclude_binaries=True,
    name='pypy',
    debug=1,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=True,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity='Developer ID...',
    entitlements_file='',
    icon=['icons/pypy.png'],
)
coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='pypy',
)
app = BUNDLE(
    coll,
    name='[pypy.app](http://pypy.app/)',
    icon='./icons/pypy.png',
    bundle_identifier='com.me.pypy',
    info_plist={
        "NSHighResolutionCapable":True,
        "com.apple.security.automation.apple-events":True,
        "NSMicrophoneUsageDescription":"This will be used to analyze slurring",
        "com.apple.security.device.microphone":True,
        "com.apple.security.device.audio-input":True
    }
)

Operating System: OSX (13.3.1)
python installed with brew
pyinstaller version: 5.13.0

I have been working on this for a while, just found: https://stackoverflow.com/questions/69811814/how-to-include-portaudio-into-a-pyinstaller-onefile-build

Where he mentions there seems to be an issue with linking, is this the same issue, is there a solution we can include in pyinstaller?

@msj121 msj121 added the triage Please triage and relabel this issue label Aug 2, 2023
@bwoodsend
Copy link
Member

Please don't post the same question in multiple places -- you're reaching the same people in both but now you're making the conversation harder to follow.

Like I said in your original question, I couldn't reproduce this. The absolute linker path is correctly replaced with an @rpath one. Can you confirm that running otool -L on your packaged copy of _portaudio.cpython-3xx-darwin.so still uses the hard-coded absolute path? Can you try freezing a simple import pyaudio program and confirm that that also shows the issue?

@msj121
Copy link
Author

msj121 commented Aug 2, 2023

@bwoodsend Sorry, at the time of posting here I didn't see a response, and it appeared to me to be a bug at this point... I guess I should've deleted the conversation, my bad, sorry.

Recent PyInstaller (5.13.0)

otool -L ./dist/pypy.app/Contents/MacOS/_sounddevice_data/portaudio-binaries/libportaudio.dylib

./dist/pymotai.app/Contents/MacOS/_sounddevice_data/portaudio-binaries/libportaudio.dylib:
	@rpath/libportaudio.2.dylib (compatibility version 3.0.0, current version 3.0.0)
	/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox (compatibility version 1.0.0, current version 1000.0.0)
	/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1775.118.101)
	/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1122.33.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)

Interestingly enough the package contents are as follows:

pypy.app/Contents/MacOS/_sounddevice_data/portaudio-binaries:
README.md libportaudio.dylib

There is no libportaudio2.dylib in the application (also no .so file).

I cannot find what is pointing to /opt/homebrew/Cellar/portaudio/19.7.0... any other ideas to check because I can force it to the R-Path if I can find the culprit?

/opt/homebrew/Cellar/portaudio/19.7.0:

libportaudio.2.dylib	libportaudio.dylib	libportaudiocpp.a	pkgconfig
libportaudio.a		libportaudiocpp.0.dylib	libportaudiocpp.dylib

I will create a simpler application as requested. portaudio is being used by "vosk" python library, should I import or add a hidden import to make sure it picks up portaudio in a different way (I had assumed it was working since it was getting something).

@rokm
Copy link
Member

rokm commented Aug 2, 2023

I think the problem is that sounddevice prefers system-installed library over the copy that it bundles in the wheel in the _sounddevice_data directory, based on their search code:

https://github.com/spatialaudio/python-sounddevice/blob/91171852b9d955e3abcb58f9b78f2868db40c8be/sounddevice.py#L61-L92

The initial ctypes.util.find_library('portaudio') call probably resolves the libportaudio.2.dylib in Homebrew installation. This probably doesn't matter in everyday python context, but it is problematic in frozen application bundles due to lack of signature on the external lib.

You'll probably have to modify that code one way or another - remove the search for system-wide lib, change the search order, or add an option to specify location of the library via environment variable (and then set the correct path via said environment variable at the start of your progam, before importing the packages).

@msj121
Copy link
Author

msj121 commented Aug 2, 2023

It appears the error will only showup if I use codesign? It fails due a .ds_store file (in parent MacOS folder and parent Resources folder) created by pyinstaller. Nevertheless, running causes the original errors to be created. My guess is that it will run smoothly UNLESS codesigning issues mean it cannot access local harddrive files... Of course will fail on another laptop.

@rokm
Copy link
Member

rokm commented Aug 2, 2023

It appears the error will only showup if I use codesign?

Yes, that makes sense. Because you are signing with a "real" codesign identity, all libraries that application is attempting to load are also expected to have valid signatures. So if the system-wide Homebrew-installed library is attempted to be loaded, it will fail due to it not being signed.

You can try instrumenting your local copy of sounddevice by adding a print(f"system lib: {_libname}") here and a print(f"fallback lib: {_libname}") here to see which copy of the library is being loaded. Then try running your signed application with portaudio installed in Homebrew and with portaudio (temporarily) uninstalled from Homebrew.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage Please triage and relabel this issue
Projects
None yet
Development

No branches or pull requests

3 participants