Files
triangles_v5/src/CMakeLists.txt
T
Krystie f0889d9b70 test/build: make ctest actually run the unit suites
Three coupled fixes to the test harness (no consensus/runtime code touched):

1. Root CMakeLists never called enable_testing(), so the top-level
   build/CTestTestfile.cmake was never generated and "cd build && ctest"
   (exactly what CI runs) discovered ZERO tests. The whole unit suite was
   silently not gating CI; only the explicitly-invoked equivalence binary
   ran. Add enable_testing() at the root so ctest finds all four test
   executables.

2. chaindb_runtime_tests.cpp and snapshotnet_tests.cpp were compiled BOTH
   into their own standalone executables AND into test_triangles via the
   test/*.cpp glob. Each #defines its own BOOST_TEST_MODULE and redefines
   the wallet/UI globals; the link only survived via
   -Wl,--allow-multiple-definition, which silently drops duplicate module
   and global symbols and can run those suites under the wrong fixture.
   Exclude both from the glob (they already have dedicated add_executable +
   add_test); nothing is lost and isolation is restored.

3. test_triangles TestingSetup opened the PRODUCTION chain DB at the default
   datadir, so ctest failed (DB lock) on any host running a live daemon and
   risked touching real chain state. Point -datadir at a fresh temp dir in
   the fixture (mirrors the standalone DataDirSetup); cleaned up on teardown.

After: ctest -N lists 4 tests; ctest runs 100% green even with a live
trianglesd holding the default datadir.
2026-07-04 16:25:26 -07:00

700 lines
28 KiB
CMake

# src/CMakeLists.txt
# Defines all build targets: libraries and executables.
# ═══════════════════════════════════════════════════════════════════════════════
# 1. Hash9 cryptographic primitives (pure C)
# ═══════════════════════════════════════════════════════════════════════════════
add_library(hash9_crypto STATIC
blake.c
groestl.c
jh.c
keccak.c
skein.c
aes_helper.c
bmw.c
cubehash.c
echo.c
fugue.c
hamsi.c
hamsi_helper.c
luffa.c
shavite.c
simd.c
)
target_include_directories(hash9_crypto PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
set_target_properties(hash9_crypto PROPERTIES LINKER_LANGUAGE C)
# Hash9 C files have colliding static symbols (IV512, DECL_STATE, etc.) — skip unity
set_target_properties(hash9_crypto PROPERTIES UNITY_BUILD OFF)
# ═══════════════════════════════════════════════════════════════════════════════
# 2. JSON library (header-only nlohmann/json via json_compat.h shim)
# ═══════════════════════════════════════════════════════════════════════════════
add_library(json_compat INTERFACE)
target_include_directories(json_compat INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/json")
# ═══════════════════════════════════════════════════════════════════════════════
# 3. Common core library (shared between daemon, Qt, and tests)
#
# EXCLUDES init.cpp, wallet.cpp (QT_GUI-conditional), noui.cpp (target-specific)
# ═══════════════════════════════════════════════════════════════════════════════
set(CORE_SOURCES
addrman.cpp
bootstrap.cpp
checkpointpublisher.cpp
checkpoints.cpp
crypter.cpp
hdwallet.cpp
crypto_ecdh.cpp
crypto_ecdsa.cpp
db.cpp
key.cpp
keystore.cpp
main.cpp
miner.cpp
net.cpp
net_bootstrap.cpp
netbase.cpp
protocol.cpp
script.cpp
sync.cpp
util.cpp
version.cpp
walletdb.cpp
kernel.cpp
pbkdf2.cpp
scrypt.cpp
smessage.cpp
syncmanager.cpp
chaindb_migrate.cpp
tor_embed_hooks.cpp
rest.cpp
trianglesrpc.cpp
rpcdump.cpp
rpcnet.cpp
rpcmining.cpp
rpcwallet.cpp
rpcblockchain.cpp
rpcrawtransaction.cpp
rpcsmessage.cpp
zmqpublishnotifier.cpp
txdb-base.cpp
txdb-factory.cpp
txdb-leveldb.cpp
utxosnapshot.cpp
snapshotnet.cpp
lz4/lz4.c
tor/onion_v3.cpp
tor/tor_process.cpp
tor/tor_embedded.cpp
i2p/i2p_embedded.cpp
)
# Scrypt assembly — platform-specific
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
enable_language(ASM)
list(APPEND CORE_SOURCES scrypt-x86_64.S)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i[3-6]86|x86")
enable_language(ASM)
list(APPEND CORE_SOURCES scrypt-x86.S)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64")
enable_language(ASM)
list(APPEND CORE_SOURCES scrypt-arm.S)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM")
enable_language(ASM)
list(APPEND CORE_SOURCES scrypt-arm.S)
endif()
# RocksDB chain database backend (always built; see top-level CMakeLists.txt
# for the rationale — RocksDB also backs the smessage store).
list(APPEND CORE_SOURCES txdb-rocksdb.cpp)
# Modernization: SQLite wallet DB backend + Berkeley→SQLite migration.
# Built unconditionally; selection happens at runtime via -walletdb.
list(APPEND CORE_SOURCES
walletdb-factory.cpp
walletdb-sqlite.cpp
walletdb-recover.cpp
walletmigrate.cpp
)
add_library(triangles_common OBJECT ${CORE_SOURCES})
target_include_directories(triangles_common PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/json"
"${CMAKE_CURRENT_SOURCE_DIR}/tor"
"${CMAKE_CURRENT_SOURCE_DIR}/i2p"
"${CMAKE_BINARY_DIR}/generated" # for build.h
)
target_compile_definitions(triangles_common PUBLIC HAVE_BUILD_INFO)
target_link_libraries(triangles_common PUBLIC
hash9_crypto
json_compat
leveldb_bundled
OpenSSL::SSL
OpenSSL::Crypto
BerkeleyDB::BerkeleyDB
Libevent::Libevent
ZLIB::ZLIB
Threads::Threads
SQLite::SQLite3
)
# Optional: UPnP
if(USE_UPNP)
target_compile_definitions(triangles_common PUBLIC USE_UPNP=1 STATICLIB MINIUPNP_STATICLIB)
target_link_libraries(triangles_common PUBLIC Miniupnpc::Miniupnpc)
if(WIN32)
target_link_libraries(triangles_common PUBLIC iphlpapi)
endif()
endif()
# Optional: IPv6
if(USE_IPV6)
target_compile_definitions(triangles_common PUBLIC USE_IPV6=1)
endif()
# Optional: ZMQ
if(USE_ZMQ)
target_compile_definitions(triangles_common PUBLIC ENABLE_ZMQ)
target_link_libraries(triangles_common PUBLIC PkgConfig::ZMQ)
endif()
# libsecp256k1 (mandatory) — ECDH / ECDSA replacement for OpenSSL EC.
# Provided by add_subdirectory(src/secp256k1) in the top-level CMakeLists.
target_link_libraries(triangles_common PUBLIC secp256k1)
# RocksDB (mandatory)
if(TARGET RocksDB::rocksdb)
target_link_libraries(triangles_common PUBLIC RocksDB::rocksdb)
elseif(TARGET PkgConfig::RocksDB)
target_link_libraries(triangles_common PUBLIC PkgConfig::RocksDB)
endif()
# Optional: Embedded Tor
if(USE_TOR_EMBEDDED)
if(TOR_SOURCE_ROOT STREQUAL "")
set(TOR_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/tor/tor-src")
endif()
target_compile_definitions(triangles_common PUBLIC ENABLE_TOR_EMBEDDED)
target_include_directories(triangles_common PUBLIC "${TOR_SOURCE_ROOT}/src/feature/api")
target_link_directories(triangles_common PUBLIC "${TOR_SOURCE_ROOT}")
# libtor.a has circular deps with libevent/openssl/zlib
# OpenSSL and zlib already linked via imported targets above, so only add
# libevent and compression libs that libtor needs but aren't yet linked.
# --start-group / --end-group resolves circular references between libtor
# and its dependencies.
# Use --allow-multiple-definition because libtor.a may pull in static
# OpenSSL objects that duplicate the DLL import lib already linked above.
# These GNU ld options are not supported on macOS (which uses lld) —
# guard with NOT APPLE so the build still works on macOS.
# On macOS, the libevent/openssl/zlib install paths are not on the
# default linker search path. Pull them in from the standard
# homebrew locations so -levent / -lssl / -lssl etc. resolve.
if(APPLE)
target_link_directories(triangles_common PUBLIC
/opt/homebrew/opt/libevent/lib
/opt/homebrew/opt/openssl@3/lib
/opt/homebrew/opt/zlib/lib
)
endif()
if(NOT APPLE)
target_link_libraries(triangles_common PUBLIC
-Wl,--allow-multiple-definition
-Wl,--start-group
)
endif()
target_link_libraries(triangles_common PUBLIC
-ltor
-levent -levent_core -levent_extra -levent_openssl
-lssl -lcrypto -lz -llzma -lzstd
)
if(NOT APPLE)
target_link_libraries(triangles_common PUBLIC
-Wl,--end-group
)
endif()
if(WIN32)
target_link_libraries(triangles_common PUBLIC iphlpapi shlwapi crypt32)
endif()
endif()
# Optional: Embedded I2P (i2pd)
if(USE_I2P_EMBEDDED)
if(I2P_SOURCE_ROOT STREQUAL "")
set(I2P_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/i2p/i2pd-src")
endif()
if(NOT EXISTS "${I2P_SOURCE_ROOT}/libi2pd/Crypto.h")
message(FATAL_ERROR
"USE_I2P_EMBEDDED=ON but i2pd source not found at ${I2P_SOURCE_ROOT}.\n"
"Run: git submodule update --init --recursive\n"
"Or set -DI2P_SOURCE_ROOT=/path/to/i2pd")
endif()
target_compile_definitions(triangles_common PUBLIC ENABLE_I2P_EMBEDDED)
target_include_directories(triangles_common PUBLIC
"${I2P_SOURCE_ROOT}"
"${I2P_SOURCE_ROOT}/libi2pd"
"${I2P_SOURCE_ROOT}/libi2pd_client"
"${I2P_SOURCE_ROOT}/i18n"
)
# i2pd builds as two static libraries: libi2pd.a (core router) and
# libi2pd_client.a (SAM, SOCKS, tunnels, client context). Both are needed.
# i2pd's own Makefile.mingw links by full static .a paths rather than
# -l flags because MinGW's linker is single-pass and CMake imported
# targets (Boost::) may not exist on MSYS2. We follow the same pattern:
# link the archives, then their Boost/zlib deps as full paths, then
# the archives again to resolve the second-pass references.
target_link_libraries(triangles_common PUBLIC
"${I2P_SOURCE_ROOT}/libi2pdclient.a"
"${I2P_SOURCE_ROOT}/libi2pd.a"
"${I2P_SOURCE_ROOT}/libi2pdlang.a"
)
if(WIN32)
# MinGW/MSYS2: Boost:: CMake imported targets are unreliable here.
# Use find_library to locate the actual .a/.dll files. Some Boost
# libs (e.g. boost_system) are header-only in newer versions and
# won't have a .a file at all — that's fine, we skip them.
if(NOT MINGW_PREFIX)
if(DEFINED ENV{MINGW_PREFIX})
set(MINGW_PREFIX "$ENV{MINGW_PREFIX}")
else()
set(MINGW_PREFIX "/mingw64")
endif()
endif()
find_library(I2P_BOOST_FS NAMES boost_filesystem-mt boost_filesystem libboost_filesystem-mt HINTS "${MINGW_PREFIX}/lib")
find_library(I2P_BOOST_PO NAMES boost_program_options-mt boost_program_options libboost_program_options-mt HINTS "${MINGW_PREFIX}/lib")
find_library(I2P_BOOST_SYS NAMES boost_system-mt boost_system libboost_system-mt HINTS "${MINGW_PREFIX}/lib")
find_library(I2P_SSL NAMES ssl libssl HINTS "${MINGW_PREFIX}/lib")
find_library(I2P_CRYPTO NAMES crypto libcrypto HINTS "${MINGW_PREFIX}/lib")
find_library(I2P_Z NAMES z libz zlib HINTS "${MINGW_PREFIX}/lib")
set(I2P_WIN_LIBS "")
foreach(lib I2P_BOOST_FS I2P_BOOST_PO I2P_BOOST_SYS I2P_SSL I2P_CRYPTO I2P_Z)
if(${lib})
list(APPEND I2P_WIN_LIBS "${${lib}}")
message(STATUS " I2P link: ${lib} = ${${lib}}")
else()
message(STATUS " I2P link: ${lib} = (not found, header-only?)")
endif()
endforeach()
target_link_libraries(triangles_common PUBLIC ${I2P_WIN_LIBS} -Wl,--allow-multiple-definition)
else()
target_link_libraries(triangles_common PUBLIC
Boost::program_options Boost::thread Boost::chrono
OpenSSL::SSL OpenSSL::Crypto
ZLIB::ZLIB
)
if(TARGET Boost::filesystem)
target_link_libraries(triangles_common PUBLIC Boost::filesystem)
endif()
if(TARGET Boost::system)
target_link_libraries(triangles_common PUBLIC Boost::system)
endif()
endif()
# Second pass: list archives again so linker resolves i2pd→Boost refs
# that were unsatisfied in the first left-to-right pass.
target_link_libraries(triangles_common PUBLIC
"${I2P_SOURCE_ROOT}/libi2pd.a"
"${I2P_SOURCE_ROOT}/libi2pdclient.a"
)
endif()
# Platform-specific libraries
if(WIN32)
target_link_libraries(triangles_common PUBLIC
ws2_32 shlwapi mswsock ole32 oleaut32 uuid gdi32 crypt32)
elseif(APPLE)
target_link_libraries(triangles_common PUBLIC
"-framework Foundation"
"-framework ApplicationServices"
"-framework AppKit")
else()
# Linux
target_link_libraries(triangles_common PUBLIC rt dl)
endif()
add_dependencies(triangles_common generate_build_info build_leveldb)
# ── Precompiled header (heavy STL + Boost + OpenSSL includes, C++ only) ──
target_precompile_headers(triangles_common PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:<string$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<vector$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<map$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<deque$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<algorithm$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<sstream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<stdexcept$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<cstdint$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<cstring$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<memory$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<functional$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<filesystem$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<fstream$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<thread$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<mutex$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<condition_variable$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<boost/algorithm/string.hpp$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<openssl/sha.h$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<openssl/crypto.h$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<openssl/rand.h$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<openssl/evp.h$<ANGLE-R>>"
)
# ═══════════════════════════════════════════════════════════════════════════════
# 4. Headless daemon (trianglesd)
# ═══════════════════════════════════════════════════════════════════════════════
if(BUILD_DAEMON)
add_executable(trianglesd
noui.cpp
init.cpp
wallet.cpp
)
# No QT_GUI define — daemon gets the #if !defined(QT_GUI) code paths
target_link_libraries(trianglesd PRIVATE triangles_common)
target_precompile_headers(trianglesd REUSE_FROM triangles_common)
if(WIN32)
set_target_properties(trianglesd PROPERTIES SUFFIX ".exe")
endif()
endif()
# ═══════════════════════════════════════════════════════════════════════════════
# 4b. JSON-RPC client (triangles-cli)
#
# Self-contained: only links univalue + boost::asio + boost::program_options
# + boost::filesystem + OpenSSL (for base64 / future TLS). Does NOT link
# triangles_common, wallet, or net — keeps the binary small.
# ═══════════════════════════════════════════════════════════════════════════════
if(BUILD_CLI)
add_executable(triangles-cli
triangles-cli.cpp
)
# No Boost dependency: uses raw POSIX/Winsock sockets for HTTP. Only links
# the json_compat header-only shim and the platform's native socket lib
# (Winsock ws2_32 on Windows; libc on POSIX). Keeps the binary small and
# avoids per-platform Boost linking pain (MSYS2 uses versioned -mt- names;
# Homebrew doesn't ship the boost_system CMake config).
target_link_libraries(triangles-cli
PRIVATE
json_compat
)
if(WIN32)
set_target_properties(triangles-cli PROPERTIES SUFFIX ".exe")
target_link_libraries(triangles-cli PRIVATE ws2_32)
endif()
if(MSVC)
set_target_properties(triangles-cli PROPERTIES
VS_WINRT_COMPONENT "console"
)
endif()
endif()
# ═══════════════════════════════════════════════════════════════════════════════
# 5. Qt5 GUI wallet (triangles-qt)
# ═══════════════════════════════════════════════════════════════════════════════
if(BUILD_QT)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS
"${CMAKE_CURRENT_SOURCE_DIR}/qt/forms"
"${CMAKE_CURRENT_SOURCE_DIR}/qt/plugins/mrichtexteditor"
)
# ui_interface.h is a hand-written header (Bitcoin convention), NOT a Qt
# Designer file. Disable AutoUic globally and run UIC manually for real .ui files.
set(CMAKE_AUTOUIC OFF)
# Collect all .ui files and run UIC on them explicitly
file(GLOB_RECURSE UI_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/qt/forms/*.ui"
"${CMAKE_CURRENT_SOURCE_DIR}/qt/plugins/mrichtexteditor/*.ui"
)
qt5_wrap_ui(UI_HEADERS ${UI_FILES})
set(QT_SOURCES
qt/triangles.cpp
qt/trianglesgui.cpp
qt/transactiontablemodel.cpp
qt/addresstablemodel.cpp
qt/optionsdialog.cpp
qt/sendcoinsdialog.cpp
qt/coincontroldialog.cpp
qt/coincontroltreewidget.cpp
qt/addressbookpage.cpp
qt/aboutdialog.cpp
qt/introdialog.cpp
qt/editaddressdialog.cpp
qt/trianglesaddressvalidator.cpp
qt/clientmodel.cpp
qt/guiutil.cpp
qt/transactionrecord.cpp
qt/optionsmodel.cpp
qt/monitoreddatamapper.cpp
qt/transactiondesc.cpp
qt/transactiondescdialog.cpp
qt/trianglesstrings.cpp
qt/trianglesamountfield.cpp
qt/transactionfilterproxy.cpp
qt/transactionview.cpp
qt/walletmodel.cpp
qt/overviewpage.cpp
qt/csvmodelwriter.cpp
qt/sendcoinsentry.cpp
qt/qvalidatedlineedit.cpp
qt/trianglesunits.cpp
qt/qvaluecombobox.cpp
qt/askpassphrasedialog.cpp
qt/hdseeddialog.cpp
qt/outlinedlabel.cpp
qt/notificator.cpp
qt/qtipcserver.cpp
qt/rpcconsole.cpp
qt/messagepage.cpp
qt/dialog_move_handler.cpp
qt/signmessagepage.cpp
qt/verifymessagepage.cpp
qt/messagemodel.cpp
qt/sendmessagesdialog.cpp
qt/sendmessagesentry.cpp
qt/qvalidatedtextedit.cpp
qt/plugins/mrichtexteditor/mrichtextedit.cpp
)
set(QT_RESOURCES qt/triangles.qrc)
set(QT_FORMS
qt/forms/coincontroldialog.ui
qt/forms/sendcoinsdialog.ui
qt/forms/addressbookpage.ui
qt/forms/aboutdialog.ui
qt/forms/editaddressdialog.ui
qt/forms/transactiondescdialog.ui
qt/forms/overviewpage.ui
qt/forms/sendcoinsentry.ui
qt/forms/askpassphrasedialog.ui
qt/forms/rpcconsole.ui
qt/forms/optionsdialog.ui
qt/forms/messagepage.ui
qt/forms/sendmessagesentry.ui
qt/forms/sendmessagesdialog.ui
qt/plugins/mrichtexteditor/mrichtextedit.ui
qt/forms/mainwindow.ui
qt/forms/signmessagepage.ui
qt/forms/verifymessagepage.ui
qt/forms/transactionspage.ui
)
# Optional QR code dialog
if(USE_QRCODE)
list(APPEND QT_SOURCES qt/qrcodedialog.cpp)
list(APPEND QT_FORMS qt/forms/qrcodedialog.ui)
endif()
# macOS Objective-C++ sources
if(APPLE)
list(APPEND QT_SOURCES
qt/macdockiconhandler.mm
qt/macnotificationhandler.mm
)
endif()
add_executable(triangles-qt WIN32 MACOSX_BUNDLE
${QT_SOURCES}
${QT_RESOURCES}
${QT_FORMS}
${UI_HEADERS}
# Per-target: compiled with QT_GUI define
init.cpp
wallet.cpp
noui.cpp
)
target_compile_definitions(triangles-qt PRIVATE
QT_GUI
QT_DISABLE_DEPRECATED_BEFORE=0
)
target_include_directories(triangles-qt PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/qt"
"${CMAKE_CURRENT_SOURCE_DIR}/qt/plugins/mrichtexteditor"
"${CMAKE_CURRENT_BINARY_DIR}"
)
target_link_libraries(triangles-qt PRIVATE
triangles_common
Qt5::Core
Qt5::Gui
Qt5::Widgets
Qt5::Network
)
# Optional: D-Bus notifications (Linux)
if(USE_DBUS)
target_compile_definitions(triangles-qt PRIVATE USE_DBUS)
target_link_libraries(triangles-qt PRIVATE Qt5::DBus)
endif()
# Optional: QR code
if(USE_QRCODE)
target_compile_definitions(triangles-qt PRIVATE USE_QRCODE)
target_link_libraries(triangles-qt PRIVATE QRencode::QRencode)
endif()
# Windows resource file (.rc with version info and icon)
if(WIN32)
target_sources(triangles-qt PRIVATE qt/res/triangles-qt.rc)
# Ensure RC compiler can find clientversion.h
if(MINGW)
set_source_files_properties(qt/res/triangles-qt.rc PROPERTIES
COMPILE_FLAGS "-I${CMAKE_CURRENT_SOURCE_DIR}"
)
endif()
endif()
# macOS bundle settings
if(APPLE)
set_target_properties(triangles-qt PROPERTIES
OUTPUT_NAME "Triangles-Qt"
MACOSX_BUNDLE_ICON_FILE triangles.icns
MACOSX_BUNDLE_BUNDLE_NAME "Triangles-Qt"
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
)
set_source_files_properties(
"${CMAKE_CURRENT_SOURCE_DIR}/qt/res/icons/triangles.icns"
PROPERTIES MACOSX_PACKAGE_LOCATION "Resources"
)
target_sources(triangles-qt PRIVATE qt/res/icons/triangles.icns)
endif()
# Translations (optional — requires LinguistTools)
if(TARGET Qt5::lrelease)
file(GLOB TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/qt/locale/triangles_*.ts")
if(TS_FILES)
set_source_files_properties(${TS_FILES} PROPERTIES
OUTPUT_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/qt/locale"
)
qt5_add_translation(QM_FILES ${TS_FILES})
target_sources(triangles-qt PRIVATE ${QM_FILES})
endif()
endif()
endif()
# ═══════════════════════════════════════════════════════════════════════════════
# 6. Unit tests (test_triangles)
# ═══════════════════════════════════════════════════════════════════════════════
if(BUILD_TESTS)
enable_testing()
file(GLOB TEST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp")
# Exclude miner_tests.cpp (never ported from Bitcoin)
list(FILTER TEST_SOURCES EXCLUDE REGEX "miner_tests\\.cpp$")
# Exclude the standalone chaindb test driver — it gets its own target
# because it needs to run without the TestingSetup global fixture.
list(FILTER TEST_SOURCES EXCLUDE REGEX "chaindb_equivalence_tests_main\\.cpp$")
# These two are standalone test drivers: each #defines its own
# BOOST_TEST_MODULE and redefines the wallet/UI globals, and each has
# a dedicated executable + add_test below. They must NOT also be
# globbed into test_triangles, or the duplicate module/main and global
# symbols only link by virtue of -Wl,--allow-multiple-definition (which
# silently drops duplicates and can run their suites under the wrong
# global fixture). Excluding them keeps each standalone module isolated.
list(FILTER TEST_SOURCES EXCLUDE REGEX "chaindb_runtime_tests\\.cpp$")
list(FILTER TEST_SOURCES EXCLUDE REGEX "snapshotnet_tests\\.cpp$")
add_executable(test_triangles
${TEST_SOURCES}
# Per-target: wallet without QT_GUI, noui for noui_connect()
wallet.cpp
noui.cpp
)
# No init.cpp — test_triangles.cpp provides its own StartShutdown() stub
target_compile_definitions(test_triangles PRIVATE
"TEST_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test/data"
)
target_include_directories(test_triangles PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/test"
)
target_link_libraries(test_triangles PRIVATE
triangles_common
Boost::unit_test_framework
)
add_test(NAME triangles_unit_tests COMMAND test_triangles --log_level=test_suite)
# ── Standalone chaindb equivalence tests ─────────────────────────────────
# Runs without the TestingSetup global fixture (which would otherwise
# open the real chain DB and lock it for the process). Sets a fresh
# temp -datadir via its own global fixture, then runs the
# chaindb_equivalence_tests suite.
add_executable(test_chaindb_equivalence
"${CMAKE_CURRENT_SOURCE_DIR}/test/chaindb_equivalence_tests_main.cpp"
# wallet.cpp provides the CWallet symbols that triangles_common
# (txdb-rocksdb, net, etc.) references, even though the chaindb
# tests themselves don't use the wallet.
wallet.cpp
)
target_include_directories(test_chaindb_equivalence PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/test"
"${CMAKE_CURRENT_SOURCE_DIR}/leveldb/include"
)
target_link_libraries(test_chaindb_equivalence PRIVATE
triangles_common
Boost::unit_test_framework
)
add_test(NAME chaindb_equivalence_tests
COMMAND test_chaindb_equivalence --log_level=test_suite)
# ── Standalone snapshotnet P2P tests ────────────────────────────────────
# Same rationale as test_chaindb_equivalence: snapshotnet needs filesystem
# and threading globals and its own tmp datadir fixture, which would
# conflict with test_triangles' heavy TestingSetup. Runs independently.
add_executable(test_snapshotnet
"${CMAKE_CURRENT_SOURCE_DIR}/test/snapshotnet_tests.cpp"
wallet.cpp
)
target_include_directories(test_snapshotnet PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/test"
"${CMAKE_CURRENT_SOURCE_DIR}/leveldb/include"
)
target_link_libraries(test_snapshotnet PRIVATE
triangles_common
Boost::unit_test_framework
)
add_test(NAME snapshotnet_tests
COMMAND test_snapshotnet --log_level=test_suite)
# ── Standalone chaindb runtime tests (CRocksTxDB wrapper layer) ─────────
# Exercises MakeChainDB / WipeChainDataDir / IsRocksDbChainBackend and
# the CRocksTxDB write/read/batch/iterator wrapper — the same code path
# the daemon uses when launched with `-chaindb=rocksdb`. The
# chaindb_equivalence_tests (above) only verify the byte-copy migration
# via the raw leveldb/rocksdb APIs; this one verifies the wrapper class.
add_executable(test_chaindb_runtime
"${CMAKE_CURRENT_SOURCE_DIR}/test/chaindb_runtime_tests.cpp"
wallet.cpp
)
target_include_directories(test_chaindb_runtime PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/test"
"${CMAKE_CURRENT_SOURCE_DIR}/leveldb/include"
)
target_link_libraries(test_chaindb_runtime PRIVATE
triangles_common
Boost::unit_test_framework
)
add_test(NAME chaindb_runtime_tests
COMMAND test_chaindb_runtime --log_level=test_suite)
endif()