#!/usr/bin/env bash # Parameterize PYTHON_VERSION=3.7.7 BUILDDIR=/tmp/electrum-build PACKAGE=Electrum GIT_REPO=https://github.com/spesmilo/electrum export GCC_STRIP_BINARIES="1" . $(dirname "$0")/../build_tools_util.sh CONTRIB_OSX="$(dirname "$(realpath "$0")")" CONTRIB="$CONTRIB_OSX/.." ROOT_FOLDER="$CONTRIB/.." src_dir=$(dirname "$0") cd $src_dir/../.. VERSION=`git describe --tags --dirty --always` which brew > /dev/null 2>&1 || fail "Please install brew from https://brew.sh/ to continue" which xcodebuild > /dev/null 2>&1 || fail "Please install Xcode and xcode command line tools to continue" # Code Signing: See https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html if [ -n "$CODESIGN_CERT" ]; then # Test the identity is valid for signing by doing this hack. There is no other way to do this. cp -f /bin/ls ./CODESIGN_TEST codesign -s "$CODESIGN_CERT" --dryrun -f ./CODESIGN_TEST > /dev/null 2>&1 res=$? rm -f ./CODESIGN_TEST if ((res)); then fail "Code signing identity \"$CODESIGN_CERT\" appears to be invalid." fi unset res info "Code signing enabled using identity \"$CODESIGN_CERT\"" else warn "Code signing DISABLED. Specify a valid macOS Developer identity installed on the system to enable signing." fi function DoCodeSignMaybe { # ARGS: infoName fileOrDirName infoName="$1" file="$2" deep="" if [ -z "$CODESIGN_CERT" ]; then # no cert -> we won't codesign return fi if [ -d "$file" ]; then deep="--deep" fi if [ -z "$infoName" ] || [ -z "$file" ] || [ ! -e "$file" ]; then fail "Argument error to internal function DoCodeSignMaybe()" fi hardened_arg="--entitlements=${CONTRIB_OSX}/entitlements.plist -o runtime" info "Code signing ${infoName}..." codesign -f -v $deep -s "$CODESIGN_CERT" $hardened_arg "$file" || fail "Could not code sign ${infoName}" } info "Installing Python $PYTHON_VERSION" export PATH="~/.pyenv/bin:~/.pyenv/shims:~/Library/Python/3.7/bin:$PATH" if [ -d "${HOME}/.pyenv" ]; then pyenv update else curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash > /dev/null 2>&1 fi PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install -s $PYTHON_VERSION && \ pyenv global $PYTHON_VERSION || \ fail "Unable to use Python $PYTHON_VERSION" info "Installing build dependencies" python3 -m pip install --no-dependencies -Ir ./contrib/deterministic-build/requirements-mac-build.txt --user \ || fail "Could not install build dependencies" info "Using these versions for building $PACKAGE:" sw_vers python3 --version echo -n "Pyinstaller " pyinstaller --version rm -rf ./dist git submodule update --init rm -rf $BUILDDIR > /dev/null 2>&1 mkdir $BUILDDIR info "generating locale" ( if ! which msgfmt > /dev/null 2>&1; then brew install gettext brew link --force gettext fi cd "$CONTRIB"/deterministic-build/electrum-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 done ) || fail "failed generating locale" info "Downloading libusb..." curl https://homebrew.bintray.com/bottles/libusb-1.0.23.high_sierra.bottle.tar.gz | \ tar xz --directory $BUILDDIR cp $BUILDDIR/libusb/1.0.23/lib/libusb-1.0.dylib contrib/osx echo "caea266f3fc3982adc55d6cb8d9bad10f6e61f0c24ce5901aa1804618e08e14d contrib/osx/libusb-1.0.dylib" | \ shasum -a 256 -c || fail "libusb checksum mismatched" info "Preparing for building libsecp256k1" brew install autoconf automake libtool "$CONTRIB"/make_libsecp256k1.sh || fail "Could not build libsecp" cp "$ROOT_FOLDER"/electrum/libsecp256k1.0.dylib contrib/osx info "Building CalinsQRReader..." d=contrib/osx/CalinsQRReader pushd $d rm -fr build # prefer building using xcode ourselves. otherwise fallback to prebuilt binary xcodebuild || cp -r prebuilt_qr build || fail "Could not build CalinsQRReader" popd DoCodeSignMaybe "CalinsQRReader.app" "${d}/build/Release/CalinsQRReader.app" info "Installing requirements..." python3 -m pip install --no-dependencies -Ir ./contrib/deterministic-build/requirements.txt --user \ || fail "Could not install requirements" info "Installing hardware wallet requirements..." python3 -m pip install --no-dependencies -Ir ./contrib/deterministic-build/requirements-hw.txt --user \ || fail "Could not install hardware wallet requirements" info "Installing dependencies specific to binaries..." python3 -m pip install --no-dependencies -Ir ./contrib/deterministic-build/requirements-binaries.txt --user \ || fail "Could not install dependencies specific to binaries" info "Building $PACKAGE..." python3 -m pip install --no-dependencies --user . > /dev/null || fail "Could not build $PACKAGE" info "Faking timestamps..." for d in ~/Library/Python/ ~/.pyenv .; do pushd $d find . -exec touch -t '200101220000' {} + popd done info "Building binary" APP_SIGN="$CODESIGN_CERT" pyinstaller --noconfirm --ascii --clean --name $VERSION contrib/osx/osx.spec || fail "Could not build binary" info "Adding bitcoin URI types to Info.plist" plutil -insert 'CFBundleURLTypes' \ -xml ' CFBundleURLName bitcoin CFBundleURLSchemes bitcoin ' \ -- dist/$PACKAGE.app/Contents/Info.plist \ || fail "Could not add keys to Info.plist. Make sure the program 'plutil' exists and is installed." DoCodeSignMaybe "app bundle" "dist/${PACKAGE}.app" if [ ! -z "$CODESIGN_CERT" ]; then if [ ! -z "$APPLE_ID_USER" ]; then info "Notarizing .app with Apple's central server..." "${CONTRIB_OSX}/notarize_app.sh" "dist/${PACKAGE}.app" || fail "Could not notarize binary." else warn "AppleID details not set! Skipping Apple notarization." fi fi info "Creating .DMG" hdiutil create -fs HFS+ -volname $PACKAGE -srcfolder dist/$PACKAGE.app dist/electrum-$VERSION.dmg || fail "Could not create .DMG" DoCodeSignMaybe ".DMG" "dist/electrum-${VERSION}.dmg" if [ -z "$CODESIGN_CERT" ]; then warn "App was built successfully but was not code signed. Users may get security warnings from macOS." warn "Specify a valid code signing identity to enable code signing." fi