diff --git a/README.md b/README.md index da7b94a8..6f76e73d 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,11 @@ To see configuration options: ./configure --help ``` -For a current Ubuntu daemon build, see `doc/build-ubuntu-24.md`. +For current build notes, see: + +- `doc/build-ubuntu-24.md` for native Ubuntu daemon and wallet builds. +- `doc/build-windows.md` for Windows cross-compilation. +- `doc/build-wallets.md` for the repeatable desktop wallet quick start. --- diff --git a/contrib/build-linux-wallet.sh b/contrib/build-linux-wallet.sh new file mode 100755 index 00000000..cc8df6e0 --- /dev/null +++ b/contrib/build-linux-wallet.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +JOBS="${JOBS:-1}" +HOST="${HOST:-x86_64-pc-linux-gnu}" +PREFIX="$ROOT/depends/$HOST" +BASE_CONFIG="$PREFIX/share/config.site" +CONFIG_SITE_FILE="${CONFIG_SITE_FILE:-/tmp/agrarian-linux-wallet-config.site}" +QT_PKG_CONFIG_DIR="${QT_PKG_CONFIG_DIR:-/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig}" +QT_BINDIR="${QT_BINDIR:-/usr/lib/qt5/bin}" +PROTOC_BINDIR="${PROTOC_BINDIR:-/usr/bin}" + +require_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "Missing required command: $1" >&2 + exit 1 + fi +} + +require_path() { + if [[ ! -e "$1" ]]; then + echo "Missing required path: $1" >&2 + exit 1 + fi +} + +cd "$ROOT" + +require_cmd make +require_cmd pkg-config +require_cmd gcc +require_cmd g++ +require_cmd sed +require_cmd cp +require_cmd "$PROTOC_BINDIR/protoc" +require_path "$QT_BINDIR/moc" +require_path "$QT_BINDIR/uic" +require_path "$QT_BINDIR/rcc" +require_path "$QT_BINDIR/lrelease" +require_path "$QT_BINDIR/lupdate" + +echo "Building native depends for $HOST..." +make -C depends -j"$JOBS" +require_path "$BASE_CONFIG" + +cp "$BASE_CONFIG" "$CONFIG_SITE_FILE" +sed -i.old \ + -e "s#^with_qt_bindir=.*#with_qt_bindir='$QT_BINDIR'#" \ + -e "s#^with_protoc_bindir=.*#with_protoc_bindir='$PROTOC_BINDIR'#" \ + -e "s#^PKG_CONFIG_LIBDIR=.*#PKG_CONFIG_LIBDIR='$PREFIX/lib/pkgconfig:$PREFIX/share/pkgconfig:$QT_PKG_CONFIG_DIR'#" \ + "$CONFIG_SITE_FILE" + +if [[ ! -f configure ]]; then + ./autogen.sh +fi + +echo "Configuring Ubuntu Qt wallet build..." +CONFIG_SITE="$CONFIG_SITE_FILE" ./configure \ + --disable-maintainer-mode \ + --disable-tests \ + --disable-bench \ + --with-gui=qt5 + +echo "Building Ubuntu Qt wallet with JOBS=$JOBS..." +make -j"$JOBS" + +echo "Linux wallet build complete:" +echo " $ROOT/src/qt/agrarian-qt" +echo " $ROOT/src/agrariand" +echo " $ROOT/src/agrarian-cli" +echo " $ROOT/src/agrarian-tx" diff --git a/contrib/build-linux.sh b/contrib/build-linux.sh index 35a7917e..108e7058 100755 --- a/contrib/build-linux.sh +++ b/contrib/build-linux.sh @@ -3,19 +3,34 @@ set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" JOBS="${JOBS:-1}" +MODE="${MODE:-daemon}" cd "$ROOT" -./autogen.sh +if [[ ! -f configure ]]; then + ./autogen.sh +fi -./configure \ - --without-gui \ - --disable-tests \ - --disable-bench \ - --disable-zmq \ - --with-miniupnpc=no \ - --with-incompatible-bdb \ - CXXFLAGS="${CXXFLAGS:--O0 -g0 --param ggc-min-expand=1 --param ggc-min-heapsize=32768}" +case "$MODE" in + daemon) + ./configure \ + --without-gui \ + --disable-tests \ + --disable-bench \ + --disable-zmq \ + --with-miniupnpc=no \ + --with-incompatible-bdb \ + CXXFLAGS="${CXXFLAGS:--O0 -g0 --param ggc-min-expand=1 --param ggc-min-heapsize=32768}" + ;; + wallet) + exec "$ROOT/contrib/build-linux-wallet.sh" + ;; + *) + echo "Unknown MODE: $MODE" >&2 + echo "Use MODE=daemon or MODE=wallet." >&2 + exit 2 + ;; +esac make -j"$JOBS" -echo "Build complete." +echo "Linux $MODE build complete." diff --git a/contrib/build-win64-wallet.sh b/contrib/build-win64-wallet.sh new file mode 100755 index 00000000..d6e48a3b --- /dev/null +++ b/contrib/build-win64-wallet.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +JOBS="${JOBS:-1}" +HOST="${HOST:-x86_64-w64-mingw32}" +PREFIX="$ROOT/depends/$HOST" +NATIVE_BIN="$PREFIX/native/bin" +PROTOBUF_VERSION="${PROTOBUF_VERSION:-2.6.1}" +PROTOBUF_SOURCE="$ROOT/depends/sources/protobuf-$PROTOBUF_VERSION.tar.bz2" +PROTOBUF_BUILD="${PROTOBUF_BUILD:-/tmp/agrarian-protobuf-$PROTOBUF_VERSION-native}" + +require_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "Missing required command: $1" >&2 + exit 1 + fi +} + +require_path() { + if [[ ! -e "$1" ]]; then + echo "Missing required path: $1" >&2 + exit 1 + fi +} + +copy_first_match() { + local name="$1" + local match + match="$(find "$ROOT/depends/work/build/$HOST" -path "*/qtbase/bin/$name" -type f | sort | tail -n 1 || true)" + if [[ -z "$match" ]]; then + echo "Could not find Qt host tool after depends build: $name" >&2 + exit 1 + fi + cp "$match" "$NATIVE_BIN/$name" +} + +ensure_posix_mingw() { + require_cmd "$HOST-g++" + if ! "$HOST-g++" --version | head -n 1 | grep -qi posix; then + cat >&2 </a #include " qtbase/src/corelib/tools/qbytearraymatcher.h && \ + sed -i.old "/#include \"qfloat16_p.h\"/a #include " qtbase/src/corelib/global/qfloat16.cpp && \ + sed -i.old "s/#if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)/#if (defined(Q_CC_MINGW) \&\& WINVER < 0x0601) || !defined(TOUCHEVENTF_MOVE)/" qtbase/src/plugins/platforms/windows/qwindowsmousehandler.cpp && \ sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ + sed -i.old "/SUBDIRS += printsupport/d" qtbase/src/plugins/plugins.pro && \ sed -i.old -e 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' -e 's|/bin/pwd|pwd|' qtbase/configure && \ sed -i.old 's/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0)/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft)/' qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ @@ -153,16 +157,9 @@ define $(package)_preprocess_cmds cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/agrarian-linux-g++ && \ sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/agrarian-linux-g++/qmake.conf && \ - patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch &&\ - patch -p1 -i $($(package)_patch_dir)/fix_configure_mac.patch &&\ - patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch &&\ - patch -p1 -i $($(package)_patch_dir)/fix_rcc_determinism.patch &&\ - patch -p1 -i $($(package)_patch_dir)/xkb-default.patch &&\ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ - patch -p1 -i $($(package)_patch_dir)/fix_riscv64_arch.patch &&\ - patch -p1 -i $($(package)_patch_dir)/fix_s390x_powerpc_mips_mipsel_architectures.patch &&\ echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf &&\ sed -i.old "s|QMAKE_CFLAGS = |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \ diff --git a/doc/build-ubuntu-24.md b/doc/build-ubuntu-24.md index 4488cb2e..19b6e0df 100644 --- a/doc/build-ubuntu-24.md +++ b/doc/build-ubuntu-24.md @@ -1,10 +1,10 @@ Copyright (c) 2026 Agrarian Developers -Ubuntu 24.04 Daemon Build Notes -================================ +Ubuntu 24.04 Build Notes +======================== -These notes describe the native daemon build path tested against current Ubuntu -24.04 system packages. +These notes describe the native daemon and desktop wallet build paths tested +against current Ubuntu 24.04 system packages. Recommended host size --------------------- @@ -16,7 +16,7 @@ building large translation units. Packages -------- -Install the native build dependencies: +Install the native daemon build dependencies: sudo apt-get update sudo apt-get install -y \ @@ -24,6 +24,12 @@ Install the native build dependencies: libboost-all-dev libevent-dev libgmp-dev libssl-dev \ libdb5.3-dev libdb5.3++-dev +For the desktop wallet, also install Qt and protobuf tools: + + sudo apt-get install -y \ + qtbase5-dev qttools5-dev-tools qtchooser \ + libqrencode-dev libprotobuf-dev protobuf-compiler + Daemon-only build ----------------- @@ -40,6 +46,35 @@ For the pool daemon, the GUI, tests, bench, ZMQ, and UPnP can be disabled: CXXFLAGS="-O0 -g0 --param ggc-min-expand=1 --param ggc-min-heapsize=32768" make -j1 +The daemon helper runs the same path: + + JOBS=1 ./contrib/build-linux.sh + +Qt wallet build +--------------- + +For the desktop wallet, use: + + JOBS=1 ./contrib/build-linux-wallet.sh + +The wallet helper builds/restores the native depends prefix first, then creates +a temporary config.site that keeps the depends libraries while allowing system +Qt 5 tools and pkg-config files to be used. + +Defaults: + + HOST=x86_64-pc-linux-gnu + QT_BINDIR=/usr/lib/qt5/bin + PROTOC_BINDIR=/usr/bin + CONFIG_SITE_FILE=/tmp/agrarian-linux-wallet-config.site + +Warnings +-------- + +Qt 5.15 and protobuf 3.x emit compatibility/deprecation warnings in a few Qt +translation units. Those warnings are expected while the Windows build remains +pinned to Qt 5.9.7 and protobuf 2.6.1. + OpenSSL 3 --------- diff --git a/doc/build-wallets.md b/doc/build-wallets.md new file mode 100644 index 00000000..3afbddfa --- /dev/null +++ b/doc/build-wallets.md @@ -0,0 +1,90 @@ +Copyright (c) 2026 Agrarian Developers + +Desktop Wallet Build Quick Start +================================ + +This page records the repeatable desktop wallet build flow for the modernized +Agrarian tree. + +Supported targets +----------------- + +The currently tested desktop wallet targets are: + +* Ubuntu 24.04 native x86_64: `src/qt/agrarian-qt` +* Windows x86_64 cross build from Ubuntu: `src/qt/agrarian-qt.exe` + +Use one job on small servers: + + JOBS=1 ./contrib/build-linux-wallet.sh + JOBS=1 ./contrib/build-win64-wallet.sh + +Use more jobs only when the host has enough memory. + +Ubuntu package baseline +----------------------- + + sudo apt-get update + sudo apt-get install -y \ + build-essential pkg-config autoconf automake libtool bsdmainutils \ + curl git make tar patch + +For the native Ubuntu wallet: + + sudo apt-get install -y \ + qtbase5-dev qttools5-dev-tools qtchooser \ + libqrencode-dev libprotobuf-dev protobuf-compiler + +For the Windows wallet: + + sudo apt-get install -y \ + mingw-w64 g++-mingw-w64-x86-64 g++-mingw-w64-x86-64-posix \ + qttools5-dev-tools + +Then select POSIX Mingw-w64 threading: + + sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix + sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix + +Why the helpers exist +--------------------- + +The wallet build is sensitive to tool version mismatches: + +* Native Ubuntu uses current system Qt tools and protobuf while keeping the + deterministic depends libraries. +* Windows uses the Qt 5.9.7 and protobuf 2.6.1 libraries from depends. Its host + tools must match those libraries closely enough for generated C++ output to + compile. + +The helper scripts keep those rules in one place so the build is repeatable on a +fresh server. + +Expected artifacts +------------------ + +After the Ubuntu wallet build: + + src/qt/agrarian-qt + src/agrariand + src/agrarian-cli + src/agrarian-tx + +After the Windows wallet build: + + src/qt/agrarian-qt.exe + src/agrariand.exe + src/agrarian-cli.exe + src/agrarian-tx.exe + +Version checks +-------------- + +On Ubuntu: + + QT_QPA_PLATFORM=offscreen src/qt/agrarian-qt --version + src/agrariand --version + +For Windows binaries from the Linux build host: + + file src/qt/agrarian-qt.exe src/agrariand.exe src/agrarian-cli.exe src/agrarian-tx.exe diff --git a/doc/build-windows.md b/doc/build-windows.md index 06b67e1d..11ae5ce0 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -12,9 +12,8 @@ SUPPORTED BUILD METHODS The following methods are known to work: -1. Linux (Ubuntu 18.04 Bionic recommended) +1. Linux (Ubuntu 24.04 tested) Using the Mingw-w64 cross-compilation toolchain. - This is the method used to produce official Windows release binaries. 2. Windows 10+ Using Windows Subsystem for Linux (WSL) with Mingw-w64. @@ -40,7 +39,7 @@ WSL allows running a Linux environment directly on Windows without a VM. Requirements: • Windows 10 (64-bit only) • Not supported on Windows Server -• Ubuntu recommended (tested on Ubuntu 18.04) +• Ubuntu recommended ------------------------------------------------------------ INSTALLING WSL @@ -53,7 +52,7 @@ INSTALLING WSL 2. Install Ubuntu - Open Microsoft Store - - Install "Ubuntu 18.04" + - Install "Ubuntu" 3. Complete Setup - Open command prompt @@ -76,9 +75,9 @@ GENERAL DEPENDENCIES ------------------------------------------------------------ sudo apt update - sudo apt upgrade - sudo apt install build-essential libtool autotools-dev \ - automake pkg-config bsdmainutils curl git + sudo apt install -y build-essential libtool autotools-dev \ + automake pkg-config bsdmainutils curl git make tar patch \ + qttools5-dev-tools A host toolchain (build-essential) is required because some dependencies (e.g., protobuf) build host utilities during the process. @@ -100,13 +99,16 @@ BUILDING FOR 64-BIT WINDOWS Install Mingw-w64 toolchain: - sudo apt install g++-mingw-w64-x86-64 + sudo apt install -y \ + mingw-w64 g++-mingw-w64-x86-64 g++-mingw-w64-x86-64-posix -Ubuntu 18.04: +Select the POSIX thread model (required): - sudo update-alternatives --config x86_64-w64-mingw32-g++ + sudo update-alternatives --set x86_64-w64-mingw32-gcc \ + /usr/bin/x86_64-w64-mingw32-gcc-posix + sudo update-alternatives --set x86_64-w64-mingw32-g++ \ + /usr/bin/x86_64-w64-mingw32-g++-posix -Select the POSIX thread model (required). ------------------------------------------------------------ IMPORTANT (WSL USERS) @@ -122,13 +124,33 @@ Autoconf scripts will fail. BUILD COMMANDS ------------------------------------------------------------ +Recommended portable helper: + + JOBS=1 ./contrib/build-win64-wallet.sh + +The helper: + +• Verifies the POSIX Mingw-w64 thread model. +• Builds the Win64 depends tree with Qt enabled. +• Stages matching Qt host tools (`moc`, `uic`, `rcc`) into the depends prefix. +• Builds/stages protobuf 2.6.1 `protoc` when system `protoc` is newer. +• Configures the wallet against the generated depends prefix. + +Manual equivalent: + PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') cd depends - make HOST=x86_64-w64-mingw32 + make HOST=x86_64-w64-mingw32 NO_QT=0 cd .. ./autogen.sh CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site \ - ./configure --prefix=/ + ./configure --prefix=/ \ + --disable-maintainer-mode \ + --disable-tests \ + --disable-bench \ + --with-gui=qt5 \ + --with-qt-incdir=$PWD/depends/x86_64-w64-mingw32/include \ + --with-qt-libdir=$PWD/depends/x86_64-w64-mingw32/lib make ============================================================ @@ -193,6 +215,14 @@ The win32 model conflicts with certain C++11 headers You MUST select the POSIX thread model when prompted by update-alternatives. +============================================================ +PROTOBUF NOTE +============================================================ + +The Windows depends build uses protobuf 2.6.1 headers and libraries. Do not use +a newer system `protoc` to regenerate wallet sources for this target. The helper +builds and stages a matching native `protoc` when needed. + ============================================================ END OF DOCUMENT ============================================================ diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 46cb7e22..56a76606 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -219,12 +219,12 @@ QVariant OptionsModel::data(const QModelIndex& index, int role) const return settings.value("fUseProxy", false); case ProxyIP: { // contains IP at index 0 and port at index 1 - QStringList strlIpPort = settings.value("addrProxy").toString().split(":", Qt::SkipEmptyParts); + QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts); return strlIpPort.at(0); } case ProxyPort: { // contains IP at index 0 and port at index 1 - QStringList strlIpPort = settings.value("addrProxy").toString().split(":", Qt::SkipEmptyParts); + QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts); return strlIpPort.at(1); } @@ -308,7 +308,7 @@ bool OptionsModel::setData(const QModelIndex& index, const QVariant& value, int break; case ProxyIP: { // contains current IP at index 0 and current port at index 1 - QStringList strlIpPort = settings.value("addrProxy").toString().split(":", Qt::SkipEmptyParts); + QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts); // if that key doesn't exist or has a changed IP if (!settings.contains("addrProxy") || strlIpPort.at(0) != value.toString()) { // construct new value from new IP and current port @@ -319,7 +319,7 @@ bool OptionsModel::setData(const QModelIndex& index, const QVariant& value, int } break; case ProxyPort: { // contains current IP at index 0 and current port at index 1 - QStringList strlIpPort = settings.value("addrProxy").toString().split(":", Qt::SkipEmptyParts); + QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts); // if that key doesn't exist or has a changed port if (!settings.contains("addrProxy") || strlIpPort.at(1) != value.toString()) { // construct new value from current IP and new port diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 2c84e07f..93be4d01 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -600,7 +600,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien } } - int length = static_cast(payment.ByteSizeLong()); + int length = payment.ByteSize(); netRequest.setHeader(QNetworkRequest::ContentLengthHeader, length); QByteArray serData(length, '\0'); if (payment.SerializeToArray(serData.data(), length)) { diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 21c98555..4347fac5 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -231,7 +231,7 @@ void TransactionView::setModel(WalletModel* model) if (model->getOptionsModel()) { // Add third party transaction URLs to context menu - QStringList listUrls = model->getOptionsModel()->getThirdPartyTxUrls().split("|", Qt::SkipEmptyParts); + QStringList listUrls = model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts); for (int i = 0; i < listUrls.size(); ++i) { QString host = QUrl(listUrls[i].trimmed(), QUrl::StrictMode).host(); if (!host.isEmpty()) {