Haven't checked if electrum-ecc compiles libsecp reproducibly. For now let's just keep the old flow. (but if we spent time on making that compilation reproducible, the appimage and the macos builds could use it directly)
122 lines
4.4 KiB
Bash
Executable File
122 lines
4.4 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
|
|
export ELECTRUM_ECC_DONT_COMPILE=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 tighten "--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 \
|
|
--no-binary :all: --only-binary cffi,cryptography,PyQt6,PyQt6-Qt6,PyQt6-sip \
|
|
--cache-dir "$WINE_PIP_CACHE_DIR" -r "$CONTRIB"/deterministic-build/requirements-binaries.txt
|
|
info "Installing hardware wallet requirements..."
|
|
$WINE_PYTHON -m pip install --no-build-isolation --no-dependencies --no-warn-script-location \
|
|
--no-binary :all: --only-binary cffi,cryptography,hidapi \
|
|
--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 .
|
|
# pyinstaller needs to be able to "import electrum_ecc", for which we need libsecp256k1:
|
|
# (or could try "pip install -e" instead)
|
|
cp electrum/libsecp256k1-*.dll "$WINEPREFIX/drive_c/python3/Lib/site-packages/electrum_ecc/"
|
|
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 --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
|