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

Find libsndfile.dylib on Apple M1 #311

Merged
merged 1 commit into from
Dec 7, 2021
Merged

Conversation

panosl
Copy link
Contributor

@panosl panosl commented Sep 9, 2021

Homebrew on Apple M1 uses a /opt/homebrew/lib instead of /usr/local/lib.
We are making sure we pick that up.

@bastibe
Copy link
Owner

bastibe commented Sep 15, 2021

Thank you very much!

I think it might be a good idea to fall back to the original path if /opt/homebrew/lib does not work, just in case homebrew or Apple fix their stuff and thereby break ours.

Homebrew on Apple M1 uses a `/opt/homebrew/lib` instead of `/usr/local/lib`.
We are making sure we pick that up.
@panosl
Copy link
Contributor Author

panosl commented Sep 15, 2021

Thank you very much!

I think it might be a good idea to fall back to the original path if /opt/homebrew/lib does not work, just in case homebrew or Apple fix their stuff and thereby break ours.

I updated the PR, it checks if /opt/homebrew/lib/ exists, else it falls back to /usr/local/lib/.

@bastibe
Copy link
Owner

bastibe commented Sep 15, 2021

Sorry for being nitpicky, but I think it would be better to try the dlopen with /opt/homebrew/lib first, and fall back to /usr/local/lib if the first dlopen failed. This way libsndfile can be saved in either directory, and we don't make any assumption on which one is correct.

@panosl
Copy link
Contributor Author

panosl commented Sep 15, 2021

No, you're not being nitpicky, I always opt for try/catch. In fact, that is how i started the implementation. Problem is, if we try/catch and the catch clause fails (because there might not be a /usr/local/lib/ and the user might not have installed homebrew yet, ergo there won't be a /opt/homebrew/lib/ yet) we'll get multiple OSErrors instead of the one.

That's the reason I did it with a ternary. But I can do it with try/catch if you prefer it.

@panosl
Copy link
Contributor Author

panosl commented Sep 15, 2021

There could be a try/catch within a try/catch, but not sure to catch in the inner one 😅

@bastibe
Copy link
Owner

bastibe commented Sep 15, 2021

That's a valid concern. Perhaps we could try to find the correct location with ctypes.util.find_library? Or at least use that to check if the library is in the default location, and only check /opt/homebrew/lib if it isn't. Else, since we concatenate _os.path.join(_some_path, _libname) anyway, we might as well check if the specific /some/path/libsndfile.dylib exists.

I'll leave the decision up to you. Since this is a very niche workaround that probably doesn't affect too many people, either way is fine.

@carbocation
Copy link

I suspect this is affecting a fair number of people on M1s who are trying to do local development using libraries that depend on python-soundfile (e.g., torchaudio users). The tips in #310 worked for me. In my specific case, this worked out to be:

bash -c "ln -s /opt/homebrew/lib/libsndfile.* /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/_soundfile_data/"

@bastibe
Copy link
Owner

bastibe commented Nov 17, 2021

If anyone with access to an M1 machine would like to finish and test this pull request, I'll be happy to merge it. But I can't code it myself, because I don't have an M1.

@oliverguhr
Copy link

I did run the tests on a MacBook Air M1. All tests passed. Thanks @panosl!

python setup.py test
/code/python-soundfile/venv/lib/python3.8/site-packages/setuptools/dist.py:458: UserWarning: Normalizing '0.10.3post1' to '0.10.3.post1'
  warnings.warn(tmpl.format(**locals()))
running test
WARNING: Testing via this command is deprecated and will be removed in a future version. Users looking for a generic test entry point independent of test runner are encouraged to use tox.
running egg_info
writing soundfile.egg-info/PKG-INFO
writing dependency_links to soundfile.egg-info/dependency_links.txt
writing requirements to soundfile.egg-info/requires.txt
writing top-level names to soundfile.egg-info/top_level.txt
package init file '_soundfile_data/__init__.py' not found (or not a regular file)
reading manifest file 'soundfile.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'soundfile.egg-info/SOURCES.txt'
running build_ext
generating cffi module '_soundfile.py'
already up-to-date
=================================================== test session starts ===================================================
platform darwin -- Python 3.8.9, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /code/python-soundfile
collected 324 items                                                                                                       

