2025-12-17 10:55:13 +01:00
cmake_minimum_required ( VERSION 3.20 )
project ( logos-blockchain-module )
set ( CMAKE_CXX_STANDARD 20 )
add_library ( blockchainmodulelib SHARED library.cpp )
# --- Optional Qt dependency (Qt6 preferred, fallback to Qt5) ---
# Enable this to link Qt Core into the `logos-blockchain-module` library without breaking
# environments where Qt isn't installed yet.
option ( UNTITLED_USE_QT "Enable Qt (Qt6/Qt5) dependency for blockchain-module" ON )
if ( UNTITLED_USE_QT )
# Auto tools make using Qt headers/classes easier when added later
set ( CMAKE_AUTOMOC ON )
set ( CMAKE_AUTOUIC ON )
set ( CMAKE_AUTORCC ON )
# Try to find Qt6 first, then Qt5. Require Core component at minimum.
find_package ( QT NAMES Qt6 Qt5 QUIET COMPONENTS Core )
if ( QT_FOUND )
find_package ( Qt ${ QT_VERSION_MAJOR } REQUIRED COMPONENTS Core )
target_link_libraries ( blockchainmodulelib PRIVATE Qt ${ QT_VERSION_MAJOR } ::Core )
target_compile_definitions ( blockchainmodulelib PRIVATE USING_QT )
else ( )
message ( WARNING "UNTITLED_USE_QT=ON but Qt was not found. Proceeding without Qt. Set CMAKE_PREFIX_PATH to your Qt installation or turn OFF the option." )
endif ( )
endif ( )
# --- External dependency: logos-blockchain ---
# This scaffolding downloads, builds, and stages artifacts from
# https://github.com/logos-blockchain/logos-blockchain
# Fill in the TODOs (e.g., GIT_TAG and the actual produced library name).
include ( ExternalProject )
set ( LOGOS_STAGE_DIR "${CMAKE_BINARY_DIR}/logos_stage" )
set ( LOGOS_INSTALL_DIR "${LOGOS_STAGE_DIR}" )
# Ensure staged include/lib directories exist at configure time to avoid
# INTERFACE_INCLUDE_DIRECTORIES pointing to a non-existent path errors
file ( MAKE_DIRECTORY "${LOGOS_INSTALL_DIR}/include" )
file ( MAKE_DIRECTORY "${LOGOS_INSTALL_DIR}/lib" )
# --- External dependency: logos-cpp-sdk ---
# Fetch and stage the C++ SDK so we can include "core/interface.h"
set ( LOGOS_CPP_SDK_STAGE_DIR "${CMAKE_BINARY_DIR}/logos_cpp_sdk_stage" )
file ( MAKE_DIRECTORY "${LOGOS_CPP_SDK_STAGE_DIR}/include" )
ExternalProject_Add ( logos_cpp_sdk_ep
G I T _ R E P O S I T O R Y h t t p s : / / g i t h u b . c o m / l o g o s - c o / l o g o s - c p p - s d k
U P D A T E _ D I S C O N N E C T E D 1
G I T _ S H A L L O W O F F
G I T _ S U B M O D U L E S " "
G I T _ S U B M O D U L E S _ R E C U R S E T R U E
# The SDK is header-first. We clone it and copy headers to a stable include dir.
C O N F I G U R E _ C O M M A N D " "
B U I L D _ C O M M A N D " "
I N S T A L L _ C O M M A N D " "
)
ExternalProject_Get_Property ( logos_cpp_sdk_ep SOURCE_DIR )
# Stage headers to a predictable location in our build tree.
add_custom_command (
O U T P U T " $ { L O G O S _ C P P _ S D K _ S T A G E _ D I R } / i n c l u d e / . s t a g e d "
C O M M A N D $ { C M A K E _ C O M M A N D } - E e c h o " S t a g i n g l o g o s - c p p - s d k headers ( core -> include/core ) "
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { L O G O S _ C P P _ S D K _ S T A G E _ D I R } / i n c l u d e / c o r e "
C O M M A N D $ { C M A K E _ C O M M A N D } - E c o p y _ d i r e c t o r y " $ { S O U R C E _ D I R } / c o r e " " $ { L O G O S _ C P P _ S D K _ S T A G E _ D I R } / i n c l u d e / c o r e "
C O M M A N D $ { C M A K E _ C O M M A N D } - E e c h o " S t a g i n g l o g o s - c p p - s d k headers ( cpp -> include/cpp ) "
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { L O G O S _ C P P _ S D K _ S T A G E _ D I R } / i n c l u d e / c p p "
C O M M A N D $ { C M A K E _ C O M M A N D } - E c o p y _ d i r e c t o r y " $ { S O U R C E _ D I R } / c p p " " $ { L O G O S _ C P P _ S D K _ S T A G E _ D I R } / i n c l u d e / c p p "
C O M M A N D $ { C M A K E _ C O M M A N D } - E t o u c h " $ { L O G O S _ C P P _ S D K _ S T A G E _ D I R } / i n c l u d e / . s t a g e d "
D E P E N D S l o g o s _ c p p _ s d k _ e p
V E R B A T I M
)
add_custom_target ( logos_cpp_sdk_stage ALL DEPENDS "${LOGOS_CPP_SDK_STAGE_DIR}/include/.staged" )
# Expose an interface target so consumers can include <core/interface.h>
add_library ( logos_cpp_sdk INTERFACE )
add_dependencies ( logos_cpp_sdk logos_cpp_sdk_stage )
target_include_directories ( logos_cpp_sdk INTERFACE "${LOGOS_CPP_SDK_STAGE_DIR}/include" )
ExternalProject_Add ( logos_ep
G I T _ R E P O S I T O R Y h t t p s : / / g i t h u b . c o m / l o g o s - b l o c k c h a i n / l o g o s - b l o c k c h a i n
# Use the repository's default branch (no explicit tag) to avoid invalid refs
U P D A T E _ D I S C O N N E C T E D 1
G I T _ S H A L L O W O F F
G I T _ S U B M O D U L E S " " # ensure submodules are fetched
G I T _ S U B M O D U L E S _ R E C U R S E T R U E
U P D A T E _ C O M M A N D " " # disable auto-update during configure
C O N F I G U R E _ C O M M A N D " " # repo is not a CMake project; skip configure
B U I L D _ C O M M A N D " " # build is driven by cargo in a separate step
I N S T A L L _ C O M M A N D " " # installation handled by custom staging
C M A K E _ A R G S
- D C M A K E _ I N S T A L L _ P R E F I X = $ { L O G O S _ I N S T A L L _ D I R }
- D C M A K E _ B U I L D _ T Y P E = $ < I F : $ < C O N F I G : > , $ { C M A K E _ B U I L D _ T Y P E } , R e l e a s e >
- D B U I L D _ S H A R E D _ L I B S = O N # TODO: keep/adjust depending on project options
I N S T A L L _ D I R $ { L O G O S _ I N S T A L L _ D I R }
)
# --- Extra step: build Rust crate with cargo after download ---
# The crate lives at the repo root and we build package `nomos-c` in release mode.
# Artifacts are expected in <repo>/target/release and headers at <repo>/nomos-c/ (crate root).
ExternalProject_Get_Property ( logos_ep SOURCE_DIR )
2025-12-17 15:38:09 +01:00
# Allow easy adjustments from CLion cache: shared library names and header file name
# Decide extension and default names per platform. Users can still override via cache.
if ( APPLE )
set ( NOMOS_EXT ".dylib" )
set ( NOMOS_BIN_DIR "lib" )
elseif ( WIN32 )
set ( NOMOS_EXT ".dll" )
# On Windows, runtime DLLs typically go to bin, import libs to lib
set ( NOMOS_BIN_DIR "bin" )
else ( )
set ( NOMOS_EXT ".so" )
set ( NOMOS_BIN_DIR "lib" )
endif ( )
2025-12-17 10:55:13 +01:00
# Source (as produced by cargo) and staged (the name we expose to consumers)
2025-12-17 15:38:09 +01:00
# Note: The crate appears to produce liblibnomos on Unix per current setup.
set ( NOMOS_C_SOURCE_DYLIB_NAME "liblibnomos${NOMOS_EXT}" CACHE STRING "Actual shared library filename produced by cargo in target/release" )
set ( NOMOS_C_DYLIB_NAME "libnomos${NOMOS_EXT}" CACHE STRING "Staged shared library filename to expose to consumers" )
2025-12-17 10:55:13 +01:00
set ( NOMOS_C_HEADER_NAME "libnomos.h" CACHE STRING "Header file to stage from nomos-c crate root" )
2025-12-17 15:38:09 +01:00
# Compute effective names that follow current platform extension, even if cache holds a different one
# This avoids stale cache issues when switching platforms or build dirs without clearing cache.
set ( _nomos_ext_regex "\\.(dylib|so|dll)$" )
set ( NOMOS_C_SOURCE_DYLIB_NAME_EFFECTIVE "${NOMOS_C_SOURCE_DYLIB_NAME}" )
set ( NOMOS_C_DYLIB_NAME_EFFECTIVE "${NOMOS_C_DYLIB_NAME}" )
string ( REGEX MATCH ${ _nomos_ext_regex } _src_has_ext "${NOMOS_C_SOURCE_DYLIB_NAME}" )
string ( REGEX MATCH ${ _nomos_ext_regex } _dst_has_ext "${NOMOS_C_DYLIB_NAME}" )
if ( _src_has_ext AND NOT NOMOS_C_SOURCE_DYLIB_NAME MATCHES ".*${NOMOS_EXT}$" )
string ( REGEX REPLACE ${ _nomos_ext_regex } "${NOMOS_EXT}" NOMOS_C_SOURCE_DYLIB_NAME_EFFECTIVE "${NOMOS_C_SOURCE_DYLIB_NAME}" )
message ( STATUS "Adjusting NOMOS_C_SOURCE_DYLIB_NAME to platform extension: ${NOMOS_C_SOURCE_DYLIB_NAME} -> ${NOMOS_C_SOURCE_DYLIB_NAME_EFFECTIVE}" )
endif ( )
if ( _dst_has_ext AND NOT NOMOS_C_DYLIB_NAME MATCHES ".*${NOMOS_EXT}$" )
string ( REGEX REPLACE ${ _nomos_ext_regex } "${NOMOS_EXT}" NOMOS_C_DYLIB_NAME_EFFECTIVE "${NOMOS_C_DYLIB_NAME}" )
message ( STATUS "Adjusting NOMOS_C_DYLIB_NAME to platform extension: ${NOMOS_C_DYLIB_NAME} -> ${NOMOS_C_DYLIB_NAME_EFFECTIVE}" )
endif ( )
set ( NOMOS_STAGED_DYLIB "${LOGOS_INSTALL_DIR}/lib/${NOMOS_C_DYLIB_NAME_EFFECTIVE}" )
2025-12-17 10:55:13 +01:00
set ( NOMOS_STAGED_HEADER "${LOGOS_INSTALL_DIR}/include/${NOMOS_C_HEADER_NAME}" )
# Provide actual rules that produce each staged file independently so the
# build regenerates whichever is missing. Each custom command uses the same
# cargo build step (idempotent if already built) and then copies the needed
# artifact. Declaring them separately ensures CMake will re-run the rule when
# either output is absent.
add_custom_command (
O U T P U T " $ { N O M O S _ S T A G E D _ D Y L I B } "
2025-12-17 15:38:09 +01:00
C O M M A N D $ { C M A K E _ C O M M A N D } - E e c h o " E n s u r i n g $ { N O M O S _ C _ D Y L I B _ N A M E _ E F F E C T I V E } exists ( building nomos-c if needed ) "
2025-12-17 10:55:13 +01:00
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v C A R G O _ T E R M _ C O L O R = a l w a y s c a r g o b u i l d - - r e l e a s e - - p a c k a g e n o m o s - c
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { L O G O S _ I N S T A L L _ D I R } / l i b "
2025-12-17 15:38:09 +01:00
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { L O G O S _ I N S T A L L _ D I R } / b i n "
C O M M A N D $ { C M A K E _ C O M M A N D } - E c o p y " $ { S O U R C E _ D I R } / t a r g e t / r e l e a s e / $ { N O M O S _ C _ S O U R C E _ D Y L I B _ N A M E _ E F F E C T I V E } " " $ { L O G O S _ I N S T A L L _ D I R } / $ { N O M O S _ B I N _ D I R } / $ { N O M O S _ C _ D Y L I B _ N A M E _ E F F E C T I V E } "
2025-12-17 10:55:13 +01:00
D E P E N D S l o g o s _ e p
W O R K I N G _ D I R E C T O R Y $ { S O U R C E _ D I R }
V E R B A T I M
)
add_custom_command (
O U T P U T " $ { N O M O S _ S T A G E D _ H E A D E R } "
C O M M A N D $ { C M A K E _ C O M M A N D } - E e c h o " E n s u r i n g l i b n o m o s . h exists ( building/staging if needed ) "
# Building also ensures any generated headers are up-to-date; harmless if not needed
C O M M A N D $ { C M A K E _ C O M M A N D } - E e n v C A R G O _ T E R M _ C O L O R = a l w a y s c a r g o b u i l d - - r e l e a s e - - p a c k a g e n o m o s - c
C O M M A N D $ { C M A K E _ C O M M A N D } - E m a k e _ d i r e c t o r y " $ { L O G O S _ I N S T A L L _ D I R } / i n c l u d e "
C O M M A N D $ { C M A K E _ C O M M A N D } - E c o p y _ i f _ d i f f e r e n t " $ { S O U R C E _ D I R } / n o m o s - c / $ { N O M O S _ C _ H E A D E R _ N A M E } " " $ { L O G O S _ I N S T A L L _ D I R } / i n c l u d e / "
D E P E N D S l o g o s _ e p
W O R K I N G _ D I R E C T O R Y $ { S O U R C E _ D I R }
V E R B A T I M
)
add_custom_target ( logos_cargo_build ALL
D E P E N D S " $ { N O M O S _ S T A G E D _ D Y L I B } " " $ { N O M O S _ S T A G E D _ H E A D E R } "
)
# Import the staged dynamic library from the cargo build
2025-12-17 15:38:09 +01:00
set ( LOGOS_IMPORTED_LIB "${LOGOS_INSTALL_DIR}/${NOMOS_BIN_DIR}/${NOMOS_C_DYLIB_NAME_EFFECTIVE}" )
add_library ( logos SHARED IMPORTED GLOBAL )
2025-12-17 10:55:13 +01:00
set_target_properties ( logos PROPERTIES
I M P O R T E D _ L O C A T I O N " $ { L O G O S _ I M P O R T E D _ L I B } "
I N T E R F A C E _ I N C L U D E _ D I R E C T O R I E S " $ { L O G O S _ I N S T A L L _ D I R } / i n c l u d e "
)
2025-12-17 15:38:09 +01:00
# On Windows, also set IMPORTED_IMPLIB if present (name assumed nomos.lib)
if ( WIN32 )
# Users can override via cache if different
set ( NOMOS_IMPORT_LIB_NAME "nomos.lib" CACHE STRING "Import library name for Windows" )
set_target_properties ( logos PROPERTIES
I M P O R T E D _ I M P L I B " $ { L O G O S _ I N S T A L L _ D I R } / l i b / $ { N O M O S _ I M P O R T _ L I B _ N A M E } "
)
endif ( )
2025-12-17 10:55:13 +01:00
add_dependencies ( logos logos_cargo_build )
# Link the imported dependency if you plan to use it from this target
target_link_libraries ( blockchainmodulelib PRIVATE logos )
# Make SDK headers available to this target and ensure they are staged before build
target_link_libraries ( blockchainmodulelib PRIVATE logos_cpp_sdk )
add_dependencies ( blockchainmodulelib logos_cpp_sdk_stage )
# Ensure our C++ target waits for the cargo-built artifacts to be staged before linking
add_dependencies ( blockchainmodulelib logos_cargo_build )
# --- Post-build: copy the compiled library to project root ---
add_custom_command ( TARGET blockchainmodulelib POST_BUILD
C O M M A N D $ { C M A K E _ C O M M A N D } - E c o p y _ i f _ d i f f e r e n t
" $ < T A R G E T _ F I L E : b l o c k c h a i n m o d u l e l i b > "
" $ { C M A K E _ S O U R C E _ D I R } / $ < T A R G E T _ F I L E _ N A M E : b l o c k c h a i n m o d u l e l i b > "
C O M M E N T " C o p y i n g $ < T A R G E T _ F I L E _ N A M E : b l o c k c h a i n m o d u l e l i b > t o p r o j e c t r o o t "
V E R B A T I M )
# Optional manual staging template (use if the project doesn't install what you need)
# ExternalProject_Get_Property(logos_ep BINARY_DIR SOURCE_DIR)
# add_custom_target(logos_stage_manual ALL
# COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_INSTALL_DIR}/lib"
# COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_INSTALL_DIR}/include"
# # TODO: copy actual produced dylib from ${BINARY_DIR} to ${LOGOS_INSTALL_DIR}/lib
# # COMMAND ${CMAKE_COMMAND} -E copy "${BINARY_DIR}/path/to/libactual.dylib" "${LOGOS_INSTALL_DIR}/lib/"
# # TODO: copy public headers from ${SOURCE_DIR}/include (or other) to staged include dir
# # COMMAND ${CMAKE_COMMAND} -E copy_directory "${SOURCE_DIR}/include" "${LOGOS_INSTALL_DIR}/include"
# DEPENDS logos_ep
# VERBATIM
# )
# add_dependencies(logos logos_stage_manual)