From 1328b2d99568b154256ba01a8d4f439b3fd7dc57 Mon Sep 17 00:00:00 2001 From: Alejandro Cabeza Romero Date: Thu, 18 Dec 2025 11:47:59 +0100 Subject: [PATCH] Fix qt compilation. --- CMakeLists.txt | 339 +++++++++++++++++++++++-------------------------- flake.lock | 124 ++++++++++++++++++ flake.nix | 294 ++++++++++++++++++------------------------ justfile | 22 +++- library.cpp | 8 +- library.h | 7 + 6 files changed, 434 insertions(+), 360 deletions(-) create mode 100644 flake.lock diff --git a/CMakeLists.txt b/CMakeLists.txt index 61a588f..6a1e821 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,228 +1,205 @@ cmake_minimum_required(VERSION 3.20) -project(logos-blockchain-module) +project(logos-blockchain-module LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -add_library(blockchainmodulelib SHARED library.cpp) +# ------------------------- +# Options / Inputs +# ------------------------- +option(UNTITLED_USE_QT "Enable Qt6 dependency" ON) +option(COPY_PLUGIN_TO_SOURCE_DIR "Copy built plugin to source dir root (dev convenience)" ON) -# --- 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) +set(LOGOS_CPP_SDK_ROOT "" CACHE PATH "Path to logos-cpp-sdk package root (must contain include/core and include/cpp)") +set(LOGOS_BLOCKCHAIN_ROOT "" CACHE PATH "Path to logos-blockchain source root (read-only in Nix store is OK)") + +if(NOT DEFINED LOGOS_CPP_SDK_ROOT OR LOGOS_CPP_SDK_ROOT STREQUAL "") + message(FATAL_ERROR "LOGOS_CPP_SDK_ROOT not set. Pass -DLOGOS_CPP_SDK_ROOT=/path/to/logos-cpp-sdk") +endif() + +if(NOT DEFINED LOGOS_BLOCKCHAIN_ROOT OR LOGOS_BLOCKCHAIN_ROOT STREQUAL "") + message(FATAL_ERROR "LOGOS_BLOCKCHAIN_ROOT not set. Pass -DLOGOS_BLOCKCHAIN_ROOT=/path/to/logos-blockchain") +endif() + +# ------------------------- +# Qt6 +# ------------------------- if(UNTITLED_USE_QT) - # Auto tools make using Qt headers/classes easier when added later + find_package(Qt6 REQUIRED COMPONENTS Core) 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() +else() + message(FATAL_ERROR "UNTITLED_USE_QT=OFF is not supported for this module (it's a Qt plugin).") 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). +# ------------------------- +# Writable stage of logos-blockchain source +# (Fixes: build.rs/cbindgen writing into source dir inside /nix/store) +# ------------------------- +set(LOGOS_BLOCKCHAIN_WORKDIR "${CMAKE_BINARY_DIR}/logos_blockchain_src") +set(LOGOS_BLOCKCHAIN_STAGE_STAMP "${LOGOS_BLOCKCHAIN_WORKDIR}/.staged") -include(ExternalProject) +add_custom_command( + OUTPUT "${LOGOS_BLOCKCHAIN_STAGE_STAMP}" + COMMAND ${CMAKE_COMMAND} -E echo "Staging logos-blockchain into writable dir: ${LOGOS_BLOCKCHAIN_WORKDIR}" + COMMAND ${CMAKE_COMMAND} -E rm -rf "${LOGOS_BLOCKCHAIN_WORKDIR}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_BLOCKCHAIN_WORKDIR}" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${LOGOS_BLOCKCHAIN_ROOT}" "${LOGOS_BLOCKCHAIN_WORKDIR}" + COMMAND ${CMAKE_COMMAND} -E touch "${LOGOS_BLOCKCHAIN_STAGE_STAMP}" + VERBATIM +) -set(LOGOS_STAGE_DIR "${CMAKE_BINARY_DIR}/logos_stage") -set(LOGOS_INSTALL_DIR "${LOGOS_STAGE_DIR}") +add_custom_target(logos_blockchain_stage ALL + DEPENDS "${LOGOS_BLOCKCHAIN_STAGE_STAMP}" +) -# Ensure staged include/lib directories exist at configure time to avoid -# INTERFACE_INCLUDE_DIRECTORIES pointing to a non-existent path errors +# ------------------------- +# Build nomos-c (Rust) and stage outputs +# ------------------------- +set(LOGOS_STAGE_DIR "${CMAKE_BINARY_DIR}/logos_stage") +set(LOGOS_INSTALL_DIR "${LOGOS_STAGE_DIR}") 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 -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=$,${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 /target/release and headers at /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. +# Platform naming 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") +# What cargo produces and what we stage as +set(NOMOS_C_SOURCE_DYLIB_NAME "liblibnomos${NOMOS_EXT}" CACHE STRING "Shared library filename produced by cargo in target/release") +set(NOMOS_C_STAGED_DYLIB_NAME "libnomos${NOMOS_EXT}" CACHE STRING "Staged shared library filename") +set(NOMOS_C_HEADER_NAME "libnomos.h" CACHE STRING "Header file name (in 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_DYLIB "${LOGOS_INSTALL_DIR}/lib/${NOMOS_C_STAGED_DYLIB_NAME}") 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. +# Build output dir for cargo (writable) +set(CARGO_TARGET_DIR "${CMAKE_BINARY_DIR}/cargo-target") + +# We will patch the SONAME so the plugin depends on "libnomos.so" not "logos_stage/lib/libnomos.so". +find_program(PATCHELF_EXE patchelf) 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 + OUTPUT "${NOMOS_STAGED_DYLIB}" + COMMAND ${CMAKE_COMMAND} -E echo "Building nomos-c (Rust) from writable copy: ${LOGOS_BLOCKCHAIN_WORKDIR}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${CARGO_TARGET_DIR}" + COMMAND ${CMAKE_COMMAND} -E env + CARGO_TERM_COLOR=always + CARGO_TARGET_DIR=${CARGO_TARGET_DIR} + cargo build --release --package nomos-c + COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_INSTALL_DIR}/lib" + COMMAND ${CMAKE_COMMAND} -E copy + "${CARGO_TARGET_DIR}/release/${NOMOS_C_SOURCE_DYLIB_NAME}" + "${NOMOS_STAGED_DYLIB}" + # Patch SONAME (Linux only) so DT_NEEDED becomes "libnomos.so" + COMMAND ${CMAKE_COMMAND} -E echo "Patching SONAME of ${NOMOS_STAGED_DYLIB_NAME}" + COMMAND ${CMAKE_COMMAND} -E env + ${PATCHELF_EXE} --set-soname "${NOMOS_C_STAGED_DYLIB_NAME}" "${NOMOS_STAGED_DYLIB}" + DEPENDS "${LOGOS_BLOCKCHAIN_STAGE_STAMP}" + WORKING_DIRECTORY "${LOGOS_BLOCKCHAIN_WORKDIR}" + 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 + OUTPUT "${NOMOS_STAGED_HEADER}" + COMMAND ${CMAKE_COMMAND} -E echo "Staging ${NOMOS_C_HEADER_NAME} from writable copy" + COMMAND ${CMAKE_COMMAND} -E make_directory "${LOGOS_INSTALL_DIR}/include" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${LOGOS_BLOCKCHAIN_WORKDIR}/nomos-c/${NOMOS_C_HEADER_NAME}" + "${NOMOS_STAGED_HEADER}" + DEPENDS "${NOMOS_STAGED_DYLIB}" + VERBATIM ) add_custom_target(logos_cargo_build ALL - DEPENDS "${NOMOS_STAGED_DYLIB}" "${NOMOS_STAGED_HEADER}" + 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" +add_library(nomos_c SHARED IMPORTED GLOBAL) +set_target_properties(nomos_c PROPERTIES + IMPORTED_LOCATION "${NOMOS_STAGED_DYLIB}" + INTERFACE_INCLUDE_DIRECTORIES "${LOGOS_INSTALL_DIR}/include" +) +add_dependencies(nomos_c logos_cargo_build) + +# ------------------------- +# logos-cpp-sdk headers (viewer-style) +# ------------------------- +add_library(logos_cpp_sdk INTERFACE) +target_include_directories(logos_cpp_sdk INTERFACE + "${LOGOS_CPP_SDK_ROOT}/include/core" + "${LOGOS_CPP_SDK_ROOT}/include/cpp" + "${LOGOS_CPP_SDK_ROOT}/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}" +# ------------------------- +# Qt plugin target +# ------------------------- +set(PLUGIN_TARGET blockchainmodulelib) + +qt_add_plugin(${PLUGIN_TARGET} + CLASS_NAME LogosBlockchainModule +) + +target_sources(${PLUGIN_TARGET} PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/library.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/metadata.json" +) + +target_link_libraries(${PLUGIN_TARGET} PRIVATE + Qt6::Core + nomos_c + logos_cpp_sdk +) + +target_compile_definitions(${PLUGIN_TARGET} PRIVATE USING_QT) + +set_target_properties(${PLUGIN_TARGET} PROPERTIES + AUTOMOC ON + AUTOUIC ON + AUTORCC ON +) + +add_dependencies(${PLUGIN_TARGET} logos_cargo_build logos_blockchain_stage) + +# Runtime: prefer libnomos next to the plugin +if(APPLE) + set_target_properties(${PLUGIN_TARGET} PROPERTIES + BUILD_RPATH "@loader_path" + INSTALL_RPATH "@loader_path" + ) +elseif(UNIX) + set_target_properties(${PLUGIN_TARGET} PROPERTIES + BUILD_RPATH "$ORIGIN" + INSTALL_RPATH "$ORIGIN" ) 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) +# Copy libnomos next to plugin in build output for runtime loading +add_custom_command(TARGET ${PLUGIN_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${NOMOS_STAGED_DYLIB}" + "$/${NOMOS_C_STAGED_DYLIB_NAME}" + COMMENT "Copying ${NOMOS_C_STAGED_DYLIB_NAME} next to plugin for runtime loading" + VERBATIM +) -# 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 - "$" - "${CMAKE_SOURCE_DIR}/$" - COMMENT "Copying $ 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) +# Dev convenience: copy the plugin to repo root +if(COPY_PLUGIN_TO_SOURCE_DIR) + add_custom_command(TARGET ${PLUGIN_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "$" + "${CMAKE_SOURCE_DIR}/$" + COMMENT "Copying plugin to source root" + VERBATIM + ) +endif() diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..81daa1b --- /dev/null +++ b/flake.lock @@ -0,0 +1,124 @@ +{ + "nodes": { + "logos-blockchain": { + "flake": false, + "locked": { + "lastModified": 1766044894, + "narHash": "sha256-q0TmdaWxtIJCj3+Cvyg/gClVW3C+FfknqsRRVYJu8fE=", + "owner": "logos-blockchain", + "repo": "logos-blockchain", + "rev": "4db92033b044b0e4eb3cc1f6ed001078f7106ac1", + "type": "github" + }, + "original": { + "owner": "logos-blockchain", + "repo": "logos-blockchain", + "type": "github" + } + }, + "logos-cpp-sdk": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1765478537, + "narHash": "sha256-MsYbIznSibDaZbf5tOUmw1k53PqXKM8A8ybbKTuAnjo=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "8a69971bc2816992920bebde882ffe12a3eaaf30", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-cpp-sdk_2": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1764699992, + "narHash": "sha256-nCmK9C9F31cHvy6lWKR5WGl99aJbS3kIsROAoZ4OrwI=", + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "rev": "5d0bbd0d1e00aad0532ffa7c8bf2c80f460a4f6d", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-cpp-sdk", + "type": "github" + } + }, + "logos-liblogos": { + "inputs": { + "logos-cpp-sdk": "logos-cpp-sdk_2", + "nixpkgs": [ + "logos-liblogos", + "logos-cpp-sdk", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1764788130, + "narHash": "sha256-ieu55pelIMUO/m7fLXUS3JT6sNBBHva0lNc1GRH2hb0=", + "owner": "logos-co", + "repo": "logos-liblogos", + "rev": "3046aa6ac4392a705b2890adec405d7c9d8d4178", + "type": "github" + }, + "original": { + "owner": "logos-co", + "repo": "logos-liblogos", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1759036355, + "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1759036355, + "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "logos-blockchain": "logos-blockchain", + "logos-cpp-sdk": "logos-cpp-sdk", + "logos-liblogos": "logos-liblogos", + "nixpkgs": [ + "logos-liblogos", + "nixpkgs" + ] + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 2392af5..298832e 100644 --- a/flake.nix +++ b/flake.nix @@ -1,189 +1,143 @@ { - description = "Logos blockchain module - CMake + Qt6 + Rust (flake)"; + description = "Logos blockchain module - Qt6 plugin wrapping nomos-c (Nix)"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; + nixpkgs.follows = "logos-liblogos/nixpkgs"; + logos-liblogos.url = "github:logos-co/logos-liblogos"; + logos-cpp-sdk.url = "github:logos-co/logos-cpp-sdk"; + + logos-blockchain = { + url = "github:logos-blockchain/logos-blockchain"; + flake = false; + }; }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachSystem [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ] (system: - let + outputs = { self, nixpkgs, logos-liblogos, logos-cpp-sdk, logos-blockchain }: + let + systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ]; + forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f { pkgs = import nixpkgs { inherit system; }; - qt = pkgs.qt6; + logosSdk = logos-cpp-sdk.packages.${system}.default; + logosBlockchainSrc = logos-blockchain; + }); + in + { + packages = forAllSystems ({ pkgs, logosSdk, logosBlockchainSrc }: + let + qt = pkgs.qt6; + llvmPkgs = pkgs.llvmPackages; + in + { + default = pkgs.stdenv.mkDerivation { + pname = "logos-blockchain-module"; + version = "dev"; + src = ./.; - # Pin circuits v0.3.1 assets per platform (add more as needed) - circuitsInfo = - if system == "aarch64-darwin" then { - url = "https://github.com/logos-blockchain/logos-blockchain-circuits/releases/download/v0.3.1/nomos-circuits-v0.3.1-macos-aarch64.tar.gz"; - sha256 = "sha256-UfTK/MJOoUY+dvGdspodhZWfZ5c298K6pwoMaQcboHE="; - } else if system == "x86_64-linux" then { - url = "https://github.com/logos-blockchain/logos-blockchain-circuits/releases/download/v0.3.1/nomos-circuits-v0.3.1-linux-x86_64.tar.gz"; - sha256 = "1if58dmly4cvb1lz6dzyg5135vavji91hdayipi6i09w6hdvhyk3"; - } else null; + nativeBuildInputs = [ + pkgs.cmake + pkgs.ninja + pkgs.pkg-config + qt.wrapQtAppsHook + pkgs.patchelf + ]; - circuitsTar = if circuitsInfo != null then pkgs.fetchurl { inherit (circuitsInfo) url sha256; } else null; + buildInputs = [ + qt.qtbase + qt.qttools - # Helper to build the project with a selected CMAKE_BUILD_TYPE - buildProject = buildType: pkgs.stdenv.mkDerivation { - pname = "logos-blockchain-module"; - version = "unstable-${builtins.substring 0 8 self.lastModifiedDate or "dev"}"; - src = ./.; + pkgs.rustc + pkgs.cargo + pkgs.git - # Tools needed at build time - nativeBuildInputs = [ - pkgs.cmake - pkgs.ninja - pkgs.pkg-config - qt.wrapQtAppsHook - pkgs.cacert - pkgs.curl - pkgs.jq - pkgs.unzip - pkgs.gnutar - ]; + llvmPkgs.clang + llvmPkgs.llvm + llvmPkgs.libclang + ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ + pkgs.libiconv + ]; - # Libraries and toolchains required - buildInputs = [ - qt.qtbase - pkgs.rustc - pkgs.cargo - pkgs.git - ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ - pkgs.libiconv - ]; + LOGOS_CPP_SDK_ROOT = "${logosSdk}"; + LOGOS_BLOCKCHAIN_ROOT = "${logosBlockchainSrc}"; - # Ensure network tools (git/curl in cmake ExternalProject) can validate TLS - SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; - GIT_SSL_CAINFO = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + LIBCLANG_PATH = "${llvmPkgs.libclang.lib}/lib"; + CLANG_PATH = "${llvmPkgs.clang}/bin/clang"; - # Ensure CMake can find Qt6 first (inline flags in configurePhase to avoid scope issues) - # Note: We do not reference a sibling attribute here because mkDerivation attrsets - # are not recursive; instead, we expand the flags directly below. + CARGO_HOME = "${"$"}TMPDIR/cargo-home"; - # ExternalProject clones during build; Nix sandboxes usually block network. - # If you use a sandboxed Nix, either disable sandbox for this build - # or vendor/pin those deps as flake inputs and patch CMake to use them. + configurePhase = '' + runHook preConfigure + cmake -S . -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DUNTITLED_USE_QT=ON \ + -DLOGOS_CPP_SDK_ROOT="$LOGOS_CPP_SDK_ROOT" \ + -DLOGOS_BLOCKCHAIN_ROOT="$LOGOS_BLOCKCHAIN_ROOT" \ + -DCOPY_PLUGIN_TO_SOURCE_DIR=OFF + runHook postConfigure + ''; - # The upstream CMakeLists has a post-build step copying the built - # library back to the source tree, which is read-only in Nix. - # Remove that step during the build. - patchPhase = '' - echo "Patching CMakeLists.txt to disable post-build copy to source tree" - # Delete the block starting at the add_custom_command(TARGET ... POST_BUILD) - # and ending before the next blank line or comment trailer - sed -i.bak \ - -e '/add_custom_command(TARGET[[:space:]]\+blockchainmodulelib[[:space:]]\+POST_BUILD/,/VERBATIM)/d' \ - CMakeLists.txt - ''; + buildPhase = '' + runHook preBuild + cmake --build build --verbose + runHook postBuild + ''; - # Use out-of-source build rooted in $NIX_BUILD_TOP for robustness across phases - configurePhase = '' - # Help CMake locate Qt6 provided by Nix - export CMAKE_PREFIX_PATH='${qt.qtbase}' - # Ensure cargo can write its cache in a writable location - export CARGO_HOME="$NIX_BUILD_TOP/cargo-home" - mkdir -p "$CARGO_HOME" - mkdir -p "$NIX_BUILD_TOP/build" - cmake -G Ninja -S . -B "$NIX_BUILD_TOP/build" \ - -DCMAKE_BUILD_TYPE=${buildType} \ - -DUNTITLED_USE_QT=ON - ''; - - buildPhase = '' - # Keep cargo cache writable for ExternalProject-driven cargo builds - export CARGO_HOME="$NIX_BUILD_TOP/cargo-home" - mkdir -p "$CARGO_HOME" - - # Provide NOMOS_CIRCUITS from pinned artifact if not set by caller - if [ -z "$NOMOS_CIRCUITS" ]; then - if [ -n "${circuitsTar}" ]; then - echo "Using pinned circuits archive for system ${system}" - unpackDir="$NIX_BUILD_TOP/circuits-unpack" - mkdir -p "$unpackDir" - # circuitsTar is a fixed-output path in the Nix store; just unpack - tar -xzf "${circuitsTar}" -C "$unpackDir" - circuit_root=$(find "$unpackDir" -mindepth 1 -maxdepth 1 -type d | head -n1) - if [ -z "$circuit_root" ]; then - echo "Could not determine circuits directory inside pinned archive" >&2 - exit 1 - fi - export NOMOS_CIRCUITS="$circuit_root" - echo "NOMOS_CIRCUITS=$NOMOS_CIRCUITS" - else - echo "No pinned circuits for system ${system}. Set NOMOS_CIRCUITS to a local path and rebuild with --impure." >&2 - exit 1 - fi - fi - ninja -C "$NIX_BUILD_TOP/build" blockchainmodulelib - ''; - - installPhase = '' - mkdir -p $out/lib $out/include - # Install the produced shared library - set -e - if ls "$NIX_BUILD_TOP/build"/libblockchainmodulelib.* >/dev/null 2>&1; then - install -m755 "$NIX_BUILD_TOP/build"/libblockchainmodulelib.* $out/lib/ - elif ls "$sourceRoot"/libblockchainmodulelib.* >/dev/null 2>&1; then - install -m755 "$sourceRoot"/libblockchainmodulelib.* $out/lib/ - else - # Fallback: search within source root - found=$(find "$NIX_BUILD_TOP" -maxdepth 3 -name 'libblockchainmodulelib.*' | head -n1) - if [ -n "$found" ]; then - install -m755 "$found" $out/lib/ - else - echo "Error: built library not found" >&2 - exit 1 - fi - fi - - # Optionally expose the module's public header - install -m644 ${./library.h} $out/include/library.h - ''; - - meta = with pkgs.lib; { - description = "Logos blockchain module (Qt6 + Rust)"; - homepage = "https://github.com/logos-co"; - platforms = platforms.all; - # Use a permissive placeholder to avoid unfree gating during builds. - # Adjust to the correct license once finalized. - license = licenses.mit; - maintainers = []; + installPhase = '' + runHook preInstall + mkdir -p $out/lib $out/include + install -m755 build/libblockchainmodulelib.* $out/lib/ + install -m644 ${./library.h} $out/include/library.h + runHook postInstall + ''; }; - }; - in - { - packages = rec { - debug = buildProject "Debug"; - release = buildProject "Release"; - default = release; - }; + } + ); - # Developer shells with all tools available - devShells.default = pkgs.mkShell { - packages = [ - pkgs.cmake - pkgs.ninja - pkgs.pkg-config - pkgs.rustc - pkgs.cargo - pkgs.git - qt.qtbase - ]; - # Help CMake find Qt6 in ad-hoc builds/CLion - CMAKE_PREFIX_PATH = qt.qtbase; - # Expose both Debug and Release convenience commands - shellHook = '' - echo "Dev shell for logos-blockchain-module" - echo "Build (Debug): cmake -B cmake-build-debug -G Ninja -DCMAKE_BUILD_TYPE=Debug -DUNTITLED_USE_QT=ON -DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH . && cmake --build cmake-build-debug --target blockchainmodulelib" - echo "Build (Release): cmake -B cmake-build-release -G Ninja -DCMAKE_BUILD_TYPE=Release -DUNTITLED_USE_QT=ON -DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH . && cmake --build cmake-build-release --target blockchainmodulelib" - ''; - }; - } - ); + devShells = forAllSystems ({ pkgs, logosSdk, logosBlockchainSrc }: + let + qt = pkgs.qt6; + llvmPkgs = pkgs.llvmPackages; + in + { + default = pkgs.mkShell { + nativeBuildInputs = [ + pkgs.cmake + pkgs.ninja + pkgs.pkg-config + pkgs.patchelf + ]; + + buildInputs = [ + qt.qtbase + qt.qttools + + pkgs.rustc + pkgs.cargo + pkgs.git + + llvmPkgs.clang + llvmPkgs.llvm + llvmPkgs.libclang + ]; + + shellHook = '' + export LOGOS_CPP_SDK_ROOT="${logosSdk}" + export LOGOS_BLOCKCHAIN_ROOT="${logosBlockchainSrc}" + + export LIBCLANG_PATH="${llvmPkgs.libclang.lib}/lib" + export CLANG_PATH="${llvmPkgs.clang}/bin/clang" + + echo "Logos Blockchain Module dev environment" + echo "LOGOS_CPP_SDK_ROOT: $LOGOS_CPP_SDK_ROOT" + echo "LOGOS_BLOCKCHAIN_ROOT: $LOGOS_BLOCKCHAIN_ROOT" + echo "LIBCLANG_PATH: $LIBCLANG_PATH" + echo "CLANG_PATH: $CLANG_PATH" + echo "" + echo "Build with:" + echo " just clean" + echo " just build" + ''; + }; + } + ); + }; } diff --git a/justfile b/justfile index cd732de..9c7ad1e 100644 --- a/justfile +++ b/justfile @@ -1,16 +1,28 @@ default: just build -# Configure the build directory (run this once, or whenever CMake config changes) +# One-time (or when CMakeLists.txt changes) configure: - cmake -S . -B build + test -n "${LOGOS_CPP_SDK_ROOT}" || (echo "LOGOS_CPP_SDK_ROOT not set" && exit 1) + test -n "${LOGOS_BLOCKCHAIN_ROOT}" || (echo "LOGOS_BLOCKCHAIN_ROOT not set" && exit 1) + cmake -S . -B build -G Ninja \ + -DUNTITLED_USE_QT=ON \ + -DLOGOS_CPP_SDK_ROOT="${LOGOS_CPP_SDK_ROOT}" \ + -DLOGOS_BLOCKCHAIN_ROOT="${LOGOS_BLOCKCHAIN_ROOT}" \ + -DCOPY_PLUGIN_TO_SOURCE_DIR=ON +# Build only (assumes configure already ran) build: cmake --build build --parallel --target blockchainmodulelib +# Build via Nix nix: - nix build path:./#debug -L + nix build .#default -L + +# Enter dev shell +dev: + nix develop .# clean: - cmake --build build --target clean - rm libblockchainmodulelib.so || true + rm -rf build + rm -f libblockchainmodulelib.so diff --git a/library.cpp b/library.cpp index 188e9d4..4f5165a 100644 --- a/library.cpp +++ b/library.cpp @@ -64,11 +64,11 @@ public: } signals: - // Required for event forwarding between modules - void eventResponse(const QString &eventName, const QVariantList &data) { - - } + // Required for event forwarding between modules + void eventResponse(const QString &eventName, const QVariantList &data); private: NomosNode *node; }; + +#include "library.moc" // Test if this is actually needed diff --git a/library.h b/library.h index 87c0ea0..79679d2 100644 --- a/library.h +++ b/library.h @@ -2,7 +2,14 @@ #define UNTITLED_LIBRARY_H #include + +#ifdef __cplusplus +extern "C" { +#endif #include +#ifdef __cplusplus +} // extern "C" +#endif class LogosBlockchainModuleAPI: public PluginInterface { private: