From 84c1327148c714ea894a94e0a006ce207a307c9a Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Sun, 17 Dec 2023 10:10:53 +0100 Subject: [PATCH 1/3] Rewrite CMake code. Please consult `README.md`, the migration guide and `test/cmake_integration` for information about what changed. --- .github/workflows/ci.yml | 26 +-- .github/workflows/coverage.yml | 8 +- .github/workflows/version_file.yml | 2 +- CMake/HighFiveConfig.cmake.in | 74 -------- CMake/HighFiveTargetDeps.cmake | 122 ------------ CMake/HighFiveTargetExport.cmake | 48 ----- CMake/config/TestHelpers.cmake | 113 ----------- CMakeLists.txt | 179 ++++++++++-------- README.md | 127 ++++++------- cmake/HighFiveConfig.cmake | 19 ++ cmake/HighFiveOptionalDependencies.cmake | 27 +++ {CMake => cmake}/HighFiveWarnings.cmake | 0 doc/developer_guide.md | 4 +- doc/installation.md | 2 +- include/highfive/H5Version.hpp | 8 +- src/examples/CMakeLists.txt | 127 ++++++++----- tests/cmake_integration/README.md | 22 +++ .../application/CMakeLists.txt | 87 +++++++++ .../application/deps/HighFive | 1 + .../application/hi5_application.cpp | 36 ++++ .../dependent_library/CMakeLists.txt | 134 +++++++++++++ .../cmake/Hi5DependentConfig.cmake.in | 24 +++ .../include/hi5_dependent/read.hpp | 17 ++ .../include/hi5_dependent/write.hpp | 8 + .../src/hi5_dependent/boost.cpp | 17 ++ .../src/hi5_dependent/read_vector.cpp | 7 + .../src/hi5_dependent/write_vector.cpp | 9 + .../test_cmake_integration.sh | 104 ++++++++++ .../test_dependent_library/CMakeList.txt | 22 +++ .../test_dependent_library/CMakeLists.txt | 22 +++ .../test_dependent_library.cpp | 34 ++++ tests/test_dependent_library/CMakeLists.txt | 42 ---- tests/test_dependent_library/deps/.gitignore | 4 - .../include/simpleton.hpp | 14 -- tests/test_dependent_library/src/otherton.cpp | 5 - .../test_dependent_library/src/simpleton.cpp | 9 - tests/test_project/CMakeLists.txt | 25 --- tests/test_project/deps/.gitignore | 4 - .../read_write_vector_dataset.cpp | 1 - tests/test_project_integration.sh | 57 ------ tests/unit/CMakeLists.txt | 12 +- 41 files changed, 860 insertions(+), 743 deletions(-) delete mode 100644 CMake/HighFiveConfig.cmake.in delete mode 100644 CMake/HighFiveTargetDeps.cmake delete mode 100644 CMake/HighFiveTargetExport.cmake delete mode 100644 CMake/config/TestHelpers.cmake create mode 100644 cmake/HighFiveConfig.cmake create mode 100644 cmake/HighFiveOptionalDependencies.cmake rename {CMake => cmake}/HighFiveWarnings.cmake (100%) create mode 100644 tests/cmake_integration/README.md create mode 100644 tests/cmake_integration/application/CMakeLists.txt create mode 120000 tests/cmake_integration/application/deps/HighFive create mode 100644 tests/cmake_integration/application/hi5_application.cpp create mode 100644 tests/cmake_integration/dependent_library/CMakeLists.txt create mode 100644 tests/cmake_integration/dependent_library/cmake/Hi5DependentConfig.cmake.in create mode 100644 tests/cmake_integration/dependent_library/include/hi5_dependent/read.hpp create mode 100644 tests/cmake_integration/dependent_library/include/hi5_dependent/write.hpp create mode 100644 tests/cmake_integration/dependent_library/src/hi5_dependent/boost.cpp create mode 100644 tests/cmake_integration/dependent_library/src/hi5_dependent/read_vector.cpp create mode 100644 tests/cmake_integration/dependent_library/src/hi5_dependent/write_vector.cpp create mode 100644 tests/cmake_integration/test_cmake_integration.sh create mode 100644 tests/cmake_integration/test_dependent_library/CMakeList.txt create mode 100644 tests/cmake_integration/test_dependent_library/CMakeLists.txt create mode 100644 tests/cmake_integration/test_dependent_library/test_dependent_library.cpp delete mode 100644 tests/test_dependent_library/CMakeLists.txt delete mode 100644 tests/test_dependent_library/deps/.gitignore delete mode 100644 tests/test_dependent_library/include/simpleton.hpp delete mode 100644 tests/test_dependent_library/src/otherton.cpp delete mode 100644 tests/test_dependent_library/src/simpleton.cpp delete mode 100644 tests/test_project/CMakeLists.txt delete mode 100644 tests/test_project/deps/.gitignore delete mode 120000 tests/test_project/read_write_vector_dataset.cpp delete mode 100644 tests/test_project_integration.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8730ed410..3460c92fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,22 +41,22 @@ jobs: - config: os: ubuntu-20.04 pkgs: '' - flags: '-DHIGHFIVE_USE_BOOST:Bool=OFF' + flags: '-DHIGHFIVE_TEST_BOOST:Bool=OFF' - config: os: ubuntu-20.04 pkgs: 'libboost-all-dev libopencv-dev' - flags: '-DHIGHFIVE_USE_OPENCV:Bool=ON -GNinja' + flags: '-DHIGHFIVE_TEST_OPENCV:Bool=ON -GNinja' - config: os: ubuntu-latest pkgs: 'libboost-all-dev libeigen3-dev libopencv-dev' - flags: '-DHIGHFIVE_USE_EIGEN:Bool=ON -DHIGHFIVE_USE_OPENCV:Bool=ON -GNinja' + flags: '-DHIGHFIVE_TEST_EIGEN:Bool=ON -DHIGHFIVE_TEST_OPENCV:Bool=ON -GNinja' - config: os: ubuntu-20.04 pkgs: 'libboost-all-dev' flags: '-DCMAKE_CXX_STANDARD=17' - config: os: ubuntu-22.04 - flags: '-DHIGHFIVE_USE_BOOST=Off -DCMAKE_CXX_STANDARD=20' + flags: '-DHIGHFIVE_TEST_BOOST=Off -DCMAKE_CXX_STANDARD=20' steps: - uses: actions/checkout@v3 @@ -195,8 +195,8 @@ jobs: run: | CMAKE_OPTIONS=( -GNinja - -DHIGHFIVE_USE_BOOST:BOOL=ON - -DHIGHFIVE_USE_EIGEN:BOOL=ON + -DHIGHFIVE_TEST_BOOST:BOOL=ON + -DHIGHFIVE_TEST_EIGEN:BOOL=ON -DHIGHFIVE_BUILD_DOCS:BOOL=FALSE -DHIGHFIVE_GLIBCXX_ASSERTIONS=${HIGHFIVE_GLIBCXX_ASSERTIONS:-OFF} -DHIGHFIVE_SANITIZER=${HIGHFIVE_SANITIZER:-OFF} @@ -246,7 +246,7 @@ jobs: sudo apt-get -qq install libhdf5-openmpi-dev - name: "CMake Project Integration" - run: bash tests/test_project_integration.sh + run: bash tests/cmake_integration/test_cmake_integration.sh # Job checking the benchmarks work @@ -291,9 +291,9 @@ jobs: run: | CMAKE_OPTIONS=( -GNinja - -DHIGHFIVE_USE_BOOST:BOOL=ON - -DHIGHFIVE_USE_EIGEN:BOOL=ON - -DHIGHFIVE_USE_XTENSOR:BOOL=ON + -DHIGHFIVE_TEST_BOOST:BOOL=ON + -DHIGHFIVE_TEST_EIGEN:BOOL=ON + -DHIGHFIVE_TEST_XTENSOR:BOOL=ON -DHIGHFIVE_BUILD_DOCS:BOOL=FALSE -DHIGHFIVE_TEST_SINGLE_INCLUDES=ON -DCMAKE_CXX_FLAGS="-coverage -O0" @@ -348,9 +348,9 @@ jobs: -T ${{matrix.vs-toolset}} -DCMAKE_CXX_STANDARD=${{matrix.cxxstd}} -DHIGHFIVE_UNIT_TESTS=ON - -DHIGHFIVE_USE_BOOST:BOOL=ON - -DHIGHFIVE_USE_EIGEN:BOOL=ON - -DHIGHFIVE_USE_XTENSOR:BOOL=ON + -DHIGHFIVE_TEST_BOOST:BOOL=ON + -DHIGHFIVE_TEST_EIGEN:BOOL=ON + -DHIGHFIVE_TEST_XTENSOR:BOOL=ON -DHIGHFIVE_TEST_SINGLE_INCLUDES=ON ) source $GITHUB_WORKSPACE/.github/build.sh diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b3f4a212b..aaf575a7d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -45,10 +45,10 @@ jobs: run: | CMAKE_OPTIONS=( -GNinja - -DHIGHFIVE_USE_BOOST:BOOL=ON - -DHIGHFIVE_USE_EIGEN:BOOL=ON - -DHIGHFIVE_USE_OPENCV:BOOL=ON - #-DHIGHFIVE_USE_XTENSOR:BOOL=ON + -DHIGHFIVE_TEST_BOOST:BOOL=ON + -DHIGHFIVE_TEST_EIGEN:BOOL=ON + -DHIGHFIVE_TEST_OPENCV:BOOL=ON + #-DHIGHFIVE_TEST_XTENSOR:BOOL=ON -DHIGHFIVE_TEST_SINGLE_INCLUDES=ON -DHIGHFIVE_BUILD_DOCS:BOOL=FALSE -DCMAKE_CXX_FLAGS="-coverage -O0" diff --git a/.github/workflows/version_file.yml b/.github/workflows/version_file.yml index 816137e95..56703f593 100644 --- a/.github/workflows/version_file.yml +++ b/.github/workflows/version_file.yml @@ -27,7 +27,7 @@ jobs: - name: Build run: | # Will trigger `configure_file` for H5Version.hpp. - cmake -DHIGHFIVE_USE_BOOST=Off -B build . + cmake -B build . - name: Test run: | diff --git a/CMake/HighFiveConfig.cmake.in b/CMake/HighFiveConfig.cmake.in deleted file mode 100644 index 464a645d0..000000000 --- a/CMake/HighFiveConfig.cmake.in +++ /dev/null @@ -1,74 +0,0 @@ -function(copy_interface_properties target source) - foreach(prop - INTERFACE_COMPILE_DEFINITIONS - INTERFACE_COMPILE_FEATURES - INTERFACE_COMPILE_OPTIONS - INTERFACE_INCLUDE_DIRECTORIES - INTERFACE_LINK_LIBRARIES - INTERFACE_SOURCES - INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) - set_property(TARGET ${target} APPEND PROPERTY ${prop} $) - endforeach() -endfunction() - -if(TARGET HighFive) - return() -endif() - -@PACKAGE_INIT@ - -# Get HighFive targets -include("${CMAKE_CURRENT_LIST_DIR}/HighFiveTargets.cmake") - -# Recreate combined HighFive -add_library(HighFive INTERFACE IMPORTED) -set_property(TARGET HighFive APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS MPI_NO_CPPBIND) # No c++ bindings - -# Ensure we activate required C++ std -if(NOT DEFINED CMAKE_CXX_STANDARD) - if(CMAKE_VERSION VERSION_LESS 3.8) - message(WARNING "HighFive requires minimum C++11. (C++14 for XTensor) \ - You may need to set CMAKE_CXX_STANDARD in you project") - else() - # A client request for a higher std overrides this - target_compile_features(HighFive INTERFACE cxx_std_11) - endif() -endif() - -# If the user sets this flag, all dependencies are preserved. -# Useful in central deployments where dependencies are not prepared later -set(HIGHFIVE_USE_INSTALL_DEPS @HIGHFIVE_USE_INSTALL_DEPS@ CACHE BOOL "Use original Highfive dependencies") -if(HIGHFIVE_USE_INSTALL_DEPS) - # If enabled in the deploy config, request c++14 - if(@HIGHFIVE_USE_XTENSOR@ AND NOT CMAKE_VERSION VERSION_LESS 3.8) - set_property(TARGET HighFive APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_14) - endif() - message(STATUS "HIGHFIVE @PROJECT_VERSION@: Using original dependencies (HIGHFIVE_USE_INSTALL_DEPS=YES)") - copy_interface_properties(HighFive HighFive_HighFive) - return() -endif() - -# When not using the pre-built dependencies, give user options -if(DEFINED HIGHFIVE_USE_BOOST) - set(HIGHFIVE_USE_BOOST ${HIGHFIVE_USE_BOOST} CACHE BOOL "Enable Boost Support") -else() - set(HIGHFIVE_USE_BOOST @HIGHFIVE_USE_BOOST@ CACHE BOOL "Enable Boost Support") -endif() -set(HIGHFIVE_USE_EIGEN "${HIGHFIVE_USE_EIGEN}" CACHE BOOL "Enable Eigen testing") -set(HIGHFIVE_USE_XTENSOR "${HIGHFIVE_USE_XTENSOR}" CACHE BOOL "Enable xtensor testing") -set(HIGHFIVE_PARALLEL_HDF5 @HIGHFIVE_PARALLEL_HDF5@ CACHE BOOL "Enable Parallel HDF5 support") -option(HIGHFIVE_VERBOSE "Enable verbose logging" @HIGHFIVE_VERBOSE@) - -if(HIGHFIVE_USE_XTENSOR AND NOT CMAKE_VERSION VERSION_LESS 3.8) - set_property(TARGET HighFive APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_14) -endif() - -if(NOT HighFive_FIND_QUIETLY) - message(STATUS "HIGHFIVE @PROJECT_VERSION@: (Re)Detecting Highfive dependencies (HIGHFIVE_USE_INSTALL_DEPS=NO)") -endif() -include("${CMAKE_CURRENT_LIST_DIR}/HighFiveTargetDeps.cmake") -foreach(dependency HighFive_libheaders libdeps) - copy_interface_properties(HighFive ${dependency}) -endforeach() - -check_required_components(HighFive) diff --git a/CMake/HighFiveTargetDeps.cmake b/CMake/HighFiveTargetDeps.cmake deleted file mode 100644 index 919b53544..000000000 --- a/CMake/HighFiveTargetDeps.cmake +++ /dev/null @@ -1,122 +0,0 @@ -# Link against target system libs -# ------------------------------- - -if(NOT TARGET libdeps) - - # Independent target to make it possible to have new dependencies each build - add_library(libdeps INTERFACE) - - if(HIGHFIVE_VERBOSE) - target_compile_definitions(libdeps INTERFACE -DHIGHFIVE_LOG_LEVEL=0) - endif() - - if(HIGHFIVE_GLIBCXX_ASSERTIONS) - target_compile_definitions(libdeps INTERFACE -D_GLIBCXX_ASSERTIONS) - endif() - - if(HIGHFIVE_HAS_FRIEND_DECLARATIONS) - target_compile_definitions(libdeps INTERFACE -DHIGHFIVE_HAS_FRIEND_DECLARATIONS=1) - endif() - - if(HIGHFIVE_SANITIZER) - target_compile_options(libdeps INTERFACE -fsanitize=${HIGHFIVE_SANITIZER}) - target_link_options(libdeps INTERFACE -fsanitize=${HIGHFIVE_SANITIZER}) - endif() - - # HDF5 - if(NOT DEFINED HDF5_C_LIBRARIES) - set(HDF5_PREFER_PARALLEL ${HIGHFIVE_PARALLEL_HDF5}) - set(HDF5_USE_STATIC_LIBRARIES ${HIGHFIVE_STATIC_HDF5}) - find_package(HDF5 REQUIRED) - endif() - - if(HIGHFIVE_PARALLEL_HDF5 AND NOT HDF5_IS_PARALLEL) - message(WARNING "Parallel HDF5 requested but libhdf5 doesnt support it") - endif() - - target_include_directories(libdeps SYSTEM INTERFACE ${HDF5_INCLUDE_DIRS}) - target_link_libraries(libdeps INTERFACE ${HDF5_LIBRARIES}) - target_compile_definitions(libdeps INTERFACE ${HDF5_DEFINITIONS}) - target_compile_definitions(libdeps INTERFACE HIGHFIVE_HAS_CONCEPTS=$) - - - # Boost - if(HIGHFIVE_USE_BOOST) - if(NOT DEFINED Boost_NO_BOOST_CMAKE) - # HighFive deactivated finding Boost via Boost's own CMake files - # in Oct 2016 (commit '25627b085'). Likely to appease one cluster. - # Boost's CMake support has since improved and likely this setting - # isn't needed anymore. It is kept for backwards compatibility. - # However, a rework of HighFive's CMake code should consider removing - # this default. Hard coding this to true has been reported to cause - # build failures. - set(Boost_NO_BOOST_CMAKE TRUE) - endif() - find_package(Boost REQUIRED COMPONENTS system serialization) - # Dont use imported targets yet, not avail before cmake 3.5 - target_include_directories(libdeps SYSTEM INTERFACE ${Boost_INCLUDE_DIR}) - target_compile_definitions(libdeps INTERFACE BOOST_ALL_NO_LIB H5_USE_BOOST) - endif() - - # Half - if(HIGHFIVE_USE_HALF_FLOAT) - find_file(FOUND_HALF half.hpp) - if (NOT FOUND_HALF) - message(FATAL_ERROR "Half-precision floating-point support requested but file half.hpp not found") - endif() - target_compile_definitions(libdeps INTERFACE H5_USE_HALF_FLOAT) - endif() - - # Eigen - if(HIGHFIVE_USE_EIGEN) - if (NOT EIGEN3_INCLUDE_DIRS) - find_package(Eigen3 NO_MODULE) - if(Eigen3_FOUND) - message(STATUS "Found Eigen ${Eigen3_VERSION}: ${EIGEN3_INCLUDE_DIRS}") - else() - find_package(PkgConfig) - pkg_check_modules(EIGEN3 REQUIRED eigen3) - endif() - endif() - if (NOT EIGEN3_INCLUDE_DIRS) - message(FATAL_ERROR "Eigen was requested but could not be found") - endif() - target_include_directories(libdeps SYSTEM INTERFACE ${EIGEN3_INCLUDE_DIRS}) - target_compile_definitions(libdeps INTERFACE H5_USE_EIGEN) - endif() - - # xtensor - if(HIGHFIVE_USE_XTENSOR) - if (NOT xtensor_INCLUDE_DIRS) - find_package(xtensor REQUIRED) - endif() - if (NOT xtl_INCLUDE_DIRS) - find_package(xtl REQUIRED) - endif() - target_include_directories(libdeps SYSTEM INTERFACE ${xtensor_INCLUDE_DIRS} ${xtl_INCLUDE_DIRS}) - target_compile_definitions(libdeps INTERFACE H5_USE_XTENSOR) - endif() - - # OpenCV - if(HIGHFIVE_USE_OPENCV) - if (NOT OpenCV_INCLUDE_DIRS) - find_package(OpenCV REQUIRED) - endif() - target_include_directories(libdeps SYSTEM INTERFACE ${OpenCV_INCLUDE_DIRS}) - target_link_libraries(libdeps INTERFACE ${OpenCV_LIBS}) - target_compile_definitions(libdeps INTERFACE H5_USE_OPENCV) - endif() - - # MPI - if(HIGHFIVE_PARALLEL_HDF5 OR HDF5_IS_PARALLEL) - find_package(MPI REQUIRED) - target_include_directories(libdeps SYSTEM INTERFACE ${MPI_CXX_INCLUDE_PATH}) - target_link_libraries(libdeps INTERFACE ${MPI_CXX_LIBRARIES}) - if(CMAKE_VERSION VERSION_LESS 3.13) - target_link_libraries(libdeps INTERFACE ${MPI_CXX_LINK_FLAGS}) - else() - target_link_options(libdeps INTERFACE "SHELL:${MPI_CXX_LINK_FLAGS}") - endif() - endif() - -endif() diff --git a/CMake/HighFiveTargetExport.cmake b/CMake/HighFiveTargetExport.cmake deleted file mode 100644 index 9906f3951..000000000 --- a/CMake/HighFiveTargetExport.cmake +++ /dev/null @@ -1,48 +0,0 @@ - -# Define the HighFive INTERFACE library -add_library(libheaders INTERFACE) - -target_include_directories(libheaders INTERFACE - "$" - "$") - -# Combined HighFive -add_library(HighFive INTERFACE) -target_compile_definitions(HighFive INTERFACE MPI_NO_CPPBIND) # No c++ bindings -target_link_libraries(HighFive INTERFACE libheaders libdeps) - - -# Generate ${PROJECT_NAME}Config.cmake - -include(CMakePackageConfigHelpers) -configure_package_config_file(${CMAKE_CURRENT_LIST_DIR}/HighFiveConfig.cmake.in - ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake - INSTALL_DESTINATION share/${PROJECT_NAME}/CMake) - -write_basic_package_version_file( - ${PROJECT_NAME}ConfigVersion.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion) - -install(FILES - CMake/HighFiveTargetDeps.cmake - ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake - ${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - DESTINATION share/${PROJECT_NAME}/CMake) - - -# Provides IMPORTED targets when using this project from build/install trees. - -# Specify targets to include in the HighFive Exports -install(TARGETS HighFive libheaders libdeps - EXPORT HighFiveTargets) - -# Generate & install the Export for the INSTALL_INTERFACE -install(EXPORT HighFiveTargets - NAMESPACE HighFive_ - FILE HighFiveTargets.cmake - DESTINATION share/${PROJECT_NAME}/CMake) - -# Generate the Export for the BUILD_INTERACE (hardly used) -export(EXPORT HighFiveTargets - FILE "${PROJECT_BINARY_DIR}/HighFiveTargets.cmake") diff --git a/CMake/config/TestHelpers.cmake b/CMake/config/TestHelpers.cmake deleted file mode 100644 index f3ca1cb74..000000000 --- a/CMake/config/TestHelpers.cmake +++ /dev/null @@ -1,113 +0,0 @@ -# TestHelpers.cmake -# -# set of Convenience functions for unit testing with cmake -# -# License: BSD 3 -# -# Copyright (c) 2016, Adrien Devresse -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -## -# enable or disable detection of SLURM and MPIEXEC -option(AUTO_TEST_WITH_SLURM "automatically add srun as test prefix in a SLURM environment" TRUE) -option(AUTO_TEST_WITH_MPIEXEC "automatically add mpiexec as test prefix in a MPICH2/OpenMPI environment" TRUE) - -### -## -## Basic SLURM support -## the prefix "srun" is added to any test in the environment -## For a slurm test execution, simply run "salloc [your_exec_parameters] ctest" -## -## -if(AUTO_TEST_WITH_SLURM) - if(NOT DEFINED SLURM_SRUN_COMMAND) - find_program(SLURM_SRUN_COMMAND - NAMES "srun" - HINTS "${SLURM_ROOT}/bin") - endif() - - if(SLURM_SRUN_COMMAND) - set(TEST_EXEC_PREFIX_DEFAULT "${SLURM_SRUN_COMMAND}") - set(TEST_MPI_EXEC_PREFIX_DEFAULT "${SLURM_SRUN_COMMAND}") - set(TEST_MPI_EXEC_BIN_DEFAULT "${SLURM_SRUN_COMMAND}") - set(TEST_WITH_SLURM ON) - message(STATUS " - AUTO_TEST_WITH_SLURM with slurm cmd ${TEST_EXEC_PREFIX_DEFAULT} ") - message(STATUS " -- set test execution prefix to ${TEST_EXEC_PREFIX_DEFAULT} ") - message(STATUS " -- set MPI test execution prefix to ${TEST_MPI_EXEC_PREFIX_DEFAULT} ") - endif() - -endif() - -### -## Basic MPIExec support, will just forward mpiexec as prefix -## -if(AUTO_TEST_WITH_MPIEXEC AND NOT TEST_WITH_SLURM) - - if(NOT DEFINED MPIEXEC) - find_program(MPIEXEC - NAMES "mpiexec" - HINTS "${MPI_ROOT}/bin") - endif() - - - if(MPIEXEC) - set(TEST_MPI_EXEC_PREFIX_DEFAULT "${MPIEXEC}") - set(TEST_MPI_EXEC_BIN_DEFAULT "${MPIEXEC}") - set(TEST_WITH_MPIEXEC ON) - message(STATUS " - AUTO_TEST_WITH_MPIEXEC cmd ${MPIEXEC} ") - message(STATUS " -- set MPI test execution prefix to ${TEST_MPI_EXEC_PREFIX_DEFAULT} ") - - endif() - -endif() - - - -### -## MPI executor program path without arguments used for testing. -## default: srun or mpiexec if found -## -set(TEST_MPI_EXEC_BIN "${TEST_MPI_EXEC_BIN_DEFAULT}" CACHE STRING "path of the MPI executor (mpiexec, mpirun) for test execution") - - - -### -## Test execution prefix. Override this variable for any execution prefix required in clustered environment -## -## To specify manually a command with argument, e.g -DTEST_EXEC_PREFIX="/var/empty/bin/srun;-n;-4" for a srun execution -## with 4 nodes -## -## default: srun if found -## -set(TEST_EXEC_PREFIX "${TEST_EXEC_PREFIX_DEFAULT}" CACHE STRING "prefix command for the test executions") - - - -### -## Test execution prefix specific for MPI programs. -## -## To specify manually a command with argument, use the cmake list syntax. e.g -DTEST_EXEC_PREFIX="/var/empty/bin/mpiexec;-n;-4" for an MPI execution -## with 4 nodes -## -## default: srun or mpiexec if found -## -set(TEST_MPI_EXEC_PREFIX "${TEST_MPI_EXEC_PREFIX_DEFAULT}" CACHE STRING "prefix command for the MPI test executions") - - - - - - - diff --git a/CMakeLists.txt b/CMakeLists.txt index 694960090..c1446545c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,43 +1,11 @@ -cmake_minimum_required(VERSION 3.1) -if(${CMAKE_VERSION} VERSION_LESS 3.13) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.13) -endif() +cmake_minimum_required(VERSION 3.13) +cmake_policy(VERSION 3.13) -project(HighFive VERSION 2.9.0) +project(HighFive VERSION 3.0.0) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp.in - ${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp) -# INCLUDES -list(APPEND CMAKE_MODULE_PATH - ${CMAKE_CURRENT_SOURCE_DIR}/CMake - ${CMAKE_CURRENT_SOURCE_DIR}/CMake/config) - -# OPTIONS -# Compatibility within Highfive 2.x series -set(USE_BOOST ON CACHE BOOL "Enable Boost Support") -set(USE_EIGEN OFF CACHE BOOL "Enable Eigen testing") -set(USE_XTENSOR OFF CACHE BOOL "Enable xtensor testing") -set(USE_OPENCV OFF CACHE BOOL "Enable OpenCV testing") -mark_as_advanced(USE_BOOST USE_EIGEN USE_XTENSOR) - -set(HIGHFIVE_UNIT_TESTS AUTO CACHE STRING "Enable unit tests (requires Catch2 to be present)") -set_property(CACHE HIGHFIVE_UNIT_TESTS PROPERTY STRINGS AUTO ON OFF) - -option(HIGHFIVE_USE_BOOST "Enable Boost Support" ${USE_BOOST}) -option(HIGHFIVE_USE_HALF_FLOAT "Enable half-precision floats" ${USE_HALF_FLOAT}) -option(HIGHFIVE_USE_EIGEN "Enable Eigen testing" ${USE_EIGEN}) -option(HIGHFIVE_USE_OPENCV "Enable OpenCV testing" ${USE_OPENCV}) -option(HIGHFIVE_USE_XTENSOR "Enable xtensor testing" ${USE_XTENSOR}) -option(HIGHFIVE_EXAMPLES "Compile examples" ON) -option(HIGHFIVE_PARALLEL_HDF5 "Enable Parallel HDF5 support" OFF) -option(HIGHFIVE_STATIC_HDF5 "Staticly link to HDF5 library" OFF) -option(HIGHFIVE_BUILD_DOCS "Enable documentation building" ON) +# Configure HighFive +# ------------------ option(HIGHFIVE_VERBOSE "Set logging level to verbose." OFF) -option(HIGHFIVE_GLIBCXX_ASSERTIONS "Enable bounds check for STL." OFF) -option(HIGHFIVE_HAS_CONCEPTS "Print readable compiler errors w/ C++20 concepts" ON) -option(HIGHFIVE_HAS_WERROR "Convert warnings to errors." OFF) # Controls if HighFive classes are friends of each other. # @@ -66,69 +34,126 @@ option(HIGHFIVE_HAS_WERROR "Convert warnings to errors." OFF) option(HIGHFIVE_HAS_FRIEND_DECLARATIONS "Enable additional friend declarations. Certain compiler require this On, others Off." OFF) mark_as_advanced(HIGHFIVE_HAS_FRIEND_DECLARATIONS) -set(HIGHFIVE_SANITIZER OFF CACHE STRING "Enable a group of sanitizers, requires compiler support. Supported: 'address' and 'undefined'.") -mark_as_advanced(HIGHFIVE_SANITIZER) +option(HIGHFIVE_FIND_HDF5 "Find and link with HDF5." On) + +# Configure Tests & Examples +# -------------------------- + +# Internal variable that controls the default value for building +# optional things like tests, examples and docs. +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(HIGHFIVE_EXTRAS_DEFAULT ON) +else() + set(HIGHFIVE_EXTRAS_DEFAULT OFF) +endif() + +option(HIGHFIVE_UNIT_TESTS "Compile unit-tests" ${HIGHFIVE_EXTRAS_DEFAULT}) +option(HIGHFIVE_EXAMPLES "Compile examples" ${HIGHFIVE_EXTRAS_DEFAULT}) +option(HIGHFIVE_BUILD_DOCS "Build documentation" ${HIGHFIVE_EXTRAS_DEFAULT}) -# In deployments we probably don't want/cant have dynamic dependencies -option(HIGHFIVE_USE_INSTALL_DEPS "End applications by default use detected dependencies here" OFF) -mark_as_advanced(HIGHFIVE_USE_INSTALL_DEPS) +option(HIGHFIVE_TEST_BOOST "Enable Boost testing" OFF) +option(HIGHFIVE_TEST_EIGEN "Enable Eigen testing" OFF) +option(HIGHFIVE_TEST_OPENCV "Enable OpenCV testing" OFF) +option(HIGHFIVE_TEST_XTENSOR "Enable xtensor testing" OFF) +option(HIGHFIVE_TEST_HALF_FLOAT "Enable half-precision floats" OFF) +# TODO remove entirely. +option(HIGHFIVE_HAS_CONCEPTS "Print readable compiler errors w/ C++20 concepts" OFF) + +option(HIGHFIVE_HAS_WERROR "Convert warnings to errors." OFF) +option(HIGHFIVE_GLIBCXX_ASSERTIONS "Enable bounds check for STL." OFF) +# TODO these some magic to get a drop down menu in ccmake +set(HIGHFIVE_SANITIZER OFF CACHE STRING "Enable a group of sanitizers, requires compiler support. Supported: 'address' and 'undefined'.") +mark_as_advanced(HIGHFIVE_SANITIZER) # Check compiler cxx_std requirements # ----------------------------------- -if(CMAKE_CXX_STANDARD EQUAL 98) - message(FATAL_ERROR "HighFive needs to be compiled with at least C++11") -endif() - if(NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 11) + if(HIGHFIVE_TEST_XTENSOR) + set(CMAKE_CXX_STANDARD 14) + else() + set(CMAKE_CXX_STANDARD 11) + endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) endif() -if(HIGHFIVE_USE_XTENSOR AND CMAKE_CXX_STANDARD LESS 14) - set(CMAKE_CXX_STANDARD 14) - set(CMAKE_CXX_STANDARD_REQUIRED ON) +if(CMAKE_CXX_STANDARD EQUAL 98) + message(FATAL_ERROR "HighFive needs to be compiled with at least C++11") +endif() + +if(HIGHFIVE_TEST_XTENSOR AND CMAKE_CXX_STANDARD LESS 14) + message(FATAL_ERROR "XTensor requires C++14 or newer.") endif() add_compile_definitions(HIGHFIVE_CXX_STD=${CMAKE_CXX_STANDARD}) -# Search dependencies (hdf5, boost, eigen, xtensor, mpi) and build target highfive_deps -include(${PROJECT_SOURCE_DIR}/CMake/HighFiveTargetDeps.cmake) +# HighFive +# -------- +add_library(HighFiveInclude INTERFACE) +add_library(HighFive::Include ALIAS HighFiveInclude) +set_target_properties(HighFiveInclude PROPERTIES EXPORT_NAME Include) + +target_include_directories(HighFiveInclude INTERFACE + $ + $ +) + +add_library(HighFive INTERFACE) +add_library(HighFive::HighFive ALIAS HighFive) + +target_link_libraries(HighFive INTERFACE HighFive::Include) + +if(HIGHFIVE_FIND_HDF5) + find_package(HDF5 REQUIRED) + target_link_libraries(HighFive INTERFACE HDF5::HDF5) +endif() + +if(HDF5_IS_PARALLEL) + find_package(MPI REQUIRED) + target_link_libraries(HighFive + INTERFACE + $ + $ + ) +endif() + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp) -# Set-up HighFive to be used in 3rd party project using exports. Create a HighFive target -include(${PROJECT_SOURCE_DIR}/CMake/HighFiveTargetExport.cmake) +# Install +# ------- +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/cmake/HighFiveConfigVersion.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY AnyNewerVersion +) -# Installation of headers (HighFive is only interface) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION "include" PATTERN "*.in" EXCLUDE) +install(TARGETS HighFive HighFiveInclude EXPORT HighFiveTargets) +install(EXPORT HighFiveTargets + FILE HighFiveTargets.cmake + NAMESPACE HighFive:: + DESTINATION lib/cmake/HighFive +) + +install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/HighFiveConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/HighFiveConfigVersion.cmake + DESTINATION lib/cmake/HighFive +) + # Preparing local building (tests, examples) # ------------------------------------------ -# Disable test if Boost was expressly disabled, or if HighFive is a sub-project -if (NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - if(HIGHFIVE_UNIT_TESTS AND NOT HighFive_FIND_QUIETLY) - message(WARNING "Unit tests have been DISABLED.") - endif() - set(HIGHFIVE_UNIT_TESTS FALSE) -endif() - -if(HIGHFIVE_UNIT_TESTS) - if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/deps/catch2/CMakeLists.txt) - add_subdirectory(deps/catch2 EXCLUDE_FROM_ALL) - list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/deps/catch2/contrib) - else() - find_package(Catch2) - if(NOT HIGHFIVE_UNIT_TESTS STREQUAL "AUTO" AND HIGHFIVE_UNIT_TESTS AND NOT Catch2_FOUND) - message(FATAL_ERROR "Please provide a Catch2 installation or clone the submodule") - elseif(NOT Catch2_FOUND) - message(WARNING "No Catch2 installation was found; Disabling unit tests.") - set(HIGHFIVE_UNIT_TESTS OFF) - endif() - endif() +if(HIGHFIVE_EXAMPLES OR HIGHFIVE_UNIT_TESTS) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/HighFiveWarnings.cmake) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/HighFiveOptionalDependencies.cmake) endif() if(HIGHFIVE_EXAMPLES) @@ -136,6 +161,8 @@ if(HIGHFIVE_EXAMPLES) endif() if(HIGHFIVE_UNIT_TESTS) + add_subdirectory(deps/catch2 EXCLUDE_FROM_ALL) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/deps/catch2/contrib) enable_testing() add_subdirectory(tests/unit) endif() diff --git a/README.md b/README.md index 668c90365..0eae323e4 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,11 @@ It integrates nicely with other CMake projects by defining (and exporting) a Hig - etc... (see [ChangeLog](./CHANGELOG.md)) ### Dependencies -- hdf5 (dev) -- hdf5-mpi (optional, opt-in with -D*HIGHFIVE_PARALLEL_HDF5*=ON) -- boost >= 1.41 (recommended, opt-out with -D*HIGHFIVE_USE_BOOST*=OFF) -- eigen3 (optional, opt-in with -D*HIGHFIVE_USE_EIGEN*=ON) -- xtensor (optional, opt-in with -D*HIGHFIVE_USE_XTENSOR*=ON) -- half (optional, opt-in with -D*HIGHFIVE_USE_HALF_FLOAT*=ON) +- HDF5 or pHDF5, including headers +- boost >= 1.41 (recommended) +- eigen3 (optional) +- xtensor (optional) +- half (optional) ### Known flaws - HighFive is not thread-safe. At best it has the same limitations as the HDF5 library. However, HighFive objects modify their members without protecting these writes. Users have reported that HighFive is not thread-safe even when using the threadsafe HDF5 library, e.g., https://github.com/BlueBrain/HighFive/discussions/675. @@ -124,11 +123,11 @@ For several 'standard' use cases the [highfive/H5Easy.hpp](include/highfive/H5Ea - scalars (to/from an extendible DataSet), - strings, - vectors (of standard types), - - [Eigen::Matrix](http://eigen.tuxfamily.org) (optional, enable CMake option `HIGHFIVE_USE_EIGEN`), + - [Eigen::Matrix](http://eigen.tuxfamily.org) (optional), - [xt::xarray](https://github.com/QuantStack/xtensor) and [xt::xtensor](https://github.com/QuantStack/xtensor) - (optional, enable CMake option `HIGHFIVE_USE_XTENSOR`). + (optional). - [cv::Mat_](https://docs.opencv.org/master/df/dfc/classcv_1_1Mat__.html) - (optional, enable CMake option `HIGHFIVE_USE_OPENCV`). + (optional). * Getting in a single line: @@ -150,16 +149,29 @@ int main() { } ``` -whereby the `int` type of this example can be replaced by any of the above types. See [easy_load_dump.cpp](src/examples/easy_load_dump.cpp) for more details. +whereby the `int` type of this example can be replaced by any of the above +types. See [easy_load_dump.cpp](src/examples/easy_load_dump.cpp) for more +details. -**Note:** Classes such as `H5Easy::File` are just short for the regular `HighFive` classes (in this case `HighFive::File`). They can thus be used interchangeably. +**Note:** Classes such as `H5Easy::File` are just short for the regular +`HighFive` classes (in this case `HighFive::File`). They can thus be used +interchangeably. ## CMake integration There's two common paths of integrating HighFive into a CMake based project. The first is to "vendor" HighFive, the second is to install HighFive as a -normal C++ library. Due to how HighFive CMake code works, sometimes following -the third Bailout Approach is needed. +normal C++ library. Since HighFive makes choices about how to integrate HDF5, +sometimes following the third Bailout Approach is needed. + +Regular HDF5 CMake variables can be used. Interesting variables include: + +* `HDF5_USE_STATIC_LIBRARIES` to link statically against the HDF5 library. +* `HDF5_PREFER_PARALLEL` to prefer pHDF5. +* `HDF5_IS_PARALLEL` to check if HDF5 is parallel. + +Please consult `tests/cmake_integration` for examples of how to write libraries +or applications using HighFive. ### Vendoring HighFive @@ -168,86 +180,55 @@ project (typically as a git submodule), for example in `third_party/HighFive`. The projects `CMakeLists.txt` add the following lines ```cmake -add_executable(foo foo.cpp) - -# You might want to turn off Boost support: -if(NOT DEFINED HIGHFIVE_USE_BOOST) - set(HIGHFIVE_USE_BOOST Off) -endif() - -# Include the subdirectory and use the target HighFive. add_subdirectory(third_party/HighFive) target_link_libraries(foo HighFive) ``` **Note:** `add_subdirectory(third_party/HighFive)` will search and "link" HDF5 -and optional dependencies such as Boost. +but wont search or link any optional dependencies such as Boost. ### Regular Installation of HighFive -Alternatively you can install HighFive once and use it in several projects via -`find_package()`. First one should clone the sources: -```bash -git clone --recursive https://github.com/BlueBrain/HighFive.git HighFive-src -``` -By default CMake will install systemwide, which is likely not appropriate. The -instruction below allow users to select a custom path where HighFive will be -installed, e.g. `HIGHFIVE_INSTALL_PREFIX=${HOME}/third_party/HighFive` or some -other location. The CMake invocations would be -```bash -cmake -DHIGHFIVE_EXAMPLES=Off \ - -DHIGHFIVE_USE_BOOST=Off \ - -DHIGHFIVE_UNIT_TESTS=Off \ - -DCMAKE_INSTALL_PREFIX=${HIGHFIVE_INSTALL_PREFIX} \ - -B HighFive-src/build \ - HighFive-src - -cmake --build HighFive-src/build -cmake --install HighFive-src/build -``` -This will install (i.e. copy) the headers to -`${HIGHFIVE_INSTALL_PREFIX}/include` and some CMake files into an appropriate -subfolder of `${HIGHFIVE_INSTALL_PREFIX}`. +Alternatively, HighFive can be install and "found" like regular software. -The projects `CMakeLists.txt` should add the following: +The project's `CMakeLists.txt` should add the following: ```cmake -# ... -add_executable(foo foo.cpp) - find_package(HighFive REQUIRED) target_link_libraries(foo HighFive) ``` -**Note:** If HighFive hasn't been installed in a default location, CMake needs -to be told where to find it which can be done by adding -`-DCMAKE_PREFIX_PATH=${HIGHFIVE_INSTALL_PREFIX}` to the CMake command for -building the project using HighFive. The variable `CMAKE_PREFIX_PATH` is a -semi-colon `;` separated list of directories. - -**Note:** `find_package(HighFive)` will search and "link" HDF5 and optional -dependencies such as Boost. +**Note:** `find_package(HighFive)` will search for HDF5. "Linking" to +`HighFive` includes linking with HDF5. The two commands will not search for or +"link" to optional dependencies such as Boost. -### The Bailout Approach -Since both `add_subdirectory` and `find_package` will trigger finding HDF5 and -other optional dependencies of HighFive as well as the `target_link_libraries` -code for "linking" with the dependencies, things can go wrong. +### Bailout Approach -Fortunately, HighFive is a header only library and all that's needed is the -headers. Preferably, the version obtained by installing HighFive, since those -include `H5Version.hpp`. Let's assume they've been copied to -`third_party/HighFive`. Then one could create a target: +To prevent HighFive from searching or "linking" to HDF5 the project's +`CMakeLists.txt` should contain the following: -```bash -add_library(HighFive INTERFACE) -target_include_directory(HighFive INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/HighFive/include) +```cmake +set(HIGHFIVE_FIND_HDF5 Off) +find_package(HighFive REQUIRED) +# Alternatively: +# add_subdirectory(third_party/HighFive) +target_link_libraries(foo HighFive::Include) +``` +### Optional Dependencies -add_executable(foo foo.cpp) -target_link_libraries(foo HighFive) +HighFive does not attempt to find or "link" to any optional dependencies, such +as Boost, Eigen, etc. Any project using HighFive with any of the optional +dependencies must include the respective header: +``` +#include +#include +``` +and add the required CMake code to find and link against the dependencies. For +Boost the required lines might be +``` +find_package(Boost REQUIRED) +target_link_libraries(foo PUBLIC Boost::headers) ``` - -One known case where this is required is when vendoring the optional -dependencies of HighFive. # Questions? diff --git a/cmake/HighFiveConfig.cmake b/cmake/HighFiveConfig.cmake new file mode 100644 index 000000000..33ce7b7b0 --- /dev/null +++ b/cmake/HighFiveConfig.cmake @@ -0,0 +1,19 @@ +include(CMakeFindDependencyMacro) + +if(NOT DEFINED HIGHFIVE_FIND_HDF5) + set(HIGHFIVE_FIND_HDF5 On) +endif() + +if(HIGHFIVE_FIND_HDF5) + find_dependency(HDF5) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/HighFiveTargets.cmake") + +if(HDF5_IS_PARALLEL) + find_dependency(MPI) + target_link_libraries(HighFive::HighFive INTERFACE MPI::MPI_C MPI::MPI_CXX) +endif() + +add_library(HighFive ALIAS HighFive::HighFive) +add_library(HighFiveInclude ALIAS HighFive::Include) diff --git a/cmake/HighFiveOptionalDependencies.cmake b/cmake/HighFiveOptionalDependencies.cmake new file mode 100644 index 000000000..53d10ecba --- /dev/null +++ b/cmake/HighFiveOptionalDependencies.cmake @@ -0,0 +1,27 @@ +if(HIGHFIVE_TEST_BOOST AND NOT TARGET HighFiveBoostDependency) + add_library(HighFiveBoostDependency INTERFACE) + find_package(Boost REQUIRED) + target_link_libraries(HighFiveBoostDependency INTERFACE Boost::headers) + # TODO check if we need Boost::disable_autolinking to cause: + # -DBOOST_ALL_NO_LIB (does something on MSVC). +endif() + +if(HIGHFIVE_TEST_EIGEN AND NOT TARGET HighFiveEigenDependency) + add_library(HighFiveEigenDependency INTERFACE) + find_package(Eigen3 REQUIRED NO_MODULE) + target_link_libraries(HighFiveEigenDependency INTERFACE Eigen3::Eigen) +endif() + +if(HIGHFIVE_TEST_XTENSOR AND NOT TARGET HighFiveXTensorDependency) + add_library(HighFiveXTensorDependency INTERFACE) + find_package(xtensor REQUIRED) + target_link_libraries(HighFiveXTensorDependency INTERFACE xtensor) +endif() + +if(HIGHFIVE_TEST_OPENCV AND NOT TARGET HighFiveOpenCVDependency) + add_library(HighFiveOpenCVDependency INTERFACE) + find_package(OpenCV REQUIRED) + target_include_directories(HighFiveOpenCVDependency SYSTEM INTERFACE ${OpenCV_INCLUDE_DIRS}) + target_link_libraries(HighFiveOpenCVDependency INTERFACE ${OpenCV_LIBS}) + target_compile_definitions(HighFiveOpenCVDependency INTERFACE H5_USE_OPENCV) +endif() diff --git a/CMake/HighFiveWarnings.cmake b/cmake/HighFiveWarnings.cmake similarity index 100% rename from CMake/HighFiveWarnings.cmake rename to cmake/HighFiveWarnings.cmake diff --git a/doc/developer_guide.md b/doc/developer_guide.md index fc388f3b5..f129ecb1d 100644 --- a/doc/developer_guide.md +++ b/doc/developer_guide.md @@ -23,8 +23,8 @@ cmake --build build --parallel ctest --test-dir build ``` -You might want to turn off Boost `-DHIGHFIVE_USE_BOOST=Off` or turn on other -optional dependencies. +You might want to turn Boost `-DHIGHFIVE_TEST_BOOST=On` or optional +dependencies on. ## Contributing There's numerous HDF5 features that haven't been wrapped yet. HighFive is a diff --git a/doc/installation.md b/doc/installation.md index e9c5b2e6e..3dfb3dc4b 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -211,7 +211,7 @@ this you type Okay, on to configure, compile and install. The CMake commands are - cmake -DCMAKE_INSTALL_PREFIX=build/install -DHIGHFIVE_USE_BOOST=Off -B build . + cmake -DCMAKE_INSTALL_PREFIX=build/install -B build . cmake --build build --parallel cmake --install build diff --git a/include/highfive/H5Version.hpp b/include/highfive/H5Version.hpp index bca2c3a83..4ffb03645 100644 --- a/include/highfive/H5Version.hpp +++ b/include/highfive/H5Version.hpp @@ -8,8 +8,8 @@ */ #pragma once -#define HIGHFIVE_VERSION_MAJOR 2 -#define HIGHFIVE_VERSION_MINOR 9 +#define HIGHFIVE_VERSION_MAJOR 3 +#define HIGHFIVE_VERSION_MINOR 0 #define HIGHFIVE_VERSION_PATCH 0 /** \brief Concatenated representation of the HighFive version. @@ -24,10 +24,10 @@ * std::cout << STRINGIFY_VALUE(HIGHFIVE_VERSION) << "\n"; * \endcode */ -#define HIGHFIVE_VERSION 2.9.0 +#define HIGHFIVE_VERSION 3.0.0 /** \brief String representation of the HighFive version. * * \warning This macro only exists from 2.7.1 onwards. */ -#define HIGHFIVE_VERSION_STRING "2.9.0" +#define HIGHFIVE_VERSION_STRING "3.0.0" diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 8b5f8b0af..ab5700c6a 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -1,51 +1,90 @@ -include(HighFiveWarnings) +set(core_examples + ${CMAKE_CURRENT_SOURCE_DIR}/compound_types.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/create_attribute_string_integer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/create_dataset_double.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/create_datatype.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/create_extensible_dataset.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/create_large_attribute.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/create_page_allocated_files.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/readme_snippet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/read_write_dataset_string.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/read_write_raw_ptr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/read_write_single_scalar.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/read_write_std_strings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/read_write_vector_dataset.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/read_write_vector_dataset_references.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/renaming_objects.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/select_by_id_dataset_cpp11.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/select_partial_dataset_cpp11.cpp +) -function(compile_example example_source) +set(easy_examples + ${CMAKE_CURRENT_SOURCE_DIR}/easy_attribute.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/easy_dumpoptions.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/easy_load_dump.cpp +) + +set(boost_examples + ${CMAKE_CURRENT_SOURCE_DIR}/boost_multi_array_2D.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boost_multiarray_complex.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boost_ublas_double.cpp +) + +set(hl_hdf5_examples + ${CMAKE_CURRENT_SOURCE_DIR}/hl_hdf5_inmemory_files.cpp +) + +set(parallel_hdf5_examples + ${CMAKE_CURRENT_SOURCE_DIR}/parallel_hdf5_collective_io.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/parallel_hdf5_independent_io.cpp +) - get_filename_component(example_filename ${example_source} NAME) - string(REPLACE ".cpp" "_bin" example_name ${example_filename}) - - if(${example_filename} MATCHES ".*eigen.*") - if(NOT HIGHFIVE_USE_EIGEN) - return() - endif() - endif() - - if(${example_filename} MATCHES ".*boost.*") - if(NOT HIGHFIVE_USE_BOOST) - return() - endif() - endif() - - if(${example_filename} MATCHES ".*parallel_hdf5.*") - if(NOT HIGHFIVE_PARALLEL_HDF5) - return() - endif() - endif() - - if(${example_filename} MATCHES ".*half_float.*") - if(NOT HIGHFIVE_USE_HALF_FLOAT) - return() - endif() - endif() - - if(${example_name} MATCHES ".*hl_hdf5.*") - find_package(HDF5 QUIET COMPONENTS HL NAMES HDF5_HL) - if(${HDF5_HL_FOUND}) - message("HDF5 HL: ${HDF5_HL_LIBRARIES}") - add_executable(${example_name} ${example_source}) - target_link_libraries(${example_name} HighFive HighFiveWarnings ${HDF5_HL_LIBRARIES}) - endif() - return() - endif() - - add_executable(${example_name} ${example_source}) - target_link_libraries(${example_name} HighFive HighFiveWarnings) +set(half_float_examples + ${CMAKE_CURRENT_SOURCE_DIR}/create_dataset_half_float.cpp +) +function(compile_example example_source) + get_filename_component(example_filename ${example_source} NAME) + string(REPLACE ".cpp" "_bin" example_name ${example_filename}) + message("example_name: ${example_name}") + + add_executable(${example_name} ${example_source}) + target_link_libraries(${example_name} PUBLIC HighFive HighFiveWarnings) + if(${ARGC} EQUAL 2) + target_link_libraries(${example_name} PUBLIC ${ARGV1}) + endif() endfunction() -file(GLOB list_example "*.cpp") -foreach(example_src ${list_example}) - compile_example(${example_src}) +foreach(example_source ${core_examples}) + compile_example(${example_source}) endforeach() + +foreach(example_source ${easy_examples}) + compile_example(${example_source}) +endforeach() + +if(HIGHFIVE_TEST_BOOST) + foreach(example_source ${boost_examples}) + compile_example(${example_source} HighFiveBoostDependency) + endforeach() +endif() + +if(HDF5_IS_PARALLEL) + foreach(example_source ${parallel_hdf5_examples}) + compile_example(${example_source}) + endforeach() +endif() + +add_library(HighFiveHlHdf5Dependency INTERFACE) +find_package(HDF5 QUIET COMPONENTS HL NAMES HDF5_HL) +if(${HDF5_HL_FOUND}) + message("HDF5 HL: ${HDF5_HL_LIBRARIES}") + target_link_libraries(HighFiveHlHdf5Dependency ${HDF5_HL_LIBRARIES}) + + foreach(example_source ${hl_hdf5_examples}) + compile_examples(${example_source} HighFiveHlHdf5Dependency) + endforeach() +endif() + +# TODO Half-float examples diff --git a/tests/cmake_integration/README.md b/tests/cmake_integration/README.md new file mode 100644 index 000000000..c69df2ced --- /dev/null +++ b/tests/cmake_integration/README.md @@ -0,0 +1,22 @@ +# Examples of CMake Integration. +This folder container examples of projects using CMake to integrate HighFive in +the project. The following examples have been provided: + +* `application` contains an application/executable + that uses HighFive and the optional Boost dependency. + +* `dependent_library` contains a library that uses HighFive in its API. It + consists of a shared and static library; and includes, as an optional + component, a Boost dependency. + +* `test_dependent_library` is an application to test that (or demonstrate how) + `dependent_library` can be consumed easily. + +## Vendoring and Integration Strategy +Note that all examples have been written to pick different vendoring and +integration strategies. This is for testing purposes only. Any real project +would pick a single integration strategy and at most two vendoring strategies. + +## Testing +Run `bash test_cmake_integration.sh` to check if the CMake integration example +are working as expected. diff --git a/tests/cmake_integration/application/CMakeLists.txt b/tests/cmake_integration/application/CMakeLists.txt new file mode 100644 index 000000000..469344e9b --- /dev/null +++ b/tests/cmake_integration/application/CMakeLists.txt @@ -0,0 +1,87 @@ +# This is an example of an application/executable using HighFive. It +# demonstrates the different vendoring strategies and targets provided by +# HighFive. + +cmake_minimum_required(VERSION 3.14) +project(Hi5Application VERSION 0.1) + +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) +endif() + +set(INTEGRATION_STRATEGY "short" CACHE STRING "Use 'Include' for HighFive::Include, 'full' for HighFive::HighFive, 'short' for HighFive.") +set(VENDOR_STRATEGY "submodule" CACHE STRING "Use 'submodule' for Git submodules, 'fetch_content' for FetchContent, 'external' for `find_package`.") +option(USE_STATIC_HDF5 "Link against static HDF5" OFF) +option(USE_BOOST "Simulates an application using Boost" OFF) + +# Controlling HDF5 features is done by directly setting the HDF5 flags. The +# interesting ones are probably: +# * HDF5_USE_STATIC_LIBRARIES +# * HDF5_PREFER_PARALLEL +if(USE_STATIC_HDF5) + set(HDF5_USE_STATIC_LIBRARIES On) +else() + set(HDF5_USE_STATIC_LIBRARIES Off) +endif() + +if(${INTEGRATION_STRATEGY} STREQUAL "bailout") + set(HIGHFIVE_FIND_HDF5 Off) +endif() + +if(${VENDOR_STRATEGY} STREQUAL "submodule") + # When vendoring via a Git submodule, this is the correct + # line to include HighFive. + add_subdirectory("deps/HighFive" EXCLUDE_FROM_ALL) +elseif(${VENDOR_STRATEGY} STREQUAL "fetch_content") + include(FetchContent) + FetchContent_Declare(HighFive + GIT_REPOSITORY $ENV{HIGHFIVE_GIT_REPOSITORY} + GIT_TAG $ENV{HIGHFIVE_GIT_TAG} + ) + FetchContent_MakeAvailable(HighFive) +elseif(${VENDOR_STRATEGY} STREQUAL "external") + # When HighFive is installed like regular software and then "found", do the + # following: + find_package(HighFive REQUIRED) +endif() + +add_executable(Hi5Application "hi5_application.cpp") + +if( ${INTEGRATION_STRATEGY} STREQUAL "Include" + OR ${INTEGRATION_STRATEGY} STREQUAL "bailout") + # Only add `-I${HIGHFIVE_DIR}/include`. + target_link_libraries(Hi5Application PUBLIC HighFive::Include) + + # Now link to HDF5 in whatever fashion you desire. + find_package(HDF5 REQUIRED) + target_link_libraries(Hi5Application PUBLIC HDF5::HDF5) + + # You might need to take care of MPI. + find_package(MPI REQUIRED) + target_link_libraries(Hi5Application PUBLIC MPI::MPI_C MPI::MPI_CXX) +elseif(${INTEGRATION_STRATEGY} STREQUAL "short") + # Highest chance of being backwards compatible with v2. + target_link_libraries(Hi5Application PUBLIC HighFive) +elseif(${INTEGRATION_STRATEGY} STREQUAL "full") + target_link_libraries(Hi5Application PUBLIC HighFive::HighFive) +endif() + +if(USE_BOOST) + find_package(Boost REQUIRED) + target_link_libraries(Hi5Application PUBLIC Boost::headers) + target_compile_definitions(Hi5Application PUBLIC HI5_APPLICATION_HAS_BOOST=1) +endif() + +if(USE_STATIC_HDF5) + find_package(ZLIB REQUIRED) + target_link_libraries(${target} PUBLIC ZLIB::ZLIB) +endif() + +# Install +# ------- +install(TARGETS Hi5Application RUNTIME DESTINATION bin) + +enable_testing() +add_test(NAME test_hi5_application COMMAND ${CMAKE_CURRENT_BINARY_DIR}/Hi5Application) diff --git a/tests/cmake_integration/application/deps/HighFive b/tests/cmake_integration/application/deps/HighFive new file mode 120000 index 000000000..08f081295 --- /dev/null +++ b/tests/cmake_integration/application/deps/HighFive @@ -0,0 +1 @@ +/home/lucg/git/bbp/HighFive/tests/cmake_integration/../.. \ No newline at end of file diff --git a/tests/cmake_integration/application/hi5_application.cpp b/tests/cmake_integration/application/hi5_application.cpp new file mode 100644 index 000000000..dd27260aa --- /dev/null +++ b/tests/cmake_integration/application/hi5_application.cpp @@ -0,0 +1,36 @@ +#include +#if HI5_APPLICATION_HAS_BOOST == 1 +#include +#endif + +int main() { + { + auto file = HighFive::File("foo.h5", HighFive::File::Truncate); + + auto dset = file.createDataSet("foo", std::vector{1.0, 2.0, 3.0}); + auto x = dset.read>(); + + for (size_t i = 0; i < x.size(); i++) { + if (x[i] != double(i + 1)) { + throw std::runtime_error("HighFiveDemo is broken."); + } + } + + std::cout << "Hi5Application: success \n"; + } + +#if HI5_APPLICATION_HAS_BOOST == 1 + { + using matrix_t = boost::numeric::ublas::matrix; + + auto file = HighFive::File("bar.h5", HighFive::File::Truncate); + matrix_t x(3, 5); + auto dset = file.createDataSet("foo", x); + auto y = dset.read(); + + std::cout << "Hi5BoostApplication: success \n"; + } +#endif + + return 0; +} diff --git a/tests/cmake_integration/dependent_library/CMakeLists.txt b/tests/cmake_integration/dependent_library/CMakeLists.txt new file mode 100644 index 000000000..1cdbaf35a --- /dev/null +++ b/tests/cmake_integration/dependent_library/CMakeLists.txt @@ -0,0 +1,134 @@ +# Do NOT document the available components and targets. Guessing CMake targets +# and components is an essential part of the game. This library for example has +# one component called `boost` and three targets. Use +# +# # Without Boost: +# find_package(Hi5Dependent REQUIRED) +# target_link_libraries(foo PUBLIC Hi5Dependent::Read Hi5Dependent::Write) +# +# # With Boost: +# find_package(Hi5Dependent REQUIRED COMPONENTS boost) +# target_link_libraries(foo PUBLIC Hi5Dependent::Read Hi5Dependent::Write) +# target_link_libraries(foo PUBLIC Hi5Dependent::Boost) + +cmake_minimum_required(VERSION 3.14) +project(Hi5Dependent VERSION 0.1) + +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) +endif() + +set(INTEGRATION_STRATEGY "short" CACHE STRING "Use 'Include' for HighFive::Include, 'full' for HighFive::HighFive, 'short' for HighFive.") +option(USE_STATIC_HDF5 "Link against static HDF5" OFF) +option(USE_BOOST "Build '${PROJECT_NAME}' with optional Boost dependency." OFF) + +if(USE_STATIC_HDF5) + set(HDF5_USE_STATIC_LIBRARIES On) +else() + set(HDF5_USE_STATIC_LIBRARIES Off) +endif() + +if(${INTEGRATION_STRATEGY} STREQUAL "bailout") + set(HIGHFIVE_FIND_HDF5 Off) +endif() + +# Since any project depending on 'Hi5Dependent' also needs HighFive, it doesn't +# make sense to vendor HighFive. Therefore, use +find_package(HighFive REQUIRED) + +# For demonstration purposes it consists of a shared and static library +add_library(${PROJECT_NAME}Write SHARED "src/hi5_dependent/write_vector.cpp") +add_library(${PROJECT_NAME}::Write ALIAS ${PROJECT_NAME}Write) +set_target_properties(${PROJECT_NAME}Write PROPERTIES EXPORT_NAME Write) + +add_library(${PROJECT_NAME}Read STATIC "src/hi5_dependent/read_vector.cpp") +add_library(${PROJECT_NAME}::Read ALIAS ${PROJECT_NAME}Read) +set_target_properties(${PROJECT_NAME}Read PROPERTIES EXPORT_NAME Read) + +set(Hi5DependentCoreTargets ${PROJECT_NAME}Write ${PROJECT_NAME}Read) +set(Hi5DependentAllTargets ${Hi5DependentCoreTargets}) + +# ... and two more for demonstrating an optional dependency (on Boost). +if(USE_BOOST) + add_library(${PROJECT_NAME}Boost SHARED "src/hi5_dependent/boost.cpp") + add_library(${PROJECT_NAME}::Boost ALIAS ${PROJECT_NAME}Boost) + set_target_properties(${PROJECT_NAME}Boost PROPERTIES EXPORT_NAME Boost) + + find_package(Boost REQUIRED) + target_link_libraries(${PROJECT_NAME}Boost PUBLIC Boost::headers) + target_compile_definitions(${PROJECT_NAME}Boost PUBLIC HI5_DEPENDENT_HAS_BOOST=1) + + list(APPEND Hi5DependentAllTargets ${PROJECT_NAME}Boost) +endif() + +foreach(target IN LISTS Hi5DependentAllTargets) + target_include_directories(${target} + PUBLIC $ + PUBLIC $ + ) + + # Remember to pick one. Writing out all variation serves testing and + # demonstration purposes only. Minimizing lines of code is probably a good + # strategy. + if( ${INTEGRATION_STRATEGY} STREQUAL "Include" + OR ${INTEGRATION_STRATEGY} STREQUAL "bailout") + target_link_libraries(${target} PUBLIC HighFive::Include) + + find_package(HDF5 REQUIRED) + target_link_libraries(${target} PUBLIC HDF5::HDF5) + + find_package(MPI REQUIRED) + target_link_libraries(${target} PUBLIC MPI::MPI_C MPI::MPI_CXX) + elseif(${INTEGRATION_STRATEGY} STREQUAL "short") + target_link_libraries(${target} PUBLIC HighFive) + elseif(${INTEGRATION_STRATEGY} STREQUAL "full") + target_link_libraries(${target} PUBLIC HighFive::HighFive) + endif() + + if(USE_STATIC_HDF5) + find_package(ZLIB REQUIRED) + target_link_libraries(${target} PUBLIC ZLIB::ZLIB) + endif() +endforeach() + +# Install +# ------- +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY AnyNewerVersion +) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ + DESTINATION "include") + +install(TARGETS ${PROJECT_NAME}Read ${PROJECT_NAME}Write EXPORT ${PROJECT_NAME}Targets) +install(EXPORT ${PROJECT_NAME}Targets + FILE ${PROJECT_NAME}Targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION cmake +) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake + @ONLY +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION cmake +) + +if(USE_BOOST) + install(TARGETS ${PROJECT_NAME}Boost EXPORT ${PROJECT_NAME}BoostTargets) + install(EXPORT ${PROJECT_NAME}BoostTargets + FILE ${PROJECT_NAME}BoostTargets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION cmake + ) +endif() diff --git a/tests/cmake_integration/dependent_library/cmake/Hi5DependentConfig.cmake.in b/tests/cmake_integration/dependent_library/cmake/Hi5DependentConfig.cmake.in new file mode 100644 index 000000000..b5df933b9 --- /dev/null +++ b/tests/cmake_integration/dependent_library/cmake/Hi5DependentConfig.cmake.in @@ -0,0 +1,24 @@ +include(CMakeFindDependencyMacro) + +find_dependency(HighFive) + +set(Hi5Dependent_INTEGRATION_STRATEGY @INTEGRATION_STRATEGY@) +if( ${Hi5Dependent_INTEGRATION_STRATEGY} STREQUAL "Include" + OR ${Hi5Dependent_INTEGRATION_STRATEGY} STREQUAL "bailout") + # Remember to 'find' any dependencies you introduce, including HDF5 if you + # use additional COMPONENTS; or MPI if you unconditionally use it. + find_dependency(MPI) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/Hi5DependentTargets.cmake") + +if(boost IN_LIST Hi5Dependent_FIND_COMPONENTS) + set(Hi5Dependent_USE_BOOST @USE_BOOST@) + + if(NOT Hi5Dependent_USE_BOOST) + message(FATAL_ERROR "Library was built without the component: boost") + endif() + + find_dependency(Boost) + include("${CMAKE_CURRENT_LIST_DIR}/Hi5DependentBoostTargets.cmake") +endif() diff --git a/tests/cmake_integration/dependent_library/include/hi5_dependent/read.hpp b/tests/cmake_integration/dependent_library/include/hi5_dependent/read.hpp new file mode 100644 index 000000000..7550efc8a --- /dev/null +++ b/tests/cmake_integration/dependent_library/include/hi5_dependent/read.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#if HI5_DEPENDENT_HAS_BOOST == 1 +#include +#endif + +namespace hi5_dependent { +std::vector read_vector(const HighFive::DataSet& dset); + +#if HI5_DEPENDENT_HAS_BOOST == 1 +boost::numeric::ublas::matrix read_boost(const HighFive::DataSet& dset); +HighFive::DataSet write_boost(HighFive::File& file, const boost::numeric::ublas::matrix& x); +#endif +} // namespace hi5_dependent diff --git a/tests/cmake_integration/dependent_library/include/hi5_dependent/write.hpp b/tests/cmake_integration/dependent_library/include/hi5_dependent/write.hpp new file mode 100644 index 000000000..469b378bf --- /dev/null +++ b/tests/cmake_integration/dependent_library/include/hi5_dependent/write.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +namespace hi5_dependent { +HighFive::DataSet write_vector(HighFive::File& file, const std::vector& x); +} diff --git a/tests/cmake_integration/dependent_library/src/hi5_dependent/boost.cpp b/tests/cmake_integration/dependent_library/src/hi5_dependent/boost.cpp new file mode 100644 index 000000000..dc5f6909a --- /dev/null +++ b/tests/cmake_integration/dependent_library/src/hi5_dependent/boost.cpp @@ -0,0 +1,17 @@ +#include +#include + +#include + +namespace hi5_dependent { + +boost::numeric::ublas::matrix read_boost(const HighFive::DataSet& dset) { + return dset.read>(); +} + +HighFive::DataSet write_boost(HighFive::File& file, + const boost::numeric::ublas::matrix& x) { + return file.createDataSet("foo", x); +} + +} // namespace hi5_dependent diff --git a/tests/cmake_integration/dependent_library/src/hi5_dependent/read_vector.cpp b/tests/cmake_integration/dependent_library/src/hi5_dependent/read_vector.cpp new file mode 100644 index 000000000..e7e6d973f --- /dev/null +++ b/tests/cmake_integration/dependent_library/src/hi5_dependent/read_vector.cpp @@ -0,0 +1,7 @@ +#include + +namespace hi5_dependent { +std::vector read_vector(const HighFive::DataSet& dset) { + return dset.read>(); +} +} // namespace hi5_dependent diff --git a/tests/cmake_integration/dependent_library/src/hi5_dependent/write_vector.cpp b/tests/cmake_integration/dependent_library/src/hi5_dependent/write_vector.cpp new file mode 100644 index 000000000..595cd9678 --- /dev/null +++ b/tests/cmake_integration/dependent_library/src/hi5_dependent/write_vector.cpp @@ -0,0 +1,9 @@ +#include + +namespace hi5_dependent { + +HighFive::DataSet write_vector(HighFive::File& file, const std::vector& x) { + return file.createDataSet("foo", x); +} + +} // namespace hi5_dependent diff --git a/tests/cmake_integration/test_cmake_integration.sh b/tests/cmake_integration/test_cmake_integration.sh new file mode 100644 index 000000000..cf80fbfdd --- /dev/null +++ b/tests/cmake_integration/test_cmake_integration.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -xeuo pipefail +cd "$( dirname "${BASH_SOURCE[0]}")" # cd here + +# All output should be within this directory. +TMP_DIR="${PWD}/tmp" + +# Root of the cmake integration tests. +TEST_DIR="${PWD}" + +# Path of the sources, build and install directory of HighFive. +HIGHFIVE_DIR="${TEST_DIR}/../.." +HIGHFIVE_BUILD_DIR="${TMP_DIR}/build-highfive" +HIGHFIVE_INSTALL_DIR="${HIGHFIVE_BUILD_DIR}/install" + +export HIGHFIVE_GIT_REPOSITORY="file://$(realpath "$HIGHFIVE_DIR")" +export HIGHFIVE_GIT_TAG=$(git rev-parse HEAD) + +test_dependent_library() { + local project="dependent_library" + local project_dir="${TEST_DIR}/${project}" + + for use_boost in On Off + do + local build_dir="${TMP_DIR}/build" + local install_dir="${TMP_DIR}/build/install" + + rm -rf ${build_dir} || true + + cmake "$@" \ + -DUSE_BOOST=${use_boost} \ + -DCMAKE_PREFIX_PATH="${HIGHFIVE_INSTALL_DIR}" \ + -DCMAKE_INSTALL_PREFIX="${install_dir}" \ + -B "${build_dir}" "${project_dir}" + + cmake --build "${build_dir}" --verbose --target install + + local test_project="test_dependent_library" + local test_build_dir="${TMP_DIR}/test_build" + local test_install_dir="${TMP_DIR}/test_build/install" + + rm -rf ${test_build_dir} || true + + cmake -DUSE_BOOST=${use_boost} \ + -DCMAKE_PREFIX_PATH="${HIGHFIVE_INSTALL_DIR};${install_dir}" \ + -DCMAKE_INSTALL_PREFIX="${test_install_dir}" \ + -B "${test_build_dir}" "${test_project}" + + cmake --build "${test_build_dir}" --verbose + ctest --test-dir "${test_build_dir}" --verbose + + done +} + +test_application() { + local project="application" + local project_dir="${TEST_DIR}/${project}" + local dep_dir="${TEST_DIR}/${project}/deps/HighFive" + + rm "${dep_dir}" || true + ln -sf "${HIGHFIVE_DIR}" "${dep_dir}" + + echo ${HIGHFIVE_DIR} + echo ${dep_dir} + + for vendor in submodule fetch_content external + do + for use_boost in On Off + do + local build_dir="${TMP_DIR}/build" + local install_dir="${TMP_DIR}/build/install" + + rm -rf ${build_dir} || true + + cmake "$@" \ + -DUSE_BOOST=${use_boost} \ + -DVENDOR_STRATEGY=${vendor} \ + -DCMAKE_PREFIX_PATH="${HIGHFIVE_INSTALL_DIR}" \ + -DCMAKE_INSTALL_PREFIX="${install_dir}" \ + -B "${build_dir}" "${project_dir}" + + cmake --build "${build_dir}" --verbose --target install + ctest --test-dir "${build_dir}" + "${install_dir}"/bin/Hi5Application + done + done +} + +cmake -DHIGHFIVE_EXAMPLES=OFF \ + -DHIGHFIVE_UNIT_TESTS=OFF \ + -DCMAKE_INSTALL_PREFIX="${HIGHFIVE_INSTALL_DIR}" \ + -B "${HIGHFIVE_BUILD_DIR}" \ + "${HIGHFIVE_DIR}" + +cmake --build "${HIGHFIVE_BUILD_DIR}" --target install + +for integration in Include full short bailout +do + test_dependent_library \ + -DINTEGRATION_STRATEGY=${integration} + + test_application \ + -DINTEGRATION_STRATEGY=${integration} +done diff --git a/tests/cmake_integration/test_dependent_library/CMakeList.txt b/tests/cmake_integration/test_dependent_library/CMakeList.txt new file mode 100644 index 000000000..b8b7cb021 --- /dev/null +++ b/tests/cmake_integration/test_dependent_library/CMakeList.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.14) +project(TestHi5Dependent VERSION 0.1) + +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) +endif() + +add_executable(test_hi5_dependent test_dependent_library.cpp) + +if(NOT USE_BOOST) + find_package(Hi5Dependent REQUIRED) +else() + find_package(Hi5Dependent REQUIRED COMPONENTS boost) + target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Boost) +endif() + +target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Read Hi5Dependent::Write) + +enable_testing() +add_test(NAME test_hi5_dependent COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_hi5_dependent) diff --git a/tests/cmake_integration/test_dependent_library/CMakeLists.txt b/tests/cmake_integration/test_dependent_library/CMakeLists.txt new file mode 100644 index 000000000..b6c7f3375 --- /dev/null +++ b/tests/cmake_integration/test_dependent_library/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.14) +project(TestHi5Dependent VERSION 0.1) + +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) +endif() + +add_executable(test_hi5_dependent test_dependent_library.cpp) + +if(NOT USE_BOOST) + find_package(Hi5Dependent REQUIRED) + target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Read Hi5Dependent::Write) +else() + find_package(Hi5Dependent REQUIRED COMPONENTS boost) + target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Read Hi5Dependent::Write) + target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Boost) +endif() + +enable_testing() +add_test(NAME run_test_hi5_dependent COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_hi5_dependent) diff --git a/tests/cmake_integration/test_dependent_library/test_dependent_library.cpp b/tests/cmake_integration/test_dependent_library/test_dependent_library.cpp new file mode 100644 index 000000000..40aef20a6 --- /dev/null +++ b/tests/cmake_integration/test_dependent_library/test_dependent_library.cpp @@ -0,0 +1,34 @@ +#include +#include + + +int main() { + { + auto file = HighFive::File("foo.h5", HighFive::File::Truncate); + + auto dset = hi5_dependent::write_vector(file, {1.0, 2.0, 3.0}); + auto x = hi5_dependent::read_vector(dset); + + for (size_t i = 0; i < x.size(); i++) { + if (x[i] != double(i + 1)) { + throw std::runtime_error("HighFiveDemo is broken."); + } + } + + std::cout << "Hi5Dependent: success \n"; + } + +#if HI5_DEPENDENT_HAS_BOOST == 1 + { + auto file = HighFive::File("bar.h5", HighFive::File::Truncate); + + boost::numeric::ublas::matrix x(3, 5); + auto dset = hi5_dependent::write_boost(file, x); + auto y = hi5_dependent::read_boost(dset); + + std::cout << "Hi5BoostDependent: success \n"; + } +#endif + + return 0; +} diff --git a/tests/test_dependent_library/CMakeLists.txt b/tests/test_dependent_library/CMakeLists.txt deleted file mode 100644 index 570dba224..000000000 --- a/tests/test_dependent_library/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -# This is a sample library to test integration via add_subdirectory and CMakeConfig -cmake_minimum_required(VERSION 3.1) - -project(test_project VERSION 0.1) - -if(NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") # For come compilers under cmake 3.1 - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) -endif() - -option(USE_BUNDLED_HIGHFIVE "Use highfive from deps folder. Otherwise must be installed" ON) - -if(USE_BUNDLED_HIGHFIVE) - add_subdirectory("deps/HighFive" EXCLUDE_FROM_ALL) -else() - find_package(HighFive REQUIRED QUIET) -endif() - -add_library(simpleton SHARED "src/simpleton.cpp" "src/otherton.cpp") -target_include_directories(simpleton - PUBLIC - $ - $) -target_link_libraries(simpleton PUBLIC HighFive) -set_property(TARGET simpleton PROPERTY POSITION_INDEPENDENT_CODE ON) - -add_library(otherton STATIC "src/simpleton.cpp" "src/otherton.cpp") -target_include_directories(otherton - PUBLIC - $ - $) -target_link_libraries(otherton PUBLIC HighFive) -set_property(TARGET otherton PROPERTY POSITION_INDEPENDENT_CODE OFF) - -install( - TARGETS simpleton otherton - EXPORT simpletonTarget - DESTINATION lib - ARCHIVE DESTINATION lib) -install(EXPORT simpletonTarget DESTINATION lib) diff --git a/tests/test_dependent_library/deps/.gitignore b/tests/test_dependent_library/deps/.gitignore deleted file mode 100644 index 5e7d2734c..000000000 --- a/tests/test_dependent_library/deps/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/tests/test_dependent_library/include/simpleton.hpp b/tests/test_dependent_library/include/simpleton.hpp deleted file mode 100644 index b98a09fda..000000000 --- a/tests/test_dependent_library/include/simpleton.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef H5_TEST_SIMPLETON_HPP -#define H5_TEST_SIMPLETON_HPP - -// Include all headers here to catch any missing `inline` statements, since -// they will be included by two different compilation units. -#include - -// Boost should always be found in this setup -#include - -void function(const HighFive::Object& obj); -void other_function(const boost::numeric::ublas::matrix& m); - -#endif diff --git a/tests/test_dependent_library/src/otherton.cpp b/tests/test_dependent_library/src/otherton.cpp deleted file mode 100644 index 3e10a3630..000000000 --- a/tests/test_dependent_library/src/otherton.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "simpleton.hpp" - -void other_function(const boost::numeric::ublas::matrix& m) { - m(0, 0) * 0.0; -} diff --git a/tests/test_dependent_library/src/simpleton.cpp b/tests/test_dependent_library/src/simpleton.cpp deleted file mode 100644 index 12cef5bfc..000000000 --- a/tests/test_dependent_library/src/simpleton.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -#include "simpleton.hpp" - -void function(const HighFive::Object& obj) { - if (!obj.isValid()) { - throw std::exception(); - } -} diff --git a/tests/test_project/CMakeLists.txt b/tests/test_project/CMakeLists.txt deleted file mode 100644 index 1a8ef098a..000000000 --- a/tests/test_project/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# This is a sample project to test integration via add_subdirectory and CMakeConfig -cmake_minimum_required(VERSION 3.1) - -project(test_project VERSION 0.1) - -if(NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") # For come compilers under cmake 3.1 - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_EXTENSIONS OFF) -endif() - -option(USE_BUNDLED_HIGHFIVE "Use highfive from deps folder. Otherwise must be installed" ON) - -if(USE_BUNDLED_HIGHFIVE) - add_subdirectory("deps/HighFive" EXCLUDE_FROM_ALL) -else() - find_package(HighFive REQUIRED) -endif() - -add_executable(read_write_bin "read_write_vector_dataset.cpp") -target_link_libraries(read_write_bin HighFive) - -enable_testing() -add_test(NAME test_project COMMAND ${CMAKE_CURRENT_BINARY_DIR}/read_write_bin) diff --git a/tests/test_project/deps/.gitignore b/tests/test_project/deps/.gitignore deleted file mode 100644 index 5e7d2734c..000000000 --- a/tests/test_project/deps/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/tests/test_project/read_write_vector_dataset.cpp b/tests/test_project/read_write_vector_dataset.cpp deleted file mode 120000 index 84b5175b8..000000000 --- a/tests/test_project/read_write_vector_dataset.cpp +++ /dev/null @@ -1 +0,0 @@ -../../src/examples/read_write_vector_dataset.cpp \ No newline at end of file diff --git a/tests/test_project_integration.sh b/tests/test_project_integration.sh deleted file mode 100644 index 955219952..000000000 --- a/tests/test_project_integration.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -set -xeo pipefail -cd "$( dirname "${BASH_SOURCE[0]}")" # cd here - -BUILD_DIR="${PWD}/build-highfive" -ROOT="${PWD}/.." -TEST_DIR="${PWD}" -INSTALL_DIR="${BUILD_DIR}/install" - -test_install() { - local project="${1}" - local project_dir="${TEST_DIR}/${project}" - local dep_dir="${TEST_DIR}/${project}/deps/HighFive" - shift - - pushd "${project_dir}" - - local build_dir="build" - - ln -sf ../../.. "${dep_dir}" - - cmake "$@" -B "${build_dir}" . - cmake --build "${build_dir}" --verbose - ctest --test-dir "${build_dir}" - - rm -f "${dep_dir}" - rm -rf "${build_dir}" - - popd -} - -cmake "${ROOT}" \ - -DHIGHFIVE_EXAMPLES=OFF \ - -DHIGHFIVE_UNIT_TESTS=OFF \ - -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \ - -B "${BUILD_DIR}" -cmake --build "${BUILD_DIR}" --target install - -for project in test_project test_dependent_library; do - # Case 1. Base case: include subdirectory - test_install "${project}" - - # Case 2. We use an install dir and all deps configuration - # Install highfive (no tests required) - test_install "${project}" \ - -DUSE_BUNDLED_HIGHFIVE=NO \ - -DHIGHFIVE_USE_INSTALL_DEPS=YES \ - -DCMAKE_PREFIX_PATH="${INSTALL_DIR}" - - # Case 3. We redetect-dependencies - test_install "${project}" \ - -DUSE_BUNDLED_HIGHFIVE=NO \ - -DHIGHFIVE_USE_INSTALL_DEPS=NO \ - -DCMAKE_PREFIX_PATH="${INSTALL_DIR}" -done - -rm -rf "${BUILD_DIR}" diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 6c19a1d2b..93533ee91 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,6 +1,5 @@ include(CTest) include(Catch) -include(HighFiveWarnings) if(MSVC) add_definitions(/bigobj) @@ -14,7 +13,6 @@ foreach(test_name tests_high_five_base tests_high_five_multi_dims tests_high_fiv endforeach() if(HIGHFIVE_PARALLEL_HDF5) - include(TestHelpers) set(tests_parallel_src "tests_high_five_parallel.cpp") ## parallel MPI tests @@ -29,7 +27,7 @@ if(HIGHFIVE_PARALLEL_HDF5) file(READ "${original_catch_script}" original_catch_script_contents) string(REGEX REPLACE "(add_command\\(add_test.*TEST_EXECUTOR})" - "\\1 ${TEST_MPI_EXEC_PREFIX_DEFAULT} -n 2" + "\\1 ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2" modified_catch_script_contents "${original_catch_script_contents}") if(original_catch_script_contents STREQUAL modified_catch_script_contents) @@ -44,17 +42,17 @@ endif() option(HIGHFIVE_TEST_SINGLE_INCLUDES "Enable testing single includes" FALSE) if(HIGHFIVE_TEST_SINGLE_INCLUDES) - file(GLOB public_headers LIST_DIRECTORIES false RELATIVE ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/include/highfive/*.hpp) + file(GLOB CONFIGURE_DEPENDS public_headers LIST_DIRECTORIES false RELATIVE ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/include/highfive/*.hpp) foreach(PUBLIC_HEADER ${public_headers}) - if(PUBLIC_HEADER STREQUAL "highfive/boost.hpp" AND NOT HIGHFIVE_USE_BOOST) + if(PUBLIC_HEADER STREQUAL "highfive/boost.hpp" AND NOT HIGHFIVE_TEST_BOOST) continue() endif() - if(PUBLIC_HEADER STREQUAL "highfive/half_float.hpp" AND NOT HIGHFIVE_USE_HALF_FLOAT) + if(PUBLIC_HEADER STREQUAL "highfive/half_float.hpp" AND NOT HIGHFIVE_TEST_HALF_FLOAT) continue() endif() - if(PUBLIC_HEADER STREQUAL "highfive/eigen.hpp" AND NOT HIGHFIVE_USE_EIGEN) + if(PUBLIC_HEADER STREQUAL "highfive/eigen.hpp" AND NOT HIGHFIVE_TEST_EIGEN) continue() endif() From 912f7012a06cbf0033ee293826554cab8a6ac513 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 13 Feb 2024 16:26:44 +0100 Subject: [PATCH 2/3] Remove generated symlink. --- tests/cmake_integration/application/deps/.gitignore | 2 ++ tests/cmake_integration/application/deps/HighFive | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 tests/cmake_integration/application/deps/.gitignore delete mode 120000 tests/cmake_integration/application/deps/HighFive diff --git a/tests/cmake_integration/application/deps/.gitignore b/tests/cmake_integration/application/deps/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/tests/cmake_integration/application/deps/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/cmake_integration/application/deps/HighFive b/tests/cmake_integration/application/deps/HighFive deleted file mode 120000 index 08f081295..000000000 --- a/tests/cmake_integration/application/deps/HighFive +++ /dev/null @@ -1 +0,0 @@ -/home/lucg/git/bbp/HighFive/tests/cmake_integration/../.. \ No newline at end of file From 64e27c1056cc39f9a105e0fbd4d4f7f8049b2119 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 13 Feb 2024 18:24:03 +0100 Subject: [PATCH 3/3] Clarify Bailout Approach. --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0eae323e4..69e979f92 100644 --- a/README.md +++ b/README.md @@ -207,11 +207,19 @@ To prevent HighFive from searching or "linking" to HDF5 the project's `CMakeLists.txt` should contain the following: ```cmake +# Prevent HighFive CMake code from searching for HDF5: set(HIGHFIVE_FIND_HDF5 Off) + +# Then "find" HighFive as usual: find_package(HighFive REQUIRED) -# Alternatively: +# alternatively, when vendoring: # add_subdirectory(third_party/HighFive) + +# Finally, use the target `HighFive::Include` which +# doesn't add a dependency on HDF5. target_link_libraries(foo HighFive::Include) + +# Proceed to find and link HDF5 as required. ``` ### Optional Dependencies