twin binary: build zbar ourselves (#6593) - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit fc89c8ffa9b1ab4012331447090b36f6f15b13fc
 (DIR) parent ea3e3ddbb8280f499bf2535d2a8a63dd174e2e44
 (HTM) Author: ghost43 <somber.night@protonmail.com>
       Date:   Tue, 15 Sep 2020 15:35:57 +0000
       
       win binary: build zbar ourselves (#6593)
       
       This allows bundling much newer zbar that includes many fixes.
       related: #6018
       
       This is largely based on
       https://github.com/Electron-Cash/Electron-Cash/pull/1362
       https://github.com/Electron-Cash/Electron-Cash/pull/1363
       https://github.com/Electron-Cash/Electron-Cash/pull/1365
       https://github.com/Electron-Cash/Electron-Cash/commit/eda015908e9d6ea9a0adfbda9db55b929c0926ba
       Diffstat:
         M contrib/build-wine/Dockerfile       |       3 +++
         M contrib/build-wine/build.sh         |       6 ++++++
         M contrib/build-wine/deterministic.s… |       2 +-
         M contrib/build-wine/prepare-wine.sh  |      12 ++----------
         M contrib/make_libsecp256k1.sh        |       2 +-
         A contrib/make_zbar.sh                |      96 +++++++++++++++++++++++++++++++
         M electrum/qrscanner.py               |      24 ++++++++++++++++--------
       
       7 files changed, 125 insertions(+), 20 deletions(-)
       ---
 (DIR) diff --git a/contrib/build-wine/Dockerfile b/contrib/build-wine/Dockerfile
       t@@ -17,8 +17,11 @@ RUN apt-get update -q && \
                p7zip-full=16.02+dfsg-6 \
                make=4.1-9.1ubuntu1 \
                mingw-w64=5.0.3-1 \
       +        mingw-w64-tools=5.0.3-1 \
       +        win-iconv-mingw-w64-dev=0.0.8-2 \
                autotools-dev=20180224.1 \
                autoconf=2.69-11 \
       +        autopoint=0.19.8.1-6ubuntu0.3 \
                libtool=2.4.6-2 \
                gettext=0.19.8.1-6
        
 (DIR) diff --git a/contrib/build-wine/build.sh b/contrib/build-wine/build.sh
       t@@ -29,6 +29,12 @@ else
            "$CONTRIB"/make_libsecp256k1.sh || fail "Could not build libsecp"
        fi
        
       +if [ -f "$PROJECT_ROOT/electrum/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..."
 (DIR) diff --git a/contrib/build-wine/deterministic.spec b/contrib/build-wine/deterministic.spec
       t@@ -34,6 +34,7 @@ binaries += [b for b in collect_dynamic_libs('PyQt5') if 'qwindowsvista' in b[0]
        
        binaries += [('C:/tmp/libsecp256k1-0.dll', '.')]
        binaries += [('C:/tmp/libusb-1.0.dll', '.')]
       +binaries += [('C:/tmp/libzbar-0.dll', '.')]
        
        datas = [
            (home+'electrum/*.json', 'electrum'),
       t@@ -41,7 +42,6 @@ datas = [
            (home+'electrum/wordlist/english.txt', 'electrum/wordlist'),
            (home+'electrum/locale', 'electrum/locale'),
            (home+'electrum/plugins', 'electrum/plugins'),
       -    ('C:\\Program Files (x86)\\ZBar\\bin\\', '.'),
            (home+'electrum/gui/icons', 'electrum/gui/icons'),
        ]
        datas += collect_data_files('trezorlib')
 (DIR) diff --git a/contrib/build-wine/prepare-wine.sh b/contrib/build-wine/prepare-wine.sh
       t@@ -5,10 +5,6 @@ NSIS_FILENAME=nsis-3.05-setup.exe
        NSIS_URL=https://downloads.sourceforge.net/project/nsis/NSIS%203/3.05/$NSIS_FILENAME
        NSIS_SHA256=1a3cc9401667547b9b9327a177b13485f7c59c2303d4b6183e7bc9e6c8d6bfdb
        
       -ZBAR_FILENAME=zbarw-20121031-setup.exe
       -ZBAR_URL=https://downloads.sourceforge.net/project/zbarw/$ZBAR_FILENAME
       -ZBAR_SHA256=177e32b272fa76528a3af486b74e9cb356707be1c5ace4ed3fcee9723e2c2c02
       -
        LIBUSB_REPO="https://github.com/libusb/libusb.git"
        LIBUSB_COMMIT="e782eeb2514266f6738e242cdcb18e3ae1ed06fa"
        # ^ tag v1.0.23
       t@@ -63,11 +59,6 @@ $PYTHON -m pip install --no-dependencies --no-warn-script-location -r "$CONTRIB"
        info "Installing dependencies specific to binaries."
        $PYTHON -m pip install --no-dependencies --no-warn-script-location -r "$CONTRIB"/deterministic-build/requirements-binaries.txt
        
       -info "Installing ZBar."
       -download_if_not_exist "$CACHEDIR/$ZBAR_FILENAME" "$ZBAR_URL"
       -verify_hash "$CACHEDIR/$ZBAR_FILENAME" "$ZBAR_SHA256"
       -wine "$CACHEDIR/$ZBAR_FILENAME" /S
       -
        info "Installing NSIS."
        download_if_not_exist "$CACHEDIR/$NSIS_FILENAME" "$NSIS_URL"
        verify_hash "$CACHEDIR/$NSIS_FILENAME" "$NSIS_SHA256"
       t@@ -101,8 +92,9 @@ info "Compiling libusb..."
        cp "$CACHEDIR/libusb/libusb/.libs/libusb-1.0.dll" $WINEPREFIX/drive_c/tmp/  || fail "Could not copy libusb to its destination"
        
        
       -# copy libsecp dll (already built)
       +# copy already built DLLs
        cp "$PROJECT_ROOT/electrum/libsecp256k1-0.dll" $WINEPREFIX/drive_c/tmp/ || fail "Could not copy libsecp to its destination"
       +cp "$PROJECT_ROOT/electrum/libzbar-0.dll" $WINEPREFIX/drive_c/tmp/ || fail "Could not copy libzbar to its destination"
        
        
        info "Building PyInstaller."
 (DIR) diff --git a/contrib/make_libsecp256k1.sh b/contrib/make_libsecp256k1.sh
       t@@ -34,7 +34,7 @@ info "Building $pkgname..."
                git fetch --all
            fi
            git reset --hard
       -    git clean -f -x -q
       +    git clean -dfxq
            git checkout "${LIBSECP_VERSION}^{commit}"
        
            if ! [ -x configure ] ; then
 (DIR) diff --git a/contrib/make_zbar.sh b/contrib/make_zbar.sh
       t@@ -0,0 +1,96 @@
       +#!/bin/bash
       +
       +# This script can be used on Linux hosts to build native libzbar binaries.
       +# sudo apt-get install pkg-config libx11-dev libx11-6 libv4l-dev libxv-dev libxext-dev libjpeg-dev
       +#
       +# It can also be used to cross-compile to Windows:
       +# $ sudo apt-get install mingw-w64 mingw-w64-tools win-iconv-mingw-w64-dev
       +# For a Windows x86 (32-bit) target, run:
       +# $ GCC_TRIPLET_HOST="i686-w64-mingw32" BUILD_TYPE="wine" ./contrib/make_zbar.sh
       +# Or for a Windows x86_64 (64-bit) target, run:
       +# $ GCC_TRIPLET_HOST="x86_64-w64-mingw32" BUILD_TYPE="wine" ./contrib/make_zbar.sh
       +
       +ZBAR_VERSION="d2893738411be897a04caa42ffc13d1f6107d3c6"
       +
       +set -e
       +
       +. $(dirname "$0")/build_tools_util.sh || (echo "Could not source build_tools_util.sh" && exit 1)
       +
       +here=$(dirname $(realpath "$0" 2> /dev/null || grealpath "$0"))
       +CONTRIB="$here"
       +PROJECT_ROOT="$CONTRIB/.."
       +
       +pkgname="zbar"
       +info "Building $pkgname..."
       +
       +(
       +    cd $CONTRIB
       +    if [ ! -d zbar ]; then
       +        git clone https://github.com/mchehab/zbar.git
       +    fi
       +    cd zbar
       +    if ! $(git cat-file -e ${ZBAR_VERSION}) ; then
       +        info "Could not find requested version $ZBAR_VERSION in local clone; fetching..."
       +        git fetch --all
       +    fi
       +    git reset --hard
       +    git clean -dfxq
       +    git checkout "${ZBAR_VERSION}^{commit}"
       +
       +    if [ "$BUILD_TYPE" = "wine" ] ; then
       +        echo "libzbar_la_LDFLAGS += -Wc,-static" >> zbar/Makefile.am
       +        echo "LDFLAGS += -Wc,-static" >> Makefile.am
       +    fi
       +    if ! [ -x configure ] ; then
       +        autoreconf -vfi || fail "Could not run autoreconf for $pkgname. Please make sure you have automake and libtool installed, and try again."
       +    fi
       +    if ! [ -r config.status ] ; then
       +        if [ "$BUILD_TYPE" = "wine" ] ; then
       +            # windows target
       +            ./configure \
       +                $AUTOCONF_FLAGS \
       +                --prefix="$here/$pkgname/dist" \
       +                --with-x=no \
       +                --enable-pthread=no \
       +                --enable-doc=no \
       +                --enable-video=yes \
       +                --with-directshow=yes \
       +                --with-jpeg=no \
       +                --with-python=no \
       +                --with-gtk=no \
       +                --with-qt=no \
       +                --with-java=no \
       +                --with-imagemagick=no \
       +                --with-dbus=no \
       +                --enable-codes=qrcode \
       +                --disable-dependency-tracking \
       +                --disable-static \
       +                --enable-shared || fail "Could not configure $pkgname. Please make sure you have a C compiler installed and try again."
       +        else
       +            # linux target
       +            ./configure \
       +                $AUTOCONF_FLAGS \
       +                --prefix="$here/$pkgname/dist" \
       +                --with-x=yes \
       +                --enable-pthread=no \
       +                --enable-doc=no \
       +                --enable-video=yes \
       +                --with-jpeg=yes \
       +                --with-python=no \
       +                --with-gtk=no \
       +                --with-qt=no \
       +                --with-java=no \
       +                --with-imagemagick=no \
       +                --with-dbus=no \
       +                --enable-codes=qrcode \
       +                --disable-static \
       +                --enable-shared || fail "Could not configure $pkgname. Please make sure you have a C compiler installed and try again."
       +        fi
       +    fi
       +    make -j4 || fail "Could not build $pkgname"
       +    make install || fail "Could not install $pkgname"
       +    . "$here/$pkgname/dist/lib/libzbar.la"
       +    host_strip "$here/$pkgname/dist/lib/$dlname"
       +    cp -fpv "$here/$pkgname/dist/lib/$dlname" "$PROJECT_ROOT/electrum" || fail "Could not copy the $pkgname binary to its destination"
       +    info "$dlname has been placed in the inner 'electrum' folder."
       +)
 (DIR) diff --git a/electrum/qrscanner.py b/electrum/qrscanner.py
       t@@ -27,6 +27,12 @@ import os
        import sys
        import ctypes
        
       +from .logging import get_logger
       +
       +
       +_logger = get_logger(__name__)
       +
       +
        if sys.platform == 'darwin':
            name = 'libzbar.dylib'
        elif sys.platform in ('windows', 'win32'):
       t@@ -35,25 +41,27 @@ else:
            name = 'libzbar.so.0'
        
        try:
       -    libzbar = ctypes.cdll.LoadLibrary(name)
       -except BaseException:
       -    libzbar = None
       +    libzbar = ctypes.cdll.LoadLibrary(os.path.join(os.path.dirname(__file__), name))
       +except BaseException as e1:
       +    try:
       +        libzbar = ctypes.cdll.LoadLibrary(name)
       +    except BaseException as e2:
       +        libzbar = None
       +        if sys.platform != 'darwin':
       +            _logger.error(f"failed to load zbar. exceptions: {[e1,e2]!r}")
        
        
       -def scan_barcode_ctypes(device='', timeout=-1, display=True, threaded=False, try_again=True):
       +def scan_barcode_ctypes(device='', timeout=-1, display=True, threaded=False):
            if libzbar is None:
                raise RuntimeError("Cannot start QR scanner; zbar not available.")
            libzbar.zbar_symbol_get_data.restype = ctypes.c_char_p
            libzbar.zbar_processor_create.restype = ctypes.POINTER(ctypes.c_int)
            libzbar.zbar_processor_get_results.restype = ctypes.POINTER(ctypes.c_int)
            libzbar.zbar_symbol_set_first_symbol.restype = ctypes.POINTER(ctypes.c_int)
       +    # libzbar.zbar_set_verbosity(100)  # verbose logs for debugging
            proc = libzbar.zbar_processor_create(threaded)
            libzbar.zbar_processor_request_size(proc, 640, 480)
            if libzbar.zbar_processor_init(proc, device.encode('utf-8'), display) != 0:
       -        if try_again:
       -            # workaround for a bug in "ZBar for Windows"
       -            # libzbar.zbar_processor_init always seem to fail the first time around
       -            return scan_barcode(device, timeout, display, threaded, try_again=False)
                raise RuntimeError("Can not start QR scanner; initialization failed.")
            libzbar.zbar_processor_set_visible(proc)
            if libzbar.zbar_process_one(proc, timeout):