diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..f3132ed --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,12 @@ +{ + "permissions": { + "allow": [ + "Bash(find:*)", + "Bash(mkdir:*)", + "Bash(cmake:*)", + "Bash(make:*)", + "Bash(cat:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ee40879..e597295 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,5 @@ build_*/** cmake-build*/** .idea puml/** -.vscode/settings.json \ No newline at end of file +.vscode/settings.json +CMakeUserPresets.json \ No newline at end of file diff --git a/ArffFiles.hpp b/ArffFiles.hpp index 1812e96..991fdb4 100644 --- a/ArffFiles.hpp +++ b/ArffFiles.hpp @@ -10,6 +10,8 @@ #include // std::isdigit #include // std::all_of std::transform #include // For file size checking +#include "arffFiles_config.h" + // Summary information structure for ARFF files struct ArffSummary { @@ -63,8 +65,7 @@ struct ArffSummary { * // Thread 2: globalArff.load("file2.arff"); // UNSAFE! */ class ArffFiles { - const std::string VERSION = "1.2.0"; - +private: // Memory usage limits (configurable via environment variables) static constexpr size_t DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 MB static constexpr size_t DEFAULT_MAX_SAMPLES = 1000000; // 1 million samples @@ -103,11 +104,11 @@ public: return *this; } - // Copy constructor (explicitly defaulted) - ArffFiles(const ArffFiles& other) = default; + // Copy constructor (explicitly delete) + ArffFiles(const ArffFiles& other) = delete; - // Copy assignment operator (explicitly defaulted) - ArffFiles& operator=(const ArffFiles& other) = default; + // Copy assignment operator (explicitly deleted) + ArffFiles& operator=(const ArffFiles& other) = delete; // Destructor (explicitly defaulted) ~ArffFiles() = default; @@ -252,7 +253,7 @@ public: } return result; } - std::string version() const { return VERSION; } + std::string version() const { return ARFFLIB_VERSION; } private: // Helper function to validate file path for security diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b34e1b..eaf59a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.1] 2025-07-15 Bug Fixes and Improvements + +### Added + +- Library version from CMake projecto to `ArffFiles.hpp` +- Library `catch2` as a conan test requirement +- Install target for CMake + ## [1.2.0] 2025-06-27 Refactoring and Improvements ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index a036144..eb28b6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.20) project(ArffFiles - VERSION 1.2.0 + VERSION 1.2.1 DESCRIPTION "Library to read Arff Files and return STL vectors with the data read." HOMEPAGE_URL "https://github.com/rmontanana/ArffFiles" LANGUAGES CXX @@ -41,14 +41,60 @@ add_subdirectory(config) # ------- if (ENABLE_TESTING) MESSAGE("Testing enabled") - Include(FetchContent) - FetchContent_Declare(Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.3.2 - ) - FetchContent_MakeAvailable(Catch2) + find_package(Catch2 REQUIRED) include(CTest) add_subdirectory(tests) endif (ENABLE_TESTING) add_library(ArffFiles INTERFACE ArffFiles.hpp) + +target_include_directories(ArffFiles INTERFACE + $ + $ + $ +) +# Install +# ------- +install(TARGETS ArffFiles EXPORT ArffFilesTargets + INCLUDES DESTINATION include +) +install(EXPORT ArffFilesTargets + FILE ArffFilesTargets.cmake + NAMESPACE ArffFiles:: + DESTINATION lib/cmake/ArffFiles +) + +# Install the main header file +install(FILES ArffFiles.hpp + DESTINATION include +) + +# Install the generated configuration header +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/configured_files/include/arffFiles_config.h" + DESTINATION include +) + +# Install documentation files +install(FILES LICENSE README.md + DESTINATION share/doc/ArffFiles +) + +# Create and install package configuration files +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/ArffFilesConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ArffFilesConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/ArffFilesConfig.cmake" + INSTALL_DESTINATION lib/cmake/ArffFiles +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/ArffFilesConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/ArffFilesConfigVersion.cmake" + DESTINATION lib/cmake/ArffFiles +) diff --git a/CMakeLists_conan.txt b/CMakeLists_conan.txt new file mode 100644 index 0000000..40b8a97 --- /dev/null +++ b/CMakeLists_conan.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20) + +project(ArffFiles + VERSION 1.2.1 + DESCRIPTION "Library to read Arff Files and return STL vectors with the data read." + HOMEPAGE_URL "https://github.com/rmontanana/ArffFiles" + LANGUAGES CXX +) + +# Subdirectories +add_subdirectory(config) diff --git a/Makefile b/Makefile index 0547324..64052f2 100644 --- a/Makefile +++ b/Makefile @@ -25,10 +25,12 @@ clean: ## Clean the tests info @echo ">>> Done"; build: ## Build a debug version of the project - @echo ">>> Building Debug ArffFiles..."; - @if [ -d ./$(f_debug) ]; then rm -rf ./$(f_debug); fi + @echo ">>> Building Debug Folding..."; + @if [ -d $(f_debug) ]; then rm -rf $(f_debug); fi @mkdir $(f_debug); - @cmake -S . -B $(f_debug) -D CMAKE_BUILD_TYPE=Debug -D ENABLE_TESTING=ON -D CODE_COVERAGE=ON + conan install . -of $(f_debug) -s build_type=Debug -b missing + cmake -B $(f_debug) -S . -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$(f_debug)/conan_toolchain.cmake -DENABLE_TESTING=ON + cmake --build $(f_debug) -t $(test_targets) $(n_procs) @echo ">>> Done"; opt = "" diff --git a/README.md b/README.md index 39f9968..8e0556d 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,10 @@ A modern C++17 header-only library to read **ARFF (Attribute-Relation File Forma ```bash # Add the package to your conanfile.txt [requires] -arff-files/1.2.0 +arff-files/1.2.1 # Or install directly -conan install arff-files/1.2.0@ +conan install arff-files/1.2.1@ ``` ### Manual Installation diff --git a/cmake/ArffFilesConfig.cmake.in b/cmake/ArffFilesConfig.cmake.in new file mode 100644 index 0000000..19c5aa6 --- /dev/null +++ b/cmake/ArffFilesConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/ArffFilesTargets.cmake") + +check_required_components(ArffFiles) \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index 9dc8829..b158289 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,19 +1,29 @@ import re from conan import ConanFile from conan.tools.files import copy +from conan.tools.cmake import CMakeToolchain, CMakeDeps class ArffFilesConan(ConanFile): name = "arff-files" version = "X.X.X" - description = "Header-only library to read ARFF (Attribute-Relation File Format) files and return STL vectors with the data read." + description = "Header-only library to read ARFF (Attribute-Relation \ + File Format) files and return STL vectors with the data read." url = "https://github.com/rmontanana/ArffFiles" license = "MIT" homepage = "https://github.com/rmontanana/ArffFiles" topics = ("arff", "data-processing", "file-parsing", "header-only", "cpp17") no_copy_source = True - exports_sources = "ArffFiles.hpp", "LICENSE", "README.md" + exports_sources = ( + "ArffFiles.hpp", + "LICENSE", + "README.md", + "CMakeLists.txt", + "config/*", + "cmake/*", + ) package_type = "header-library" + settings = "build_type", "compiler", "arch", "os" def init(self): # Read the CMakeLists.txt file to get the version @@ -26,15 +36,61 @@ class ArffFilesConan(ConanFile): if match: self.version = match.group(1) + def build_requirements(self): + self.tool_requires("cmake/[>=3.15]") + self.test_requires("catch2/3.8.1") + + def layout(self): + # Only use cmake_layout for conan packaging, not for development builds + # This can be detected by checking if we're in a conan cache folder + if ( + hasattr(self, "folders") + and hasattr(self.folders, "base_build") + and self.folders.base_build + and ".conan2" in self.folders.base_build + ): + from conan.tools.cmake import cmake_layout + + cmake_layout(self) + + def generate(self): + # Generate CMake toolchain file + tc = CMakeToolchain(self) + tc.generate() + + # Generate CMake dependencies file (needed for test requirements like catch2) + deps = CMakeDeps(self) + deps.generate() + + def build(self): + # Use CMake to generate the config file through existing config system + from conan.tools.cmake import CMake + + cmake = CMake(self) + # Configure with minimal options - just enough to generate the config file + cmake.configure( + build_script_folder=None, + cli_args=["-DENABLE_TESTING=OFF", "-DCODE_COVERAGE=OFF"], + ) + # No need to build anything, just configure to generate the config file + def package(self): - # Copy header file to include directory + # Copy header file copy( self, - "*.hpp", + "ArffFiles.hpp", src=self.source_folder, dst=self.package_folder, keep_path=False, ) + # Copy the generated config file from CMake build folder + copy( + self, + "arffFiles_config.h", + src=f"{self.build_folder}/configured_files/include", + dst=self.package_folder, + keep_path=False, + ) # Copy license and readme for package documentation copy( self, @@ -50,13 +106,6 @@ class ArffFilesConan(ConanFile): dst=self.package_folder, keep_path=False, ) - copy( - self, - "CMakeLists.txt", - src=self.source_folder, - dst=self.package_folder, - keep_path=False, - ) def package_info(self): # Header-only library configuration diff --git a/config/config.h.in b/config/config.h.in index d6c6362..0646c04 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -1,11 +1,10 @@ #pragma once -#include -#include +#define ARFFLIB_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define ARFFLIB_VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define ARFFLIB_VERSION_PATCH @PROJECT_VERSION_PATCH@ -#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR @ -#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR @ -#define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH @ +#define ARFFLIB_VERSION "@PROJECT_VERSION@" static constexpr std::string_view arffFiles_project_name = "@PROJECT_NAME@"; static constexpr std::string_view arffFiles_project_version = "@PROJECT_VERSION@"; diff --git a/tests/TestArffFiles.cc b/tests/TestArffFiles.cc index 0dbf53a..f2ea907 100644 --- a/tests/TestArffFiles.cc +++ b/tests/TestArffFiles.cc @@ -3,7 +3,6 @@ #include #include #include "ArffFiles.hpp" -#include "arffFiles_config.h" #include class Paths { @@ -28,7 +27,7 @@ public: TEST_CASE("Version Test", "[ArffFiles]") { ArffFiles arff; - REQUIRE(arff.version() == "1.1.0"); + REQUIRE(arff.version() == "1.2.1"); } TEST_CASE("Load Test", "[ArffFiles]") {