osx.spec (6236B)
1 # -*- mode: python -*- 2 3 from PyInstaller.utils.hooks import collect_data_files, collect_submodules, collect_dynamic_libs 4 5 import sys, os 6 7 PACKAGE='Electrum' 8 PYPKG='electrum' 9 MAIN_SCRIPT='run_electrum' 10 ICONS_FILE=PYPKG + '/gui/icons/electrum.icns' 11 APP_SIGN = os.environ.get('APP_SIGN', '') 12 13 def fail(*msg): 14 RED='\033[0;31m' 15 NC='\033[0m' # No Color 16 print("\r🗯 {}ERROR:{}".format(RED, NC), *msg) 17 sys.exit(1) 18 19 def codesign(identity, binary): 20 d = os.path.dirname(binary) 21 saved_dir=None 22 if d: 23 # switch to directory of the binary so codesign verbose messages don't include long path 24 saved_dir = os.path.abspath(os.path.curdir) 25 os.chdir(d) 26 binary = os.path.basename(binary) 27 os.system("codesign -v -f -s '{}' '{}'".format(identity, binary))==0 or fail("Could not code sign " + binary) 28 if saved_dir: 29 os.chdir(saved_dir) 30 31 def monkey_patch_pyinstaller_for_codesigning(identity): 32 # Monkey-patch PyInstaller so that we app-sign all binaries *after* they are modified by PyInstaller 33 # If we app-sign before that point, the signature will be invalid because PyInstaller modifies 34 # @loader_path in the Mach-O loader table. 35 try: 36 import PyInstaller.depend.dylib 37 _saved_func = PyInstaller.depend.dylib.mac_set_relative_dylib_deps 38 except (ImportError, NameError, AttributeError): 39 # Hmm. Likely wrong PyInstaller version. 40 fail("Could not monkey-patch PyInstaller for code signing. Please ensure that you are using PyInstaller 3.4.") 41 _signed = set() 42 def my_func(fn, distname): 43 _saved_func(fn, distname) 44 if (fn, distname) not in _signed: 45 codesign(identity, fn) 46 _signed.add((fn,distname)) # remember we signed it so we don't sign again 47 PyInstaller.depend.dylib.mac_set_relative_dylib_deps = my_func 48 49 50 for i, x in enumerate(sys.argv): 51 if x == '--name': 52 VERSION = sys.argv[i+1] 53 break 54 else: 55 raise Exception('no version') 56 57 electrum = os.path.abspath(".") + "/" 58 block_cipher = None 59 60 # see https://github.com/pyinstaller/pyinstaller/issues/2005 61 hiddenimports = [] 62 hiddenimports += collect_submodules('pkg_resources') # workaround for https://github.com/pypa/setuptools/issues/1963 63 hiddenimports += collect_submodules('trezorlib') 64 hiddenimports += collect_submodules('safetlib') 65 hiddenimports += collect_submodules('btchip') 66 hiddenimports += collect_submodules('keepkeylib') 67 hiddenimports += collect_submodules('websocket') 68 hiddenimports += collect_submodules('ckcc') 69 hiddenimports += collect_submodules('bitbox02') 70 hiddenimports += ['PyQt5.QtPrintSupport'] # needed by Revealer 71 72 datas = [ 73 (electrum + PYPKG + '/*.json', PYPKG), 74 (electrum + PYPKG + '/lnwire/*.csv', PYPKG + '/lnwire'), 75 (electrum + PYPKG + '/wordlist/english.txt', PYPKG + '/wordlist'), 76 (electrum + PYPKG + '/locale', PYPKG + '/locale'), 77 (electrum + PYPKG + '/plugins', PYPKG + '/plugins'), 78 (electrum + PYPKG + '/gui/icons', PYPKG + '/gui/icons'), 79 ] 80 datas += collect_data_files('trezorlib') 81 datas += collect_data_files('safetlib') 82 datas += collect_data_files('btchip') 83 datas += collect_data_files('keepkeylib') 84 datas += collect_data_files('ckcc') 85 datas += collect_data_files('bitbox02') 86 87 # Add the QR Scanner helper app 88 datas += [(electrum + "contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app", "./contrib/osx/CalinsQRReader/build/Release/CalinsQRReader.app")] 89 90 # Add libusb so Trezor and Safe-T mini will work 91 binaries = [(electrum + "contrib/osx/libusb-1.0.dylib", ".")] 92 binaries += [(electrum + "contrib/osx/libsecp256k1.0.dylib", ".")] 93 94 # Workaround for "Retro Look": 95 binaries += [b for b in collect_dynamic_libs('PyQt5') if 'macstyle' in b[0]] 96 97 # We don't put these files in to actually include them in the script but to make the Analysis method scan them for imports 98 a = Analysis([electrum+ MAIN_SCRIPT, 99 electrum+'electrum/gui/qt/main_window.py', 100 electrum+'electrum/gui/text.py', 101 electrum+'electrum/util.py', 102 electrum+'electrum/wallet.py', 103 electrum+'electrum/simple_config.py', 104 electrum+'electrum/bitcoin.py', 105 electrum+'electrum/dnssec.py', 106 electrum+'electrum/commands.py', 107 electrum+'electrum/plugins/cosigner_pool/qt.py', 108 electrum+'electrum/plugins/email_requests/qt.py', 109 electrum+'electrum/plugins/trezor/qt.py', 110 electrum+'electrum/plugins/safe_t/client.py', 111 electrum+'electrum/plugins/safe_t/qt.py', 112 electrum+'electrum/plugins/keepkey/qt.py', 113 electrum+'electrum/plugins/ledger/qt.py', 114 electrum+'electrum/plugins/coldcard/qt.py', 115 ], 116 binaries=binaries, 117 datas=datas, 118 hiddenimports=hiddenimports, 119 hookspath=[]) 120 121 # http://stackoverflow.com/questions/19055089/pyinstaller-onefile-warning-pyconfig-h-when-importing-scipy-or-scipy-signal 122 for d in a.datas: 123 if 'pyconfig' in d[0]: 124 a.datas.remove(d) 125 break 126 127 # Strip out parts of Qt that we never use. Reduces binary size by tens of MBs. see #4815 128 qt_bins2remove=('qtweb', 'qt3d', 'qtgame', 'qtdesigner', 'qtquick', 'qtlocation', 'qttest', 'qtxml') 129 print("Removing Qt binaries:", *qt_bins2remove) 130 for x in a.binaries.copy(): 131 for r in qt_bins2remove: 132 if x[0].lower().startswith(r): 133 a.binaries.remove(x) 134 print('----> Removed x =', x) 135 136 # If code signing, monkey-patch in a code signing step to pyinstaller. See: https://github.com/spesmilo/electrum/issues/4994 137 if APP_SIGN: 138 monkey_patch_pyinstaller_for_codesigning(APP_SIGN) 139 140 pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) 141 142 exe = EXE( 143 pyz, 144 a.scripts, 145 exclude_binaries=True, 146 name=MAIN_SCRIPT, 147 debug=False, 148 strip=False, 149 upx=True, 150 icon=electrum+ICONS_FILE, 151 console=False, 152 ) 153 154 app = BUNDLE( 155 exe, 156 a.binaries, 157 a.zipfiles, 158 a.datas, 159 version = VERSION, 160 name=PACKAGE + '.app', 161 icon=electrum+ICONS_FILE, 162 bundle_identifier=None, 163 info_plist={ 164 'NSHighResolutionCapable': 'True', 165 'NSSupportsAutomaticGraphicsSwitching': 'True' 166 }, 167 )