diff --git a/CMakeLists.txt b/CMakeLists.txt index 909fccaf33..dc87d505f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,8 @@ if(NOT CMAKE_BUILD_TYPE) set(__NO_USER_CMAKE_BUILD_TYPE ON CACHE BOOL "True if the user didn't set a build type on the command line") endif() -set(BITCOIN_QT_OSX_BUNDLE_NAME "BitcoinCashNode-Qt") +set(BITCOIN_QT_OSX_BUNDLE_NAME "DeVault-Qt") +set(DEVAULT_QT_OSX_BUNDLE_IDENTIFIER "cc.devault.DeVault-Qt") # Find the python interpreter. This is required for several targets. find_package(Python 3.6 COMPONENTS Interpreter REQUIRED) diff --git a/cmake/platforms/OSX.cmake b/cmake/platforms/OSX.cmake index 56235ccb5d..124af56259 100644 --- a/cmake/platforms/OSX.cmake +++ b/cmake/platforms/OSX.cmake @@ -1,13 +1,20 @@ # Copyright (c) 2017 The Bitcoin developers set(CMAKE_SYSTEM_NAME Darwin) -set(CMAKE_SYSTEM_PROCESSOR x86_64) # Use given TOOLCHAIN_PREFIX if specified if(CMAKE_TOOLCHAIN_PREFIX) set(TOOLCHAIN_PREFIX ${CMAKE_TOOLCHAIN_PREFIX}) else() - set(TOOLCHAIN_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-apple-darwin23) + set(TOOLCHAIN_PREFIX x86_64-apple-darwin23) +endif() + +string(REGEX MATCH "^[^-]+" CMAKE_SYSTEM_PROCESSOR ${TOOLCHAIN_PREFIX}) +if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + # CMake and the Apple SDK use arm64, while GNU target triples use aarch64. + set(CMAKE_OSX_ARCHITECTURES arm64) +else() + set(CMAKE_OSX_ARCHITECTURES ${CMAKE_SYSTEM_PROCESSOR}) endif() # On OSX, we use clang by default. @@ -20,8 +27,7 @@ set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN_PREFIX}) # On OSX we use various stuff from Apple's SDK. set(OSX_SDK_PATH "${CMAKE_CURRENT_SOURCE_DIR}/depends/SDKs/MacOSX14.5.sdk") set(CMAKE_OSX_SYSROOT ${OSX_SDK_PATH}) -set(CMAKE_OSX_DEPLOYMENT_TARGET 14.5) -set(CMAKE_OSX_ARCHITECTURES x86_64) +set(CMAKE_OSX_DEPLOYMENT_TARGET 12.0) # target environment on the build host system # set 1st to dir with the cross compiler's C/C++ headers/libs diff --git a/contrib/guix/README.md b/contrib/guix/README.md index 5d6f18b528..e0e23e5352 100644 --- a/contrib/guix/README.md +++ b/contrib/guix/README.md @@ -12,7 +12,7 @@ hermetic, pinnable toolchain. It replaces the deprecated `contrib/gitian-*` setu ## Mandatory targets (none optional) `x86_64-linux-gnu`, `x86_64-w64-mingw32`, `aarch64-linux-gnu`, `x86_64-apple-darwin23`, -`arm64-apple-darwin23`. +`aarch64-apple-darwin23` (Apple Silicon). ## Install Guix (once, on the build host) @@ -48,10 +48,25 @@ make -C depends download ./contrib/guix/guix-build # ...or a subset while developing: HOSTS="x86_64-linux-gnu" ./contrib/guix/guix-build +# macOS release artifacts (repeat for Apple Silicon): +HOSTS="x86_64-apple-darwin23" ./contrib/guix/guix-build ``` Artifacts land in `guix-build/output///`. +For each Darwin host, a normal GUI build emits: + +- `devault--.tar.gz`: the command-line node and tools; +- `devault---unsigned.dmg`: the reproducible unsigned disk image; and +- `devault---unsigned.tar.gz`: the unsigned `DeVault-Qt.app`, detached-signature + scripts, and the host-specific `codesign_allocate`/`pagestuff` utilities. + +The signing handoff intentionally contains no certificate or credentials. On a credentialed +macOS release machine, extract it, change into its `unsigned-app-/` directory, source +`signing.env`, then use `detached-sig-create.sh` and `detached-sig-apply.sh`. Apple signing and +notarization happen outside this hermetic Guix build. `GUIX_NO_QT=1` is a Darwin smoke-build +mode: it produces only the command-line archive and skips the app/DMG artifacts. + ## Verify reproducibility Run the build twice into clean trees (or on two machines) and compare: diff --git a/contrib/guix/guix-build b/contrib/guix/guix-build index c2d7559646..a96b6fdc2d 100755 --- a/contrib/guix/guix-build +++ b/contrib/guix/guix-build @@ -49,6 +49,20 @@ if [ ! -d "${REPO_ROOT}/depends/sources" ]; then exit 1 fi +# The macOS SDK is proprietary and supplied by the builder. The source snapshot includes it +# from depends/SDKs, so reject a Darwin build before creating a container if it is missing. +for host in ${HOSTS}; do + case "${host}" in + *-apple-darwin23) + SDK_PATH="${REPO_ROOT}/depends/SDKs/MacOSX14.5.sdk" + if [ ! -d "${SDK_PATH}" ]; then + echo "ERROR: macOS SDK missing at ${SDK_PATH}. Extract MacOSX14.5.sdk there before building Darwin targets." >&2 + exit 1 + fi + ;; + esac +done + # Build inputs that must NOT enter the clean source snapshot (regenerated in-container, # or irrelevant dev junk). depends/sources is excluded here and hardlinked in separately # (it is large; hardlinks are space-free on the same filesystem). diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 1915be1f14..3c95a5f035 100755 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -33,7 +33,7 @@ declare -A TOOLCHAIN_FILE=( [x86_64-w64-mingw32]="cmake/platforms/Win64.cmake" [aarch64-linux-gnu]="cmake/platforms/LinuxAArch64.cmake" [x86_64-apple-darwin23]="cmake/platforms/OSX.cmake" - [arm64-apple-darwin23]="cmake/platforms/OSXArm64.cmake" # TODO(G4) + [aarch64-apple-darwin23]="cmake/platforms/OSX.cmake" ) TF="${TOOLCHAIN_FILE[$HOST]:?unknown HOST '$HOST'}" @@ -53,9 +53,8 @@ case "$HOST" in x86_64-w64-mingw32) CMAKE_EXTRA+=( "-DCPACK_PACKAGE_FILE_NAME=${DISTNAME}-win64-setup-unsigned" ) ;; - arm64-apple-darwin23) - # Until OSX.cmake is parameterized, this passes the prefix/arch through. - CMAKE_EXTRA+=( "-DCMAKE_TOOLCHAIN_PREFIX=arm64-apple-darwin23" ) + *-apple-darwin23) + CMAKE_EXTRA+=( "-DCMAKE_TOOLCHAIN_PREFIX=${HOST}" ) ;; esac @@ -160,6 +159,11 @@ fi PATH="${DEPENDS_PATH}" make -C "${REPO_ROOT}/depends" HOST="${HOST}" "${DEPENDS_OPTS[@]}" -j"${JOBS:-$(nproc)}" DEPENDS_PREFIX="${REPO_ROOT}/depends/${HOST}" +# The cross-Darwin DMG target generates its .DS_Store with Python modules built by depends. +if [[ "${HOST}" == *-apple-darwin23 ]]; then + export PYTHONPATH="${DEPENDS_PREFIX}/native/lib/python3/dist-packages${PYTHONPATH:+:${PYTHONPATH}}" +fi + # security-check.py (run via `ninja security-check` below) shells out to $OBJDUMP/$READELF to # introspect the built binaries. Its defaults (/usr/bin/objdump, /usr/bin/readelf) are the native # binutils, which cannot parse a Windows PE -> "cannot open" and a spurious failure. Point them at @@ -203,7 +207,11 @@ echo "--- install ---" # Install into INSTALL_DIR (= CMAKE_INSTALL_PREFIX). Host-specific packaging (NSIS/dmg/tar) # happens per-host below; we do NOT run a generic `ninja package` for Linux (we build our # own deterministic tarball from the install tree instead). -DESTDIR="" cmake --install "${BUILD_DIR}" || ninja -C "${BUILD_DIR}" install +if [[ "${HOST}" == *-apple-darwin23 ]]; then + DESTDIR="" cmake --install "${BUILD_DIR}" --strip || ninja -C "${BUILD_DIR}" install +else + DESTDIR="" cmake --install "${BUILD_DIR}" || ninja -C "${BUILD_DIR}" install +fi # --- Per-host packaging + debug split + normalization ---------------------- # Common: split debug symbols into *.dbg, strip, deterministic archive. @@ -250,8 +258,39 @@ case "$HOST" in zip -X@ "${OUTDIR}/${DISTNAME}-win64.zip" ) ;; *-apple-darwin23) - # macOS: .app via macdeployqtplus, then .dmg. TODO(G4): wire macdeploy + codesign-ready. - echo "TODO(G4): darwin packaging (.app/.dmg) not yet implemented for ${HOST}" >&2 + # Keep command-line artifacts independent of the GUI bundle. + ( cd "${INSTALL_DIR}/.." && \ + find "${DISTNAME}" -not -path "*.app" -not -path "*.app/*" | sort | \ + tar --no-recursion --owner=0 --group=0 --mtime="@${SOURCE_DATE_EPOCH}" \ + -c -T - | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" ) + + if [ "${GUIX_NO_QT:-0}" = "1" ]; then + echo "--- GUIX_NO_QT=1: skipping macOS app and DMG packaging ---" + else + echo "--- macOS deploy directory ---" + ninja -C "${BUILD_DIR}" osx-deploydir + OSX_VOLNAME="$(cat "${BUILD_DIR}/osx_volname")" + DARWIN_ARCH="${HOST%%-*}" + [ "${DARWIN_ARCH}" = "aarch64" ] && DARWIN_ARCH="arm64" + HANDOFF_DIR="${BUILD_DIR}/unsigned-app-${HOST}" + rm -rf "${HANDOFF_DIR}" + mkdir -p "${HANDOFF_DIR}" + cp "${BUILD_DIR}/osx_volname" "${HANDOFF_DIR}/" + cp "${REPO_ROOT}/contrib/macdeploy/detached-sig-create.sh" "${HANDOFF_DIR}/" + cp "${REPO_ROOT}/contrib/macdeploy/detached-sig-apply.sh" "${HANDOFF_DIR}/" + cp "${DEPENDS_PREFIX}/native/bin/${HOST}-codesign_allocate" "${HANDOFF_DIR}/codesign_allocate" + cp "${DEPENDS_PREFIX}/native/bin/${HOST}-pagestuff" "${HANDOFF_DIR}/pagestuff" + printf 'BUNDLE=dist/DeVault-Qt.app\nARCH=%s\nexport BUNDLE ARCH\n' "${DARWIN_ARCH}" > "${HANDOFF_DIR}/signing.env" + mv "${BUILD_DIR}/dist" "${HANDOFF_DIR}/" + ( cd "${BUILD_DIR}" && \ + find "$(basename "${HANDOFF_DIR}")" -print0 | sort -z | \ + tar --null --no-recursion --owner=0 --group=0 --mtime="@${SOURCE_DATE_EPOCH}" \ + -c -T - | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" ) + + echo "--- macOS DMG ---" + ninja -C "${BUILD_DIR}" osx-dmg + mv "${BUILD_DIR}/${OSX_VOLNAME}.dmg" "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.dmg" + fi ;; esac diff --git a/contrib/guix/libexec/prelude.bash b/contrib/guix/libexec/prelude.bash index 3eb3bb8c4a..19effc2779 100755 --- a/contrib/guix/libexec/prelude.bash +++ b/contrib/guix/libexec/prelude.bash @@ -68,14 +68,13 @@ umask 0022 export OUTDIR_BASE="${OUTDIR_BASE:-${REPO_ROOT}/guix-build/output/${VERSION}}" # --- Host -> CMake toolchain file map -------------------------------------- -# (Apple-Silicon entry depends on the OSX.cmake fix tracked in the impl plan, G4.) declare -gA CMAKE_TOOLCHAIN_FILE=( [x86_64-linux-gnu]="cmake/platforms/Linux64.cmake" [x86_64-w64-mingw32]="cmake/platforms/Win64.cmake" [aarch64-linux-gnu]="cmake/platforms/LinuxAArch64.cmake" [x86_64-apple-darwin23]="cmake/platforms/OSX.cmake" - [arm64-apple-darwin23]="cmake/platforms/OSXArm64.cmake" # TODO(G4): create/parameterize + [aarch64-apple-darwin23]="cmake/platforms/OSX.cmake" ) # Full mandatory release set (none optional — cb 2026-06-13). -export HOSTS_DEFAULT="x86_64-linux-gnu x86_64-w64-mingw32 aarch64-linux-gnu x86_64-apple-darwin23 arm64-apple-darwin23" +export HOSTS_DEFAULT="x86_64-linux-gnu x86_64-w64-mingw32 aarch64-linux-gnu x86_64-apple-darwin23 aarch64-apple-darwin23" diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index c3306a2d5c..ebe1ccb436 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -16,8 +16,13 @@ ;;; branches (G2/G3/G4) still need validation against the pin as each phase is brought up. (use-modules (gnu packages) + (gnu packages cdrom) (gnu packages cross-base) ; cross-gcc / cross-binutils / cross-libc (gnu packages gcc) ; gcc-12 (base compiler for the linux cross toolchain) + (gnu packages gnome) + (gnu packages image) + (gnu packages imagemagick) + (gnu packages llvm) (guix profiles)) ;;; --------------------------------------------------------------------------- @@ -42,7 +47,7 @@ "gperf" ; fontconfig "file" ; many configure scripts probe with `file` ;; scripting - "python" ; build/codegen scripts (xcb-proto, qt) + "python" "python-setuptools" ; build/codegen scripts and depends' native Python modules "perl" ; openssl/qt build steps in depends ;; archive / text / determinism utilities "coreutils" ; touch --date, sha256sum, sort, ... @@ -129,12 +134,17 @@ (list (specification->package "gcc-cross-x86_64-w64-mingw32-toolchain@14") (specification->package "nsis-x86_64"))) - ;; G4 — macOS (x86_64 + arm64 apple-darwin23): clang + cctools/ld64/libtapi, plus the - ;; builder-supplied MacOSX14.5.sdk under depends/SDKs/ (NOT in this manifest). - ;; TODO(G4): port Core's clang/cctools/ld64 set; also fix OSX.cmake's hardcoded x86_64. + ;; G4 — macOS targets use clang/lld from Guix and the builder-supplied Apple SDK. + ;; cctools, ld64, libtapi, and the target-prefixed binary tools are built by depends. ((or (string=? host "x86_64-apple-darwin23") - (string=? host "arm64-apple-darwin23")) - '()) + (string=? host "aarch64-apple-darwin23")) + (list clang-toolchain-18 + lld-18 + (make-lld-wrapper lld-18 #:lld-as-ld? #t) + xorriso + librsvg + imagemagick + libtiff)) (else (error "manifest.scm: unknown HOST" host)))) diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py index 13ba6d9ebc..7baea6a43c 100755 --- a/contrib/macdeploy/custom_dsstore.py +++ b/contrib/macdeploy/custom_dsstore.py @@ -55,7 +55,7 @@ ds['.']['vSrn'] = ('long', 1) ds['Applications']['Iloc'] = (370, 156) -ds['BitcoinCashNode-Qt.app']['Iloc'] = (128, 156) +ds['DeVault-Qt.app']['Iloc'] = (128, 156) ds.flush() ds.close() diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh index 43aa2ebc6a..950aa81f91 100755 --- a/contrib/macdeploy/detached-sig-apply.sh +++ b/contrib/macdeploy/detached-sig-apply.sh @@ -8,7 +8,7 @@ set -e UNSIGNED="$1" SIGNATURE="$2" -ARCH=x86_64 +ARCH="${ARCH:-x86_64}" ROOTDIR=dist TEMPDIR=signed.temp OUTDIR=signed-app diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index cbd0b8c555..75d3db22d1 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -7,8 +7,9 @@ export LC_ALL=C set -e ROOTDIR=dist -BUNDLE="${ROOTDIR}/BitcoinCashNode-Qt.app" +BUNDLE="${BUNDLE:-${ROOTDIR}/DeVault-Qt.app}" CODESIGN=codesign +PAGESTUFF="${PAGESTUFF:-./pagestuff}" TEMPDIR=sign.temp TEMPLIST="${TEMPDIR}/signatures.txt" OUT=signature.tar.gz @@ -27,8 +28,8 @@ ${CODESIGN} -f --file-list ${TEMPLIST} "$@" "${BUNDLE}" grep -Fv CodeResources < "${TEMPLIST}" | while read -r i; do TARGETFILE="${BUNDLE}/$(echo "${i}" | sed "s|.*${BUNDLE}/||")" - SIZE=$(pagestuff "$i" -p | tail -2 | grep size | sed 's/[^0-9]*//g') - OFFSET=$(pagestuff "$i" -p | tail -2 | grep offset | sed 's/[^0-9]*//g') + SIZE=$("${PAGESTUFF}" "$i" -p | tail -2 | grep size | sed 's/[^0-9]*//g') + OFFSET=$("${PAGESTUFF}" "$i" -p | tail -2 | grep offset | sed 's/[^0-9]*//g') SIGNFILE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}.sign" DIRNAME="$(dirname "${SIGNFILE}")" mkdir -p "${DIRNAME}" diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index d275f3ac72..c8f47f67e7 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -348,7 +348,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/share/qt/Info.plist.cmake.in" MACOSX_BUNDLE_BUNDLE_NAME "${BITCOIN_QT_OSX_BUNDLE_NAME}" MACOSX_BUNDLE_BUNDLE_VERSION "${bitcoin-cash-node_VERSION}" - MACOSX_BUNDLE_GUI_IDENTIFIER "org.bitcoincashnode.${BITCOIN_QT_OSX_BUNDLE_NAME}" + MACOSX_BUNDLE_GUI_IDENTIFIER "${DEVAULT_QT_OSX_BUNDLE_IDENTIFIER}" MACOSX_BUNDLE_ICON_FILE "${BITCOINQT_BUNDLE_ICON_NAME}" MACOSX_BUNDLE_INFO_STRING "${bitcoin-cash-node_VERSION}, Copyright © 2009-${COPYRIGHT_YEAR} ${COPYRIGHT_HOLDERS_FINAL}" MACOSX_BUNDLE_LONG_VERSION_STRING "${bitcoin-cash-node_VERSION}" diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm index 6aa54b9284..64f1fe18d6 100644 --- a/src/qt/macnotificationhandler.mm +++ b/src/qt/macnotificationhandler.mm @@ -12,7 +12,7 @@ @implementation NSBundle (returnCorrectIdentifier) - (NSString *)__bundleIdentifier { if (self == [NSBundle mainBundle]) { - return @"org.bitcoincashnode.BitcoinCashNode-Qt"; + return @"cc.devault.DeVault-Qt"; } else { return [self __bundleIdentifier]; }