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

can't find torchtext dylib files #375

Closed
inferense opened this issue Jan 31, 2022 · 30 comments · Fixed by #676
Closed

can't find torchtext dylib files #375

inferense opened this issue Jan 31, 2022 · 30 comments · Fixed by #676
Labels

Comments

@inferense
Copy link

Pyinstaller builds successfully, however when I run the exe I get an error related to missing torchtext dylib files.

I get the following warnings during the freezing:

98346 WARNING: Cannot find path ./libc++.1.dylib (needed by .../env/lib/python3.9/site-packages/torchtext/_torchtext.so)
98346 WARNING: Cannot find path ./libtorch_python.dylib (needed by .../env/lib/python3.9/site-packages/torchtext/_torchtext.so)
98346 WARNING: Cannot find path ./libtorch.dylib (needed by .../env/lib/python3.9/site-packages/torchtext/_torchtext.so)
98346 WARNING: Cannot find path ./libtorch_cpu.dylib (needed by .../env/lib/python3.9/site-packages/torchtext/_torchtext.so)
98347 WARNING: Cannot find path ./libc10.dylib (needed by .../env/lib/python3.9/site-packages/torchtext/_torchtext.so)

I can find the last 4 dylib files (except libc++.1.dylib) in my env/torch module and can copy them manually to the dist folder but that doesn't seem like a good workaround and I still can't find libc++.1.dylib. Updating path / binaries in .spec file doesn't help.

Any ideas on how to resolve this?

  • Output of pyinstaller --version: 4.8
  • Version of Python: 3.9
  • torchtext: 0.11.2
  • torch: 1.10.2
  • Platform: MacOS 12.1 -->
  • How you installed Python: python.org
@rokm
Copy link
Member

rokm commented Jan 31, 2022

It's in site-packages/torchvision/.dylibs/libc++.1.0.dylib.

That said, those warnings are result of our dependency scanner lacking support for proper interpretation of rpaths, and are often just warnings. Those libraries may end up collected anyway, due to other dependency chains.

In fact, trying to freeze a simple import torchtext program, I think the problem is that torch dylibs are collected twice, once in application's top level directory (due to dependency analysis) and once in torch/lib (due to brute-force hook), and this duplication causes a crash. The only way to get the program working is to replace the libraries in top-level directory with symbolic links:

  • libc10.dylib -> torch/lib/libc10.dylib
  • libtorch.dylib -> torch/lib/libtorch.dylib
  • libtorch_cpu.dylib -> torch/lib/libtorch_cpu.dylib
  • libtorch_global_deps.dylib -> torch/lib/libtorch_global_deps.dylib
  • libtorch_python.dylib -> torch/lib/libtorch_python.dylib

@inferense
Copy link
Author

this works, thank you!

@bwoodsend bwoodsend transferred this issue from pyinstaller/pyinstaller Feb 1, 2022
@geoffr98
Copy link

Romk,

Can you please explain further your comment : " The only way to get the program working is to replace the libraries in top-level directory with symbolic links"

What top-level directory?

I am asking because I think I'm seeing the same problem. When I run pyinstaller I see the following warnings:
37358 WARNING: Cannot find path ./libtorch_cpu.dylib (needed by /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torchaudio/_torchaudio.so) 37358 WARNING: Cannot find path ./libtorchaudio.so (needed by /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torchaudio/_torchaudio.so) 37358 WARNING: Cannot find path ./libc10.dylib (needed by /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torchaudio/_torchaudio.so) 37358 WARNING: Cannot find path ./libtorch_python.dylib (needed by /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torchaudio/_torchaudio.so) 37358 WARNING: Cannot find path ./libtorch.dylib (needed by /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torchaudio/_torchaudio.so)

Then when I run the code I get the following messages:
[53127] WARNING: file already exists but should not: /var/folders/95/mfn5xj2s59jgjjch0b8f5jbw0000gn/T/_MEI8pNwtp/torch/_C.cpython-38-darwin.so [53127] WARNING: file already exists but should not: /var/folders/95/mfn5xj2s59jgjjch0b8f5jbw0000gn/T/_MEI8pNwtp/torch/_dl.cpython-38-darwin.so
and:
ImportError: dlopen(/var/folders/95/mfn5xj2s59jgjjch0b8f5jbw0000gn/T/_MEI8pNwtp/torchaudio/_torchaudio.so, 2): Library not loaded: @loader_path/../libtorchaudio.so Referenced from: /private/var/folders/95/mfn5xj2s59jgjjch0b8f5jbw0000gn/T/_MEI8pNwtp/torchaudio/_torchaudio.so

@rokm
Copy link
Member

rokm commented Feb 25, 2022

What top-level directory?

Top-level application directory of a onedir build.

@geoffr98
Copy link

I think I'm not understanding something as it's still not working. (same missing dylib errrors)

(I am actually trying a onefile build, but did test a onedir build with the same results)

I am running pyinstaller from the same directory where I created the linked files.

f01898e9b5db0000:SD_Release-2022_02_25-09_49 user$ ls -al
total 12872

....deleted some files for clarity ....
-rw-r--r--   1 rpm  staff      305 Feb 25 09:49 Run_SD.py
lrwxr-xr-x   1 rpm  staff       83 Feb 26 10:12 libc10.dylib -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torch/lib/libc10.dylib
lrwxr-xr-x   1 rpm  staff       85 Feb 26 10:12 libtorch.dylib -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torch/lib/libtorch.dylib
lrwxr-xr-x   1 rpm  staff       89 Feb 26 10:25 libtorch_cpu.dylib -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torch/lib/libtorch_cpu.dylib
lrwxr-xr-x   1 rpm  staff       92 Feb 26 10:12 libtorch_python.dylib -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torch/lib/libtorch_python.dylib
lrwxr-xr-x   1 rpm  staff       92 Feb 26 10:10 libtorchaudio.so -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torchaudio/lib/libtorchaudio.so
drwxr-xr-x   7 rpm  staff      224 Feb 25 09:49 snakers4_silero-vad_master

f01898e9b5db0000:SD_Release-2022_02_25-09_49 rpm$

And here is the pyinstaller command:

pyinstaller --paths='/Users/rpm/.pyenv/versions/3.8.8/Python.framework/Versions/3.8/lib/python3.8/site-packages/' --paths='/Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/' --hidden-import torch --hidden-import torchaudio --hidden-import platform --hidden-import msgpack --hidden-import ipaddress --hidden-import wave --hidden-import sounddevice --hidden-import soundfile --hidden-import Logger --hidden-import Load_config --hidden-import Smart_Device --hidden-import Audio_Sender --hidden-import json --hidden-import websockets --hidden-import websockets.legacy --hidden-import websockets.legacy.client --hidden-import websockets.legacy.server --hidden-import signal --hidden-import asyncio --clean --osx-bundle-identifier com.myprogram.SD --add-data ./snakers4_silero-vad_master:./snakers4_silero-vad_master --add-data *.bin:./ --add-data Sconfig.json:./ --onefile Run_SD.py

@rokm
Copy link
Member

rokm commented Feb 26, 2022

--paths='/Users/rpm/.pyenv/versions/3.8.8/Python.framework/Versions/3.8/lib/python3.8/site-packages/' --paths='/Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/'

If you find yourself adding your python's site-packages to search path, you're likely doing something wrong. If it actually solves some kind of problem, then you either have not activated your virtual environment, or you have installed PyInstaller in an environment that is different from your target virtual environment.

In either case, you're not going to be in for a pleasant experience - better sort out your environments before trying anything else.

--hidden-import torch --hidden-import torchaudio --hidden-import platform --hidden-import msgpack --hidden-import ipaddress --hidden-import wave --hidden-import sounddevice --hidden-import soundfile --hidden-import Logger --hidden-import Load_config --hidden-import Smart_Device --hidden-import Audio_Sender --hidden-import json --hidden-import websockets --hidden-import websockets.legacy --hidden-import websockets.legacy.client --hidden-import websockets.legacy.server --hidden-import signal --hidden-import asyncio

Are these really necessary?

--onefile

Don't use onefile until you have a onedir build up and running. The latter is much easier to debug in terms of checking for missing files.

-rw-r--r-- 1 rpm staff 305 Feb 25 09:49 Run_SD.py
lrwxr-xr-x 1 rpm staff 83 Feb 26 10:12 libc10.dylib -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torch/lib/libc10.dylib
lrwxr-xr-x 1 rpm staff 85 Feb 26 10:12 libtorch.dylib -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torch/lib/libtorch.dylib
lrwxr-xr-x 1 rpm staff 89 Feb 26 10:25 libtorch_cpu.dylib -> /Users/rpm/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torch/lib/libtorch_cpu.dylib

Just for the record, these symlinks are not what we were discussing earlier in this thread. We were talking about manually modifying the generated onedir dist directory, and replacing the duplicated .dylibs with symlinks to work around PyInstaller's shortcomings w.r.t. torch on macOS.

The error you were getting,

ImportError: dlopen(/var/folders/95/mfn5xj2s59jgjjch0b8f5jbw0000gn/T/_MEI8pNwtp/torchaudio/_torchaudio.so, 2): Library not loaded: @loader_path/../libtorchaudio.so Referenced from: /private/var/folders/95/mfn5xj2s59jgjjch0b8f5jbw0000gn/T/_MEI8pNwtp/torchaudio/_torchaudio.so

indicates that libtorchaudio.so is missing from the top-level frozen application's directory, so either it is not collected at all, or it is collected in a "wrong" directory (e.g., its original sub-directory, whereas PyInstaller's path rewriting expects it to be in the top-level directory).

Create a onedir build and check what the actual situation is.

(Although it is likely that torchaudio libs also reference the torch libs, so you'll end up with the same problem as was originally discussed here in the context of torchtext. But currently, you're probably hitting a different problem with that missing libtorchaudio.so).

@geoffr98
Copy link

  1. I've removed the --paths and it is working (was added along time ago and things have changed since).
  2. I tried removing the --hidden-imports and I get an error when I try to run the program ( ModuleNotFoundError: No module named 'ipaddress' ). This is the same error I was getting for each module and was fixed by adding them is as hidden-imports.
  3. Removing the --hidden-imports for torch and torchauido does get rid of the error message about the .dylibs, but when I run it complains ( ModuleNotFoundError: No module named 'torch' )
  4. If I keep the --hidden-imports I get the missing dylib warnings, but are in the onedir directory. On the other hand libtorchaudio.so is missing, and as expected when I try to run the program it complains that it is missing. (Note: running my program does work as expected when using python RunSD.py)
  5. If I copy the so into the dist directory and try to run the program I get a pile of errors:
    libc++abi.dylib: terminating with uncaught exception of type c10::Error: Type c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > could not be converted to any of the known types. Exception raised from operator() at ../aten/src/ATen/core/jit_type.h:1674 (most recent call first): frame #0: c10::Error::Error(c10::SourceLocation, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) + 98 (0x142383522 in libc10.dylib) frame #1: c10::detail::torchCheckFail(char const*, char const*, unsigned int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 106 (0x142381c3a in libc10.dylib) frame #2: c10::detail::getTypePtr_<c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > >::call()::'lambda'()::operator()() const + 260 (0x12c45dd34 in libtorch_cpu.dylib)

Any further suggestions?

@rokm
Copy link
Member

rokm commented Feb 26, 2022

If I copy the so into the dist directory and try to run the program I get a pile of errors:

This pile of errors is probably due to duplicated copies, as was discussed before in this thread. So you'll need to replace the copies in top-level directory with symlinks to the copies in corresponding sub-directories. This goes for the torch dylibs that I listed earlier in #375 (comment), but may also apply to the libtorchaudio.so if another copy was collected in the corresponding sub-directory.

@geoffr98
Copy link

Thanks - I now have a onedir build that is able to run!

After running pyinstaller I needed to:

  1. Delete from the base onedir directory and link the following:
rm libtorch_python.dylib
rm libtorch.dylib
rm libc10.dylib
rm libtorch_cpu.dylib

ln -s ./torch/lib/libtorch_python.dylib libtorch_python.dylib
ln -s ./torch/lib/libtorch.dylib libtorch.dylib
ln -s ./torch/lib/libc10.dylib libc10.dylib
ln -s ./torch/lib/libtorch_cpu.dylib libtorch_cpu.dylib
  1. Copy across libtorchaudio.so
    cp ~/.pyenv/versions/3.8.8/lib/python3.8/site-packages/torchaudio/lib/libtorchaudio.so .

Now that this is running, how do I make these same changes with a onefile build???

@rokm
Copy link
Member

rokm commented Feb 27, 2022

Now that this is running, how do I make these same changes with a onefile build???

Since PyInstaller does not support symlinks in a onefile build, the only way to make this work in a onefile build at the moment is to perform these cleanup steps at the beginning of your python program.

