In `build-electrum-git.sh`, the `-w` CLI arg is removed: it was apparently ignored as we are using a .spec file,
and pyinstaller 5.0+ is now raising a hard error (see https://github.com/pyinstaller/pyinstaller/issues/6660).
```
option(s) not allowed:
--console/--nowindowed/--windowed/--noconsole
makespec options not valid when a .spec file is given
```
-----
In ecc_fast.py, we don't sys.exit() anymore as pyinstaller 5.0+ tries to import electrum during the Analysis phase.
see https://github.com/pyinstaller/pyinstaller/pull/6171
```
57912 INFO: Looking for dynamic libraries
1746 INFO: gettext setting initial language to None
1932 ERROR: libsecp256k1 library failed to load. exceptions: [FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-2.dll' (or one of its depende
ncies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-1.dll' (or one of its dependenc
ies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'C:\\python3\\lib\\site-packages\\electrum\\libsecp256k1-0.dll' (or one of its dependencie
s). Try using the full path with constructor syntax."), FileNotFoundError("Could not find module 'libsecp256k1-2.dll' (or one of its dependencies). Try using the full path with constructor
syntax."), FileNotFoundError("Could not find module 'libsecp256k1-1.dll' (or one of its dependencies). Try using the full path with constructor syntax."), FileNotFoundError("Could not find
module 'libsecp256k1-0.dll' (or one of its dependencies). Try using the full path with constructor syntax.")]
Traceback (most recent call last):
File "C:\python3\lib\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\python3\lib\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "C:\python3\scripts\pyinstaller.exe\__main__.py", line 7, in <module>
File "C:\python3\lib\site-packages\PyInstaller\__main__.py", line 194, in _console_script_run
run()
File "C:\python3\lib\site-packages\PyInstaller\__main__.py", line 180, in run
run_build(pyi_config, spec_file, **vars(args))
File "C:\python3\lib\site-packages\PyInstaller\__main__.py", line 61, in run_build
PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 1006, in main
build(specfile, distpath, workpath, clean_build)
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 928, in build
exec(code, spec_namespace)
File "deterministic.spec", line 55, in <module>
a = Analysis([home+'run_electrum',
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 428, in __init__
self.__postinit__()
File "C:\python3\lib\site-packages\PyInstaller\building\datastruct.py", line 184, in __postinit__
self.assemble()
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 736, in assemble
isolated.call(find_binary_dependencies, self.binaries, self.binding_redirects, collected_packages)
File "C:\python3\lib\site-packages\PyInstaller\isolated\_parent.py", line 372, in call
return isolated.call(function, *args, **kwargs)
File "C:\python3\lib\site-packages\PyInstaller\isolated\_parent.py", line 302, in call
raise RuntimeError(f"Child process call to {function.__name__}() failed with:\n" + output)
RuntimeError: Child process call to find_binary_dependencies() failed with:
File "C:\python3\lib\site-packages\PyInstaller\isolated\_child.py", line 63, in run_next_command
output = function(*args, **kwargs)
File "C:\python3\lib\site-packages\PyInstaller\building\build_main.py", line 177, in find_binary_dependencies
__import__(package)
File "C:\python3\lib\site-packages\electrum\__init__.py", line 20, in <module>
from .wallet import Wallet
File "C:\python3\lib\site-packages\electrum\wallet.py", line 53, in <module>
from .bip32 import BIP32Node, convert_bip32_intpath_to_strpath, convert_bip32_strpath_to_intpath
File "C:\python3\lib\site-packages\electrum\bip32.py", line 11, in <module>
from . import constants
File "C:\python3\lib\site-packages\electrum\constants.py", line 30, in <module>
from . import bitcoin
File "C:\python3\lib\site-packages\electrum\bitcoin.py", line 35, in <module>
from . import ecc
File "C:\python3\lib\site-packages\electrum\ecc.py", line 39, in <module>
from .ecc_fast import _libsecp256k1, SECP256K1_EC_UNCOMPRESSED
File "C:\python3\lib\site-packages\electrum\ecc_fast.py", line 151, in <module>
sys.exit(f"Error: Failed to load libsecp256k1.")
SystemExit: Error: Failed to load libsecp256k1.
🗯 ERROR: build-electrum-git failed
```
Also, the -OO flag is removed from wine python, for similar reasons:
pyinstaller imports electrum, and in electrum/__init__.py, we raise
if -O is used: 9b1fb0e5fe/electrum/__init__.py (L40)
117 lines
4.0 KiB
Bash
Executable File
117 lines
4.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
NAME_ROOT=electrum
|
|
|
|
export PYTHONDONTWRITEBYTECODE=1 # don't create __pycache__/ folders with .pyc files
|
|
|
|
|
|
# Let's begin!
|
|
set -e
|
|
|
|
. "$CONTRIB"/build_tools_util.sh
|
|
|
|
pushd $WINEPREFIX/drive_c/electrum
|
|
|
|
VERSION=$(git describe --tags --dirty --always)
|
|
info "Last commit: $VERSION"
|
|
|
|
# Load electrum-locale for this release
|
|
git submodule update --init
|
|
|
|
LOCALE="$WINEPREFIX/drive_c/electrum/electrum/locale/"
|
|
# we want the binary to have only compiled (.mo) locale files; not source (.po) files
|
|
rm -rf "$LOCALE"
|
|
"$CONTRIB/build_locale.sh" "$CONTRIB/deterministic-build/electrum-locale/locale/" "$LOCALE"
|
|
|
|
find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} +
|
|
popd
|
|
|
|
|
|
# opt out of compiling C extensions
|
|
export AIOHTTP_NO_EXTENSIONS=1
|
|
export YARL_NO_EXTENSIONS=1
|
|
export MULTIDICT_NO_EXTENSIONS=1
|
|
export FROZENLIST_NO_EXTENSIONS=1
|
|
|
|
info "Installing requirements..."
|
|
$WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-binary :all: --no-warn-script-location \
|
|
--cache-dir "$WINE_PIP_CACHE_DIR" -r "$CONTRIB"/deterministic-build/requirements.txt
|
|
info "Installing dependencies specific to binaries..."
|
|
# TODO use "--no-binary :all:" (but we don't have a C compiler...)
|
|
$WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-warn-script-location \
|
|
--cache-dir "$WINE_PIP_CACHE_DIR" -r "$CONTRIB"/deterministic-build/requirements-binaries.txt
|
|
info "Installing hardware wallet requirements..."
|
|
# TODO use "--no-binary :all:" (but we don't have a C compiler...)
|
|
$WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-warn-script-location \
|
|
--cache-dir "$WINE_PIP_CACHE_DIR" -r "$CONTRIB"/deterministic-build/requirements-hw.txt
|
|
|
|
pushd $WINEPREFIX/drive_c/electrum
|
|
# see https://github.com/pypa/pip/issues/2195 -- pip makes a copy of the entire directory
|
|
info "Pip installing Electrum. This might take a long time if the project folder is large."
|
|
$WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-warn-script-location .
|
|
popd
|
|
|
|
|
|
rm -rf dist/
|
|
|
|
# build standalone and portable versions
|
|
info "Running pyinstaller..."
|
|
ELECTRUM_CMDLINE_NAME="$NAME_ROOT-$VERSION" wine "$WINE_PYHOME/scripts/pyinstaller.exe" --noconfirm --ascii --clean deterministic.spec
|
|
|
|
# set timestamps in dist, in order to make the installer reproducible
|
|
pushd dist
|
|
find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} +
|
|
popd
|
|
|
|
info "building NSIS installer"
|
|
# $VERSION could be passed to the electrum.nsi script, but this would require some rewriting in the script itself.
|
|
makensis -DPRODUCT_VERSION=$VERSION electrum.nsi
|
|
|
|
cd dist
|
|
mv electrum-setup.exe $NAME_ROOT-$VERSION-setup.exe
|
|
cd ..
|
|
|
|
info "Padding binaries to 8-byte boundaries, and fixing COFF image checksum in PE header"
|
|
# note: 8-byte boundary padding is what osslsigncode uses:
|
|
# https://github.com/mtrojnar/osslsigncode/blob/6c8ec4427a0f27c145973450def818e35d4436f6/osslsigncode.c#L3047
|
|
(
|
|
cd dist
|
|
for binary_file in ./*.exe; do
|
|
info ">> fixing $binary_file..."
|
|
# code based on https://github.com/erocarrera/pefile/blob/bbf28920a71248ed5c656c81e119779c131d9bd4/pefile.py#L5877
|
|
python3 <<EOF
|
|
pe_file = "$binary_file"
|
|
with open(pe_file, "rb") as f:
|
|
binary = bytearray(f.read())
|
|
pe_offset = int.from_bytes(binary[0x3c:0x3c+4], byteorder="little")
|
|
checksum_offset = pe_offset + 88
|
|
checksum = 0
|
|
|
|
# Pad data to 8-byte boundary.
|
|
remainder = len(binary) % 8
|
|
binary += bytes(8 - remainder)
|
|
|
|
for i in range(len(binary) // 4):
|
|
if i == checksum_offset // 4: # Skip the checksum field
|
|
continue
|
|
dword = int.from_bytes(binary[i*4:i*4+4], byteorder="little")
|
|
checksum = (checksum & 0xffffffff) + dword + (checksum >> 32)
|
|
if checksum > 2 ** 32:
|
|
checksum = (checksum & 0xffffffff) + (checksum >> 32)
|
|
|
|
checksum = (checksum & 0xffff) + (checksum >> 16)
|
|
checksum = (checksum) + (checksum >> 16)
|
|
checksum = checksum & 0xffff
|
|
checksum += len(binary)
|
|
|
|
# Set the checksum
|
|
binary[checksum_offset : checksum_offset + 4] = int.to_bytes(checksum, byteorder="little", length=4)
|
|
|
|
with open(pe_file, "wb") as f:
|
|
f.write(binary)
|
|
EOF
|
|
done
|
|
)
|
|
|
|
sha256sum dist/electrum*.exe
|