diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3265d37..1eb0f24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,10 +60,15 @@ jobs: run: | mkdir cpp/build cd cpp/build - cmake -G Ninja -S .. -DHDF5_ROOT="$CONDA_PREFIX" - ninja + cmake -G Ninja -S .. -DHDF5_ROOT="$CONDA_PREFIX" -DCMAKE_INSTALL_PREFIX=../install + ninja install cd ../.. just run-cpp + - name: Test cpp example + run: | + cd cpp/example + cmake -B build -S . -DCMAKE_PREFIX_PATH=../install + cmake --build build --config Release - name: Copy LICENSE for deployment run: | cp LICENSE.txt python/LICENSE diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index d58ffcc..fef7d35 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,7 +1,18 @@ +# Copyright (C) 2025 UMCG +# Copyright (C) 2023-2026 University College London +# SPDX-License-Identifier: Apache-2.0 + cmake_minimum_required(VERSION 3.12.0) # older would work, but could give warnings on policy CMP0074 -project(petsird VERSION 0.7.2) +include(GNUInstallDirs) + +project(PETSIRD VERSION 0.9.0 LANGUAGES CXX) +set(PETSIRD_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/PETSIRD-0.9") + +include(CMakePackageConfigHelpers) -set(CMAKE_CXX_STANDARD 17) +# Not required, as this is set in the yardl-generated file +# set(CMAKE_CXX_STANDARD 17) +# set(CMAKE_CXX_STANDARD_REQUIRED ON) if(WIN32) add_compile_options(/W3 /WX) @@ -19,10 +30,57 @@ endif() # sourcesOutputDir: ../cpp/generated/petsird add_subdirectory(generated/petsird) -# create a petsird library target -# Currently it is just empty, but allows creating target properties which are transitive -add_library(petsird) +target_include_directories(petsird_generated + PUBLIC + $ + $ +) + +# petsird_generated is an OBJECT library. Those are a bit hard +# to handle for external projects, so create a "real" library as well. +# This is the one people should use. +add_library(petsird STATIC) target_link_libraries(petsird PUBLIC petsird_generated) -target_include_directories(petsird PUBLIC "${PROJECT_SOURCE_DIR}/generated") add_subdirectory(helpers) + +install(TARGETS petsird petsird_generated petsird_helpers + EXPORT PETSIRDTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +install(EXPORT PETSIRDTargets + NAMESPACE PETSIRD:: + DESTINATION ${PETSIRD_CMAKE_DIR} +) + +install( + DIRECTORY generated/petsird/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/petsird +) + +install( + DIRECTORY helpers/include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + + +configure_package_config_file( + cmake/PETSIRDConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/PETSIRDConfig.cmake + INSTALL_DESTINATION ${PETSIRD_CMAKE_DIR} +) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/PETSIRDConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/PETSIRDConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/PETSIRDConfigVersion.cmake + DESTINATION ${PETSIRD_CMAKE_DIR} +) diff --git a/cpp/README.md b/cpp/README.md index e087aad..52d3cd1 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -1,6 +1,6 @@ -# PETSIRD basic C++ example +# PETSIRD C++ library and example -This directory contains some C++ example code to read/write PETSIRD data. You need to `yardl generate` in the `model` directory first. +This directory builds a library from C++ code to read/write PETSIRD data. You need to `yardl generate` in the `model` directory first. The C++ code shows writing to and reading from an HDF5 file @@ -8,8 +8,9 @@ The C++ code shows writing to and reading from an HDF5 file ```sh mkdir -p build - cmake -G Ninja -S . -B build -DHDF5_ROOT=$CONDA_PREFIX - ninja + cmake -G Ninja -S . -B build -DHDF5_ROOT=$CONDA_PREFIX -DCMAKE_INSTALL_PREFIX=~/install + cd build + ninja install ``` If you did not use `conda` to install HDF5, do not add the `-DHDF5_ROOT=$CONDA_PREFIX` part of the `cmake` line. @@ -20,15 +21,4 @@ The C++ code shows writing to and reading from an HDF5 file ## Using this is a library -Currently, we do not install files yet. You therefore need to do something -like -```cmake -set(PETSIRD_dir ../PETSIRD/cpp/) # or wherever -add_subdirectory(${PETSIRD_dir} PETSIRD) - -# only uses petsird -add_executable(your_executable PUBLIC STIR_PETSIRD_convertor.cpp petsird) - -# also uses helpers -add_library(your_lib PUBLIC petsird_helpers) -``` +See the [example directory](example/README.md) diff --git a/cpp/cmake/PETSIRDConfig.cmake.in b/cpp/cmake/PETSIRDConfig.cmake.in new file mode 100644 index 0000000..6d42169 --- /dev/null +++ b/cpp/cmake/PETSIRDConfig.cmake.in @@ -0,0 +1,33 @@ +# CMake Config file for PETSIRD +# This file defines a few targets, but you should only use the following: +# PETSIRD::petsird : library with basic routines for IO (generated via yardl) +# PETSIRD::helpers : library with extra helper functions (depends on PETSIRD::petsird) +# +# Usage: +# find_package(PETSIRD REQUIRED CONFIG) +# add_executable(mine mine.cpp) +# target_link_libraries(mine PUBLIC PETSIRD::helpers) + +# Copyright (C) 2025 UMCG +# Copyright (C) 2026 University College London +# SPDX-License-Identifier: Apache-2.0 + + +@PACKAGE_INIT@ +include(CMakeFindDependencyMacro) +find_dependency(date) +# We need both xtensor and xtensor-blas +# (the latter doesn't depend on the former, weirdly) +find_dependency(xtensor) +find_dependency(xtensor-blas) +if(@PETSIRD_GENERATED_USE_NDJSON@) + find_dependency(nlohmann_json) +endif() +if(@PETSIRD_GENERATED_USE_HDF5@) + find_dependency(HDF5 COMPONENTS CXX) +endif() +include("${CMAKE_CURRENT_LIST_DIR}/PETSIRDTargets.cmake") +check_required_components(PETSIRD) + +# alias that should be future-proof +add_library(PETSIRD::helpers ALIAS PETSIRD::petsird_helpers) diff --git a/cpp/example/.gitignore b/cpp/example/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/cpp/example/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/cpp/example/CMakeLists.txt b/cpp/example/CMakeLists.txt new file mode 100644 index 0000000..c4dc21c --- /dev/null +++ b/cpp/example/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.12.0) +project(PETSIRDTest VERSION 0.1.0) + +set(CMAKE_CXX_STANDARD 17) +find_package(PETSIRD REQUIRED CONFIG) +add_executable(PETSIRD_test PETSIRD_test.cpp) +target_link_libraries(PETSIRD_test PUBLIC PETSIRD::petsird) +add_executable(PETSIRD_test_helpers PETSIRD_test_helpers.cpp) +target_link_libraries(PETSIRD_test_helpers PUBLIC PETSIRD::helpers) + +# install(TARGETS PETSIRD_test DESTINATION bin) diff --git a/cpp/example/PETSIRD_test.cpp b/cpp/example/PETSIRD_test.cpp new file mode 100644 index 0000000..f12ed2e --- /dev/null +++ b/cpp/example/PETSIRD_test.cpp @@ -0,0 +1,35 @@ +#include +#include "petsird/binary/protocols.h" +using petsird::binary::PETSIRDReader; + +int +main(int argc, char const* argv[]) +{ + auto prog_name = argv[0]; + + std::string filename; + // option processing + while (argc > 1 && (strncmp(argv[1], "-", 1) == 0)) + { + if (strcmp(argv[1], "--input") == 0 || strcmp(argv[1], "-i") == 0) + { + filename = argv[2]; + ++argv; + --argc; + } + else + { + std::cerr << "Wrong options\n"; + return 1; + } + ++argv; + --argc; + } + + // Open the file + PETSIRDReader reader(filename); + petsird::Header header; + reader.ReadHeader(header); + + return 0; +} diff --git a/cpp/example/PETSIRD_test_helpers.cpp b/cpp/example/PETSIRD_test_helpers.cpp new file mode 100644 index 0000000..1f8e28e --- /dev/null +++ b/cpp/example/PETSIRD_test_helpers.cpp @@ -0,0 +1,36 @@ +#include +#include "petsird/binary/protocols.h" +using petsird::binary::PETSIRDReader; +#include "petsird_helpers/create.h" + +int +main(int argc, char const* argv[]) +{ + auto prog_name = argv[0]; + + std::string filename; + // option processing + while (argc > 1 && (strncmp(argv[1], "-", 1) == 0)) + { + if (strcmp(argv[1], "--input") == 0 || strcmp(argv[1], "-i") == 0) + { + filename = argv[2]; + ++argv; + --argc; + } + else + { + std::cerr << "Wrong options\n"; + return 1; + } + ++argv; + --argc; + } + + // Open the file + PETSIRDReader reader(filename); + petsird::Header header; + reader.ReadHeader(header); + + return 0; +} diff --git a/cpp/example/README.md b/cpp/example/README.md new file mode 100644 index 0000000..37a763e --- /dev/null +++ b/cpp/example/README.md @@ -0,0 +1,18 @@ +# PETSIRD basic C++ example using PETSIRD + +This directory contains some CMake/C++ example code on how to use +the PETSIRD library as an "external" user. + +## Usage: + +Assuming you installed PETSIRD in `~/install`, you should be able to +run the following from this directory: +```sh + cmake -B build -S . -DCMAKE_PREFIX_PATH=~/install + cmake --build build --config Release + ``` + +If you have multiple versions of PETSIRD, you can be more specific: +```sh + cmake -B build -S . -DPETSIRD_DIR=~/install/lib/cmake/PETSIRD-0.7 + ``` diff --git a/cpp/helpers/CMakeLists.txt b/cpp/helpers/CMakeLists.txt index 127bcc0..0bbdfb1 100644 --- a/cpp/helpers/CMakeLists.txt +++ b/cpp/helpers/CMakeLists.txt @@ -3,11 +3,23 @@ find_package(xtensor-blas REQUIRED) # create a petsird_helpers library target # Currently it is just empty, but allows creating target properties which are transitive add_library(petsird_helpers INTERFACE) -target_link_libraries(petsird_helpers INTERFACE petsird xtensor-blas) -target_include_directories(petsird_helpers INTERFACE "${PROJECT_SOURCE_DIR}/helpers/include") +# Future change for when we have sources: +# add_library(petsird_helpers ${PETSIRD_HELPERS_SOURCES}) + +target_include_directories(petsird_helpers + INTERFACE + $ + $ +) + +target_link_libraries(petsird_helpers + INTERFACE + petsird + xtensor-blas +) add_executable(petsird_generator petsird_generator.cpp) -target_link_libraries(petsird_generator petsird_helpers) +target_link_libraries(petsird_generator PRIVATE petsird_generated petsird_helpers) add_executable(petsird_analysis petsird_analysis.cpp) -target_link_libraries(petsird_analysis petsird_helpers) +target_link_libraries(petsird_analysis PRIVATE petsird_generated petsird_helpers) diff --git a/environment.yml b/environment.yml index 2e8c2c1..f12938f 100644 --- a/environment.yml +++ b/environment.yml @@ -19,5 +19,5 @@ dependencies: - pre-commit=4.0.1 - python>=3.11.3 - shellcheck>=0.8.0 - - xtensor>=0.24.2 + - xtensor>=0.24.2, < 0.27 - xtensor-blas