在没有 python 的情况下将 py2app 应用程序发送到 Mac

Send py2app application to Mac without python

我有一个 tkinter 应用程序,我想将其分发给我的同事,他们没有安装 python。 我将 py2app 与以下 setup.py 文件

一起使用
from setuptools import setup

import sys
sys.setrecursionlimit(5000)

#APP would be the name of the file your code is in.
APP = ['Doughnut_stress.py']
DATA_FILES = ['C20.icns']
#The Magic is in OPTIONS.
OPTIONS = {
    'packages': ['tkinter', 'matplotlib'],
    'includes': ['tkinter'],
    'argv_emulation': False,
    'iconfile': 'C20.icns', #change app.icns to the image file name!!!
    'plist': {
        'CFBundleName': 'Axial bearing program',
        'CFBundleDisplayName': 'Axial bearing program',
        'CFBundleGetInfoString': "Calculates C20 axial bearing",
        'CFBundleVersion': "0.0.0",
        'CFBundleShortVersionString': "0.0.0",
        'NSHumanReadableCopyright': u"Copyright © 2020, Component 2.0 A/S, All Rights Reserved"
    }
    }

setup(
    app=APP,
    name='Axial bearing program', #change to anything
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)

然后我使用

python setup.py py2app

将程序编译成应用程序。请注意,我已将 python 符号链接到 python3。我的python3是3.7.5版本,是通过MacPorts安装的。 py2app是0.20版本,tkinter是8.6版本

程序编译正常,我可以从终端 运行 或双击应用程序文件,它按预期运行。

但是,当我将它发送给我的同事并尝试通过双击该应用程序从他的计算机打开它时,我会弹出一个窗口,我可以在其中选择 "Open Console" 或 "Terminate" . 如果我 运行 通过终端程序(通过 运行ning APP_NAME.app/Contents/MacOS/APP_NAME)我得到以下错误

Traceback (most recent call last):
  File "/Users/prm/Downloads/Component 2.0 axial bearing program.app/Contents/Resources/__boot__.py", line 416, in <module>
    _run()
  File "/Users/prm/Downloads/Component 2.0 axial bearing program.app/Contents/Resources/__boot__.py", line 394, in _run
    exec(compile(source, path, "exec"), globals(), globals())
  File "/Users/prm/Downloads/Component 2.0 axial bearing program.app/Contents/Resources/Doughnut_stress.py", line 31, in <module>
    root = Tk()
  File "tkinter/__init__.pyc", line 2023, in __init__
_tkinter.TclError: Can't find a usable init.tcl in the following directories: 
    /opt/local/lib/tcl8.6 {/Users/prm/Downloads/Component 2.0 axial bearing program.app/Contents/lib/tcl8.6} {/Users/prm/Downloads/Component 2.0 axial bearing program.app/lib/tcl8.6} {/Users/prm/Downloads/Component 2.0 axial bearing program.app/Contents/library} {/Users/prm/Downloads/Component 2.0 axial bearing program.app/library} {/Users/prm/Downloads/Component 2.0 axial bearing program.app/tcl8.6.9/library} /Users/prm/Downloads/tcl8.6.9/library



This probably means that Tcl wasn't installed properly.

2020-01-20 15:54:28.439 Component 2.0 axial bearing program[34251:2906750] Component 2.0 axial bearing program Error

我还可以 运行 APP_NAME.app/Contents/MacOS/python 中包含的 python 文件,这会产生此错误

Could not find platform independent libraries <prefix>
Could not find platform dependent libraries <exec_prefix>
Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
Fatal Python error: initfsencoding: unable to load the file system codec
ModuleNotFoundError: No module named 'encodings'

Current thread 0x000000010d0f8dc0 (most recent call first):
Abort trap: 6

前段时间有人在 Reddit 上发帖讨论过这个问题,但没有得到回复 https://www.reddit.com/r/learnpython/comments/c1on6f/py2app_in_a_mac_without_python/

我该如何解决这个问题,以便分发我的 python 应用程序?

除了我使用的是 pygame,我遇到了与您完全相同的问题。这是一个快速修复:

而不是简单地 python setup.py py2app,尝试:

python setup.py py2app --packages="encodings"

(对我来说,我做了 python setup.py py2app --packages="pygame" 并且成功了)

我的设置出现同样的问题(缺少 init.tcl):

  • macOS 10.15.5,带有 Python 3.7.7 解释器的 venv(包括 TCL8.6),py2app 0.21
  • 事实证明TCL既没有被py2app复制到venv也没有复制到.app,所以生成的.app在Python安装目录(/Library/Frameworks/Python.[=48= .7/lib/tcl8.6) 在我的设置中。
    • 然而,这在没有安装 Python 的设置中不可用 -> 错误

解决方案

当我手动复制时:

- /Library/Frameworks/Python.framework/Versions/3.7/lib/tcl8
- /Library/Frameworks/Python.framework/Versions/3.7/lib/tcl8.6
- /Library/Frameworks/Python.framework/Versions/3.7/lib/tk8.6

- path_to_venv/lib

py2app 将从那里获取它并将其存储在以下位置的 .app 中:

- path_to_project/dist/myApp.app/Contents/Resources/lib/

并从这里通过 python 代码

找到

后续步骤

我看到 2 个主要选项如何自动化它:

  1. 在 py2app 安装文件中检查 venv 结构中的 TCL 可用性,如果不可用则从系统位置复制它
  2. 直接在py2app中实现