Browse Source

Merge pull request #7355 from SomberNight/202106_build

build: clean up build scripts, consolidate instructions, reduce code dupe
patch-4
ghost43 4 years ago
committed by GitHub
parent
commit
086c1397af
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      .travis.yml
  2. 50
      contrib/android/Readme.md
  3. 68
      contrib/android/build.sh
  4. 10
      contrib/android/build_docker_image.sh
  5. 3
      contrib/android/buildozer.spec
  6. 4
      contrib/android/make_apk
  7. 19
      contrib/build-linux/appimage/README.md
  8. 296
      contrib/build-linux/appimage/build.sh
  9. 263
      contrib/build-linux/appimage/make_appimage.sh
  10. 35
      contrib/build-linux/sdist/README.md
  11. 65
      contrib/build-linux/sdist/build.sh
  12. 60
      contrib/build-linux/sdist/make_sdist.sh
  13. 43
      contrib/build-linux/sdist/make_tgz
  14. 58
      contrib/build-wine/README.md
  15. 97
      contrib/build-wine/build.sh
  16. 67
      contrib/build-wine/make_win.sh
  17. 95
      contrib/release.sh

29
.travis.yml

@ -58,10 +58,8 @@ jobs:
- sudo apt-get update - sudo apt-get update
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- docker version - docker version
install:
- sudo docker build --no-cache -t electrum-wine-builder-img ./contrib/build-wine/
script: script:
- sudo docker run --name electrum-wine-builder-cont -v $PWD:/opt/wine64/drive_c/electrum --rm --workdir /opt/wine64/drive_c/electrum/contrib/build-wine electrum-wine-builder-img ./build.sh - ELECBUILD_COMMIT=HEAD ./contrib/build-wine/build.sh
after_success: true after_success: true
- if: (branch = master) OR (tag IS present) - if: (branch = master) OR (tag IS present)
name: "Android build" name: "Android build"
@ -69,17 +67,15 @@ jobs:
python: 3.7 python: 3.7
services: services:
- docker - docker
install:
- ./contrib/android/build_docker_image.sh
script: script:
- sudo chown -R 1000:1000 . - sudo chown -R 1000:1000 .
# Output something every minute or Travis kills the job # Output something every minute or Travis kills the job
- while sleep 60; do echo "=====[ $SECONDS seconds still running ]====="; done & - while sleep 60; do echo "=====[ $SECONDS seconds still running ]====="; done &
- sudo docker run -it -u 1000:1000 --rm --name electrum-android-builder-cont --env CI=true -v $PWD:/home/user/wspace/electrum --workdir /home/user/wspace/electrum electrum-android-builder-img ./contrib/android/make_apk - ELECBUILD_COMMIT=HEAD ./contrib/android/build.sh
# kill background sleep loop # kill background sleep loop
- kill %1 - kill %1
- ls -la bin - ls -la dist
- if [ $(ls bin | grep -c Electrum-*) -eq 0 ]; then exit 1; fi - if [ $(ls dist | grep -c Electrum-*) -eq 0 ]; then exit 1; fi
after_success: true after_success: true
# disabled for now as travis started to always time out: # disabled for now as travis started to always time out:
- if: false AND ((branch = master) OR (tag IS present)) - if: false AND ((branch = master) OR (tag IS present))
@ -100,10 +96,8 @@ jobs:
python: false python: false
services: services:
- docker - docker
install:
- sudo docker build --no-cache -t electrum-appimage-builder-img ./contrib/build-linux/appimage/
script: script:
- sudo docker run --name electrum-appimage-builder-cont -v $PWD:/opt/electrum --rm --workdir /opt/electrum/contrib/build-linux/appimage electrum-appimage-builder-img ./build.sh - ELECBUILD_COMMIT=HEAD ./contrib/build-linux/appimage/build.sh
after_success: true after_success: true
- if: (branch = master) OR (tag IS present) - if: (branch = master) OR (tag IS present)
name: "tarball build" name: "tarball build"
@ -111,19 +105,8 @@ jobs:
python: false python: false
services: services:
- docker - docker
before_install:
# hack: travis already cloned the repo, but we re-clone now, as we need to have umask set BEFORE cloning
- umask 0022
- mkdir fresh_clone && cd fresh_clone
- git clone https://github.com/$TRAVIS_REPO_SLUG.git && cd electrum
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then git fetch origin pull/$TRAVIS_PULL_REQUEST/merge; fi
- git checkout $TRAVIS_COMMIT
- echo "Second git clone ready at $PWD"
install:
- sudo docker build --no-cache -t electrum-sdist-builder-img ./contrib/build-linux/sdist/
script: script:
- echo "Building sdist at $PWD" - ELECBUILD_COMMIT=HEAD ./contrib/build-linux/sdist/build.sh
- sudo docker run --name electrum-sdist-builder-cont -v $PWD:/opt/electrum --rm --workdir /opt/electrum/contrib/build-linux/sdist electrum-sdist-builder-img ./build.sh
after_success: true after_success: true
- stage: release check - stage: release check
install: install:

50
contrib/android/Readme.md