EDIT: and the missing libtorchaudio.so can be collected via --add-binary command-line option.

@geoffr98
Copy link

Thanks so much - I now have it fully working as a single file distribution !

Your responsiveness has been amazing.

@CarlGao4
Copy link
Contributor

CarlGao4 commented Jun 22, 2022

I also encountered this. I found that there is no hook for torchaudio but only for torch and torchvision. The hook for torch is very simple: datas = [(get_module_paths('torch')[1], 'torch'), ]. So I made a same hook-torchaudio.py: datas = [(get_module_paths('torchaudio')[1], 'torch'), ]. But it still tells:

1513 WARNING: Cannot find path ./libc10.dylib (needed by /Users/rosa/miniconda3/envs/DemucsPack/lib/python3.9/site-packages/torchaudio/_torchaudio.so)
1513 WARNING: Cannot find path ./libtorchaudio.so (needed by /Users/rosa/miniconda3/envs/DemucsPack/lib/python3.9/site-packages/torchaudio/_torchaudio.so)
1513 WARNING: Cannot find path ./libtorch_python.dylib (needed by /Users/rosa/miniconda3/envs/DemucsPack/lib/python3.9/site-packages/torchaudio/_torchaudio.so)
1513 WARNING: Cannot find path ./libtorch.dylib (needed by /Users/rosa/miniconda3/envs/DemucsPack/lib/python3.9/site-packages/torchaudio/_torchaudio.so)
1513 WARNING: Cannot find path ./libtorch_cpu.dylib (needed by /Users/rosa/miniconda3/envs/DemucsPack/lib/python3.9/site-packages/torchaudio/_torchaudio.so)

But all those binaries are packed. And when I run the program, I got this error:

pyimod04_ctypes.install.<locals>.PyInstallerImportError: Failed to load dynlib/dll '.../torchaudio/lib/libtorchaudio.so'. Most likely this dynlib/dll was not found when the application was frozen.

Sometimes it is not the error above:

ImportError: dlopen(.../torchaudio/_torchaudio.so, 2): Library not loaded: @loader_path/../libtorchaudio.so
  Referenced from: .../torchaudio/_torchaudio.so
  Reason: image not found

I tried to use otool and found the copied binary is different from the oringinal:

./lib/python3.9/site-packages/torchaudio/_torchaudio.so:
        @rpath/_torchaudio.so (compatibility version 0.0.0, current version 0.0.0)
        @rpath/libtorchaudio.so (compatibility version 0.0.0, current version 0.0.0)
        @rpath/libtorch_python.dylib (compatibility version 0.0.0, current version 0.0.0)
        @rpath/libtorch.dylib (compatibility version 0.0.0, current version 0.0.0)
        @rpath/libtorch_cpu.dylib (compatibility version 0.0.0, current version 0.0.0)
        @rpath/libc10.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 902.1.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
./dist/Test/torchaudio/_torchaudio.so:
        @loader_path/../_torchaudio.so (compatibility version 0.0.0, current version 0.0.0)
        @loader_path/../libtorchaudio.so (compatibility version 0.0.0, current version 0.0.0)
        @loader_path/../libtorch_python.dylib (compatibility version 0.0.0, current version 0.0.0)
        @loader_path/../libtorch.dylib (compatibility version 0.0.0, current version 0.0.0)
        @loader_path/../libtorch_cpu.dylib (compatibility version 0.0.0, current version 0.0.0)
        @loader_path/../libc10.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 902.1.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)

The error is same when I use --add-binary and --exclude-module torchaudio instead of self-made hook.

I can't copy them after the build is finished, because I need a .app file. Copying manually will cause the signature to fail.

@rokm
Copy link
Member

rokm commented Jun 22, 2022

I can't copy them after the build is finished, because I need a .app file. Copying manually will cause the signature to fail.

You can modify the generated .app bundle and then re-sign it manually...

@JMMarchant
Copy link

Is there a similar workaround (for either the onedir or the onefile solution) for packaging on Windows where the ability to create symlinks isn't available to the average user?

@rokm
Copy link
Member

rokm commented Sep 30, 2022

Is there a similar workaround (for either the onedir or the onefile solution) for packaging on Windows where the ability to create symlinks isn't available to the average user?

This issue and its work-around are macOS-specific, so no. If you have problems on Windows, open a new issue and provide the error traceback (as well as python and pyinstaller version), so we can see what's going on.

