For years, NVDA has used Py2exe to package Python code into something that is executable on a system that doesn't have Python installed. For Python 2.7, we have been at Py2exe 0.6.9 (introduced in 2008) for a long time. For Python 3, a new version has been introduced in 2014 which looks like a rewrite. The last official release (0.9.2.2) was introduced in 2014.

Starting with Python 3.6 (end 2016) however, Python contains a backwards incompatible change of the byte code format that is not supported by the official py2exe.

Note that many parts of the build process of NVDA are handled by SCons. This includes:

  • Compiling, linking and code signing all the additional libraries, such as NVDAHelper, liblouis, minhook, ESPeak
  • Compiling ESpeak dictionaries, CLDR data and gettext translations
  • Converting documentation to HTML using TXT2Tags, see #8734

In summary, Scons deals with everything that is required to run NVDA from source, Py2exe is not involved in that process. Py2exe gets called as soon as a distribution of NVDA is created. The portable distribution that Py2exe creates is then packed into a launcher using NSiS.

Requirements

Before deciding on what packaging tool to use, this section lists the requirements for a packaging tool, based on the work that is now performed by Py2exe.

  1. Byte compile every source file into a *.pyc or *.pyo file. Note that for Python 3, only the *pyc files remain.

  2. Byte compile every Python dependency (comtypes, pyserial, etc.) required to run NVDA.

  3. Collect Python extension modules (*.pyd files)

  4. Bundle the several byte compiled files into a library.zip file in the main folder of the distribution.

  5. Exclude several unneeded modules

  6. Create executables from certain source files:

    source destination(s) description
    nvda.pyw nvda_noUIAccess.exe, nvda_uiAccess.exe Main executables (see below)
    nvda_eoaProxy.pyw nvda_eoaProxy.exe Used to integrate in Windows 7 EOA center
    nvda_slave.pyw nvda_slave.exe Used for add-on installation from shell, elevated rights during installation, etc.
  7. Bundle a manifest with the executables. Theoretically, this can also be done using SCons, though in contrast to what I thought earlier, there is no code within the current scons structure of NVDA that can be reused for this.

  8. Make sure that the UIAccess flag is added to the manifest of nvda_uiAccess.exe and nvda_eoaProxy.exe. Strictly spoken, this is code that has been added to our subclass of build_exe.py2exe in order to inject the UIAccess flag into the manifest created by py2exe. However, droppign py2exe in favour of another tool might force us to completely rewrite this logic.

  9. Embed the NVDA logo into the executables as icon.

  10. Set several version info flags in the version info resource of the executables.

  11. Collect several system dll's not available on every system. This includes visual C++ redistributables.

  12. Collect data files created using SCons, such as several libraries, language files, documentation, etc.

Alternatives

According to research and ideas from others, there are four packaging/freezing options that can be used with Python 3. The following sections provide short descriptions along with pros and cons.

Py2exe fork by @albertosottile

See https://github.com/albertosottile/py2exe

Thankfully, @albertosottile contacted us in #8375 (comment), commenting that he picked up Py2exe where it has been abandoned in 2014. This resulted into a release of Py2exe 0.93.0. This version is said to work with Python 3.6 and 3.7.

Pros

  • Stick to the same tool as used before. Though heavily changed under the hood, it still promises to be mostly compatible with older setup files. According to the original readme:

    It is planned to achive full compatibility with the setup-scripts for Python 2; however this is probably not yet the case.

  • Probably the least efford if @albertosottile's fork proves to be working.

Cons

  • A look at the code of Py2exe for Python 3 seems to reveal that the support to create manifests is not yet implemented, that is, there is lots of commented out code that seems to origin from the Python 2 version. Having said that, the logic to embed resource files in the executable still seems to be available and an example setup files shows an alternative method to embed the manifest. It's just not compatible with the current approach in our setup.py.
  • @albertosottile's fork of this project is pretty new. Some details:

Requirements scheme

Feature supported
Create multiple executables Yes
Bundle manifest Yes, but differently than before, might require pr to upstream
UIAccess No explicit support, see manifest
Embed logo Yes
Set version info Yes
Collect system dll's Yes
Collect external Python dependencies and *.pyd files Yes
Collect data files Yes
Library file Yes

PyInstaller

PyInstaller is an alternative tool to build executables. It also supports byte code encryption, though that seems not very useful in the case of NVDA.

Pros

  • This tool supports most functionality we need out of the box, including stuff that's now handled by scons, such as:

    • Code signing
    • Full automatic support for CRTs
    • Manifests with UAC
  • It is very actively maintained.