@ -9,8 +9,7 @@ To generate an APK file, follow these instructions.
binaries that match the official releases._ binaries that match the official releases._
This assumes an Ubuntu (x86_64) host, but it should not be too hard to adapt to another This assumes an Ubuntu (x86_64) host, but it should not be too hard to adapt to another
similar system. The docker commands should be executed in the project's root similar system.
folder.
1. Install Docker 1. Install Docker
@ -21,49 +20,20 @@ folder.
$ sudo apt-get install -y docker-ce $ sudo apt-get install -y docker-ce
``` ```
2. Build image 2. Build binaries
``` ```
$ ./contrib/android/build_docker_image.sh $ ./build.sh
``` ```
If you want reproducibility, try instead e.g.:
3. Build binaries
It's recommended to build from a fresh clone
(but you can skip this if reproducibility is not necessary).
``` ```
$ FRESH_CLONE=contrib/android/fresh_clone && \ $ ELECBUILD_COMMIT=HEAD ELECBUILD_NOCACHE=1 ./build.sh release-unsigned
sudo rm -rf $FRESH_CLONE && \
umask 0022 && \
mkdir -p $FRESH_CLONE && \
cd $FRESH_CLONE && \
git clone https://github.com/spesmilo/electrum.git && \
cd electrum
``` ```
And then build from this directory:
```
$ git checkout $REV
$ mkdir --parents $PWD/.buildozer/.gradle
$ sudo docker run -it --rm \
--name electrum-android-builder-cont \
-v $PWD:/home/user/wspace/electrum \
-v $PWD/.buildozer/.gradle:/home/user/.gradle \
-v ~/.keystore:/home/user/.keystore \
--workdir /home/user/wspace/electrum \
electrum-android-builder-img \
./contrib/android/make_apk
```
Note: this builds a debug apk. `make_apk` takes an optional parameter
which can be either `release` or `release-unsigned`.
This mounts the project dir inside the container, Note: `build.sh` takes an optional parameter which can be
and so the modifications will affect it, e.g. `.buildozer` folder `release`, `release-unsigned`, or `debug` (default).
will be created.
5. The generated binary is in `./bin`. 3. The generated binary is in `./dist`.
## Verifying reproducibility and comparing against official binary ## Verifying reproducibility and comparing against official binary
@ -95,7 +65,7 @@ You probably need to clear the cache: `rm -rf .buildozer/android/platform/build-
### How do I deploy on connected phone for quick testing? ### How do I deploy on connected phone for quick testing?
Assuming `adb` is installed: Assuming `adb` is installed:
``` ```
$ adb -d install -r bin/Electrum-*-arm64-v8a-debug.apk $ adb -d install -r dist/Electrum-*-arm64-v8a-debug.apk
$ adb shell monkey -p org.electrum.electrum 1 $ adb shell monkey -p org.electrum.electrum 1
``` ```
@ -154,7 +124,7 @@ $ run-as org.electrum.electrum cp /data/data/org.electrum.electrum/files/data/wa
### How to investigate diff between binaries if reproducibility fails? ### How to investigate diff between binaries if reproducibility fails?
``` ```
cd bin/ cd dist/
unzip Electrum-*.apk1 -d apk1 unzip Electrum-*.apk1 -d apk1
mkdir apk1/assets/private_mp3/ mkdir apk1/assets/private_mp3/
tar -xzvf apk1/assets/private.mp3 --directory apk1/assets/private_mp3/ tar -xzvf apk1/assets/private.mp3 --directory apk1/assets/private_mp3/

68
contrib/android/build.sh

@ -0,0 +1,68 @@
#!/bin/bash
#
# env vars:
# - ELECBUILD_NOCACHE: if set, forces rebuild of docker image
# - ELECBUILD_COMMIT: if set, do a fresh clone and git checkout
set -e
PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../.."
PROJECT_ROOT_OR_FRESHCLONE_ROOT="$PROJECT_ROOT"
CONTRIB="$PROJECT_ROOT/contrib"
CONTRIB_ANDROID="$CONTRIB/android"
DISTDIR="$PROJECT_ROOT/dist"
. "$CONTRIB"/build_tools_util.sh
DOCKER_BUILD_FLAGS=""
if [ ! -z "$ELECBUILD_NOCACHE" ] ; then
info "ELECBUILD_NOCACHE is set. forcing rebuild of docker image."
DOCKER_BUILD_FLAGS="--pull --no-cache"
fi
info "building docker image."
cp "$CONTRIB/deterministic-build/requirements-build-android.txt" "$CONTRIB_ANDROID/requirements-build-android.txt"
sudo docker build \
$DOCKER_BUILD_FLAGS \
-t electrum-android-builder-img \
"$CONTRIB_ANDROID"
rm "$CONTRIB_ANDROID/requirements-build-android.txt"
# maybe do fresh clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
info "ELECBUILD_COMMIT=$ELECBUILD_COMMIT. doing fresh clone and git checkout."
FRESH_CLONE="$CONTRIB_ANDROID/fresh_clone/electrum" && \
sudo rm -rf "$FRESH_CLONE" && \
umask 0022 && \
git clone "$PROJECT_ROOT" "$FRESH_CLONE" && \
cd "$FRESH_CLONE"
git checkout "$ELECBUILD_COMMIT"
PROJECT_ROOT_OR_FRESHCLONE_ROOT="$FRESH_CLONE"
else
info "not doing fresh clone."
fi
DOCKER_RUN_FLAGS=""
if [[ -n "$1" && "$1" == "release" ]] ; then
info "'release' mode selected. mounting ~/.keystore inside container."
DOCKER_RUN_FLAGS="-v $HOME/.keystore:/home/user/.keystore"
fi
info "building binary..."
mkdir --parents "$PROJECT_ROOT_OR_FRESHCLONE_ROOT"/.buildozer/.gradle
sudo docker run -it --rm \
--name electrum-android-builder-cont \
-v "$PROJECT_ROOT_OR_FRESHCLONE_ROOT":/home/user/wspace/electrum \
-v "$PROJECT_ROOT_OR_FRESHCLONE_ROOT"/.buildozer/.gradle:/home/user/.gradle \
$DOCKER_RUN_FLAGS \
--workdir /home/user/wspace/electrum \
electrum-android-builder-img \
./contrib/android/make_apk "$@"
# make sure resulting binary location is independent of fresh_clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
mkdir --parents "$DISTDIR/"
sudo cp -f "$FRESH_CLONE/dist"/* "$DISTDIR/"
fi

10
contrib/android/build_docker_image.sh

@ -1,10 +0,0 @@
#!/bin/bash
set -e
CONTRIB_ANDROID="$(dirname "$(readlink -e "$0")")"
CONTRIB="$CONTRIB_ANDROID"/..
cp "$CONTRIB/deterministic-build/requirements-build-android.txt" "$CONTRIB_ANDROID/requirements-build-android.txt"
sudo docker build -t electrum-android-builder-img "$CONTRIB_ANDROID"
rm "$CONTRIB_ANDROID/requirements-build-android.txt"

3
contrib/android/buildozer.spec

@ -206,6 +206,9 @@ p4a.local_recipes = %(source.dir)s/contrib/android/p4a_recipes/
# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
log_level = 1 log_level = 1
# (str) Path to build output (i.e. .apk, .ipa) storage
bin_dir = ./dist
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# List as sections # List as sections

4
contrib/android/make_apk

@ -82,5 +82,5 @@ popd
info "done." info "done."
ls -la "$PROJECT_ROOT/bin" ls -la "$PROJECT_ROOT/dist"
sha256sum "$PROJECT_ROOT/bin"/* sha256sum "$PROJECT_ROOT/dist"/*

19
contrib/build-linux/appimage/README.md

@ -6,7 +6,6 @@ AppImage binary for Electrum
This assumes an Ubuntu host, but it should not be too hard to adapt to another This assumes an Ubuntu host, but it should not be too hard to adapt to another
similar system. The host architecture should be x86_64 (amd64). similar system. The host architecture should be x86_64 (amd64).
The docker commands should be executed in the project's root folder.
We currently only build a single AppImage, for x86_64 architecture. We currently only build a single AppImage, for x86_64 architecture.
Help to adapt these scripts to build for (some flavor of) ARM would be welcome, Help to adapt these scripts to build for (some flavor of) ARM would be welcome,
@ -22,25 +21,17 @@ see [issue #5159](https://github.com/spesmilo/electrum/issues/5159).
$ sudo apt-get install -y docker-ce $ sudo apt-get install -y docker-ce
``` ```
2. Build image 2. Build binary
``` ```
$ sudo docker build -t electrum-appimage-builder-img contrib/build-linux/appimage $ ./build.sh
``` ```
If you want reproducibility, try instead e.g.:
3. Build binary
``` ```
$ sudo docker run -it \ $ ELECBUILD_COMMIT=HEAD ELECBUILD_NOCACHE=1 ./build.sh
--name electrum-appimage-builder-cont \
-v $PWD:/opt/electrum \
--rm \
--workdir /opt/electrum/contrib/build-linux/appimage \
electrum-appimage-builder-img \
./build.sh
``` ```
4. The generated binary is in `./dist`. 3. The generated binary is in `./dist`.
## FAQ ## FAQ

296
contrib/build-linux/appimage/build.sh

@ -1,263 +1,57 @@
#!/bin/bash #!/bin/bash
#
# env vars:
# - ELECBUILD_NOCACHE: if set, forces rebuild of docker image
# - ELECBUILD_COMMIT: if set, do a fresh clone and git checkout
set -e set -e
PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../../.." PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../../.."
PROJECT_ROOT_OR_FRESHCLONE_ROOT="$PROJECT_ROOT"
CONTRIB="$PROJECT_ROOT/contrib" CONTRIB="$PROJECT_ROOT/contrib"
CONTRIB_APPIMAGE="$CONTRIB/build-linux/appimage" CONTRIB_APPIMAGE="$CONTRIB/build-linux/appimage"
DISTDIR="$PROJECT_ROOT/dist" DISTDIR="$PROJECT_ROOT/dist"
BUILDDIR="$CONTRIB_APPIMAGE/build/appimage"
APPDIR="$BUILDDIR/electrum.AppDir"
CACHEDIR="$CONTRIB_APPIMAGE/.cache/appimage"
PIP_CACHE_DIR="$CACHEDIR/pip_cache"
export GCC_STRIP_BINARIES="1"
# pinned versions
# note: compiling python 3.8.x requires at least glibc 2.27,
# which is first available on ubuntu 18.04
PYTHON_VERSION=3.7.10
PKG2APPIMAGE_COMMIT="eb8f3acdd9f11ab19b78f5cb15daa772367daf15"
SQUASHFSKIT_COMMIT="ae0d656efa2d0df2fcac795b6823b44462f19386"
VERSION=`git describe --tags --dirty --always`
APPIMAGE="$DISTDIR/electrum-$VERSION-x86_64.AppImage"
. "$CONTRIB"/build_tools_util.sh . "$CONTRIB"/build_tools_util.sh
rm -rf "$BUILDDIR"
mkdir -p "$APPDIR" "$CACHEDIR" "$PIP_CACHE_DIR" "$DISTDIR"
# potential leftover from setuptools that might make pip put garbage in binary
rm -rf "$PROJECT_ROOT/build"
info "downloading some dependencies."
download_if_not_exist "$CACHEDIR/functions.sh" "https://raw.githubusercontent.com/AppImage/pkg2appimage/$PKG2APPIMAGE_COMMIT/functions.sh"
verify_hash "$CACHEDIR/functions.sh" "78b7ee5a04ffb84ee1c93f0cb2900123773bc6709e5d1e43c37519f590f86918"
download_if_not_exist "$CACHEDIR/appimagetool" "https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage"
verify_hash "$CACHEDIR/appimagetool" "d918b4df547b388ef253f3c9e7f6529ca81a885395c31f619d9aaf7030499a13"
download_if_not_exist "$CACHEDIR/Python-$PYTHON_VERSION.tar.xz" "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz"
verify_hash "$CACHEDIR/Python-$PYTHON_VERSION.tar.xz" "f8d82e7572c86ec9d55c8627aae5040124fd2203af400c383c821b980306ee6b"
info "building python."
tar xf "$CACHEDIR/Python-$PYTHON_VERSION.tar.xz" -C "$BUILDDIR"
(
cd "$BUILDDIR/Python-$PYTHON_VERSION"
LC_ALL=C export BUILD_DATE=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%b %d %Y")
LC_ALL=C export BUILD_TIME=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%H:%M:%S")
# Patch taken from Ubuntu http://archive.ubuntu.com/ubuntu/pool/main/p/python3.7/python3.7_3.7.6-1.debian.tar.xz
patch -p1 < "$CONTRIB_APPIMAGE/patches/python-3.7-reproducible-buildinfo.diff"
./configure \
--cache-file="$CACHEDIR/python.config.cache" \
--prefix="$APPDIR/usr" \
--enable-ipv6 \
--enable-shared \
-q
make -j4 -s || fail "Could not build Python"
make -s install > /dev/null || fail "Could not install Python"
# When building in docker on macOS, python builds with .exe extension because the
# case insensitive file system of macOS leaks into docker. This causes the build
# to result in a different output on macOS compared to Linux. We simply patch
# sysconfigdata to remove the extension.
# Some more info: https://bugs.python.org/issue27631
sed -i -e 's/\.exe//g' "$APPDIR"/usr/lib/python3.7/_sysconfigdata*
)
info "Building squashfskit"
git clone "https://github.com/squashfskit/squashfskit.git" "$BUILDDIR/squashfskit"
(
cd "$BUILDDIR/squashfskit"
git checkout "${SQUASHFSKIT_COMMIT}^{commit}"
make -C squashfs-tools mksquashfs || fail "Could not build squashfskit"
)
MKSQUASHFS="$BUILDDIR/squashfskit/squashfs-tools/mksquashfs"
"$CONTRIB"/make_libsecp256k1.sh || fail "Could not build libsecp"
cp -f "$PROJECT_ROOT/electrum/libsecp256k1.so.0" "$APPDIR/usr/lib/libsecp256k1.so.0" || fail "Could not copy libsecp to its destination"
appdir_python() {
env \
PYTHONNOUSERSITE=1 \
LD_LIBRARY_PATH="$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH}" \
"$APPDIR/usr/bin/python3.7" "$@"
}
python='appdir_python'
info "installing pip."
"$python" -m ensurepip
break_legacy_easy_install
info "preparing electrum-locale."
(
cd "$PROJECT_ROOT"
git submodule update --init
pushd "$CONTRIB"/deterministic-build/electrum-locale
if ! which msgfmt > /dev/null 2>&1; then
fail "Please install gettext"
fi
# we want the binary to have only compiled (.mo) locale files; not source (.po) files
rm -rf "$PROJECT_ROOT/electrum/locale/"
for i in ./locale/*; do
dir="$PROJECT_ROOT/electrum/$i/LC_MESSAGES"
mkdir -p $dir
msgfmt --output-file="$dir/electrum.mo" "$i/electrum.po" || true
done
popd
)
info "Installing build dependencies."
"$python" -m pip install --no-dependencies --no-binary :all: --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements-build-appimage.txt"
info "installing electrum and its dependencies."
# note: we prefer compiling C extensions ourselves, instead of using binary wheels,
# hence "--no-binary :all:" flags. However, we specifically allow
# - PyQt5, as it's harder to build from source
# - cryptography, as building it would need openssl 1.1, not available on ubuntu 16.04
"$python" -m pip install --no-dependencies --no-binary :all: --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements.txt"
"$python" -m pip install --no-dependencies --no-binary :all: --only-binary PyQt5,PyQt5-Qt5,cryptography --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements-binaries.txt"
"$python" -m pip install --no-dependencies --no-binary :all: --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements-hw.txt"
"$python" -m pip install --no-dependencies --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" "$PROJECT_ROOT"
# was only needed during build time, not runtime
"$python" -m pip uninstall -y Cython
info "copying zbar"
cp "/usr/lib/x86_64-linux-gnu/libzbar.so.0" "$APPDIR/usr/lib/libzbar.so.0"
info "desktop integration."
cp "$PROJECT_ROOT/electrum.desktop" "$APPDIR/electrum.desktop"
cp "$PROJECT_ROOT/electrum/gui/icons/electrum.png" "$APPDIR/electrum.png"
# add launcher
cp "$CONTRIB_APPIMAGE/apprun.sh" "$APPDIR/AppRun"
info "finalizing AppDir."
(
export PKG2AICOMMIT="$PKG2APPIMAGE_COMMIT"
. "$CACHEDIR/functions.sh"
cd "$APPDIR"
# copy system dependencies
copy_deps; copy_deps; copy_deps
move_lib
# apply global appimage blacklist to exclude stuff
# move usr/include out of the way to preserve usr/include/python3.7m.
mv usr/include usr/include.tmp
delete_blacklisted
mv usr/include.tmp usr/include
) || fail "Could not finalize AppDir"
info "Copying additional libraries"
(
# On some systems it can cause problems to use the system libusb (on AppImage excludelist)
cp -f /usr/lib/x86_64-linux-gnu/libusb-1.0.so "$APPDIR/usr/lib/libusb-1.0.so" || fail "Could not copy libusb"
# some distros lack libxkbcommon-x11
cp -f /usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0 "$APPDIR"/usr/lib/x86_64-linux-gnu || fail "Could not copy libxkbcommon-x11"
# some distros lack some libxcb libraries (see https://github.com/Electron-Cash/Electron-Cash/issues/2196)
cp -f /usr/lib/x86_64-linux-gnu/libxcb-* "$APPDIR"/usr/lib/x86_64-linux-gnu || fail "Could not copy libxcb"
)
info "stripping binaries from debug symbols."
# "-R .note.gnu.build-id" also strips the build id
# "-R .comment" also strips the GCC version information
strip_binaries()
{
chmod u+w -R "$APPDIR"
{
printf '%s\0' "$APPDIR/usr/bin/python3.7"
find "$APPDIR" -type f -regex '.*\.so\(\.[0-9.]+\)?$' -print0
} | xargs -0 --no-run-if-empty --verbose strip -R .note.gnu.build-id -R .comment
}
strip_binaries
remove_emptydirs()
{
find "$APPDIR" -type d -empty -print0 | xargs -0 --no-run-if-empty rmdir -vp --ignore-fail-on-non-empty
}
remove_emptydirs
info "removing some unneeded stuff to decrease binary size."
rm -rf "$APPDIR"/usr/{share,include}
PYDIR="$APPDIR"/usr/lib/python3.7
rm -rf "$PYDIR"/{test,ensurepip,lib2to3,idlelib,turtledemo}
rm -rf "$PYDIR"/{ctypes,sqlite3,tkinter,unittest}/test
rm -rf "$PYDIR"/distutils/{command,tests}
rm -rf "$PYDIR"/config-3.7m-x86_64-linux-gnu
rm -rf "$PYDIR"/site-packages/{opt,pip,setuptools,wheel}
rm -rf "$PYDIR"/site-packages/Cryptodome/SelfTest
rm -rf "$PYDIR"/site-packages/{psutil,qrcode,websocket}/tests
# rm lots of unused parts of Qt/PyQt. (assuming PyQt 5.15.3+ layout)
for component in connectivity declarative help location multimedia quickcontrols2 serialport webengine websockets xmlpatterns ; do
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/translations/qt${component}_*
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/resources/qt${component}_*
done
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/{qml,libexec}
rm -rf "$PYDIR"/site-packages/PyQt5/{pyrcc*.so,pylupdate*.so,uic}
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/plugins/{bearer,gamepads,geometryloaders,geoservices,playlistformats,position,renderplugins,sceneparsers,sensors,sqldrivers,texttospeech,webview}
for component in Bluetooth Concurrent Designer Help Location NetworkAuth Nfc Positioning PositioningQuick Qml Quick Sensors SerialPort Sql Test Web Xml ; do
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/lib/libQt5${component}*
rm -rf "$PYDIR"/site-packages/PyQt5/Qt${component}*
done
rm -rf "$PYDIR"/site-packages/PyQt5/Qt.so
# these are deleted as they were not deterministic; and are not needed anyway
find "$APPDIR" -path '*/__pycache__*' -delete
# note that *.dist-info is needed by certain packages.
# e.g. see https://gitlab.com/python-devs/importlib_metadata/issues/71
for f in "$PYDIR"/site-packages/importlib_metadata-*.dist-info; do mv "$f" "$(echo "$f" | sed s/\.dist-info/\.dist-info2/)"; done
rm -rf "$PYDIR"/site-packages/*.dist-info/
rm -rf "$PYDIR"/site-packages/*.egg-info/
for f in "$PYDIR"/site-packages/importlib_metadata-*.dist-info2; do mv "$f" "$(echo "$f" | sed s/\.dist-info2/\.dist-info/)"; done
find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} +
info "creating the AppImage."
(
cd "$BUILDDIR"
cp "$CACHEDIR/appimagetool" "$CACHEDIR/appimagetool_copy"
# zero out "appimage" magic bytes, as on some systems they confuse the linker
sed -i 's|AI\x02|\x00\x00\x00|' "$CACHEDIR/appimagetool_copy"
chmod +x "$CACHEDIR/appimagetool_copy"
"$CACHEDIR/appimagetool_copy" --appimage-extract
# We build a small wrapper for mksquashfs that removes the -mkfs-fixed-time option
# that mksquashfs from squashfskit does not support. It is not needed for squashfskit.
cat > ./squashfs-root/usr/lib/appimagekit/mksquashfs << EOF
#!/bin/sh
args=\$(echo "\$@" | sed -e 's/-mkfs-fixed-time 0//')
"$MKSQUASHFS" \$args
EOF
env VERSION="$VERSION" ARCH=x86_64 SOURCE_DATE_EPOCH=1530212462 ./squashfs-root/AppRun --no-appstream --verbose "$APPDIR" "$APPIMAGE"
)
info "done." DOCKER_BUILD_FLAGS=""
ls -la "$DISTDIR" if [ ! -z "$ELECBUILD_NOCACHE" ] ; then
sha256sum "$DISTDIR"/* info "ELECBUILD_NOCACHE is set. forcing rebuild of docker image."
DOCKER_BUILD_FLAGS="--pull --no-cache"
fi
info "building docker image."
sudo docker build \
$DOCKER_BUILD_FLAGS \
-t electrum-appimage-builder-img \
"$CONTRIB_APPIMAGE"
# maybe do fresh clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
info "ELECBUILD_COMMIT=$ELECBUILD_COMMIT. doing fresh clone and git checkout."
FRESH_CLONE="$CONTRIB_APPIMAGE/fresh_clone/electrum" && \
sudo rm -rf "$FRESH_CLONE" && \
umask 0022 && \
git clone "$PROJECT_ROOT" "$FRESH_CLONE" && \
cd "$FRESH_CLONE"
git checkout "$ELECBUILD_COMMIT"
PROJECT_ROOT_OR_FRESHCLONE_ROOT="$FRESH_CLONE"
else
info "not doing fresh clone."
fi
info "building binary..."
sudo docker run -it \
--name electrum-appimage-builder-cont \
-v "$PROJECT_ROOT_OR_FRESHCLONE_ROOT":/opt/electrum \
--rm \
--workdir /opt/electrum/contrib/build-linux/appimage \
electrum-appimage-builder-img \
./make_appimage.sh
# make sure resulting binary location is independent of fresh_clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
mkdir --parents "$DISTDIR/"
sudo cp -f "$FRESH_CLONE/dist"/* "$DISTDIR/"
fi

263
contrib/build-linux/appimage/make_appimage.sh

@ -0,0 +1,263 @@
#!/bin/bash
set -e
PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../../.."
CONTRIB="$PROJECT_ROOT/contrib"
CONTRIB_APPIMAGE="$CONTRIB/build-linux/appimage"
DISTDIR="$PROJECT_ROOT/dist"
BUILDDIR="$CONTRIB_APPIMAGE/build/appimage"
APPDIR="$BUILDDIR/electrum.AppDir"
CACHEDIR="$CONTRIB_APPIMAGE/.cache/appimage"
PIP_CACHE_DIR="$CACHEDIR/pip_cache"
export GCC_STRIP_BINARIES="1"
# pinned versions
# note: compiling python 3.8.x requires at least glibc 2.27,
# which is first available on ubuntu 18.04
PYTHON_VERSION=3.7.10
PKG2APPIMAGE_COMMIT="eb8f3acdd9f11ab19b78f5cb15daa772367daf15"
SQUASHFSKIT_COMMIT="ae0d656efa2d0df2fcac795b6823b44462f19386"
VERSION=`git describe --tags --dirty --always`
APPIMAGE="$DISTDIR/electrum-$VERSION-x86_64.AppImage"
. "$CONTRIB"/build_tools_util.sh
rm -rf "$BUILDDIR"
mkdir -p "$APPDIR" "$CACHEDIR" "$PIP_CACHE_DIR" "$DISTDIR"
# potential leftover from setuptools that might make pip put garbage in binary
rm -rf "$PROJECT_ROOT/build"
info "downloading some dependencies."
download_if_not_exist "$CACHEDIR/functions.sh" "https://raw.githubusercontent.com/AppImage/pkg2appimage/$PKG2APPIMAGE_COMMIT/functions.sh"
verify_hash "$CACHEDIR/functions.sh" "78b7ee5a04ffb84ee1c93f0cb2900123773bc6709e5d1e43c37519f590f86918"
download_if_not_exist "$CACHEDIR/appimagetool" "https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage"
verify_hash "$CACHEDIR/appimagetool" "d918b4df547b388ef253f3c9e7f6529ca81a885395c31f619d9aaf7030499a13"
download_if_not_exist "$CACHEDIR/Python-$PYTHON_VERSION.tar.xz" "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz"
verify_hash "$CACHEDIR/Python-$PYTHON_VERSION.tar.xz" "f8d82e7572c86ec9d55c8627aae5040124fd2203af400c383c821b980306ee6b"
info "building python."
tar xf "$CACHEDIR/Python-$PYTHON_VERSION.tar.xz" -C "$BUILDDIR"
(
cd "$BUILDDIR/Python-$PYTHON_VERSION"
LC_ALL=C export BUILD_DATE=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%b %d %Y")
LC_ALL=C export BUILD_TIME=$(date -u -d "@$SOURCE_DATE_EPOCH" "+%H:%M:%S")
# Patch taken from Ubuntu http://archive.ubuntu.com/ubuntu/pool/main/p/python3.7/python3.7_3.7.6-1.debian.tar.xz
patch -p1 < "$CONTRIB_APPIMAGE/patches/python-3.7-reproducible-buildinfo.diff"
./configure \
--cache-file="$CACHEDIR/python.config.cache" \
--prefix="$APPDIR/usr" \
--enable-ipv6 \
--enable-shared \
-q
make -j4 -s || fail "Could not build Python"
make -s install > /dev/null || fail "Could not install Python"
# When building in docker on macOS, python builds with .exe extension because the
# case insensitive file system of macOS leaks into docker. This causes the build
# to result in a different output on macOS compared to Linux. We simply patch
# sysconfigdata to remove the extension.
# Some more info: https://bugs.python.org/issue27631
sed -i -e 's/\.exe//g' "$APPDIR"/usr/lib/python3.7/_sysconfigdata*
)
info "Building squashfskit"
git clone "https://github.com/squashfskit/squashfskit.git" "$BUILDDIR/squashfskit"
(
cd "$BUILDDIR/squashfskit"
git checkout "${SQUASHFSKIT_COMMIT}^{commit}"
make -C squashfs-tools mksquashfs || fail "Could not build squashfskit"
)
MKSQUASHFS="$BUILDDIR/squashfskit/squashfs-tools/mksquashfs"
"$CONTRIB"/make_libsecp256k1.sh || fail "Could not build libsecp"
cp -f "$PROJECT_ROOT/electrum/libsecp256k1.so.0" "$APPDIR/usr/lib/libsecp256k1.so.0" || fail "Could not copy libsecp to its destination"
appdir_python() {
env \
PYTHONNOUSERSITE=1 \
LD_LIBRARY_PATH="$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH}" \
"$APPDIR/usr/bin/python3.7" "$@"
}
python='appdir_python'
info "installing pip."
"$python" -m ensurepip
break_legacy_easy_install
info "preparing electrum-locale."
(
cd "$PROJECT_ROOT"
git submodule update --init
pushd "$CONTRIB"/deterministic-build/electrum-locale
if ! which msgfmt > /dev/null 2>&1; then
fail "Please install gettext"
fi
# we want the binary to have only compiled (.mo) locale files; not source (.po) files
rm -rf "$PROJECT_ROOT/electrum/locale/"
for i in ./locale/*; do
dir="$PROJECT_ROOT/electrum/$i/LC_MESSAGES"
mkdir -p $dir
msgfmt --output-file="$dir/electrum.mo" "$i/electrum.po" || true
done
popd
)
info "Installing build dependencies."
"$python" -m pip install --no-dependencies --no-binary :all: --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements-build-appimage.txt"
info "installing electrum and its dependencies."
# note: we prefer compiling C extensions ourselves, instead of using binary wheels,
# hence "--no-binary :all:" flags. However, we specifically allow
# - PyQt5, as it's harder to build from source
# - cryptography, as building it would need openssl 1.1, not available on ubuntu 16.04
"$python" -m pip install --no-dependencies --no-binary :all: --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements.txt"
"$python" -m pip install --no-dependencies --no-binary :all: --only-binary PyQt5,PyQt5-Qt5,cryptography --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements-binaries.txt"
"$python" -m pip install --no-dependencies --no-binary :all: --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" -r "$CONTRIB/deterministic-build/requirements-hw.txt"
"$python" -m pip install --no-dependencies --no-warn-script-location \
--cache-dir "$PIP_CACHE_DIR" "$PROJECT_ROOT"
# was only needed during build time, not runtime
"$python" -m pip uninstall -y Cython
info "copying zbar"
cp "/usr/lib/x86_64-linux-gnu/libzbar.so.0" "$APPDIR/usr/lib/libzbar.so.0"
info "desktop integration."
cp "$PROJECT_ROOT/electrum.desktop" "$APPDIR/electrum.desktop"
cp "$PROJECT_ROOT/electrum/gui/icons/electrum.png" "$APPDIR/electrum.png"
# add launcher
cp "$CONTRIB_APPIMAGE/apprun.sh" "$APPDIR/AppRun"
info "finalizing AppDir."
(
export PKG2AICOMMIT="$PKG2APPIMAGE_COMMIT"
. "$CACHEDIR/functions.sh"
cd "$APPDIR"
# copy system dependencies
copy_deps; copy_deps; copy_deps
move_lib
# apply global appimage blacklist to exclude stuff
# move usr/include out of the way to preserve usr/include/python3.7m.
mv usr/include usr/include.tmp
delete_blacklisted
mv usr/include.tmp usr/include
) || fail "Could not finalize AppDir"
info "Copying additional libraries"
(
# On some systems it can cause problems to use the system libusb (on AppImage excludelist)
cp -f /usr/lib/x86_64-linux-gnu/libusb-1.0.so "$APPDIR/usr/lib/libusb-1.0.so" || fail "Could not copy libusb"
# some distros lack libxkbcommon-x11
cp -f /usr/lib/x86_64-linux-gnu/libxkbcommon-x11.so.0 "$APPDIR"/usr/lib/x86_64-linux-gnu || fail "Could not copy libxkbcommon-x11"
# some distros lack some libxcb libraries (see https://github.com/Electron-Cash/Electron-Cash/issues/2196)
cp -f /usr/lib/x86_64-linux-gnu/libxcb-* "$APPDIR"/usr/lib/x86_64-linux-gnu || fail "Could not copy libxcb"
)
info "stripping binaries from debug symbols."
# "-R .note.gnu.build-id" also strips the build id
# "-R .comment" also strips the GCC version information
strip_binaries()
{
chmod u+w -R "$APPDIR"
{
printf '%s\0' "$APPDIR/usr/bin/python3.7"
find "$APPDIR" -type f -regex '.*\.so\(\.[0-9.]+\)?$' -print0
} | xargs -0 --no-run-if-empty --verbose strip -R .note.gnu.build-id -R .comment
}
strip_binaries
remove_emptydirs()
{
find "$APPDIR" -type d -empty -print0 | xargs -0 --no-run-if-empty rmdir -vp --ignore-fail-on-non-empty
}
remove_emptydirs
info "removing some unneeded stuff to decrease binary size."
rm -rf "$APPDIR"/usr/{share,include}
PYDIR="$APPDIR"/usr/lib/python3.7
rm -rf "$PYDIR"/{test,ensurepip,lib2to3,idlelib,turtledemo}
rm -rf "$PYDIR"/{ctypes,sqlite3,tkinter,unittest}/test
rm -rf "$PYDIR"/distutils/{command,tests}
rm -rf "$PYDIR"/config-3.7m-x86_64-linux-gnu
rm -rf "$PYDIR"/site-packages/{opt,pip,setuptools,wheel}
rm -rf "$PYDIR"/site-packages/Cryptodome/SelfTest
rm -rf "$PYDIR"/site-packages/{psutil,qrcode,websocket}/tests
# rm lots of unused parts of Qt/PyQt. (assuming PyQt 5.15.3+ layout)
for component in connectivity declarative help location multimedia quickcontrols2 serialport webengine websockets xmlpatterns ; do
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/translations/qt${component}_*
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/resources/qt${component}_*
done
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/{qml,libexec}
rm -rf "$PYDIR"/site-packages/PyQt5/{pyrcc*.so,pylupdate*.so,uic}
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/plugins/{bearer,gamepads,geometryloaders,geoservices,playlistformats,position,renderplugins,sceneparsers,sensors,sqldrivers,texttospeech,webview}
for component in Bluetooth Concurrent Designer Help Location NetworkAuth Nfc Positioning PositioningQuick Qml Quick Sensors SerialPort Sql Test Web Xml ; do
rm -rf "$PYDIR"/site-packages/PyQt5/Qt5/lib/libQt5${component}*
rm -rf "$PYDIR"/site-packages/PyQt5/Qt${component}*
done
rm -rf "$PYDIR"/site-packages/PyQt5/Qt.so
# these are deleted as they were not deterministic; and are not needed anyway
find "$APPDIR" -path '*/__pycache__*' -delete
# note that *.dist-info is needed by certain packages.
# e.g. see https://gitlab.com/python-devs/importlib_metadata/issues/71
for f in "$PYDIR"/site-packages/importlib_metadata-*.dist-info; do mv "$f" "$(echo "$f" | sed s/\.dist-info/\.dist-info2/)"; done
rm -rf "$PYDIR"/site-packages/*.dist-info/
rm -rf "$PYDIR"/site-packages/*.egg-info/
for f in "$PYDIR"/site-packages/importlib_metadata-*.dist-info2; do mv "$f" "$(echo "$f" | sed s/\.dist-info2/\.dist-info/)"; done
find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} +
info "creating the AppImage."
(
cd "$BUILDDIR"
cp "$CACHEDIR/appimagetool" "$CACHEDIR/appimagetool_copy"
# zero out "appimage" magic bytes, as on some systems they confuse the linker
sed -i 's|AI\x02|\x00\x00\x00|' "$CACHEDIR/appimagetool_copy"
chmod +x "$CACHEDIR/appimagetool_copy"
"$CACHEDIR/appimagetool_copy" --appimage-extract
# We build a small wrapper for mksquashfs that removes the -mkfs-fixed-time option
# that mksquashfs from squashfskit does not support. It is not needed for squashfskit.
cat > ./squashfs-root/usr/lib/appimagekit/mksquashfs << EOF
#!/bin/sh
args=\$(echo "\$@" | sed -e 's/-mkfs-fixed-time 0//')
"$MKSQUASHFS" \$args
EOF
env VERSION="$VERSION" ARCH=x86_64 SOURCE_DATE_EPOCH=1530212462 ./squashfs-root/AppRun --no-appstream --verbose "$APPDIR" "$APPIMAGE"
)
info "done."
ls -la "$DISTDIR"
sha256sum "$DISTDIR"/*

35
contrib/build-linux/sdist/README.md

@ -5,8 +5,7 @@ Source tarballs
distributables that match the official releases._ distributables that match the official releases._
This assumes an Ubuntu (x86_64) host, but it should not be too hard to adapt to another This assumes an Ubuntu (x86_64) host, but it should not be too hard to adapt to another
similar system. The docker commands should be executed in the project's root similar system.
folder.
1. Install Docker 1. Install Docker
@ -17,36 +16,14 @@ folder.
$ sudo apt-get install -y docker-ce $ sudo apt-get install -y docker-ce
``` ```
2. Build image 2. Build source tarball
``` ```
$ sudo docker build -t electrum-sdist-builder-img contrib/build-linux/sdist $ ./build.sh
``` ```
If you want reproducibility, try instead e.g.:
3. Build source tarballs
It's recommended to build from a fresh clone
(but you can skip this if reproducibility is not necessary).
``` ```
$ FRESH_CLONE=contrib/build-linux/sdist/fresh_clone && \ $ ELECBUILD_COMMIT=HEAD ELECBUILD_NOCACHE=1 ./build.sh
sudo rm -rf $FRESH_CLONE && \
umask 0022 && \
mkdir -p $FRESH_CLONE && \
cd $FRESH_CLONE && \
git clone https://github.com/spesmilo/electrum.git && \
cd electrum
``` ```
And then build from this directory: 3. The generated distributables are in `./dist`.
```
$ git checkout $REV
$ sudo docker run -it \
--name electrum-sdist-builder-cont \
-v $PWD:/opt/electrum \
--rm \
--workdir /opt/electrum/contrib/build-linux/sdist \
electrum-sdist-builder-img \
./build.sh
```
4. The generated distributables are in `./dist`.

65
contrib/build-linux/sdist/build.sh

@ -1,32 +1,57 @@
#!/bin/bash #!/bin/bash
#
# env vars:
# - ELECBUILD_NOCACHE: if set, forces rebuild of docker image
# - ELECBUILD_COMMIT: if set, do a fresh clone and git checkout
set -e set -e
PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../../.." PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../../.."
PROJECT_ROOT_OR_FRESHCLONE_ROOT="$PROJECT_ROOT"
CONTRIB="$PROJECT_ROOT/contrib" CONTRIB="$PROJECT_ROOT/contrib"
CONTRIB_SDIST="$CONTRIB/build-linux/sdist" CONTRIB_SDIST="$CONTRIB/build-linux/sdist"
DISTDIR="$PROJECT_ROOT/dist" DISTDIR="$PROJECT_ROOT/dist"
. "$CONTRIB"/build_tools_util.sh . "$CONTRIB"/build_tools_util.sh
# note that at least py3.7 is needed, to have https://bugs.python.org/issue30693
python3 --version || fail "python interpreter not found"
break_legacy_easy_install DOCKER_BUILD_FLAGS=""
if [ ! -z "$ELECBUILD_NOCACHE" ] ; then
# upgrade to modern pip so that it knows the flags we need. info "ELECBUILD_NOCACHE is set. forcing rebuild of docker image."
# we will then install a pinned version of pip as part of requirements-build-sdist DOCKER_BUILD_FLAGS="--pull --no-cache"
python3 -m pip install --upgrade pip fi
info "Installing pinned requirements." info "building docker image."
python3 -m pip install --no-dependencies --no-warn-script-location -r "$CONTRIB"/deterministic-build/requirements-build-sdist.txt sudo docker build \
$DOCKER_BUILD_FLAGS \
-t electrum-sdist-builder-img \
"$CONTRIB"/make_packages || fail "make_packages failed" "$CONTRIB_SDIST"
"$CONTRIB_SDIST"/make_tgz || fail "make_tgz failed" # maybe do fresh clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
info "ELECBUILD_COMMIT=$ELECBUILD_COMMIT. doing fresh clone and git checkout."
info "done." FRESH_CLONE="$CONTRIB_SDIST/fresh_clone/electrum" && \
ls -la "$DISTDIR" sudo rm -rf "$FRESH_CLONE" && \
sha256sum "$DISTDIR"/* umask 0022 && \
git clone "$PROJECT_ROOT" "$FRESH_CLONE" && \
cd "$FRESH_CLONE"
git checkout "$ELECBUILD_COMMIT"
PROJECT_ROOT_OR_FRESHCLONE_ROOT="$FRESH_CLONE"
else
info "not doing fresh clone."
fi
info "building binary..."
sudo docker run -it \
--name electrum-sdist-builder-cont \
-v "$PROJECT_ROOT_OR_FRESHCLONE_ROOT":/opt/electrum \
--rm \
--workdir /opt/electrum/contrib/build-linux/sdist \
electrum-sdist-builder-img \
./make_sdist.sh
# make sure resulting binary location is independent of fresh_clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
mkdir --parents "$DISTDIR/"
sudo cp -f "$FRESH_CLONE/dist"/* "$DISTDIR/"
fi

60
contrib/build-linux/sdist/make_sdist.sh

@ -0,0 +1,60 @@
#!/bin/bash
set -e
PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../../.."
CONTRIB="$PROJECT_ROOT/contrib"
CONTRIB_SDIST="$CONTRIB/build-linux/sdist"
DISTDIR="$PROJECT_ROOT/dist"
LOCALE="$PROJECT_ROOT/electrum/locale/"
. "$CONTRIB"/build_tools_util.sh
# note that at least py3.7 is needed, to have https://bugs.python.org/issue30693
python3 --version || fail "python interpreter not found"
break_legacy_easy_install
# upgrade to modern pip so that it knows the flags we need.
# we will then install a pinned version of pip as part of requirements-build-sdist
python3 -m pip install --upgrade pip
info "Installing pinned requirements."
python3 -m pip install --no-dependencies --no-warn-script-location -r "$CONTRIB"/deterministic-build/requirements-build-sdist.txt
"$CONTRIB"/make_packages || fail "make_packages failed"
git submodule update --init
(
cd "$CONTRIB/deterministic-build/electrum-locale/"
if ! which msgfmt > /dev/null 2>&1; then
echo "Please install gettext"
exit 1
fi
# We include both source (.po) and compiled (.mo) locale files in the source dist.
# Maybe we should exclude the compiled locale files? see https://askubuntu.com/a/144139
# (also see MANIFEST.in)
rm -rf "$LOCALE"
for i in ./locale/*; do
dir="$PROJECT_ROOT/electrum/$i/LC_MESSAGES"
mkdir -p "$dir"
msgfmt --output-file="$dir/electrum.mo" "$i/electrum.po" || true
cp $i/electrum.po "$PROJECT_ROOT/electrum/$i/electrum.po"
done
)
(
cd "$PROJECT_ROOT"
find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} +
# note: .zip sdists would not be reproducible due to https://bugs.python.org/issue40963
TZ=UTC faketime -f '2000-11-11 11:11:11' python3 setup.py --quiet sdist --format=gztar
)
info "done."
ls -la "$DISTDIR"
sha256sum "$DISTDIR"/*

43
contrib/build-linux/sdist/make_tgz

@ -1,43 +0,0 @@
#!/bin/bash
set -e
CONTRIB_SDIST="$(dirname "$(readlink -e "$0")")"
CONTRIB="$CONTRIB_SDIST"/../..
ROOT_FOLDER="$CONTRIB"/..
PACKAGES="$ROOT_FOLDER"/packages/
LOCALE="$ROOT_FOLDER"/electrum/locale/
if [ ! -d "$PACKAGES" ]; then
echo "Run make_packages first!"
exit 1
fi
git submodule update --init
(
cd "$CONTRIB/deterministic-build/electrum-locale/"
if ! which msgfmt > /dev/null 2>&1; then
echo "Please install gettext"
exit 1
fi
# We include both source (.po) and compiled (.mo) locale files in the source dist.
# Maybe we should exclude the compiled locale files? see https://askubuntu.com/a/144139
# (also see MANIFEST.in)
rm -rf "$LOCALE"
for i in ./locale/*; do
dir="$ROOT_FOLDER/electrum/$i/LC_MESSAGES"
mkdir -p "$dir"
msgfmt --output-file="$dir/electrum.mo" "$i/electrum.po" || true
cp $i/electrum.po "$ROOT_FOLDER/electrum/$i/electrum.po"
done
)
(
cd "$ROOT_FOLDER"
find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} +
# note: .zip sdists would not be reproducible due to https://bugs.python.org/issue40963
TZ=UTC faketime -f '2000-11-11 11:11:11' python3 setup.py --quiet sdist --format=gztar
)

58
contrib/build-wine/README.md

@ -5,8 +5,7 @@ Windows binaries
binaries that match the official releases._ binaries that match the official releases._
This assumes an Ubuntu (x86_64) host, but it should not be too hard to adapt to another This assumes an Ubuntu (x86_64) host, but it should not be too hard to adapt to another
similar system. The docker commands should be executed in the project's root similar system.
folder.
1. Install Docker 1. Install Docker
@ -21,40 +20,17 @@ folder.
(see [#6971](https://github.com/spesmilo/electrum/issues/6971)). (see [#6971](https://github.com/spesmilo/electrum/issues/6971)).
If having problems, try to upgrade to at least `docker 20.10`. If having problems, try to upgrade to at least `docker 20.10`.
2. Build image 2. Build Windows binaries
``` ```
$ sudo docker build -t electrum-wine-builder-img contrib/build-wine $ ./build.sh
``` ```
If you want reproducibility, try instead e.g.:
Note: see [this](https://stackoverflow.com/a/40516974/7499128) if having dns problems
3. Build Windows binaries
It's recommended to build from a fresh clone
(but you can skip this if reproducibility is not necessary).
``` ```
$ FRESH_CLONE=contrib/build-wine/fresh_clone && \ $ ELECBUILD_COMMIT=HEAD ELECBUILD_NOCACHE=1 ./build.sh
sudo rm -rf $FRESH_CLONE && \
mkdir -p $FRESH_CLONE && \
cd $FRESH_CLONE && \
git clone https://github.com/spesmilo/electrum.git && \
cd electrum
``` ```
And then build from this directory: 3. The generated binaries are in `./contrib/build-wine/dist`.
```
$ git checkout $REV
$ sudo docker run -it \
--name electrum-wine-builder-cont \
-v $PWD:/opt/wine64/drive_c/electrum \
--rm \
--workdir /opt/wine64/drive_c/electrum/contrib/build-wine \
electrum-wine-builder-img \
./build.sh
```
4. The generated binaries are in `./contrib/build-wine/dist`.
@ -71,18 +47,18 @@ The release signing procedure involves a signer (the holder of the
certificate/key) and one or multiple trusted verifiers: certificate/key) and one or multiple trusted verifiers:
| Signer | Verifier | | Signer | Verifier |
|-----------------------------------------------------------|-----------------------------------| |-----------------------------------------------------------|--------------------------------------|
| Build .exe files using `build.sh` | | | Build .exe files using `make_win.sh` | |
| Sign .exe with `./sign.sh` | | | Sign .exe with `./sign.sh` | |
| Upload signed files to download server | | | Upload signed files to download server | |
| | Build .exe files using `build.sh` | | | Build .exe files using `make_win.sh` |
| | Compare files using `unsign.sh` | | | Compare files using `unsign.sh` |
| | Sign .exe file using `gpg -b` | | | Sign .exe file using `gpg -b` |
| Signer and verifiers: | | Signer and verifiers: |
|-----------------------------------------------------------------------------------------------| |--------------------------------------------------------------------------------------------------|
| Upload signatures to 'electrum-signatures' repo, as `$version/$filename.$builder.asc` | | Upload signatures to 'electrum-signatures' repo, as `$version/$filename.$builder.asc` |

97
contrib/build-wine/build.sh

@ -1,67 +1,56 @@
#!/bin/bash #!/bin/bash
#
# env vars:
# - ELECBUILD_NOCACHE: if set, forces rebuild of docker image
# - ELECBUILD_COMMIT: if set, do a fresh clone and git checkout
set -e set -e
here="$(dirname "$(readlink -e "$0")")" PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../.."
test -n "$here" -a -d "$here" || exit PROJECT_ROOT_OR_FRESHCLONE_ROOT="$PROJECT_ROOT"
CONTRIB="$PROJECT_ROOT/contrib"
if [ -z "$WIN_ARCH" ] ; then CONTRIB_WINE="$CONTRIB/build-wine"
export WIN_ARCH="win32" # default
fi
if [ "$WIN_ARCH" = "win32" ] ; then
export GCC_TRIPLET_HOST="i686-w64-mingw32"
elif [ "$WIN_ARCH" = "win64" ] ; then
export GCC_TRIPLET_HOST="x86_64-w64-mingw32"
else
echo "unexpected WIN_ARCH: $WIN_ARCH"
exit 1
fi
export BUILD_TYPE="wine"
export GCC_TRIPLET_BUILD="x86_64-pc-linux-gnu"
export GCC_STRIP_BINARIES="1"
export CONTRIB="$here/.."
export PROJECT_ROOT="$CONTRIB/.."
export CACHEDIR="$here/.cache/$WIN_ARCH"
export PIP_CACHE_DIR="$CACHEDIR/wine_pip_cache"
export WINE_PIP_CACHE_DIR="c:/electrum/contrib/build-wine/.cache/$WIN_ARCH/wine_pip_cache"
export DLL_TARGET_DIR="$CACHEDIR/dlls"
export WINEPREFIX="/opt/wine64"
export WINEDEBUG=-all
export WINE_PYHOME="c:/python3"
export WINE_PYTHON="wine $WINE_PYHOME/python.exe -OO -B"
. "$CONTRIB"/build_tools_util.sh . "$CONTRIB"/build_tools_util.sh
info "Clearing $here/build and $here/dist..."
rm "$here"/build/* -rf
rm "$here"/dist/* -rf
mkdir -p "$CACHEDIR" "$DLL_TARGET_DIR" "$PIP_CACHE_DIR" DOCKER_BUILD_FLAGS=""
if [ ! -z "$ELECBUILD_NOCACHE" ] ; then
if [ -f "$DLL_TARGET_DIR/libsecp256k1-0.dll" ]; then info "ELECBUILD_NOCACHE is set. forcing rebuild of docker image."
info "libsecp256k1 already built, skipping" DOCKER_BUILD_FLAGS="--pull --no-cache"
else
"$CONTRIB"/make_libsecp256k1.sh || fail "Could not build libsecp"
fi fi
if [ -f "$DLL_TARGET_DIR/libzbar-0.dll" ]; then info "building docker image."
info "libzbar already built, skipping" sudo docker build \
$DOCKER_BUILD_FLAGS \
-t electrum-wine-builder-img \
"$CONTRIB_WINE"
# maybe do fresh clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
info "ELECBUILD_COMMIT=$ELECBUILD_COMMIT. doing fresh clone and git checkout."
FRESH_CLONE="$CONTRIB_WINE/fresh_clone/electrum" && \
sudo rm -rf "$FRESH_CLONE" && \
umask 0022 && \
git clone "$PROJECT_ROOT" "$FRESH_CLONE" && \
cd "$FRESH_CLONE"
git checkout "$ELECBUILD_COMMIT"
PROJECT_ROOT_OR_FRESHCLONE_ROOT="$FRESH_CLONE"
else else
"$CONTRIB"/make_zbar.sh || fail "Could not build zbar" info "not doing fresh clone."
fi fi
$here/prepare-wine.sh || fail "prepare-wine failed" info "building binary..."
sudo docker run -it \
info "Resetting modification time in C:\Python..." --name electrum-wine-builder-cont \
# (Because of some bugs in pyinstaller) -v "$PROJECT_ROOT_OR_FRESHCLONE_ROOT":/opt/wine64/drive_c/electrum \
pushd /opt/wine64/drive_c/python* --rm \
find -exec touch -d '2000-11-11T11:11:11+00:00' {} + --workdir /opt/wine64/drive_c/electrum/contrib/build-wine \
popd electrum-wine-builder-img \
ls -l /opt/wine64/drive_c/python* ./make_win.sh
$here/build-electrum-git.sh || fail "build-electrum-git failed" # make sure resulting binary location is independent of fresh_clone
if [ ! -z "$ELECBUILD_COMMIT" ] ; then
info "Done." mkdir --parents "$PROJECT_ROOT/contrib/build-wine/dist/"
sudo cp -f "$FRESH_CLONE/contrib/build-wine/dist"/* "$PROJECT_ROOT/contrib/build-wine/dist/"
fi

67
contrib/build-wine/make_win.sh

@ -0,0 +1,67 @@
#!/bin/bash
set -e
here="$(dirname "$(readlink -e "$0")")"
test -n "$here" -a -d "$here" || exit
if [ -z "$WIN_ARCH" ] ; then
export WIN_ARCH="win32" # default
fi
if [ "$WIN_ARCH" = "win32" ] ; then
export GCC_TRIPLET_HOST="i686-w64-mingw32"
elif [ "$WIN_ARCH" = "win64" ] ; then
export GCC_TRIPLET_HOST="x86_64-w64-mingw32"
else
echo "unexpected WIN_ARCH: $WIN_ARCH"
exit 1
fi
export BUILD_TYPE="wine"
export GCC_TRIPLET_BUILD="x86_64-pc-linux-gnu"
export GCC_STRIP_BINARIES="1"
export CONTRIB="$here/.."
export PROJECT_ROOT="$CONTRIB/.."
export CACHEDIR="$here/.cache/$WIN_ARCH"
export PIP_CACHE_DIR="$CACHEDIR/wine_pip_cache"
export WINE_PIP_CACHE_DIR="c:/electrum/contrib/build-wine/.cache/$WIN_ARCH/wine_pip_cache"
export DLL_TARGET_DIR="$CACHEDIR/dlls"
export WINEPREFIX="/opt/wine64"
export WINEDEBUG=-all
export WINE_PYHOME="c:/python3"
export WINE_PYTHON="wine $WINE_PYHOME/python.exe -OO -B"
. "$CONTRIB"/build_tools_util.sh
info "Clearing $here/build and $here/dist..."
rm "$here"/build/* -rf
rm "$here"/dist/* -rf
mkdir -p "$CACHEDIR" "$DLL_TARGET_DIR" "$PIP_CACHE_DIR"
if [ -f "$DLL_TARGET_DIR/libsecp256k1-0.dll" ]; then
info "libsecp256k1 already built, skipping"
else
"$CONTRIB"/make_libsecp256k1.sh || fail "Could not build libsecp"
fi
if [ -f "$DLL_TARGET_DIR/libzbar-0.dll" ]; then
info "libzbar already built, skipping"
else
"$CONTRIB"/make_zbar.sh || fail "Could not build zbar"
fi
"$here/prepare-wine.sh" || fail "prepare-wine failed"
info "Resetting modification time in C:\Python..."
# (Because of some bugs in pyinstaller)
pushd /opt/wine64/drive_c/python*
find -exec touch -d '2000-11-11T11:11:11+00:00' {} +
popd
ls -l /opt/wine64/drive_c/python*
"$here/build-electrum-git.sh" || fail "build-electrum-git failed"
info "Done."

95
contrib/release.sh

@ -1,10 +1,14 @@
#
# Note: update locale before:
# 1. cd /opt/electrum-locale && ./update && push
# 2. cd to the submodule dir, and git pull
# 3. cd .. && git push
#!/bin/bash #!/bin/bash
# Note: steps before doing a new release:
#
# - update locale:
# 1. cd /opt/electrum-locale && ./update && push
# 2. cd to the submodule dir, and git pull
# 3. cd .. && git push
# - update RELEASE-NOTES and version.py
# - git tag
ELECTRUM_DIR=/opt/electrum ELECTRUM_DIR=/opt/electrum
WWW_DIR=/opt/electrum-web WWW_DIR=/opt/electrum-web
@ -20,6 +24,9 @@ REV=`git describe --tags`
echo "REV: $REV" echo "REV: $REV"
COMMIT=$(git rev-parse HEAD) COMMIT=$(git rev-parse HEAD)
export ELECBUILD_COMMIT="${COMMIT}^{commit}"
#export ELECBUILD_NOCACHE=1
git_status=$(git status --porcelain) git_status=$(git status --porcelain)
if [ ! -z "$git_status" ]; then if [ ! -z "$git_status" ]; then
@ -35,25 +42,7 @@ target=Electrum-$VERSION.tar.gz
if test -f dist/$target; then if test -f dist/$target; then
echo "file exists: $target" echo "file exists: $target"
else else
pushd . ./contrib/build-linux/sdist/build.sh
sudo docker build -t electrum-sdist-builder-img contrib/build-linux/sdist
FRESH_CLONE=contrib/build-linux/sdist/fresh_clone && \
sudo rm -rf $FRESH_CLONE && \
umask 0022 && \
mkdir -p $FRESH_CLONE && \
cd $FRESH_CLONE && \
git clone https://github.com/spesmilo/electrum.git &&\
cd electrum
git checkout "${COMMIT}^{commit}"
sudo docker run -it \
--name electrum-sdist-builder-cont \
-v $PWD:/opt/electrum \
--rm \
--workdir /opt/electrum/contrib/build-linux/sdist \
electrum-sdist-builder-img \
./build.sh
popd
cp /opt/electrum/contrib/build-linux/sdist/fresh_clone/electrum/dist/$target dist/
fi fi
# appimage # appimage
@ -66,14 +55,7 @@ fi
if test -f dist/$target; then if test -f dist/$target; then
echo "file exists: $target" echo "file exists: $target"
else else
sudo docker build -t electrum-appimage-builder-img contrib/build-linux/appimage ./contrib/build-linux/appimage/build.sh
sudo docker run -it \
--name electrum-appimage-builder-cont \
-v $PWD:/opt/electrum \
--rm \
--workdir /opt/electrum/contrib/build-linux/appimage \
electrum-appimage-builder-img \
./build.sh
fi fi
@ -83,21 +65,7 @@ if test -f dist/$target; then
echo "file exists: $target" echo "file exists: $target"
else else
pushd . pushd .
FRESH_CLONE=contrib/build-wine/fresh_clone && \ ./contrib/build-wine/build.sh
sudo rm -rf $FRESH_CLONE && \
mkdir -p $FRESH_CLONE && \
cd $FRESH_CLONE && \
git clone https://github.com/spesmilo/electrum.git && \
cd electrum
git checkout "${COMMIT}^{commit}"
sudo docker run -it \
--name electrum-wine-builder-cont \
-v $PWD:/opt/wine64/drive_c/electrum \
--rm \
--workdir /opt/wine64/drive_c/electrum/contrib/build-wine \
electrum-wine-builder-img \
./build.sh
# do this in the fresh clone directory!
cd contrib/build-wine/ cd contrib/build-wine/
./sign.sh ./sign.sh
cp ./signed/*.exe /opt/electrum/dist/ cp ./signed/*.exe /opt/electrum/dist/
@ -111,40 +79,17 @@ target2=Electrum-$VERSION.0-arm64-v8a-release.apk
if test -f dist/$target1; then if test -f dist/$target1; then
echo "file exists: $target1" echo "file exists: $target1"
else else
pushd . ./contrib/android/build.sh release
./contrib/android/build_docker_image.sh
FRESH_CLONE=contrib/android/fresh_clone && \
sudo rm -rf $FRESH_CLONE && \
umask 0022 && \
mkdir -p $FRESH_CLONE && \
cd $FRESH_CLONE && \
git clone https://github.com/spesmilo/electrum.git && \
cd electrum
git checkout "${COMMIT}^{commit}"
mkdir --parents $PWD/.buildozer/.gradle
sudo docker run -it --rm \
--name electrum-android-builder-cont \
-v $PWD:/home/user/wspace/electrum \
-v $PWD/.buildozer/.gradle:/home/user/.gradle \
-v ~/.keystore:/home/user/.keystore \
--workdir /home/user/wspace/electrum \
electrum-android-builder-img \
./contrib/android/make_apk release
popd
cp contrib/android/fresh_clone/electrum/bin/$target1 dist/
cp contrib/android/fresh_clone/electrum/bin/$target2 dist/
fi fi
# wait for dmg before signing # wait for dmg before signing
if test -f dist/electrum-$VERSION.dmg; then if test -f dist/electrum-$VERSION.dmg; then
if test -f dist/electrum-$VERSION.dmg.asc; then if test -f dist/electrum-$VERSION.dmg.asc; then
echo "packages are already signed" echo "packages are already signed"
else else
echo "signing packages" echo "signing packages"
./contrib/sign_packages ThomasV ./contrib/sign_packages ThomasV
fi fi
else else
echo "dmg is missing, aborting" echo "dmg is missing, aborting"
@ -154,7 +99,7 @@ fi
echo "build complete" echo "build complete"
sha256sum dist/*.tar.gz sha256sum dist/*.tar.gz
sha256sum dist/*.AppImage sha256sum dist/*.AppImage
sha256sum contrib/build-wine/fresh_clone/electrum/contrib/build-wine/dist/*.exe sha256sum contrib/build-wine/dist/*.exe
echo -n "proceed (y/n)? " echo -n "proceed (y/n)? "
read answer read answer

Loading…
Cancel
Save