# Copyright (c) 2020, The Monero Project # Copyright (c) 2024-2025, The Wownero Project # # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are # permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of # conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list # of conditions and the following disclaimer in the documentation and/or other # materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors may be # used to endorse or promote products derived from this software without specific # prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL # THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cmake_minimum_required(VERSION 3.5.0) project(wownero-lws) enable_language(CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_definitions(-DBOOST_UUID_DISABLE_ALIGNMENT) # This restores UUID's std::has_unique_object_representations property option(BUILD_TESTS "Build Tests" OFF) option(WITH_RMQ "Build with RMQ publish support" OFF) if (WITH_RMQ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMLWS_RMQ_ENABLED") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMLWS_RMQ_ENABLED") endif() # If `WOWNERO_BUILD_DIR` is not specified, wownero unit tests will be built with this hack set (LWS_BUILD_TESTS "${BUILD_TESTS}") set (BUILD_TESTS "Off") option(SANITIZER "Use specific sanitizer" OFF) if(NOT SANITIZER STREQUAL "OFF") if (MSVC) message(FATAL_ERROR "Cannot sanitize with MSVC") else() message(STATUS "Using sanitizer=${SANITIZER}") add_compile_options("-fsanitize=${SANITIZER}") add_link_options("-fsanitize=${SANITIZER}") endif() endif() if(STATIC) if(MSVC) set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .dll.a .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) else() set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) endif() endif() set(WOWNERO_LIBRARIES daemon_messages serialization net cryptonote_core cryptonote_basic cryptonote_format_utils_basic ringct ringct_basic multisig hardforks checkpoints blockchain_db common lmdb lmdb_lib device cncrypto randomx epee easylogging version wallet-crypto ) set(WOWNERO_OPTIONAL wallet-crypto) if (WOWNERO_BUILD_DIR) set(WOWNERO_SEARCH_PATHS "/contrib/epee/src" "/external/db_drivers/liblmdb" "/external/easylogging++" "/external/randomwow" "/src" "/src/crypto" "/src/crypto/wallet" "/src/cryptonote_basic" "/src/lmdb" "/src/ringct" "/src/rpc" "/src/common" "/src/serialization" "/src/net" "/src/cryptonote_core" "/src/multisig" "/src/hardforks" "/src/checkpoints" "/src/blockchain_db" "/src/device" "/src/mnemonics" ) # # Pull some information from wownero build # # Needed due to "bug" in wownero CMake - the `project` function is used twice! if (NOT WOWNERO_SOURCE_DIR) message(FATAL_ERROR "The argument -DWOWNERO_SOURCE_DIR must specify a location of a wownero source tree") endif() get_filename_component(WOWNERO_SOURCE_DIR "${WOWNERO_SOURCE_DIR}" ABSOLUTE) get_filename_component(WOWNERO_BUILD_DIR "${WOWNERO_BUILD_DIR}" ABSOLUTE) message(STATUS "WOWNERO_SOURCE_DIR: ${WOWNERO_SOURCE_DIR}") message(STATUS "WOWNERO_BUILD_DIR: ${WOWNERO_BUILD_DIR}") if (NOT EXISTS "${WOWNERO_BUILD_DIR}/CMakeCache.txt") message(FATAL_ERROR "Wownero cache not found at ${WOWNERO_BUILD_DIR}/CMakeCache.txt. Please ensure WOWNERO_BUILD_DIR is correct and Wownero has been configured.") endif() # wownero `master` and release branches use different LIBSODIUM # find routines. So the upstream cmake names differ load_cache(${WOWNERO_BUILD_DIR} READ_WITH_PREFIX wownero_ Boost_THREAD_LIBRARY_RELEASE CMAKE_CXX_COMPILER EXTRA_LIBRARIES LIBUDEV_LIBRARY usb_LIBRARY HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY LMDB_INCLUDE wownero_SOURCE_DIR OPENSSL_INCLUDE_DIR OPENSSL_CRYPTO_LIBRARY OPENSSL_SSL_LIBRARY ZMQ_LIB ZMQ_INCLUDE_PATH sodium_LIBRARY_RELEASE SODIUM_LIBRARY UNBOUND_LIBRARIES PGM_LIBRARY NORM_LIBRARY GSSAPI_LIBRARY PROTOLIB_LIBRARY ) if (wownero_wownero_SOURCE_DIR AND NOT (wownero_wownero_SOURCE_DIR MATCHES "${WOWNERO_SOURCE_DIR}")) message(WARNING "Mismatch detected: wownero_wownero_SOURCE_DIR='${wownero_wownero_SOURCE_DIR}' vs WOWNERO_SOURCE_DIR='${WOWNERO_SOURCE_DIR}'. Proceeding anyway...") endif() if (wownero_CMAKE_CXX_COMPILER AND NOT (CMAKE_CXX_COMPILER STREQUAL wownero_CMAKE_CXX_COMPILER)) message(FATAL_ERROR "Compiler for wownero build (${wownero_CMAKE_CXX_COMPILER}) differs from this project (${CMAKE_CXX_COMPILER})") endif() if ("${wownero_UNBOUND_LIBRARIES}" STREQUAL "UNBOUND_LIBRARIES-NOTFOUND") unset(wownero_UNBOUND_LIBRARIES) endif() if ("${wownero_HIDAPI_LIBRARY}" STREQUAL "HIDAPI_LIBRARY-NOTFOUND") unset(wownero_HIDAPI_INCLUDE_DIR) unset(wownero_HIDAPI_LIBRARY) endif() set(WOWNERO_LIBRARY_PATHS "") foreach (PATH ${WOWNERO_SEARCH_PATHS}) list(APPEND WOWNERO_LIBRARY_PATHS "${WOWNERO_BUILD_DIR}${PATH}") endforeach() foreach (LIB ${WOWNERO_LIBRARIES}) find_library(LIB_PATH NAMES "${LIB}" PATHS ${WOWNERO_BUILD_DIR} ${WOWNERO_LIBRARY_PATHS} PATH_SUFFIXES "/src/${LIB}" "external/${LIB}" NO_DEFAULT_PATH) list(FIND WOWNERO_OPTIONAL "${LIB}" LIB_OPTIONAL) if (NOT LIB_PATH) if (LIB_OPTIONAL EQUAL -1) message(FATAL_ERROR "Unable to find required Wownero library ${LIB}") endif() else () set(LIB_NAME "wownero::${LIB}") add_library(${LIB_NAME} STATIC IMPORTED) set_target_properties(${LIB_NAME} PROPERTIES IMPORTED_LOCATION ${LIB_PATH}) list(APPEND IMPORTED_WOWNERO_LIBRARIES "${LIB_NAME}") endif() unset(LIB_PATH CACHE) endforeach() set(LMDB_INCLUDE "${wownero_LMDB_INCLUDE}") set(LMDB_LIB_PATH "wownero::lmdb") else () # NOT WOWNERO_BUILD_DIR if (NOT WOWNERO_SOURCE_DIR) set (WOWNERO_SOURCE_DIR "${wownero-lws_SOURCE_DIR}/external/monero") endif () include(FetchContent) FetchContent_Declare(wownero SOURCE_DIR "${WOWNERO_SOURCE_DIR}" EXCLUDE_FROM_ALL) if (NOT wownero_POPULATED) FetchContent_MakeAvailable(wownero) endif () set(WOWNERO_BUILD_DIR "${wownero_BINARY_DIR}") set(IMPORTED_WOWNERO_LIBRARIES "${WOWNERO_LIBRARIES}") set(LMDB_LIB_PATH "lmdb") set(wownero_Boost_THREAD_LIBRARY_RELEASE "${Boost_THREAD_LIBRARY_RELEASE}") # Wownero uses ZMQ_LIB directly (via find_library), not pkg-config set(wownero_ZMQ_LIB "${ZMQ_LIB}") set(wownero_ZMQ_INCLUDE_PATH "${ZMQ_INCLUDE_PATH}") if (SODIUM_LIBRARY) set(wownero_SODIUM_LIBRARY "${SODIUM_LIBRARY}") else() set(wownero_SODIUM_LIBRARY "${wownero_sodium_LIBRARY_RELEASE}") endif() endif() # # Dependencies specific to wownero-lws # set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) # boost set(Boost_NO_BOOST_CMAKE ON) # If Wownero was built statically, we should probably do the same if (WOWNERO_BUILD_DIR AND NOT STATIC) if (wownero_Boost_THREAD_LIBRARY_RELEASE MATCHES ".*\\.a$") message(STATUS "Wownero build was static, enabling STATIC for this project") set(STATIC ON) endif() endif() if(STATIC) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_RUNTIME ON) endif() find_package(Boost 1.70 QUIET REQUIRED COMPONENTS chrono context coroutine filesystem program_options regex serialization thread) get_filename_component(REAL_Boost_THREAD_LIBRARY "${Boost_THREAD_LIBRARY}" REALPATH) get_filename_component(REAL_wownero_Boost_THREAD_LIBRARY "${wownero_Boost_THREAD_LIBRARY_RELEASE}" REALPATH) if (NOT (REAL_Boost_THREAD_LIBRARY STREQUAL REAL_wownero_Boost_THREAD_LIBRARY)) message(STATUS "Found Boost_THREAD_LIBRARY: ${Boost_THREAD_LIBRARY} (real: ${REAL_Boost_THREAD_LIBRARY})") message(STATUS "Found wownero_Boost_THREAD_LIBRARY_RELEASE: ${wownero_Boost_THREAD_LIBRARY_RELEASE} (real: ${REAL_wownero_Boost_THREAD_LIBRARY})") message(FATAL_ERROR "Boost libraries for wownero build differs from this project") endif() if (WITH_RMQ) find_path(RMQ_INCLUDE_DIR "amqp.h") find_library(RMQ_LIBRARY rabbitmq REQUIRED) else() set(RMQ_INCLUDE_DIR "") set(RMQ_LIBRARY "") endif() # Use ZMQ from Wownero build if (wownero_ZMQ_INCLUDE_PATH) set(ZMQ_INCLUDE_PATH "${wownero_ZMQ_INCLUDE_PATH}") endif() if (wownero_ZMQ_LIB) set(ZMQ_LIB "${wownero_ZMQ_LIB}") endif() if (wownero_SODIUM_LIBRARY) set(SODIUM_LIBRARY "${wownero_SODIUM_LIBRARY}") else () set(SODIUM_LIBRARY "${wownero_sodium_LIBRARY_RELEASE}") endif () if(NOT ZMQ_LIB) message(FATAL_ERROR "Could not find required libzmq") endif() if(wownero_PGM_LIBRARY AND NOT "${wownero_PGM_LIBRARY}" STREQUAL "PGM_LIBRARY-NOTFOUND") set(ZMQ_LIB "${ZMQ_LIB};${wownero_PGM_LIBRARY}") endif() if(wownero_NORM_LIBRARY AND NOT "${wownero_NORM_LIBRARY}" STREQUAL "NORM_LIBRARY-NOTFOUND") set(ZMQ_LIB "${ZMQ_LIB};${wownero_NORM_LIBRARY}") if(NOT wownero_PROTOLIB_LIBRARY OR "${wownero_PROTOLIB_LIBRARY}" STREQUAL "PROTOLIB_LIBRARY-NOTFOUND") find_library(PROTOLIB_LIBRARY NAMES protokit protolib) if(PROTOLIB_LIBRARY) set(wownero_PROTOLIB_LIBRARY "${PROTOLIB_LIBRARY}") endif() endif() endif() if(wownero_GSSAPI_LIBRARY AND NOT "${wownero_GSSAPI_LIBRARY}" STREQUAL "GSSAPI_LIBRARY-NOTFOUND") set(ZMQ_LIB "${ZMQ_LIB};${wownero_GSSAPI_LIBRARY}") endif() if(wownero_PROTOLIB_LIBRARY AND NOT "${wownero_PROTOLIB_LIBRARY}" STREQUAL "PROTOLIB_LIBRARY-NOTFOUND") set(ZMQ_LIB "${ZMQ_LIB};${wownero_PROTOLIB_LIBRARY}") endif() if(wownero_sodium_LIBRARY_RELEASE AND NOT "${wownero_sodium_LIBRARY_RELEASE}" STREQUAL "sodium_LIBRARY_RELEASE-NOTFOUND") set(ZMQ_LIB "${ZMQ_LIB};${wownero_sodium_LIBRARY_RELEASE}") endif() if(STATIC AND NOT IOS) if(UNIX) find_package(ZLIB) if(ZLIB_FOUND) set(wownero_OPENSSL_CRYPTO_LIBRARY "${wownero_OPENSSL_CRYPTO_LIBRARY};${ZLIB_LIBRARIES}") endif() find_library(ZSTD_LIBRARY NAMES zstd) if(ZSTD_LIBRARY) set(wownero_OPENSSL_CRYPTO_LIBRARY "${wownero_OPENSSL_CRYPTO_LIBRARY};${ZSTD_LIBRARY}") else() set(wownero_OPENSSL_CRYPTO_LIBRARY "${wownero_OPENSSL_CRYPTO_LIBRARY};zstd") endif() find_library(EVENT_LIBRARY NAMES event libevent) if(EVENT_LIBRARY) set(wownero_UNBOUND_LIBRARIES "${wownero_UNBOUND_LIBRARIES};${EVENT_LIBRARY}") else() set(wownero_UNBOUND_LIBRARIES "${wownero_UNBOUND_LIBRARIES};event") endif() set(wownero_OPENSSL_LIBRARIES "${wownero_OPENSSL_LIBRARIES};${CMAKE_DL_LIBS};${CMAKE_THREAD_LIBS_INIT};rt") endif() endif() if(APPLE) find_library(IOKIT_LIBRARY IOKit) list(APPEND IMPORTED_WOWNERO_LIBRARIES ${IOKIT_LIBRARY}) endif() add_library(wownero::libraries INTERFACE IMPORTED) set_property(TARGET wownero::libraries PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR} ${wownero_HIDAPI_INCLUDE_DIRS} ${wownero_OPENSSL_INCLUDE_DIR} "${WOWNERO_BUILD_DIR}/generated_include" "${WOWNERO_SOURCE_DIR}/contrib/epee/include" "${WOWNERO_SOURCE_DIR}/external/easylogging++" "${WOWNERO_SOURCE_DIR}/external/rapidjson/include" "${WOWNERO_SOURCE_DIR}/external/supercop/include" "${WOWNERO_SOURCE_DIR}/src" ) set_property(TARGET wownero::libraries PROPERTY INTERFACE_LINK_LIBRARIES ${IMPORTED_WOWNERO_LIBRARIES} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${wownero_HIDAPI_LIBRARY} ${wownero_usb_LIBRARY} ${wownero_LIBUDEV_LIBRARY} ${wownero_OPENSSL_SSL_LIBRARY} ${wownero_OPENSSL_CRYPTO_LIBRARY} ${SODIUM_LIBRARY} ${wownero_UNBOUND_LIBRARIES} ${ZMQ_LIB} ${CMAKE_DL_LIBS} Threads::Threads rt ) # # Build wownero-lws code # add_subdirectory(src) if (LWS_BUILD_TESTS) enable_testing() add_subdirectory(tests) endif()