Cons

  • Building multiple executables at once seems to be broken

  • It does not integrate very well with distutils. It looks like the PyInstaller documentation suggests using a batch file to write down command line commands. Alternatively, you can use a spec file. Writing a setup.py for your package seems unsupported. Having said that, we're now calling a python interpretter from scons to execute the setup script, so basically, we're using a command line call already. This is therefore no show stopper, just a change of approach.

  • More importantly, I've seen ridiculous tracebacks with one of my test applications referring to pyinstaller:

     Traceback (most recent call last):
    File "main.py", line 1, in <module>
    File "c:\python36\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
    exec(bytecode, module.__dict__)
    File "core.py", line 5, in <module>
    File "c:\python36\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
    exec(bytecode, module.__dict__)

    It looks like every import is somehow redirected to pyInstaller. I'm pretty sure this will cause issues with our use of comtypes com interface modules, globalPlugins, etc. which rely on appending paths to the module path variable. Showing raw paths to the python directory also looks a bit cheap, but I recall that with py2exe, we also had to work around this.

Requirements scheme

Here is the official features page from PyInstaller

Feature supported
Create multiple executables No, broken in v3.0, see pyinstaller/pyinstaller#1527
Bundle manifest Yes
UIAccess Yes
Embed logo Yes
Set version info Yes
Collect system dll's Yes
Collect external Python dependencies and *.pyd files Yes
Collect data files Yes
Library file No, seems to require a custom implementation using scripting according to features section, but no information found in documentation so far

cx_Freeze

This is an alternative that integrates well with distutils. Note that it is far from compatible with py2exe, so setup.py would still require an overhaul. Running cx_Freeze also results into a package structure that is very similar to the one py2exe creates, including a librar .zip file in the lib sub directory. The default settings do not create a zip file, but that can be customized easily.

cx_Freeze is hosted on GitHub. We can include it as a separate submodule. Though it requires some c code to be compiled, that shouldn't be that much of a problem and takes less than 20 seconds, so that doesn't justify an inclusion in misc deps in my opinion.

Pros

  • We're using it for a @BabbageCom Python project including wx and comtypes, and it works pretty well for our aims. So, I do have experience with it.
  • It can replace paths shown in tracebacks
  • Can include MSVC redistributable automatically
  • Can include additional files in the library zip file

Cons

  • No official build supporting Python 3.7, we'd have to build from source.

  • There is no built-in support for manifests and setting the UI Access privilege level. We will probably have to implement this manually, either by expanding setup.py or by building the base executables ourselves.

  • By default, cx_freeze assumes that all python stuff is in a lib sub directory (i.e. in lib/library.zip) rather than in the root of the folder where the executables live. This is not easily customisable and seems to be hard-coded behaviour. We're using the lib folder for our x86 libraries, storing the python library in there might be a bit ugly.

  • When there is a startup error, cx_Freeze shows an error message box including the name of cx_Freeze itself. This might be confusing for users.

  • The last commit for the project dates from september 2018. There are 260 open issues, including two from myself:

    Both issues haven't gotten any attention.

Requirements scheme

Feature supported
Create multiple executables Yes
Bundle manifest No, should probably be embedded in base executables
UIAccess No
Embed logo Yes
Set version info Yes
Collect system dll's Yes
Collect external Python dependencies and *.pyd files Yes
Collect data files Yes
Library file Yes

Nuitka

Suggestion by @ctoth in #8375 (comment)

Nuitka chooses a completely different approach. Instead of compiling the Python code to byte code and bundling a loader with it, it converts all code to c and then compiles it using VC++ and links it against the Python library. It also claims to be faster than CPython.

PROS

  • Nuitka might improve performance.

Cons

  • As all python code has to be converted to C++ and then compiled, creating a distribution of NVDA is going to be a time-consuming process. We might be able to provide pre-compiled obj files for static dependencies (such as wx and comtypes). This requires some investigation, to find out and is currently undocumented.
  • It looks like Nuitka doesn't support changing the path of modules. I'm not even sure whether it would be possible to make Nuitka import python code bundled in add-ons. This is something to find out if we decide to explore this direction further.
  • THere is a huge runtime difference between running NVDA from source and from a distribution.

Requirements scheme

Feature supported
Create multiple executables Yes
Bundle manifest No
UIAccess No
Embed logo Yes
Set version info No
Collect system dll's No
Collect external Python dependencies and *.pyd files Unsure
Collect data files No
Library file No

HO to proceed?

Based on the above outline, I propose the following order of investigation of our options:

  1. Devote time to investigate using the Py2exe fork by @albertosottile. He seems to be pretty interested in our possible efforts to freeze NVDA with his fork. It might also be the least effort on our end. However, it would help to know what his goals are with the project, and whether he's willing to maintain it in the near and far future. @albertosottile: Would you be able to elaborate on this?
  2. Try to get in touch with the PyInstaller developers to point them at the main cons listed above. The most major question would be whether there would be support for addons and custom comtypes com interfaces.
  3. Try to get in touch with @anthony-tuininga to ask him about whether he's intending to continue the active development of cx_Freeze.
  4. Based on the outcome of 2 and 3 when 1 fails, decide between PyInstaller and cx_Freeze. In the current state, cx_Freeze has my preference, but that preference may change.

Note that option 1, 2 and 3 could be worked on in parallel. I'm tempted to consider Nuitka being out of scope for now.

