python3 pyinstaller 打包后执行文件运行错误 No such file or directory 和 Cannot load native module 解决方法

卢磊
2023-12-01

 

目录

实例1.No such file or directory 错误  --add-binary 参数解决

实例2.Cannot load native module 错误 强制引入解决

总结


使用 pyinstaller 打包 python3 程序经常会出现 No such file or directory  或 Cannot load native module 错误 都是因为需要的文件未打入到最后的执行文件中,此时在使用pyinstaller时需要用到参数 --add-binary 以及在入口文件函数中加入使用代码 来解决

 

实例1.No such file or directory 错误  --add-binary 参数解决

打包入口python文件:

pyinstaller -F -w test.py

运行打包后的执行文件:

[root@0109c795032d src]# ./dist/test
Traceback (most recent call last):
  File "test.py", line 19, in <module>
    from salt.client.ssh import ssh_py_shim
  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/test/pyimod03_importers.py", line 540, in exec_module
  File "salt/client/ssh/__init__.py", line 205, in <module>
  File "salt/utils/files.py", line 396, in fopen
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/_MEIudOUhL/salt/client/ssh/ssh_py_shim.pyc'
[5034] Failed to execute script test

通过报错可以看到是缺少文件,pyinstaller时增加 --add-binary 参数即可,具体如下:

pyinstaller -F -w test.py \
--add-binary="/opt/python3/lib/python*/site-packages/salt/client/ssh/ssh_py_shim.py:salt/client/ssh"

参数解释:

--add-binary的语法是:--add-binary <SRC;DEST or SRC:DEST> 

src是打包后的执行文件,缺少的文件在本机的位置,

dest是运行执行文件时,需要动态拷贝到的目录位置,dest是相对目录,

打包后的执行文件绝对路径 都是从 /tmp/_MEIudOUhL/ 开始的 这里是_MEIudOUhL是自动产生的每次不一样

dest只需要写相对目录即可,比如这里是 salt/client/ssh

最后的绝对路径就是 /tmp/_MEIudOUhL/salt/client/ssh 

src和dest分隔符 linux下是冒号: windows下是分号;

添加此参数含义就是 把本机的 ssh_py_shim.py 文件打包到执行文件中,并且运行时动态释放到 相对目录 salt/client/ssh 中,从而解决 错误提示 的找不到文件问题

需要注意:

错误提示中报错找不到 ssh_py_shim.pyc 但此处引入的时 ssh_py_shim.py

这是因为 在整个函数调用栈中 倒数第二层 salt/client/ssh/__init__.py 里边有如下代码:

if not is_windows():
    shim_file = os.path.join(os.path.dirname(__file__), "ssh_py_shim.py")
    if not os.path.exists(shim_file):
        # On esky builds we only have the .pyc file
        shim_file += "c"
    with salt.utils.files.fopen(shim_file) as ssh_py_shim:
        SSH_PY_SHIM = ssh_py_shim.read()

可以看到 ssh_py_shim.py 文件也是可以的,所以只要找到 ssh_py_shim.py 或者 ssh_py_shim.pyc 在 "salt/utils/files.py", line 396, 的 fopen 函数中都不会 出现找不到文件错误

官网实例:

https://pyinstaller.readthedocs.io/en/stable/usage.html#shortening-the-command

里边展示了 多个 --add-binary 和 其他相关参数的使用实例

 

实例2.Cannot load native module 错误 强制引入解决

pyinstaller 打包运行后错误如下:

  File "test/test.py", line 41, in init_test
  File "salt/transport/client.py", line 27, in factory
  File "salt/utils/asynchronous.py", line 70, in __init__
  File "salt/transport/client.py", line 131, in factory
  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/test/pyimod03_importers.py", line 540, in exec_module
  File "salt/transport/zeromq.py", line 23, 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/test/pyimod03_importers.py", line 540, in exec_module
  File "salt/crypt.py", line 65, 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/test/pyimod03_importers.py", line 540, in exec_module
  File "Cryptodome/Cipher/__init__.py", line 27, 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/test/pyimod03_importers.py", line 540, in exec_module
  File "Cryptodome/Cipher/_mode_ecb.py", line 35, in <module>
  File "Cryptodome/Util/_raw_api.py", line 297, in load_pycryptodome_raw_lib
OSError: Cannot load native module 'Cryptodome.Cipher._raw_ecb': Trying '_raw_ecb.cpython-39-x86_64-linux-gnu.so': cannot load library '/tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.cpython-39-x86_64-linux-gnu.so': /tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.cpython-39-x86_64-linux-gnu.so: cannot open shared object file: No such file or directory.  Additionally, ctypes.util.find_library() did not manage to locate a library called '/tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.cpython-39-x86_64-linux-gnu.so', Trying '_raw_ecb.abi3.so': cannot load library '/tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.abi3.so': /tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.abi3.so: cannot open shared object file: No such file or directory.  Additionally, ctypes.util.find_library() did not manage to locate a library called '/tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.abi3.so', Trying '_raw_ecb.so': cannot load library '/tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.so': /tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.so: cannot open shared object file: No such file or directory.  Additionally, ctypes.util.find_library() did not manage to locate a library called '/tmp/_MEIPh0VXD/Cryptodome/Util/../Cipher/_raw_ecb.so'

此错误也开始缺少文件,缺少 _raw_ecb.cpython-39-x86_64-linux-gnu.so 或 _raw_ecb.so 首先加入 --add-binary

pyinstaller -F -w test.py \
--add-binary="/opt/python3/lib/python*/site-packages/Crypto/Cipher/_raw_ecb.cpython-39-x86_64-linux-gnu.so:Cryptodome/Util/../Cipher"

打包运行还是报此错误,反复检查 源文件 目标地址 都是正确的,

此时需要 复制在后边工程中引用 _raw_ecb 造成错误的代码 到入口函数

让pyinstaller充分知道我会使用 _raw_ecb.cpython-39-x86_64-linux-gnu.so 中的函数,从而强制打包此so文件

加入代码具体如下:

# 入口
if __name__ == "__main__":
    # 用于 pyinstaller 无法打包 salt 库
    try:
        ip = "127.0.0.1"
        port = 1234

        config = {
            'id': 'root',
            'log_level': 'debug',
            'master_ip': ip ,
            'master_port': port,
            'auth_timeout': 5,
            'auth_tries': 1,
            'master_uri': f'tcp://{ip}:{port}'
        }

        salt.transport.client.ReqChannel.factory(config, crypt='clear')
    except Exception as e:
        pass

再用pyinstaller打包

pyinstaller -F -w test.py \
--add-binary="/opt/python3/lib/python*/site-packages/Crypto/Cipher/_raw_ecb.cpython-39-x86_64-linux-gnu.so:Cryptodome/Util/../Cipher"

此时不用 --add-binary 也是应该可以的,未测试了

 

总结

出现错误 总体思路 还是通过函数调用栈来 倒推分析,

如果出现找不到文件情况 可以使用 

1.--add-binary 参数

2.强制引入

来解决问题

 

 

 类似资料: