electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

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 )