@AdrienLF
Copy link

AdrienLF commented Dec 5, 2022

Still having this issue with torch 1.12.1, pyinstaller 5.6.2 and pyinstaller-hooks-contrib 2022.13:

pyimod03_ctypes.install.<locals>.PyInstallerImportError: Failed to load dynlib/dll '/.../dist/.../libtorch_global_deps.dylib'. Most likely this dynlib/dll was not found when the application was frozen.

I added the symlinks, but the error stays the same.

I deleted the libs and symlinks in the top folder, same issue. I deleted the lib folder in pytorch in the onedir, same issue. Not sure what else to do, does anyone have an idea?

@rokm
Copy link
Member

rokm commented Dec 5, 2022

Still having this issue with torch 1.12.1, pyinstaller 5.6.2 and pyinstaller-hooks-contrib 2022.13:

pyimod03_ctypes.install.<locals>.PyInstallerImportError: Failed to load dynlib/dll '/.../dist/.../libtorch_global_deps.dylib'. Most likely this dynlib/dll was not found when the application was frozen.

I added the symlinks, but the error stays the same.

I deleted the libs and symlinks in the top folder, same issue. I deleted the lib folder in pytorch in the onedir, same issue. Not sure what else to do, does anyone have an idea?

When you were creating symlinks and removing libs, did you actually see libtorch_global_deps.dylib among the collected files? Because the error implies that the shared library was not collected in the first place, which is different from the issue that we were working-around here...

That said, if I freeze a simple import torch program, the libtorch_global_deps.dylib is collected by the hook into its original location, torch/lib/libtorch_global_deps.dylib (and it seems to be discovered there via ctypes). Can you check if it was collected there in your case? If not, how did you install torch - pip, conda, ...? Also, can we see the whole error traceback, so we can see where the ctypes import attempt originated from?

@AdrienLF
Copy link

AdrienLF commented Dec 5, 2022

Sure, I actually made a test with a new environment, so let me share it with you:

I created a conda env with only pyinstaller and pytorch. I used conda to install pytorch, with:

conda install pytorch torchvision torchaudio -c pytorch

Then I wrote a simple script, that runs correctly:

import torch

dev = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
print(dev)

Then, I just ran pyinstaller with its default settings:

pyinstaller Pyinstaller_pytorch.py

And this is the full error I have:


Traceback (most recent call last):
  File "PyInstaller/loader/pyimod03_ctypes.py", line 53, in __init__
  File "ctypes/__init__.py", line 374, in __init__
OSError: dlopen(/Users/adrienlefalher/Dropbox/PYCHARM/pyinstaller_test/dist/Pyinstaller_pytorch/torch/lib/libtorch_global_deps.dylib, 10): Library not loaded: @rpath/libmkl_intel_lp64.dylib

  Referenced from: /Users/adrienlefalher/Dropbox/PYCHARM/pyinstaller_test/dist/Pyinstaller_pytorch/torch/lib/libtorch_global_deps.dylib
  Reason: image not found

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "Pyinstaller_pytorch.py", line 1, in <module>
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "PyInstaller/loader/pyimod02_importers.py", line 499, in exec_module
  File "torch/__init__.py", line 191, in <module>
    _load_global_deps()
  File "torch/__init__.py", line 153, in _load_global_deps
    ctypes.CDLL(lib_path, mode=ctypes.RTLD_GLOBAL)
  File "PyInstaller/loader/pyimod03_ctypes.py", line 55, in __init__
pyimod03_ctypes.install.<locals>.PyInstallerImportError: Failed to load dynlib/dll '/Users/adrienlefalher/Dropbox/PYCHARM/pyinstaller_test/dist/Pyinstaller_pytorch/torch/lib/libtorch_global_deps.dylib'. Most likely this dynlib/dll was not found when the application was frozen.
[95460] Failed to execute script 'Pyinstaller_pytorch' due to unhandled exception!

It did collect the libs in pytorch/lib:

libc10.dylib
libshm.dylib
libtorch_cpu.dylib
libtorch_global_deps.dylib
libtorch_python.dylib
libtorch.dylib

And in the "base" directory, I also have the mkl libs:

libmkl_intel_ilp64.1.dylib
libmkl_intel_ilp64.dylib
libmkl_intel_lp64.1.dylib
libmkl_intel_lp64.dylib
libmkl_intel_thread.1.dylib
libmkl_intel_thread.dylib

@rokm
Copy link
Member

rokm commented Dec 5, 2022

So first, unless you absolutely have to use Anaconda, I suggest you to switch to python.org python + pip-installed packages when building with PyInstaller - because in addition to spotty Anaconda support (on top of already less-than-ideal torch support), you'll also end up with bloated builds, because we don't handle symlinks correctly, and so versioned dylibs collected from anaconda installation will end up as separate copies (instead of a single copy and symlinks).


Back to the issue, though: the problem is that torch/lib/libtorch_global_deps.dylib cannot find its dependency, libmkl_intel_lp64.dylib, which was originally discoverable via rpath, but this now points to incorrect directory due to relative paths being changed w.r.t. to original installation layout.

This can be fixed by manually adjusting the rpath to point to correct directory:

install_name_tool -rpath @loader_path/../../../../ @loader_path/../.. dist/<program>/torch/lib/libtorch_global_deps.dylib

Unfortunately, that's not the only lib with such problem. libmkl_intel_lp64.dylib also won't be able to find libiomp5.dylib; this time, because rpath is not set (and is probably inherited, but those inherited paths don't point to the correct location). The fix is to explicitly add rpath that points to the correct location (= @loader_path, i.e., the same directory as the library on which we are setting the rpath):

install_name_tool -add_rpath @loader_path dist/program/libmkl_intel_lp64.dylib
install_name_tool -add_rpath @loader_path dist/program/libmkl_intel_thread.1.dylib

(and so on for any other MKL library that has problem finding libiomp5.dylib).

Changing/adding rpath invalidates the signature (even if it is just ad-hoc one), so you might need to re-sign the modified libraries as well. If you did not use signing identity with PyInstaller, then you can just re-sing with ad-hoc identity, which is what PyInstaller uses by default.

@AdrienLF
Copy link

AdrienLF commented Dec 6, 2022

As per your instructions, I recreated the environment with pip. However, I still have an issue with torchvision. I could create a new issue for it, but I wanted to show it to you here:


torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: 
Traceback (most recent call last):
  File "src/__main__.py", line 3, in <module>
  File "src/initialisation/initialisation.py", line 10, in <module>
  File "src/front/remi_interface.py", line 17, in <module>
  File "src/front/IconoController.py", line 19, in <module>
  File "src/algorithms/ImagesToEmbeddings.py", line 13, in <module>
  File "src_model/Model.py", line 11, in <module>
  File "torchvision/__init__.py", line 5, in <module>
  File "torchvision/models/__init__.py", line 3, in <module>
  File "torchvision/models/densenet.py", line 32, in <module>
  File "torchvision/models/densenet.py", line 68, in _DenseLayer
  File "/Users/.../torch/_jit_internal.py", line 915, in _overload_method
    _check_overload_body(func)
  File "/Users/.../torch/_jit_internal.py", line 835, in _check_overload_body
    parsed_def = parse_def(func)
  File "/Users/.../torch/_sources.py", line 122, in parse_def
    sourcelines, file_lineno, filename = get_source_lines_and_file(
  File "/Users/.../torch/_sources.py", line 23, in get_source_lines_and_file
    sourcelines, file_lineno = inspect.getsourcelines(obj)
  File "inspect.py", line 1006, in getsourcelines
  File "inspect.py", line 831, in findsource
  File "linecache.py", line 46, in getlines
  File "linecache.py", line 137, in updatecache
  File "codecs.py", line 322, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 in position 16: invalid continuation byte

I found on stackoverflow to change the compat.py file in pyinstaller and replaced

out = out.decode(encoding)

with

out = out.decode(encoding, errors='ignore')

however, it doesn't look like a great solution, and doesn't solve the issue anyway.

@rokm
Copy link
Member

rokm commented Dec 6, 2022

This looks like an encoding problem with the source file that's required by torch's JIT. Based on the traceback, I think it should be torchvision/models/densenet.py.

Has this file been collected by PyInstaller (since we typically do not collect sources, and we do not have a torchvision hook that would force collection, unlike for base torch). If the file is collected, can you run diff against the original torchvision/models/densenet.py from your venv, and see if there is any difference? Or perhaps, if you try to replace the collected file with a fresh manual copy, does this fix the problem?

@AdrienLF
Copy link

AdrienLF commented Dec 6, 2022

I only have the .pyc file in torchvision in the pyinstaller, so it has not been collected.
Copy pasting the original torchvision folder into the pyinstaller torchvision folder then gives me this error at runtime:


/Users/adrienlefalher/Dropbox/PYCHARM/ICONO/dist/ICONO/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: Failed to load dynlib/dll '/Users/adrienlefalher/Dropbox/PYCHARM/ICONO/dist/ICONO/torchvision/image.so'. Most likely this dynlib/dll was not found when the application was frozen.
  warn(f"Failed to load image Python extension: {e}")

I really appreciate all your swift help, thank you.

@rokm
Copy link
Member

rokm commented Dec 6, 2022

I only have the .pyc file in torchvision in the pyinstaller, so it has not been collected.

Are you building with --debug noarchive or --debug all? If not, the .pyc files should be collected into the executable-embedded archive and not as individual files...

Copy pasting the original torchvision folder into the pyinstaller torchvision folder then gives me this error at runtime:


/Users/adrienlefalher/Dropbox/PYCHARM/ICONO/dist/ICONO/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: Failed to load dynlib/dll '/Users/adrienlefalher/Dropbox/PYCHARM/ICONO/dist/ICONO/torchvision/image.so'. Most likely this dynlib/dll was not found when the application was frozen.
  warn(f"Failed to load image Python extension: {e}")

Like before, there was likely more to that error than only last line (e.g., missing dependency).

If you copied the whole torchvision folder, you probably overwrote the shared libraries that PyInstaller processed. Instead of manual copying, can you try adding --collect-all torchvision to your PyInstaller command (we usually discourage use of this one, but it's the quickest way to ensure that source .py files are collected...).

@AdrienLF
Copy link

AdrienLF commented Dec 8, 2022

Rebuilding the env with venv instead of conda and using --collect-all torchvision solved my issue :) Thanks!

@oooooooo
Copy link

I had the same problem, and I solved it by rm & ln -s the dylibs in the torch.
I want to onefile because onedir solved.

Since PyInstaller does not support symlinks in a onefile build, the only way to make this work in a onefile build at the moment is to perform these cleanup steps at the beginning of your python program.

How can I do this exactly? Which option should I use?

@rokm
Copy link
Member

rokm commented Feb 20, 2023

Since PyInstaller does not support symlinks in a onefile build, the only way to make this work in a onefile build at the moment is to perform these cleanup steps at the beginning of your python program.

How can I do this exactly? Which option should I use?

There's no option for this. You need to implement the required steps in your python code, at the start of your program (using os.remove, os.symlink, etc.).

@oooooooo
Copy link

I have written code like this.

import os
import stanza
import sys

for filename in sorted(os.listdir('.')):
    print(f"check {filename}")

For --onedir, os.remove and os.symlink are possible. And segmentfaults could be resolved.

$ pyinstaller main.py --onedir
$ cd dist/main
$ ./main
check PIL
check base_library.zip
check certifi
check charset_normalizer
check google
check lib-dynload
check libXau.6.0.0.dylib
check libbrotlicommon.1.0.9.dylib
(snip)

In --onefile how can I find the following files?

  • libc10.dylib
  • libshm.dylib
  • libtorch_cpu.dylib
  • libtorch_global_deps.dylib
  • libtorch_python.dylib
  • libtorch.dylib
$ pyinstaller main.py --onefile
$ cd dist/main
$ ./main
check main

@rokm
Copy link
Member

rokm commented Feb 20, 2023

for filename in sorted(os.listdir('.')):

Instead of using '.', which assumes that your application directory is your current working directory (which is never true for onefile, and not necessarily true for onedir, either), you should either use os.path.dirname(__file__) or sys._MEIPASS, as described in docs.

@oooooooo
Copy link

Wow, it worked. Thank you very much.

@CarlGao4
Copy link
Contributor

CarlGao4 commented Apr 27, 2023

Has this issue been fixed since torch and torchaudio, torchtext 2.0 has been released? I'm no longer using macOS, but I had to manually copy the missing DLLs on Windows when I encountered this problem on macOS. I have just tested again, and my Windows application functions well without any further operation after packing with PyInstaller, so I guess that the issue will also be fixed once pytorch (and other torch utilities) is updated to 2.0

Can anybody try that?

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

Successfully merging a pull request may close this issue.

7 participants