tests/test_argspec.py ....                                                                                          [  1%]
tests/test_soundfile.py ........................................................................................... [ 29%]
................................................................Exception ignored from cffi callback <function SoundFile._init_virtual_io.<locals>.vio_seek at 0x107d361f0>:
Traceback (most recent call last):
  File "/code/python-soundfile/soundfile.py", line 1209, in vio_seek
    file.seek(offset, whence)
ValueError: I/O operation on closed file
Exception ignored from cffi callback <function SoundFile._init_virtual_io.<locals>.vio_tell at 0x107d36040>:
Traceback (most recent call last):
  File "/code/python-soundfile/soundfile.py", line 1237, in vio_tell
    return file.tell()
ValueError: I/O operation on closed file
Exception ignored from cffi callback <function SoundFile._init_virtual_io.<locals>.vio_tell at 0x107d36040>:
Traceback (most recent call last):
  File "/code/python-soundfile/soundfile.py", line 1237, in vio_tell
    return file.tell()
ValueError: I/O operation on closed file
Exception ignored from cffi callback <function SoundFile._init_virtual_io.<locals>.vio_get_filelen at 0x107cd0550>:
Traceback (most recent call last):
  File "/code/python-soundfile/soundfile.py", line 1201, in vio_get_filelen
    curr = file.tell()
ValueError: I/O operation on closed file
Exception ignored from cffi callback <function SoundFile._init_virtual_io.<locals>.vio_seek at 0x107d361f0>:
Traceback (most recent call last):
  File "/code/python-soundfile/soundfile.py", line 1209, in vio_seek
    file.seek(offset, whence)
ValueError: I/O operation on closed file
Exception ignored from cffi callback <function SoundFile._init_virtual_io.<locals>.vio_write at 0x107d360d0>:
Traceback (most recent call last):
  File "/code/python-soundfile/soundfile.py", line 1229, in vio_write
    written = file.write(data)
ValueError: I/O operation on closed file
................................................... [ 64%]
..................................................................................................................  [100%]

==================================================== warnings summary =====================================================
tests/test_soundfile.py:105
  /code/python-soundfile/tests/test_soundfile.py:105: PytestDeprecationWarning: @pytest.yield_fixture is deprecated.
  Use @pytest.fixture instead; they are the same.
    def file_inmemory():

tests/test_soundfile.py:111
  /code/python-soundfile/tests/test_soundfile.py:111: PytestDeprecationWarning: @pytest.yield_fixture is deprecated.
  Use @pytest.fixture instead; they are the same.
    def sf_stereo_r(file_stereo_r):

tests/test_soundfile.py:117
  /code/python-soundfile/tests/test_soundfile.py:117: PytestDeprecationWarning: @pytest.yield_fixture is deprecated.
  Use @pytest.fixture instead; they are the same.
    def sf_stereo_w(file_w):

tests/test_soundfile.py:123
  /code/python-soundfile/tests/test_soundfile.py:123: PytestDeprecationWarning: @pytest.yield_fixture is deprecated.
  Use @pytest.fixture instead; they are the same.
    def sf_stereo_rplus(file_stereo_rplus):

tests/test_soundfile.py:129
  /code/python-soundfile/tests/test_soundfile.py:129: PytestDeprecationWarning: @pytest.yield_fixture is deprecated.
  Use @pytest.fixture instead; they are the same.
    def sf_stereo_wplus(file_wplus):

tests/test_soundfile.py::test_truncate[obj-False]
  /code/python-soundfile/.eggs/pytest-6.2.5-py3.8.egg/_pytest/unraisableexception.py:78: PytestUnraisableExceptionWarning: Exception ignored from cffi callback <function SoundFile._init_virtual_io.<locals>.vio_write at 0x107cd0a60>: None
  
  Traceback (most recent call last):
    File "/code/python-soundfile/soundfile.py", line 1229, in vio_write
      written = file.write(data)
  ValueError: I/O operation on closed file
  
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))

-- Docs: https://docs.pytest.org/en/stable/warnings.html
============================================= 324 passed, 6 warnings in 1.81s =============================================

@bastibe
Copy link
Owner

bastibe commented Dec 7, 2021

Brilliant! Thank you all!

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

Successfully merging this pull request may close these issues.

4 participants