Python3.7 exe编译工具对比zz的更多相关文章

  1. Java逆向武器库_反编译工具

    1.反编译工具之_jd-gui 官网下载地址:http://java-decompiler.github.io/#jd-gui-download 使用: 下载后解压直接使用即可. jd-gui的优势是 ...

  2. Java 反编译工具哪家强?对比分析瞧一瞧

    前言 Java 反编译,一听可能觉得高深莫测,其实反编译并不是什么特别高级的操作,Java 对于 Class 字节码文件的生成有着严格的要求,如果你非常熟悉 Java 虚拟机规范,了解 Class 字 ...

  3. Python3 与 C# 面向对象之~继承与多态 Python3 与 C# 面向对象之~封装 Python3 与 NetCore 基础语法对比(Function专栏) [C#]C#时间日期操作 [C#]C#中字符串的操作 [ASP.NET]NTKO插件使用常见问题 我对C#的认知。

    Python3 与 C# 面向对象之-继承与多态   文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html 目录: 2.继承 ¶ 2.1.单继 ...

  4. 工欲善其事,必先利其器 软件工具开发关键词 protractor自动化测试工具 RegexBuddy正则 CodeSmith,LightSwitch:代码生成 CheatEngine:玩游戏修改内存值必备神器 ApkIDE:Android反编译工具 Reflector:反编译dll动态链接库

    工欲善其事,必先利其器 本文版权归翟士丹(Stan Zhai)和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利. 原文地址:http ...

  5. 通过ILSpy反编译工具和ilasm修改.NET程序

    文章来源:https://blog.peos.cn/2016/12/26/ilspy-ilasm-ildasm-net.html 金庸群侠传X中,田青文.木婉清.王语嫣的点穴游戏忒难过了,所以上网摸索 ...

  6. apk反编译工具

    反编译工具: apktool:资源文件获取,可以提取出图片文件和布局文件进行使用查看 dex2jar:将apk反编译成Java源码(classes.dex转化成jar文件) jd-gui:查看APK中 ...

  7. eclipse安装反编译工具

    身为一名程序员来说,日常最常做的就是编写代码和查看别人写好的源代码了,有时候打开别人写的class文件发现根本不是自己想要的,所以给大家介绍一种eclipse中反编译class文件的工具. 第一步:下 ...

  8. .net混淆、反编译工具调查

    常用的工具列表[比较常见的] 混淆器.加密 Dotfuscator VS默认带的工具,不过是个社区版 强度不大 dotNET Reactor 使用了NativeCode 和混淆的形式 Xenocode ...

  9. Eclipse反编译工具Jad及插件JadClipse配置

    Jad是一个Java的一个反编译工具,是用命令行执行,和通常JDK自带的java,javac命令是一样的.不过因为是控制台运行,所以用起来不太方便.不过幸好有一个eclipse的插件JadClipse ...

随机推荐

  1. 【洛谷5439】【XR-2】永恒(树链剖分,线段树)

    [洛谷5439][XR-2]永恒(树链剖分,线段树) 题面 洛谷 题解 首先两个点的\(LCP\)就是\(Trie\)树上的\(LCA\)的深度. 考虑一对点的贡献,如果这两个点不具有祖先关系,那么这 ...

  2. netCore3.0+webapi到前端vue(前端)

    前篇已经完成后端配置并获取到api连接 https://www.cnblogs.com/ouyangkai/p/11504279.html 前端项目用的是VS code编译器完成 vue 第一步 引入 ...

  3. 宣布Visual Studio Code Installer for Java

    自从第一个Java语言服务器在微软苏黎世办公室的一个小型会议室的黑客马拉松中开发已经差不多3年了,该会议室的人员来自Red Hat,IBM,Codenvy和Microsoft,后来成为Visual S ...

  4. yii2 HeadersAlreadySentException 报错

    An Error occurred while handling another error:exception 'yii\web\HeadersAlreadySentException' with ...

  5. css样式篇

    list-style list-style-type     设置列表项标记的类型 list-style-position  可设置outside(列表项目标记放置在文本以内,且环绕文本根据标记对齐) ...

  6. 元素增删事件DOMNodeInserted和DOMNodeRemoved

    监听元素变化的三种方法: 对于表单类型的控件,使用onchange事件最好. 使用DOMNodeInserted和DOMNodeRemoved事件 使用定时器定时检测(下策) 有时需要给一个class ...

  7. 前端开发JS——数组

    25.数组 1)声明数组: ①构造函数创建数组 var arr = new Array(); console.log(arr):        //[]   var arr = new Array(2 ...

  8. iOS处理含中文的请求链接

    NSString *urlStr = @""; // 将中文URL进行转码 urlStr = [urlStr stringByAddingPercentEscapesUsingEn ...

  9. Visual Studio Code 远程开发探秘

    摘要: IDE新时代! 作者:SHUHARI 的博客 原文:Visual Studio Code 远程开发探秘 Fundebug按照原文要求转载,版权归原作者所有. 在以前的文章 有趣的项目 - 在浏 ...

  10. windows 如何cmd启动redis

    运行cmd 然后到redis路径 运行命令: redis-server redis.windows.conf