logos-blockchain-module/CMakeLists.txt
Alejandro Cabeza Romero 7937b0aae0
Handle different OSs.
2025-12-17 15:38:09 +01:00

229 lines
11 KiB
CMake

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
GIT_REPOSITORY https://github.com/logos-co/logos-cpp-sdk
UPDATE_DISCONNECTED 1
GIT_SHALLOW OFF
GIT_SUBMODULES ""
GIT_SUBMODULES_RECURSE TRUE
# The SDK is header-first. We clone it and copy headers to a stable include dir.
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Get_Property(logos_cpp_sdk_ep SOURCE_DIR)
# Stage headers to a predictable location in our build tree.
add_custom_command(
OUTPUT "${LOGOS_CPP_SDK_STAGE_DIR}/include/.staged"
COMMAND ${CMAKE_COMMAND} -E echo "Staging logos-cpp-sdk headers (core -> include/core)"
COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_CPP_SDK_STAGE_DIR}/include/core"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${SOURCE_DIR}/core" "${LOGOS_CPP_SDK_STAGE_DIR}/include/core"
COMMAND ${CMAKE_COMMAND} -E echo "Staging logos-cpp-sdk headers (cpp -> include/cpp)"
COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_CPP_SDK_STAGE_DIR}/include/cpp"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${SOURCE_DIR}/cpp" "${LOGOS_CPP_SDK_STAGE_DIR}/include/cpp"
COMMAND ${CMAKE_COMMAND} -E touch "${LOGOS_CPP_SDK_STAGE_DIR}/include/.staged"
DEPENDS logos_cpp_sdk_ep
VERBATIM
)
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
GIT_REPOSITORY https://github.com/logos-blockchain/logos-blockchain
# Use the repository's default branch (no explicit tag) to avoid invalid refs
UPDATE_DISCONNECTED 1
GIT_SHALLOW OFF
GIT_SUBMODULES "" # ensure submodules are fetched
GIT_SUBMODULES_RECURSE TRUE
UPDATE_COMMAND "" # disable auto-update during configure
CONFIGURE_COMMAND "" # repo is not a CMake project; skip configure
BUILD_COMMAND "" # build is driven by cargo in a separate step
INSTALL_COMMAND "" # installation handled by custom staging
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${LOGOS_INSTALL_DIR}
-DCMAKE_BUILD_TYPE=$<IF:$<CONFIG:>,${CMAKE_BUILD_TYPE},Release>
-DBUILD_SHARED_LIBS=ON # TODO: keep/adjust depending on project options
INSTALL_DIR ${LOGOS_INSTALL_DIR}
)
# --- 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)
# 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()
# Source (as produced by cargo) and staged (the name we expose to consumers)
# 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")
set(NOMOS_C_HEADER_NAME "libnomos.h" CACHE STRING "Header file to stage from nomos-c crate root")
# 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}")
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(
OUTPUT "${NOMOS_STAGED_DYLIB}"
COMMAND ${CMAKE_COMMAND} -E echo "Ensuring ${NOMOS_C_DYLIB_NAME_EFFECTIVE} exists (building nomos-c if needed)"
COMMAND ${CMAKE_COMMAND} -E env CARGO_TERM_COLOR=always cargo build --release --package nomos-c
COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_INSTALL_DIR}/lib"
COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_INSTALL_DIR}/bin"
COMMAND ${CMAKE_COMMAND} -E copy "${SOURCE_DIR}/target/release/${NOMOS_C_SOURCE_DYLIB_NAME_EFFECTIVE}" "${LOGOS_INSTALL_DIR}/${NOMOS_BIN_DIR}/${NOMOS_C_DYLIB_NAME_EFFECTIVE}"
DEPENDS logos_ep
WORKING_DIRECTORY ${SOURCE_DIR}
VERBATIM
)
add_custom_command(
OUTPUT "${NOMOS_STAGED_HEADER}"
COMMAND ${CMAKE_COMMAND} -E echo "Ensuring libnomos.h exists (building/staging if needed)"
# Building also ensures any generated headers are up-to-date; harmless if not needed
COMMAND ${CMAKE_COMMAND} -E env CARGO_TERM_COLOR=always cargo build --release --package nomos-c
COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_INSTALL_DIR}/include"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SOURCE_DIR}/nomos-c/${NOMOS_C_HEADER_NAME}" "${LOGOS_INSTALL_DIR}/include/"
DEPENDS logos_ep
WORKING_DIRECTORY ${SOURCE_DIR}
VERBATIM
)
add_custom_target(logos_cargo_build ALL
DEPENDS "${NOMOS_STAGED_DYLIB}" "${NOMOS_STAGED_HEADER}"
)
# Import the staged dynamic library from the cargo build
set(LOGOS_IMPORTED_LIB "${LOGOS_INSTALL_DIR}/${NOMOS_BIN_DIR}/${NOMOS_C_DYLIB_NAME_EFFECTIVE}")
add_library(logos SHARED IMPORTED GLOBAL)
set_target_properties(logos PROPERTIES
IMPORTED_LOCATION "${LOGOS_IMPORTED_LIB}"
INTERFACE_INCLUDE_DIRECTORIES "${LOGOS_INSTALL_DIR}/include"
)
# 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
IMPORTED_IMPLIB "${LOGOS_INSTALL_DIR}/lib/${NOMOS_IMPORT_LIB_NAME}"
)
endif()
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
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:blockchainmodulelib>"
"${CMAKE_SOURCE_DIR}/$<TARGET_FILE_NAME:blockchainmodulelib>"
COMMENT "Copying $<TARGET_FILE_NAME:blockchainmodulelib> to project root"
VERBATIM)
# 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)