From d438e25b9b6e1993a8839ef811b2e2533c17bf40 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 15 Feb 2016 22:16:09 -0800 Subject: [PATCH] Successfully builds a .exe with Python3/Qt5. Switched from pyinstaller to py2exe. (#261) --- BUILD.md | 6 +- install/build_exe.bat | 6 +- install/onionshare-win.spec | 46 ----- install/onionshare.nsi | 171 ++++++------------ .../onionshare.py} | 10 +- setup.py | 25 +++ 6 files changed, 91 insertions(+), 173 deletions(-) delete mode 100644 install/onionshare-win.spec rename install/{onionshare-launcher.py => windows_scripts/onionshare.py} (75%) diff --git a/BUILD.md b/BUILD.md index 1055ac71..088392bf 100644 --- a/BUILD.md +++ b/BUILD.md @@ -104,7 +104,7 @@ These instructions include adding folders to the path in Windows. To do this, go First, download and install the 32-bit (x86) version of Python 3.4.x from https://www.python.org/downloads/windows/. You need 3.4 instead of 3.5 because PyQt5 was built with 3.4. Add `C:\Python34` and `C:\Python34\Scripts` to the path. -Open a command prompt and install some dependencies with pip: `pip install flask stem pyinstaller` +Open a command prompt and install some dependencies with pip: `pip install flask stem py2exe` Download and install Qt5 from https://www.qt.io/download-open-source/. I downloaded `qt-unified-windows-x86-2.0.2-2-online.exe`. There's no need to login to a Qt account during installation. Make sure you install the latest Qt 5.x. @@ -133,12 +133,12 @@ If you want to sign binaries with Authenticode: ### To make a .exe: -* Open a command prompt, cd into the onionshare directory, and type: `pyinstaller -y install\onionshare-win.spec`. Inside the `dist` folder there will be a folder called `onionshare` with `onionshare.exe` in it. +* Open a command prompt, cd into the onionshare directory, and type: `python setup.py py2exe`. `onionshare.exe` and all of its supporting files will get created inside the `dist` folder. ### To build the installer: Note that you must have a codesigning certificate installed in order to use the `install\build_exe.bat` script, because it codesigns `onionshare.exe`, `uninstall.exe`, and `OnionShare_Setup.exe`. -s + Open a command prompt, cd to the onionshare directory, and type: `install\build_exe.bat` This will prompt you to codesign three binaries and execute one unsigned binary. When you're done clicking through everything you will have `dist\OnionShare_Setup.exe`. diff --git a/install/build_exe.bat b/install/build_exe.bat index 869d734e..b68566f4 100644 --- a/install/build_exe.bat +++ b/install/build_exe.bat @@ -1,8 +1,8 @@ -REM use pyinstaller to builder a folder with onionshare.exe -pyinstaller -y install\onionshare-win.spec +REM use py2exe to builder a folder with onionshare.exe +python setup.py py2exe REM sign onionshare.exe -signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 dist\onionshare\onionshare.exe +signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 dist\onionshare.exe REM build an installer, dist\OnionShare_Setup.exe makensis.exe install\onionshare.nsi diff --git a/install/onionshare-win.spec b/install/onionshare-win.spec deleted file mode 100644 index 332bee2d..00000000 --- a/install/onionshare-win.spec +++ /dev/null @@ -1,46 +0,0 @@ -# -*- mode: python -*- -a = Analysis(['onionshare-launcher.py'], - #hiddenimports=['onionshare', 'onionshare_gui'], - #excludes=['_tkinter'], - hookspath=None, - runtime_hooks=None) -a.datas += [ - ('images/logo.png', 'images/logo.png', 'DATA'), - ('images/drop_files.png', 'images/drop_files.png', 'DATA'), - ('images/server_stopped.png', 'images/server_stopped.png', 'DATA'), - ('images/server_started.png', 'images/server_started.png', 'DATA'), - ('images/server_working.png', 'images/server_working.png', 'DATA'), - ('locale/de.json', 'locale/de.json', 'DATA'), - ('locale/en.json', 'locale/en.json', 'DATA'), - ('locale/eo.json', 'locale/eo.json', 'DATA'), - ('locale/es.json', 'locale/es.json', 'DATA'), - ('locale/fi.json', 'locale/fi.json', 'DATA'), - ('locale/fr.json', 'locale/fr.json', 'DATA'), - ('locale/it.json', 'locale/it.json', 'DATA'), - ('locale/nl.json', 'locale/nl.json', 'DATA'), - ('locale/no.json', 'locale/no.json', 'DATA'), - ('locale/pt.json', 'locale/pt.json', 'DATA'), - ('locale/ru.json', 'locale/ru.json', 'DATA'), - ('locale/tr.json', 'locale/tr.json', 'DATA'), - ('version', 'version', 'DATA'), -] -pyz = PYZ(a.pure) -exe = EXE(pyz, - a.scripts, - exclude_binaries=True, - name='onionshare.exe', - debug=False, - strip=False, - upx=True, - icon='install/onionshare.ico', - console=False) -coll = COLLECT(exe, - a.binaries, - a.zipfiles, - a.datas, - Tree('onionshare', prefix='onionshare'), - Tree('onionshare_gui', prefix='onionshare_gui'), - [('LICENSE', 'LICENSE', 'DATA')], - strip=False, - upx=True, - name='onionshare') diff --git a/install/onionshare.nsi b/install/onionshare.nsi index 547212ff..a4c87b07 100644 --- a/install/onionshare.nsi +++ b/install/onionshare.nsi @@ -1,9 +1,9 @@ !define APPNAME "OnionShare" -!define BINPATH "..\dist\onionshare" +!define BINPATH "..\dist" !define ABOUTURL "https:\\onionshare.org\" # change these with each release -!define INSTALLSIZE 31616 +!define INSTALLSIZE 60104 !define VERSIONMAJOR 0 !define VERSIONMINOR 8 !define VERSIONSTRING "0.8.1" @@ -61,27 +61,13 @@ FunctionEnd Section "install" # application SetOutPath "$INSTDIR" - File "onionshare.ico" File "${BINPATH}\onionshare.exe" - File "${BINPATH}\license" - SetOutPath "$INSTDIR\onionshare" - File "${BINPATH}\onionshare\__init__.py" - File "${BINPATH}\onionshare\404.html" - File "${BINPATH}\onionshare\helpers.py" - File "${BINPATH}\onionshare\hs.py" - File "${BINPATH}\onionshare\index.html" - File "${BINPATH}\onionshare\onionshare.py" - File "${BINPATH}\onionshare\socks.py" - File "${BINPATH}\onionshare\strings.py" - File "${BINPATH}\onionshare\web.py" - SetOutPath "$INSTDIR\onionshare_gui" - File "${BINPATH}\onionshare_gui\__init__.py" - File "${BINPATH}\onionshare_gui\common.py" - File "${BINPATH}\onionshare_gui\downloads.py" - File "${BINPATH}\onionshare_gui\file_selection.py" - File "${BINPATH}\onionshare_gui\onionshare_gui.py" - File "${BINPATH}\onionshare_gui\options.py" - File "${BINPATH}\onionshare_gui\server_status.py" + File "${BINPATH}\license.txt" + File "${BINPATH}\version" + File "${BINPATH}\onionshare.ico" + SetOutPath "$INSTDIR\html" + File "${BINPATH}\html\404.html" + File "${BINPATH}\html\index.html" SetOutPath "$INSTDIR\images" File "${BINPATH}\images\logo.png" File "${BINPATH}\images\drop_files.png" @@ -103,54 +89,35 @@ Section "install" File "${BINPATH}\locale\tr.json" # dependencies + SetOutPath "$INSTDIR\platforms" + File "${BINPATH}\platforms\qwindows.dll" SetOutPath $INSTDIR + File "${BINPATH}\_bz2.pyd" File "${BINPATH}\_ctypes.pyd" + File "${BINPATH}\_decimal.pyd" File "${BINPATH}\_hashlib.pyd" + File "${BINPATH}\_lzma.pyd" + File "${BINPATH}\_multiprocessing.pyd" File "${BINPATH}\_socket.pyd" File "${BINPATH}\_ssl.pyd" - File "${BINPATH}\bz2.pyd" - File "${BINPATH}\microsoft.vc90.crt.manifest" - File "${BINPATH}\msvcm90.dll" - File "${BINPATH}\msvcp90.dll" - File "${BINPATH}\msvcr90.dll" - File "${BINPATH}\onionshare.exe.manifest" + File "${BINPATH}\icudt53.dll" + File "${BINPATH}\icuin53.dll" + File "${BINPATH}\icuuc53.dll" + File "${BINPATH}\library.zip" + File "${BINPATH}\license.txt" File "${BINPATH}\pyexpat.pyd" - File "${BINPATH}\PyQt4.QtCore.pyd" - File "${BINPATH}\PyQt4.QtGui.pyd" - File "${BINPATH}\python27.dll" - File "${BINPATH}\pywintypes27.dll" - File "${BINPATH}\qtcore4.dll" - File "${BINPATH}\qtgui4.dll" - File "${BINPATH}\qtopengl4.dll" - File "${BINPATH}\qtsvg4.dll" - File "${BINPATH}\qtxml4.dll" + File "${BINPATH}\PyQt5.QtCore.pyd" + File "${BINPATH}\PyQt5.QtGui.pyd" + File "${BINPATH}\PyQt5.QtWidgets.pyd" + File "${BINPATH}\python34.dll" + File "${BINPATH}\pywintypes34.dll" + File "${BINPATH}\Qt5Core.dll" + File "${BINPATH}\Qt5Gui.dll" + File "${BINPATH}\Qt5Widgets.dll" File "${BINPATH}\select.pyd" File "${BINPATH}\sip.pyd" File "${BINPATH}\unicodedata.pyd" - File "${BINPATH}\win32api.pyd" - File "${BINPATH}\win32pipe.pyd" File "${BINPATH}\win32wnet.pyd" - SetOutPath "$INSTDIR\qt4_plugins\accessible" - File "${BINPATH}\qt4_plugins\accessible\qtaccessiblewidgets4.dll" - SetOutPath "$INSTDIR\qt4_plugins\codecs" - File "${BINPATH}\qt4_plugins\codecs\qcncodecs4.dll" - File "${BINPATH}\qt4_plugins\codecs\qjpcodecs4.dll" - File "${BINPATH}\qt4_plugins\codecs\qkrcodecs4.dll" - File "${BINPATH}\qt4_plugins\codecs\qtwcodecs4.dll" - SetOutPath "$INSTDIR\qt4_plugins\graphicssystems" - File "${BINPATH}\qt4_plugins\graphicssystems\qglgraphicssystem4.dll" - SetOutPath "$INSTDIR\qt4_plugins\iconengines" - File "${BINPATH}\qt4_plugins\iconengines\qsvgicon4.dll" - SetOutPath "$INSTDIR\qt4_plugins\imageformats" - File "${BINPATH}\qt4_plugins\imageformats\qgif4.dll" - File "${BINPATH}\qt4_plugins\imageformats\qico4.dll" - File "${BINPATH}\qt4_plugins\imageformats\qjpeg4.dll" - File "${BINPATH}\qt4_plugins\imageformats\qmng4.dll" - File "${BINPATH}\qt4_plugins\imageformats\qsvg4.dll" - File "${BINPATH}\qt4_plugins\imageformats\qtga4.dll" - File "${BINPATH}\qt4_plugins\imageformats\qtiff4.dll" - SetOutPath "$INSTDIR\include" - File "${BINPATH}\Include\pyconfig.h" # uninstaller !ifndef INNER @@ -195,25 +162,11 @@ FunctionEnd # remove files Delete "$INSTDIR\onionshare.exe" - Delete "$INSTDIR\LICENSE" + Delete "$INSTDIR\license.txt" + Delete "$INSTDIR\version" Delete "$INSTDIR\onionshare.ico" - Delete "$INSTDIR\uninstall.exe" - Delete "$INSTDIR\onionshare\__init__.py" - Delete "$INSTDIR\onionshare\404.html" - Delete "$INSTDIR\onionshare\helpers.py" - Delete "$INSTDIR\onionshare\hs.py" - Delete "$INSTDIR\onionshare\index.html" - Delete "$INSTDIR\onionshare\onionshare.py" - Delete "$INSTDIR\onionshare\socks.py" - Delete "$INSTDIR\onionshare\strings.py" - Delete "$INSTDIR\onionshare\web.py" - Delete "$INSTDIR\onionshare_gui\__init__.py" - Delete "$INSTDIR\onionshare_gui\common.py" - Delete "$INSTDIR\onionshare_gui\downloads.py" - Delete "$INSTDIR\onionshare_gui\file_selection.py" - Delete "$INSTDIR\onionshare_gui\onionshare_gui.py" - Delete "$INSTDIR\onionshare_gui\options.py" - Delete "$INSTDIR\onionshare_gui\server_status.py" + Delete "$INSTDIR\html\404.html" + Delete "$INSTDIR\html\index.html" Delete "$INSTDIR\images\logo.png" Delete "$INSTDIR\images\drop_files.png" Delete "$INSTDIR\images\server_stopped.png" @@ -231,60 +184,38 @@ FunctionEnd Delete "$INSTDIR\locale\pt.json" Delete "$INSTDIR\locale\ru.json" Delete "$INSTDIR\locale\tr.json" - Delete "$INSTDIR\qt4_plugins\accessible\qtaccessiblewidgets4.dll" - Delete "$INSTDIR\qt4_plugins\graphicssystems\qglgraphicssystem4.dll" - Delete "$INSTDIR\qt4_plugins\iconengines\qsvgicon4.dll" - Delete "$INSTDIR\qt4_plugins\codecs\qjpcodecs4.dll" - Delete "$INSTDIR\qt4_plugins\codecs\qkrcodecs4.dll" - Delete "$INSTDIR\qt4_plugins\codecs\qtwcodecs4.dll" - Delete "$INSTDIR\qt4_plugins\codecs\qcncodecs4.dll" - Delete "$INSTDIR\qt4_plugins\imageformats\qmng4.dll" - Delete "$INSTDIR\qt4_plugins\imageformats\qico4.dll" - Delete "$INSTDIR\qt4_plugins\imageformats\qgif4.dll" - Delete "$INSTDIR\qt4_plugins\imageformats\qjpeg4.dll" - Delete "$INSTDIR\qt4_plugins\imageformats\qsvg4.dll" - Delete "$INSTDIR\qt4_plugins\imageformats\qtga4.dll" - Delete "$INSTDIR\qt4_plugins\imageformats\qtiff4.dll" - Delete "$INSTDIR\Include\pyconfig.h" + Delete "$INSTDIR\platforms\qwindows.dll" + Delete "$INSTDIR\_bz2.pyd" Delete "$INSTDIR\_ctypes.pyd" + Delete "$INSTDIR\_decimal.pyd" Delete "$INSTDIR\_hashlib.pyd" + Delete "$INSTDIR\_lzma.pyd" + Delete "$INSTDIR\_multiprocessing.pyd" Delete "$INSTDIR\_socket.pyd" Delete "$INSTDIR\_ssl.pyd" - Delete "$INSTDIR\bz2.pyd" - Delete "$INSTDIR\Microsoft.VC90.CRT.manifest" - Delete "$INSTDIR\msvcm90.dll" - Delete "$INSTDIR\msvcp90.dll" - Delete "$INSTDIR\msvcr90.dll" - Delete "$INSTDIR\onionshare.exe.manifest" + Delete "$INSTDIR\icudt53.dll" + Delete "$INSTDIR\icuin53.dll" + Delete "$INSTDIR\icuuc53.dll" + Delete "$INSTDIR\library.zip" + Delete "$INSTDIR\license.txt" Delete "$INSTDIR\pyexpat.pyd" - Delete "$INSTDIR\PyQt4.QtCore.pyd" - Delete "$INSTDIR\PyQt4.QtGui.pyd" - Delete "$INSTDIR\python27.dll" - Delete "$INSTDIR\pywintypes27.dll" - Delete "$INSTDIR\QtCore4.dll" - Delete "$INSTDIR\QtGui4.dll" - Delete "$INSTDIR\QtOpenGL4.dll" - Delete "$INSTDIR\QtSvg4.dll" - Delete "$INSTDIR\QtXml4.dll" + Delete "$INSTDIR\PyQt5.QtCore.pyd" + Delete "$INSTDIR\PyQt5.QtGui.pyd" + Delete "$INSTDIR\PyQt5.QtWidgets.pyd" + Delete "$INSTDIR\python34.dll" + Delete "$INSTDIR\pywintypes34.dll" + Delete "$INSTDIR\Qt5Core.dll" + Delete "$INSTDIR\Qt5Gui.dll" + Delete "$INSTDIR\Qt5Widgets.dll" Delete "$INSTDIR\select.pyd" Delete "$INSTDIR\sip.pyd" Delete "$INSTDIR\unicodedata.pyd" - Delete "$INSTDIR\win32api.pyd" - Delete "$INSTDIR\win32pipe.pyd" Delete "$INSTDIR\win32wnet.pyd" - rmDir "$INSTDIR\onionshare" - rmDir "$INSTDIR\onionshare_gui" + rmDir "$INSTDIR\html" rmDir "$INSTDIR\images" rmDir "$INSTDIR\locale" - rmDir "$INSTDIR\Include" - rmDir "$INSTDIR\qt4_plugins\accessible" - rmDir "$INSTDIR\qt4_plugins\bearer" - rmDir "$INSTDIR\qt4_plugins\codecs" - rmDir "$INSTDIR\qt4_plugins\graphicssystems" - rmDir "$INSTDIR\qt4_plugins\iconengines" - rmDir "$INSTDIR\qt4_plugins\imageformats" - rmDir "$INSTDIR\qt4_plugins" + rmDir "$INSTDIR\platforms" rmDir "$INSTDIR" # remove uninstaller information from the registry diff --git a/install/onionshare-launcher.py b/install/windows_scripts/onionshare.py similarity index 75% rename from install/onionshare-launcher.py rename to install/windows_scripts/onionshare.py index 83c8e910..3880e1da 100644 --- a/install/onionshare-launcher.py +++ b/install/windows_scripts/onionshare.py @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ from __future__ import division -import os, sys, subprocess, time, hashlib, platform, json, locale, socket +import os, subprocess, time, hashlib, platform, json, locale, socket import argparse, queue, inspect, base64, random, functools, logging, ctypes import hmac, shutil import stem, stem.control, flask @@ -26,4 +26,12 @@ from PyQt5 import QtCore, QtWidgets, QtGui import onionshare, onionshare_gui +# Disable py2exe logging in Windows. Comment these if you need logs. See: +# http://www.py2exe.org/index.cgi/StderrLog +# http://stackoverflow.com/questions/20549843/py2exe-generate-log-file +import sys +f = open(os.devnull, 'w') +sys.stdout = f +sys.stderr = f + onionshare_gui.main() diff --git a/setup.py b/setup.py index 9ad89b47..957b929d 100644 --- a/setup.py +++ b/setup.py @@ -121,3 +121,28 @@ elif system == 'Darwin': }, setup_requires=['py2app', 'flask', 'stem'], ) + +elif system == 'Windows': + import py2exe + setup( + name='OnionShare', + version=version, + description=description, + long_description=long_description, + data_files=[ + ('images', images), + ('locale', locale), + ('html', ['onionshare/index.html', 'onionshare/404.html']), + ('', ['version', 'install/license.txt', 'install/onionshare.ico']), + ('platforms', ['C:\\Python34\\Lib\\site-packages\\PyQt5\\plugins\\platforms\\qwindows.dll']) + ], + windows=['install/windows_scripts/onionshare.py'], + options={ + 'py2exe': { + 'includes': [ + 'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWidgets', + 'jinja2', 'jinja2.ext', 'sip'] + } + }, + setup_requires=['py2exe', 'flask', 'stem'], + )