From 2c2661c9e25d98cca05b09f7d9f3e8eeb6666a0a Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Sat, 17 Oct 2020 22:16:12 +0200 Subject: [PATCH 1/2] Add PMDK build dependency --- CMake/FindPMDK.cmake | 1040 +++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 6 + scripts/compile_dep.sh | 20 +- scripts/dl_dep.sh | 16 +- src/daemon/CMakeLists.txt | 2 + 5 files changed, 1074 insertions(+), 10 deletions(-) create mode 100644 CMake/FindPMDK.cmake diff --git a/CMake/FindPMDK.cmake b/CMake/FindPMDK.cmake new file mode 100644 index 000000000..9e3ba73ec --- /dev/null +++ b/CMake/FindPMDK.cmake @@ -0,0 +1,1040 @@ +## +# Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain +# Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany +# +# This software was partially supported by the +# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). +# +# This software was partially supported by the +# ADA-FS project under the SPPEXA project funded by the DFG. +# +# SPDX-License-Identifier: MIT +## + +#[=======================================================================[.rst: + +FindPMDK +--------- + +Find PMDK include directories and libraries. + +Introduction +^^^^^^^^^^^^ + +This module can be used by invoking :command:`find_package` with the form:: + + find_package(PMDK + [version] [EXACT] # Minimum or EXACT version e.g. 1.9.1 + [REQUIRED] # Fail with error if PMDK is not found + [COMPONENTS ...] # PMDK libraries by their canonical name + # e.g. "pmemobj" for "libpmemobj" + ) + +This module finds headers and requested component libraries and reports the +results in the following variables:: + + PMDK_FOUND - True if headers and requested libraries were found + PMDK_INCLUDE_DIRS - PMDK include directories + PMDK_LIBRARY_DIRS - Link directories for PMDK libraries + PMDK_LIBRARIES - PMDK component libraries to be linked + + PMDK__FOUND - True if component was found + ( is upper-case, e.g. PMDK_PMEM_FOUND) + PMDK__LIBRARY - Libraries to link for component + (may include target_link_libraries debug/optimized + keywords) + + PMDK_VERSION_STRING - PMDK version number in x.y.z format + PMDK_VERSION - Same as PMDK_VERSION_STRING + PMDK_VERSION_MAJOR - PMDK major version number (e.g. 1 in 1.9.1-rc1) + PMDK_VERSION_MINOR - PMDK minor version number (e.g. 9 in 1.9.1-rc1) + PMDK_VERSION_PATCH - PMDK subminor version number (e.g. 1 in 1.9.1-rc1) + PMDK_VERSION_TWEAK - PMDK tweak version number (e.g. rc1 in 1.9.1-rc1) + PMDK_VERSION_COUNT - Amount of version components (e.g. 2 in 1.9) + +.. note:: + Since PMDK does not yet provide version information in the headers but does + install ``pkg-config`` description files, version matching is done using + CMake's ``PkgConfig`` module. Thus, ``pkg-config`` needs to be available in + the system and the ``PKG_CONFIG_PATH`` environment variable may need to be + appropriately set (see ``pkg-config``'s man page for more details). + +This module reads hints about search locations from variables:: + + PMDK_ROOT - Preferred installation prefix + (or PMDKROOT) + PMDK_INCLUDEDIR - Preferred include directory e.g. /include + PMDK_LIBRARYDIR - Preferred library directory e.g. /lib + PMDK_NO_SYSTEM_PATHS - Set to ON to disable searching in locations not + specified by these hint variables. Default is OFF. + PMDK_ADDITIONAL_VERSIONS - List of PMDK versions not known to this module. + +and saves search results persistently in CMake cache entries:: + + PMDK_INCLUDE_DIR - Directory containing PMDK headers + PMDK_LIBRARY_DIR_RELEASE - Directory containing release PMDK libraries + PMDK_LIBRARY_DIR_DEBUG - Directory containing debug PMDK libraries + PMDK__LIBRARY_DEBUG - Component library debug variant + PMDK__LIBRARY_RELEASE - Component library release variant + +Users may set these hints or results as ``CACHE`` entries. Projects should +not read these entries directly but instead use the above result variables. +One may specify these as environment variables if they are not specified as +CMake variables or cache entries. + + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module also defines the following :prop_tgt:`IMPORTED` targets, if found:: + + PMDK::PMDK - Target for the complete PMDK library + PMDK:: - Target for specific component dependencies (shared + or static libraries). Note that is lower-case + +Implicit dependencies such as ``PMDK::libpmemobj`` requiring ``PMDK::pmem`` +will be automatically detected and satisfied, even if ``pmem`` is not +specified when using :command:`find_package` and if ``PMDK::pmem`` is not +added to :command:`target_link_libraries`. + +It is important to note that the imported targets behave differently +than variables created by this module: multiple calls to +:command:`find_package(PMDK)` in the same directory or sub-directories with +different options (e.g. static or shared) will not override the +values of the targets created by the first call. + +Lookup Details +^^^^^^^^^^^^^^ + +This module first searches for the ``PMDK`` header files using the above +hint variables (excluding ``PMDK_LIBRARYDIR``) and saves the result in +``PMDK_INCLUDE_DIR``. Then it searches for requested component libraries +using the above hints (excluding ``PMDK_INCLUDEDIR`` and +``PMDK_ADDITIONAL_VERSIONS``) and "lib" directories near ``PMDK_INCLUDE_DIR``. +It saves the library directories in ``PMDK_LIBRARY_DIR_DEBUG`` and +``PMDK_LIBRARY_DIR_RELEASE`` and individual library locations in +``PMDK__LIBRARY_DEBUG`` and ``PMDK__LIBRARY_RELEASE``. +When one changes settings used by previous searches in the same build +tree (excluding environment variables) this module discards previous +search results affected by the changes and searches again. + +PMDK libraries come in RELEASE and DEBUG variants which (if installed) are +stored in separate locations. Users or projects may tell this module which +variant to find by setting variables:: + + PMDK_USE_DEBUG_LIBS - Set to ON or OFF to specify whether to search + and use the debug libraries. Default is ON. + PMDK_USE_RELEASE_LIBS - Set to ON or OFF to specify whether to search + and use the release libraries. Default is ON. + PMDK_USE_STATIC_LIBS - Set to ON to force the use of the static + libraries. Default is OFF. + +Other variables one may set to control this module are:: + + PMDK_DEBUG - Set to ON to enable debug output from FindPMDK. + Please enable this before filing any bug report. + PMDK_LIBRARY_DIR - Default value for PMDK_LIBRARY_DIR_RELEASE and + PMDK_LIBRARY_DIR_DEBUG. + +Examples +^^^^^^^^ + +Example to find PMDK headers only: + +.. code-block:: cmake + + find_package(PMDK 1.36.0) + if(PMDK_FOUND) + include_directories(${PMDK_INCLUDE_DIRS}) + add_executable(foo foo.cc) + endif() + +Example to find PMDK libraries and use imported targets: + +.. code-block:: cmake + + find_package(PMDK 1.9.1 REQUIRED + COMPONENTS + pmemobj pmempool rpmem) + add_executable(foo foo.cc) + target_link_libraries(foo PMDK::pmemobj PMDK::pmempool + PMDK::rpmem) + +Example to find PMDK headers and some *static* (release only) libraries: + +.. code-block:: cmake + + set(PMDK_USE_STATIC_LIBS ON) # only find static libs + set(PMDK_USE_DEBUG_LIBS OFF) # ignore debug libs and + set(PMDK_USE_RELEASE_LIBS ON) # only find release libs + find_package(PMDK 1.9.1 + COMPONENTS + pmemobj pmempool rpmem ...) + if(PMDK_FOUND) + include_directories(${PMDK_INCLUDE_DIRS}) + add_executable(foo foo.cc) + target_link_libraries(foo ${PMDK_LIBRARIES}) + endif() + +#]=======================================================================] + +include(CMakePrintHelpers) + +# The FPHSA helper provides standard way of reporting final search results to +# the user including the version and component checks. +include(FindPackageHandleStandardArgs) + + + +#------------------------------------------------------------------------------- +# FindPMDK functions & macros +# + +# +# Print debug text if PMDK_DEBUG is set. +# Call example: +# _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "debug message") +# +function(_PMDK_DEBUG_PRINT file line text) + if(PMDK_DEBUG) + message(STATUS "[ ${file}:${line} ] ${text}") + endif() +endfunction() + + +# +# _PMDK_DEBUG_PRINT_VAR(file line variable_name [ENVIRONMENT] +# [SOURCE "short explanation of origin of var value"]) +# +# ENVIRONMENT - look up environment variable instead of CMake variable +# +# Print variable name and its value if PMDK_DEBUG is set. +# Call example: +# _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" PMDK_ROOT) +# +function(_PMDK_DEBUG_PRINT_VAR file line name) + if(PMDK_DEBUG) + cmake_parse_arguments(_args "ENVIRONMENT" "SOURCE" "" ${ARGN}) + + unset(source) + if(_args_SOURCE) + set(source " (${_args_SOURCE})") + endif() + + if(_args_ENVIRONMENT) + if(DEFINED ENV{${name}}) + set(value "\"$ENV{${name}}\"") + else() + set(value "") + endif() + set(_name "ENV{${name}}") + else() + if(DEFINED "${name}") + set(value "\"${${name}}\"") + else() + set(value "") + endif() + set(_name "${name}") + endif() + + _PMDK_DEBUG_PRINT("${file}" "${line}" "${_name} = ${value}${source}") + endif() +endfunction() + + +# +# Get component headers. This is the primary header (or headers) for +# a given component, and is used to check that the headers are present +# as well as the library itself as an extra sanity check of the build +# environment. +# +# component - the component to check +# _hdrs +# +function(_PMDK_COMPONENT_HEADERS component _hdrs) + + # Note: new PMDK components will require adding here. The header + # must be present in all versions of PMDK providing a library. + set(_PMDK_PMEM_HEADERS "libpmem.h") + set(_PMDK_PMEMBLK_HEADERS "libpmemblk.h") + set(_PMDK_PMEMLOG_HEADERS "libpmemlog.h") + set(_PMDK_PMEMOBJ_HEADERS "libpmemobj.h") + set(_PMDK_PMEMPOOL_HEADERS "libpmempool.h") + set(_PMDK_RPMEM_HEADERS "librpmem.h") + set(_PMDK_PMEM2_HEADERS "libpmem2.h") + + string(TOUPPER ${component} uppercomponent) + set(${_hdrs} ${_PMDK_${uppercomponent}_HEADERS} PARENT_SCOPE) + + string(REGEX REPLACE ";" " " _pmdk_HDRS_STRING "${_PMDK_${uppercomponent}_HEADERS}") + if (NOT _pmdk_HDRS_STRING) + set(_pmdk_HDRS_STRING "(none)") + endif() + + _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Headers for PMDK::${component}: ${_pmdk_HDRS_STRING}") +endfunction() + + +# +# Get component dependencies. Requires the dependencies to have been +# defined for the PMDK release version. +# +# component - the component to check +# _ret - list of library dependencies +# +function(_PMDK_COMPONENT_DEPENDENCIES component _ret) + + set(_PMDK_IMPORTED_TARGETS TRUE) + if(PMDK_VERSION_STRING) + if(PMDK_VERSION_STRING VERSION_LESS 1.9.1) + message(WARNING "Imported targets and dependency information not " + "available for PMDK version ${PMDK_VERSION_STRING} " + "(all versions older than 1.9.1)") + else() + set(_PMDK_PMEMBLK_DEPENDENCIES pmem) + set(_PMDK_PMEMLOG_DEPENDENCIES pmem) + set(_PMDK_PMEMOBJ_DEPENDENCIES pmem) + set(_PMDK_PMEMPOOL_DEPENDENCIES pmem) + set(_PMDK_RPMEM_DEPENDENCIES pmem) + if(PMDK_VERSION_STRING VERSION_GREATER_EQUAL 1.10.0) + message(WARNING "New PMDK version ${PMDK_VERSION_STRING} may have " + "incorrect or missing dependencies and imported " + "targets") + endif() + endif() + endif() + + string(TOUPPER ${component} uppercomponent) + set(${_ret} ${_PMDK_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) + set(_PMDK_IMPORTED_TARGETS ${_PMDK_IMPORTED_TARGETS} PARENT_SCOPE) + + string(REGEX REPLACE ";" " " _pmdk_DEPS_STRING "${_PMDK_${uppercomponent}_DEPENDENCIES}") + if (NOT _pmdk_DEPS_STRING) + set(_pmdk_DEPS_STRING "(none)") + endif() + + message(STATUS "Dependencies for PMDK::${component}: ${_pmdk_DEPS_STRING}") + + _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Dependencies for PMDK::${component}: ${_pmdk_DEPS_STRING}") + +endfunction() + + +# +# Determine if any missing dependencies require adding to the component list. +# +# Sets _PMDK_${COMPONENT}_DEPENDENCIES for each required component, +# plus _PMDK_IMPORTED_TARGETS (TRUE if imported targets should be +# defined; FALSE if dependency information is unavailable). +# +# componentvar - the component list variable name +# extravar - the indirect dependency list variable name +# +# +function(_PMDK_MISSING_DEPENDENCIES componentvar extravar) + # _pmdk_unprocessed_components - list of components requiring processing + # _pmdk_processed_components - components already processed (or currently being processed) + # _pmdk_new_components - new components discovered for future processing + # + list(APPEND _pmdk_unprocessed_components ${${componentvar}}) + + while(_pmdk_unprocessed_components) + list(APPEND _pmdk_processed_components ${_pmdk_unprocessed_components}) + foreach(component ${_pmdk_unprocessed_components}) + string(TOUPPER ${component} uppercomponent) + set(${_ret} ${_PMDK_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) + _PMDK_COMPONENT_DEPENDENCIES("${component}" _PMDK_${uppercomponent}_DEPENDENCIES) + set(_PMDK_${uppercomponent}_DEPENDENCIES ${_PMDK_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) + set(_PMDK_IMPORTED_TARGETS ${_PMDK_IMPORTED_TARGETS} PARENT_SCOPE) + foreach(componentdep ${_PMDK_${uppercomponent}_DEPENDENCIES}) + if (NOT ("${componentdep}" IN_LIST _pmdk_processed_components OR "${componentdep}" IN_LIST _pmdk_new_components)) + list(APPEND _pmdk_new_components ${componentdep}) + endif() + endforeach() + endforeach() + set(_pmdk_unprocessed_components ${_pmdk_new_components}) + unset(_pmdk_new_components) + endwhile() + set(_pmdk_extra_components ${_pmdk_processed_components}) + if(_pmdk_extra_components AND ${componentvar}) + list(REMOVE_ITEM _pmdk_extra_components ${${componentvar}}) + endif() + set(${componentvar} ${_pmdk_processed_components} PARENT_SCOPE) + set(${extravar} ${_pmdk_extra_components} PARENT_SCOPE) +endfunction() + + +# +# Find the given library (var). +# Use 'build_type' to support different lib paths for RELEASE or DEBUG builds +# +macro(_PMDK_FIND_LIBRARY var build_type) + + find_library(${var} ${ARGN}) + + if(${var}) + # If this is the first library found then save PMDK_LIBRARY_DIR_[RELEASE,DEBUG]. + if(NOT PMDK_LIBRARY_DIR_${build_type}) + get_filename_component(_dir "${${var}}" PATH) + set(PMDK_LIBRARY_DIR_${build_type} "${_dir}" CACHE PATH "PMDK library directory ${build_type}" FORCE) + endif() + endif() + + # If PMDK_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there. + if(PMDK_LIBRARY_DIR_${build_type}) + set(_PMDK_LIBRARY_SEARCH_DIRS_${build_type} ${PMDK_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "PMDK_LIBRARY_DIR_${build_type}") + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + # "_PMDK_LIBRARY_SEARCH_DIRS_${build_type}") + endif() +endmacro() + +# Detect changes in used variables. +# Compares the current variable value with the last one. +# In short form: +# v != v_LAST -> CHANGED = 1 +# v is defined, v_LAST not -> CHANGED = 1 +# v is not defined, but v_LAST is -> CHANGED = 1 +# otherwise -> CHANGED = 0 +# CHANGED is returned in variable named ${changed_var} +macro(_PMDK_CHANGE_DETECT changed_var) + set(${changed_var} 0) + foreach(v ${ARGN}) + if(DEFINED _PMDK_COMPONENTS_SEARCHED) + if(${v}) + if(_${v}_LAST) + string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED) + else() + set(_${v}_CHANGED 1) + endif() + elseif(_${v}_LAST) + set(_${v}_CHANGED 1) + endif() + if(_${v}_CHANGED) + set(${changed_var} 1) + endif() + else() + set(_${v}_CHANGED 0) + endif() + endforeach() +endmacro() + +# +# Check the existence of the libraries. +# +macro(_PMDK_ADJUST_LIB_VARS basename) + if(PMDK_INCLUDE_DIR) + if(PMDK_${basename}_LIBRARY_DEBUG AND PMDK_${basename}_LIBRARY_RELEASE) + # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for + # single-config generators, set optimized and debug libraries + get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(_isMultiConfig OR CMAKE_BUILD_TYPE) + set(PMDK_${basename}_LIBRARY optimized ${PMDK_${basename}_LIBRARY_RELEASE} debug ${PMDK_${basename}_LIBRARY_DEBUG}) + else() + # For single-config generators where CMAKE_BUILD_TYPE has no value, + # just use the release libraries + set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_RELEASE} ) + endif() + # FIXME: This probably should be set for both cases + set(PMDK_${basename}_LIBRARIES optimized ${PMDK_${basename}_LIBRARY_RELEASE} debug ${PMDK_${basename}_LIBRARY_DEBUG}) + endif() + + # if only the release version was found, set the debug variable also to the release version + if(PMDK_${basename}_LIBRARY_RELEASE AND NOT PMDK_${basename}_LIBRARY_DEBUG) + set(PMDK_${basename}_LIBRARY_DEBUG ${PMDK_${basename}_LIBRARY_RELEASE}) + set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_RELEASE}) + set(PMDK_${basename}_LIBRARIES ${PMDK_${basename}_LIBRARY_RELEASE}) + endif() + + # if only the debug version was found, set the release variable also to the debug version + if(PMDK_${basename}_LIBRARY_DEBUG AND NOT PMDK_${basename}_LIBRARY_RELEASE) + set(PMDK_${basename}_LIBRARY_RELEASE ${PMDK_${basename}_LIBRARY_DEBUG}) + set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_DEBUG}) + set(PMDK_${basename}_LIBRARIES ${PMDK_${basename}_LIBRARY_DEBUG}) + endif() + + # If the debug & release library ends up being the same, omit the keywords + if("${PMDK_${basename}_LIBRARY_RELEASE}" STREQUAL "${PMDK_${basename}_LIBRARY_DEBUG}") + set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_RELEASE} ) + set(PMDK_${basename}_LIBRARIES ${PMDK_${basename}_LIBRARY_RELEASE} ) + endif() + + if(PMDK_${basename}_LIBRARY AND PMDK_${basename}_HEADER) + set(PMDK_${basename}_FOUND ON) + endif() + endif() + + # Make variables changeable to the advanced user + mark_as_advanced( + PMDK_${basename}_LIBRARY_RELEASE + PMDK_${basename}_LIBRARY_DEBUG + ) +endmacro() + +# +# End functions/macros +# +#------------------------------------------------------------------------------- + + +#------------------------------------------------------------------------------- +# main. +#------------------------------------------------------------------------------- + +# If the user sets PMDK_LIBRARY_DIR, use it as the default for both +# configurations. +if(NOT PMDK_LIBRARY_DIR_RELEASE AND PMDK_LIBRARY_DIR) + set(PMDK_LIBRARY_DIR_RELEASE "${PMDK_LIBRARY_DIR}") +endif() + +if(NOT PMDK_LIBRARY_DIR_DEBUG AND PMDK_LIBRARY_DIR) + set(PMDK_LIBRARY_DIR_DEBUG "${PMDK_LIBRARY_DIR}") +endif() + +if(NOT DEFINED PMDK_USE_DEBUG_LIBS) + set(PMDK_USE_DEBUG_LIBS TRUE) +endif() + +if(NOT DEFINED PMDK_USE_RELEASE_LIBS) + set(PMDK_USE_RELEASE_LIBS TRUE) +endif() + +# Check the version of PMDK against the requested version. +if(PMDK_FIND_VERSION AND NOT PMDK_FIND_VERSION_MINOR) + message(SEND_ERROR "When requesting a specific version of PMDK, you must " + "provide at least the major and minor version numbers, " + "e.g., 1.9") +endif() + +if(PMDK_FIND_VERSION_EXACT) + # The version may appear in a directory with or without the patch level, + # even when the patch level is non-zero + set(_PMDK_TESTS_VERSIONS + "${PMDK_FIND_VERSION_MAJOR}.${PMDK_FIND_VERSION_MINOR}.${PMDK_FIND_VERSION_PATCH}" + "${PMDK_FIND_VERSION_MAJOR}.${PMDK_FIND_VERSION_MINOR}") +else() + # The user has not requested an exact version. Among known versions, find + # those that are acceptable to the user request. + # + # Note: When adding a new PMDK release, also update the dependency + # information in _PMDK_COMPONENT_DEPENDENCIES and + # _PMDK_COMPONENT_HEADERS. See the instructions at the top of + # _PMDK_COMPONENT_DEPENDENCIES. + set(_PMDK_KNOWN_VERSIONS ${PMDK_ADDITIONAL_VERSIONS} + "1.9.1" "1.9" "1.9-rc2" "1.9-rc1" "1.8.1" "1.8" "1.8-rc2" "1.8-rc1" "1.7.1" + "1.7" "1.7-rc2" "1.7-rc1" "1.6.1" "1.6.1-rc1" "1.6" "1.6-rc3" "1.6-rc2" + "1.6-rc1" "1.5.2" "1.5.2-rc1" "1.5.1" "1.5.1-rc3" "1.5.1-rc2" "1.5.1-rc1" + "1.5" "1.5-rc2" "1.5-rc1" "1.4.3" "1.4.3-rc1" "1.4.2" "1.4.2-rc1" "1.4.1" + "1.4.1-rc4" "1.4.1-rc3" "1.4.1-rc2" "1.4.1-rc1" "1.4" "1.4-rc4" "1.4-rc3" + "1.4-rc2" "1.4-rc1" "1.3.3" "1.3.3-rc1" "1.3+b2" "1.3+b1" "1.3" "1.3-rc2" + "1.3-rc1" "1.2.4" "1.2.4-rc1" "1.2+wtp1" "1.2+b3" "1.2+b2" "1.2+b1" "1.2" + "1.2-rc3" "1.2-rc2" "1.2-rc1" "1.1" "1.1-rc3" "1.1-rc2" "1.1-rc1" "1.0+b2" + "1.0+b1" "1.0" "1.0-rc3" "1.0-rc2" "1.0-rc1" "0.4+b3" "0.4+b2" "0.4+b1" + "0.4" "0.4-rc2" "0.4-rc1" "0.3+b3" "0.3+b2" "0.3+b1" "0.3" "0.3-rc2" + "0.3-rc1" "0.2+b4" "0.2+b3" "0.2+b2" "0.2+b1" "0.2" "0.2-rc3" "0.2-rc2" + "0.2-rc1" "0.1+b16" "0.1+b15" "0.1+b14" "0.1+b13" "0.1+b12" "0.1+b11" + "0.1+b10" "0.1+b9" "0.1+b8" "0.1+b7" "0.1+b6" "0.1+b5" "0.1+b4" "0.1+b3" + "0.1+b2" "0.1+b1" "0.1" + ) + + set(_PMDK_TESTS_VERSIONS) + if(PMDK_FIND_VERSION) + set(_PMDK_FIND_VERSION_SHORT "${PMDK_FIND_VERSION_MAJOR}.${PMDK_FIND_VERSION_MINOR}") + + # select acceptable versions + foreach(version ${_PMDK_KNOWN_VERSIONS}) + if(NOT "${version}" VERSION_LESS "${PMDK_FIND_VERSION}") + # This version is high enough + list(APPEND _PMDK_TESTS_VERSIONS "${version}") + elseif("${version}.99" VERSION_EQUAL "${_PMDK_FIND_VERSION_SHORT}.99") + # This version is a short-form for the requested version with + # the patch level dropped. + list(APPEND _PMDK_TESTS_VERSIONS "${version}") + endif() + endforeach() + else() + # Any version is acceptable + set(_PMDK_TESTS_VERSIONS "${_PMDK_KNOWN_VERSIONS}") + endif() +endif() + +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_TEST_VERSIONS") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_USE_STATIC_LIBS") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_ADDITIONAL_VERSIONS") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_NO_SYSTEM_PATHS") + +# Collect environment variable inputs as hints. +foreach(v PMDKROOT PMDK_ROOT PMDK_INCLUDEDIR PMDK_LIBRARYDIR) + set(_env $ENV{${v}}) + if(_env) + file(TO_CMAKE_PATH "${_env}" _ENV_${v}) + else() + set(_ENV_${v} "") + endif() +endforeach() + +if(NOT _ENV_PMDK_ROOT AND _ENV_PMDKROOT) + set(_ENV_PMDK_ROOT "${_ENV_PMDKROOT}") +endif() + +# Collect inputs and cached results. +if(NOT PMDK_ROOT AND PMDKROOT) + set(PMDK_ROOT "${PMDKROOT}") +endif() + +set(_PMDK_VARS_DIR + PMDK_ROOT + PMDK_NO_SYSTEM_PATHS + ) + +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_ROOT") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_ROOT" ENVIRONMENT) +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_INCLUDEDIR") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_INCLUDEDIR" ENVIRONMENT) +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_LIBRARYDIR") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_LIBRARYDIR" ENVIRONMENT) + + +# ------------------------------------------------------------------------ +# Search for PMDK include DIR +# ------------------------------------------------------------------------ + +set(_PMDK_VARS_INC PMDK_INCLUDEDIR PMDK_INCLUDE_DIR PMDK_ADDITIONAL_VERSIONS) +_PMDK_CHANGE_DETECT(_PMDK_CHANGE_INCDIR ${_PMDK_VARS_DIR} ${_PMDK_VARS_INC}) + +# Clear PMDK_INCLUDE_DIR if it did not change but other input affecting the +# location did. We will find a new one based on the new inputs. +if(_PMDK_CHANGE_INCDIR AND NOT _PMDK_INCLUDE_DIR_CHANGED) + unset(PMDK_INCLUDE_DIR CACHE) +endif() + +if(NOT PMDK_INCLUDE_DIR) + set(_PMDK_INCLUDE_SEARCH_DIRS "") + + if(PMDK_INCLUDEDIR) + list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${PMDK_INCLUDEDIR}) + elseif(_ENV_PMDK_INCLUDEDIR) + list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${_ENV_PMDK_INCLUDEDIR}) + endif() + + if(PMDK_ROOT) + list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${PMDK_ROOT}/include ${PMDK_ROOT}) + elseif(_ENV_PMDK_ROOT) + list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${_ENV_PMDK_ROOT}/include ${_ENV_PMDK_ROOT}) + endif() + + if(PMDK_NO_SYSTEM_PATHS) + list(APPEND _PMDK_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + endif() + + _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_INCLUDE_SEARCH_DIRS") + + # Look for a standard PMDK header file + find_path(PMDK_INCLUDE_DIR + NAMES libpmem.h + HINTS ${_PMDK_INCLUDE_SEARCH_DIRS} + ) +endif() + +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_INCLUDE_DIR") + + +# ------------------------------------------------------------------------ +# Extract version information using pkg-config +# +# TODO: This will fail if pkg-config is not available, but version +# information is unfortunately only contained in the installed .pc +# files. In the future it would be more portable to extract version +# information from a installed header, if the developers end up add +# providing this information. +# ------------------------------------------------------------------------ + +find_package(PkgConfig) + +if(PMDK_FIND_VERSION) + +if(NOT PKG_CONFIG_FOUND) + message(FATAL_ERROR "ERROR: pkg-config is required to determine PMDK's " + "installed version. If pkg-config cannot be installed " + "and you are certain that PMDK's installed version " + "is the correct one, you can disable this check by " + "removing the version number in the call to " + "find_package(PMDK ...)") +endif() + +pkg_get_variable(PMDK_VERSION_STRING libpmem version) + +if(NOT PMDK_VERSION_STRING) + message(FATAL_ERROR "ERROR: Failed to determine PMDK version.") +endif() + +set(PMDK_VERSION ${PMDK_VERSION_STRING}) + +string(REGEX MATCH "([0-9]+).([0-9]+)(.([0-9]+))?([+-](((rc)|b)[0-9]+))?" _ ${PMDK_VERSION_STRING}) +set(PMDK_VERSION_MAJOR ${CMAKE_MATCH_1}) +set(PMDK_VERSION_MINOR ${CMAKE_MATCH_2}) +set(PMDK_VERSION_PATCH ${CMAKE_MATCH_4}) +set(PMDK_VERSION_TWEAK ${CMAKE_MATCH_6}) + +set(PMDK_VERSION_COUNT 2) + +if(PMDK_VERSION_PATCH) + math(EXPR PMDK_VERSION_COUNT "${PMDK_VERSION_COUNT} + 1") +endif() + +if(PMDK_VERSION_TWEAK) + math(EXPR PMDK_VERSION_COUNT "${PMDK_VERSION_COUNT} + 1") +endif() + +endif() + +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_STRING") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_MAJOR") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_MINOR") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_PATCH") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_TWEAK") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_COUNT") + + +# ------------------------------------------------------------------------ +# Begin finding PMDK libraries +# ------------------------------------------------------------------------ + +set(_PMDK_VARS_NAME + PMDK_USE_STATIC_LIBS + ) +_PMDK_CHANGE_DETECT(_PMDK_CHANGE_LIBNAME ${_PMDK_VARS_NAME}) + +set(_PMDK_VARS_LIB "") +foreach(c DEBUG RELEASE) + set(_PMDK_VARS_LIB_${c} PMDK_LIBRARYDIR PMDK_LIBRARY_DIR_${c}) + list(APPEND _PMDK_VARS_LIB ${_PMDK_VARS_LIB_${c}}) + _PMDK_CHANGE_DETECT(_PMDK_CHANGE_LIBDIR_${c} ${_PMDK_VARS_DIR} ${_PMDK_VARS_LIB_${c}} PMDK_INCLUDE_DIR) + + # Clear PMDK_LIBRARY_DIR_${c} if it did not change but other input affecting + # the location did. We will find a new one based on the new inputs. + if(_PMDK_CHANGE_LIBDIR_${c} AND NOT _PMDK_LIBRARY_DIR_${c}_CHANGED) + unset(PMDK_LIBRARY_DIR_${c} CACHE) + endif() + + # If PMDK_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value. + if(PMDK_LIBRARY_DIR_${c}) + set(_PMDK_LIBRARY_SEARCH_DIRS_${c} ${PMDK_LIBRARY_DIR_${c}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + else() + set(_PMDK_LIBRARY_SEARCH_DIRS_${c} "") + if(PMDK_LIBRARYDIR) + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${PMDK_LIBRARYDIR}) + elseif(_ENV_PMDK_LIBRARYDIR) + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${_ENV_PMDK_LIBRARYDIR}) + endif() + + if(PMDK_ROOT) + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${PMDK_ROOT}/lib ${PMDK_ROOT}/stage/lib) + elseif(_ENV_PMDK_ROOT) + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${_ENV_PMDK_ROOT}/lib ${_ENV_PMDK_ROOT}/stage/lib) + endif() + + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} + ${PMDK_INCLUDE_DIR}/lib + ${PMDK_INCLUDE_DIR}/../lib + ${PMDK_INCLUDE_DIR}/stage/lib + ) + + if("${c}" STREQUAL "DEBUG") + # PMDK debug libraries are installed in a `pmdk_debug` subdir + list(TRANSFORM _PMDK_LIBRARY_SEARCH_DIRS_${c} APPEND "/pmdk_debug") + endif() + + if(PMDK_NO_SYSTEM_PATHS) + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + endif() + + endif() +endforeach() + +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_RELEASE") +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_DEBUG") + +# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES +if(PMDK_USE_STATIC_LIBS) + set( _PMDK_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + endif() +endif() + +_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_FIND_COMPONENTS") + +# If the user didn't ask for a particular component to be searched, +# assume that they wanted all the components in the library +if(NOT PMDK_FIND_COMPONENTS) + set(PMDK_FIND_COMPONENTS + "pmem" "pmemblk" "pmemlog" "pmempool" "rpmem" "pmem2" + ) +endif() + +# Additional components may be required via component dependencies. +# Add any missing components to the list. +_PMDK_MISSING_DEPENDENCIES(PMDK_FIND_COMPONENTS _PMDK_EXTRA_FIND_COMPONENTS) + +foreach(COMPONENT ${PMDK_FIND_COMPONENTS}) + + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + + set( _pmdk_docstring_release "PMDK ${COMPONENT} library (release)") + set( _pmdk_docstring_debug "PMDK ${COMPONENT} library (debug)") + + # + # Find headers + # + _PMDK_COMPONENT_HEADERS("${COMPONENT}" PMDK_${UPPERCOMPONENT}_HEADER_NAME) + + # Look for a standard PMDK header file. + if(PMDK_${UPPERCOMPONENT}_HEADER_NAME) + if(EXISTS "${PMDK_INCLUDE_DIR}/${PMDK_${UPPERCOMPONENT}_HEADER_NAME}") + set(PMDK_${UPPERCOMPONENT}_HEADER ON) + else() + set(PMDK_${UPPERCOMPONENT}_HEADER OFF) + endif() + else() + set(PMDK_${UPPERCOMPONENT}_HEADER ON) + message(WARNING "No header defined for ${COMPONENT}; skipping header check " + "(note: header-only libraries have no designated component)") + endif() + + # + # Find RELEASE libraries + # + unset(_PMDK_RELEASE_NAMES) + foreach(component IN LISTS COMPONENT) + list(APPEND _PMDK_RELEASE_NAMES + ${component} + ) + endforeach() + + _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: " + "${_PMDK_RELEASE_NAMES}") + + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_RELEASE_NAMES") + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_RELEASE") + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_pmdk_docstring_release") + + # if PMDK_LIBRARY_DIR_RELEASE is not defined, + # but PMDK_LIBRARY_DIR_DEBUG is, also look there for RELEASE libs + if(NOT PMDK_LIBRARY_DIR_RELEASE AND PMDK_LIBRARY_DIR_DEBUG) + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_RELEASE ${PMDK_LIBRARY_DIR_DEBUG}) + endif() + + # Avoid passing backslashes to _PMDK_FIND_LIBRARY due to macro re-parsing. + unset(_PMDK_LIBRARY_SEARCH_DIRS_tmp) + string(REPLACE "\\" "/" _PMDK_LIBRARY_SEARCH_DIRS_tmp "${_PMDK_LIBRARY_SEARCH_DIRS_RELEASE}") + + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_RELEASE") + + if(PMDK_USE_RELEASE_LIBS) + _PMDK_FIND_LIBRARY(PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE RELEASE + NAMES ${_PMDK_RELEASE_NAMES} + HINTS ${_PMDK_LIBRARY_SEARCH_DIRS_tmp} + NAMES_PER_DIR + DOC "${_pmdk_docstring_release}" + ) + + _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE") + endif() + + # + # Find DEBUG libraries + # + unset(_PMDK_DEBUG_NAMES) + foreach(component IN LISTS COMPONENT) + list(APPEND _PMDK_DEBUG_NAMES + ${component} + ) + endforeach() + + _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: " + "${_PMDK_DEBUG_NAMES}") + + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_DEBUG_NAMES") + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_DEBUG") + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_pmdk_docstring_debug") + + # if PMDK_LIBRARY_DIR_DEBUG is not defined, + # but PMDK_LIBRARY_DIR_RELEASE is, also look there for DEBUG libs + if(NOT PMDK_LIBRARY_DIR_DEBUG AND PMDK_LIBRARY_DIR_RELEASE) + list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_DEBUG ${PMDK_LIBRARY_DIR_RELEASE}) + endif() + + + # Avoid passing backslashes to _PMDK_FIND_LIBRARY due to macro re-parsing. + unset(_PMDK_LIBRARY_SEARCH_DIRS_tmp) + string(REPLACE "\\" "/" _PMDK_LIBRARY_SEARCH_DIRS_tmp "${_PMDK_LIBRARY_SEARCH_DIRS_DEBUG}") + + # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_DEBUG") + + if(PMDK_USE_DEBUG_LIBS) + _PMDK_FIND_LIBRARY(PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG DEBUG + NAMES ${_PMDK_DEBUG_NAMES} + HINTS ${_PMDK_LIBRARY_SEARCH_DIRS_tmp} + NAMES_PER_DIR + NO_DEFAULT_PATH + DOC "${_pmdk_docstring_debug}" + ) + + _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG") + endif() + + _PMDK_ADJUST_LIB_VARS(${UPPERCOMPONENT}) +endforeach() + +# Restore the original find library ordering +if(PMDK_USE_STATIC_LIBS) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_PMDK_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +# ------------------------------------------------------------------------ +# End finding PMDK libraries +# ------------------------------------------------------------------------ + + +set(PMDK_INCLUDE_DIRS ${PMDK_INCLUDE_DIR}) +set(PMDK_LIBRARY_DIRS) +if(PMDK_LIBRARY_DIR_RELEASE) + list(APPEND PMDK_LIBRARY_DIRS ${PMDK_LIBRARY_DIR_RELEASE}) +endif() +if(PMDK_LIBRARY_DIR_DEBUG) + list(APPEND PMDK_LIBRARY_DIRS ${PMDK_LIBRARY_DIR_DEBUG}) +endif() +if(PMDK_LIBRARY_DIRS) + list(REMOVE_DUPLICATES PMDK_LIBRARY_DIRS) +endif() + + +# ------------------------------------------------------------------------ +# Call FPHSA helper, see https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html +# ------------------------------------------------------------------------ + +# Define aliases as needed by the component handler in the FPHSA helper below +foreach(component IN LISTS PMDK_FIND_COMPONENTS) + string(TOUPPER ${component} uppercomponent) + if(DEFINED PMDK_${uppercomponent}_FOUND) + set(PMDK_${component}_FOUND ${PMDK_${uppercomponent}_FOUND}) + endif() +endforeach() + +find_package_handle_standard_args(PMDK + REQUIRED_VARS PMDK_INCLUDE_DIR + VERSION_VAR PMDK_VERSION_STRING + HANDLE_COMPONENTS) + + +# ------------------------------------------------------------------------ +# Add imported targets +# ------------------------------------------------------------------------ +if(PMDK_FOUND) + foreach(COMPONENT ${PMDK_FIND_COMPONENTS}) + + if(_PMDK_IMPORTED_TARGETS AND NOT TARGET PMDK::${COMPONENT}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + + if(PMDK_${UPPERCOMPONENT}_FOUND) + add_library(PMDK::${COMPONENT} UNKNOWN IMPORTED) + + if(PMDK_INCLUDE_DIRS) + set_target_properties(PMDK::${COMPONENT} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${PMDK_INCLUDE_DIRS}") + endif() + + if(EXISTS "${PMDK_${UPPERCOMPONENT}_LIBRARY}") + set_target_properties(PMDK::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${PMDK_${UPPERCOMPONENT}_LIBRARY}") + endif() + + if(EXISTS "${PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE}") + set_property(TARGET PMDK::${COMPONENT} APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(PMDK::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE}") + endif() + + if(EXISTS "${PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG}") + set_property(TARGET PMDK::${COMPONENT} APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(PMDK::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG}") + endif() + + if(_PMDK_${UPPERCOMPONENT}_DEPENDENCIES) + unset(_PMDK_${UPPERCOMPONENT}_TARGET_DEPENDENCIES) + foreach(dep ${_PMDK_${UPPERCOMPONENT}_DEPENDENCIES}) + list(APPEND _PMDK_${UPPERCOMPONENT}_TARGET_DEPENDENCIES PMDK::${dep}) + endforeach() + set_target_properties(PMDK::${COMPONENT} PROPERTIES + INTERFACE_LINK_LIBRARIES "${_PMDK_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}") + endif() + endif() + endif() + endforeach() +endif() + + +# ------------------------------------------------------------------------ +# Finalize +# ------------------------------------------------------------------------ + +# Report PMDK_LIBRARIES +set(PMDK_LIBRARIES "") +foreach(component IN LISTS PMDK_FIND_COMPONENTS) + string(TOUPPER ${component} uppercomponent) + if(PMDK_${uppercomponent}_FOUND) + list(APPEND PMDK_LIBRARIES ${PMDK_${uppercomponent}_LIBRARY}) + endif() +endforeach() + +# Configure display of cache entries in GUI. +foreach(v PMDKROOT PMDK_ROOT ${_PMDK_VARS_INC} ${_PMDK_VARS_LIB}) + get_property(_type CACHE ${v} PROPERTY TYPE) + if(_type) + set_property(CACHE ${v} PROPERTY ADVANCED 1) + if("x${_type}" STREQUAL "xUNINITIALIZED") + if("x${v}" STREQUAL "xPMDK_ADDITIONAL_VERSIONS") + set_property(CACHE ${v} PROPERTY TYPE STRING) + else() + set_property(CACHE ${v} PROPERTY TYPE PATH) + endif() + endif() + endif() +endforeach() + +# Record last used values of input variables so we can +# detect on the next run if the user changed them. +foreach(v + ${_PMDK_VARS_INC} ${_PMDK_VARS_LIB} + ${_PMDK_VARS_DIR} ${_PMDK_VARS_NAME} + ) + if(DEFINED ${v}) + set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.") + else() + unset(_${v}_LAST CACHE) + endif() +endforeach() + +# Maintain a persistent list of components requested anywhere since +# the last flush. +set(_PMDK_COMPONENTS_SEARCHED "${_PMDK_COMPONENTS_SEARCHED}") +list(APPEND _PMDK_COMPONENTS_SEARCHED ${PMDK_FIND_COMPONENTS}) +list(REMOVE_DUPLICATES _PMDK_COMPONENTS_SEARCHED) +list(SORT _PMDK_COMPONENTS_SEARCHED) +set(_PMDK_COMPONENTS_SEARCHED "${_PMDK_COMPONENTS_SEARCHED}" + CACHE INTERNAL "Components requested for this build tree.") diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f3a2a190..06ddebb96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,12 @@ find_package(Threads REQUIRED) find_package(Date REQUIRED) +# PMDK for NVM support +find_package(PMDK 1.9.1 REQUIRED + COMPONENTS + pmem + ) + option(CREATE_CHECK_PARENTS "Check parent directory existance before creating child node" ON) message(STATUS "[gekkofs] Create checks parents: ${CREATE_CHECK_PARENTS}") diff --git a/scripts/compile_dep.sh b/scripts/compile_dep.sh index a7d35ebe6..d0d240792 100755 --- a/scripts/compile_dep.sh +++ b/scripts/compile_dep.sh @@ -13,26 +13,26 @@ VALID_DEP_OPTIONS="mogon2 mogon1 ngio direct all ci" MOGON1_DEPS=( "zstd" "lz4" "snappy" "capstone" "ofi" "mercury" "argobots" "margo" "rocksdb" - "syscall_intercept" "date" "verbs" + "syscall_intercept" "date" "verbs" "pmdk" ) MOGON2_DEPS=( "bzip2" "zstd" "lz4" "snappy" "capstone" "ofi" "mercury" "argobots" "margo" "rocksdb" - "syscall_intercept" "date" "psm2" + "syscall_intercept" "date" "psm2" "pmdk" ) NGIO_DEPS=( "zstd" "lz4" "snappy" "capstone" "ofi" "mercury" "argobots" "margo" "rocksdb" - "syscall_intercept" "date" "agios" "psm2" + "syscall_intercept" "date" "agios" "psm2" "pmdk" ) DIRECT_DEPS=( - "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" + "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "pmdk" ) ALL_DEPS=( "bzip2" "zstd" "lz4" "snappy" "capstone" "bmi" "ofi" "mercury" "argobots" "margo" "rocksdb" - "syscall_intercept" "date" "agios" + "syscall_intercept" "date" "agios" "pmdk" ) CI_DEPS=( @@ -487,4 +487,14 @@ if check_dependency "date" "${DEP_CONFIG[@]}"; then make install fi +# PMDK +if check_dependency "date" "${DEP_CONFIG[@]}"; then + echo "############################################################ Installing: PMDK" + CURR=${SOURCE}/pmdk + cd "${CURR}" + make -j"${CORES}" + make install prefix="${INSTALL}" +fi + + echo "Done" diff --git a/scripts/dl_dep.sh b/scripts/dl_dep.sh index 342e32a5a..85249e4c7 100755 --- a/scripts/dl_dep.sh +++ b/scripts/dl_dep.sh @@ -13,26 +13,26 @@ VALID_DEP_OPTIONS="mogon2 mogon1 ngio direct all ci" MOGON1_DEPS=( "zstd" "lz4" "snappy" "capstone" "ofi-verbs" "mercury" "argobots" "margo" "rocksdb" - "syscall_intercept" "date" + "syscall_intercept" "date" "pmdk" ) MOGON2_DEPS=( "bzip2" "zstd" "lz4" "snappy" "capstone" "ofi-experimental" "mercury" "argobots" "margo" "rocksdb-experimental" - "syscall_intercept" "date" "psm2" + "syscall_intercept-glibc3" "date" "psm2" "pmdk" ) NGIO_DEPS=( "zstd" "lz4" "snappy" "capstone" "ofi-experimental" "mercury" "argobots" "margo" "rocksdb" - "syscall_intercept" "date" "psm2" "agios" + "syscall_intercept" "date" "psm2" "agios" "pmdk" ) DIRECT_DEPS=( - "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" + "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "pmdk" ) ALL_DEPS=( "bzip2" "zstd" "lz4" "snappy" "capstone" "bmi" "ofi" "mercury" "argobots" "margo" "rocksdb" - "syscall_intercept" "date" "agios" + "syscall_intercept" "date" "pmdk" "agios" ) CI_DEPS=( @@ -407,6 +407,12 @@ fi if check_dependency "date" "${DEP_CONFIG[@]}"; then clonedeps "date" "https://github.com/HowardHinnant/date.git" "e7e1482087f58913b80a20b04d5c58d9d6d90155" & fi + +# get PMDK +if check_dependency "pmdk" "${DEP_CONFIG[@]}"; then + clonedeps "pmdk" "https://github.com/pmem/pmdk.git" "1.9.1" & +fi + # Wait for all download to be completed wait echo "Done" diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index 793ced82f..b64908d89 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -45,6 +45,8 @@ set(DAEMON_LINK_LIBRARIES ${ABT_LIBRARIES} mercury ${MARGO_LIBRARIES} + # PMDK + PMDK::pmem # others Boost::boost Boost::program_options -- GitLab From 145bcb425bc1debd860b08f25d82a39ffd6306d6 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Mon, 19 Oct 2020 18:45:39 +0200 Subject: [PATCH 2/2] PMDK pools can now be created --- include/daemon/backend/data/pmdk/pool.hpp | 139 +++++++++++++ src/daemon/backend/data/CMakeLists.txt | 5 + src/daemon/backend/data/pmdk/CMakeLists.txt | 29 +++ src/daemon/backend/data/pmdk/pool.cpp | 217 ++++++++++++++++++++ tests/unit/CMakeLists.txt | 3 + tests/unit/test_storage_pmdk.cpp | 175 ++++++++++++++++ 6 files changed, 568 insertions(+) create mode 100644 include/daemon/backend/data/pmdk/pool.hpp create mode 100644 src/daemon/backend/data/pmdk/CMakeLists.txt create mode 100644 src/daemon/backend/data/pmdk/pool.cpp create mode 100644 tests/unit/test_storage_pmdk.cpp diff --git a/include/daemon/backend/data/pmdk/pool.hpp b/include/daemon/backend/data/pmdk/pool.hpp new file mode 100644 index 000000000..96a256cc0 --- /dev/null +++ b/include/daemon/backend/data/pmdk/pool.hpp @@ -0,0 +1,139 @@ +/* + Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + SPDX-License-Identifier: MIT +*/ + +#ifndef GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP +#define GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP + +#include +#include + +namespace fs = boost::filesystem; + +namespace pmdk { + +/** + * This class implements a RAII-enabled non-volatile memory pool based on + * Intel's PMDK C library. + */ +class pool { + +public: + /** + * Create a pool of non-volatile memory of a fixed `size` under + * `parent_dir`. Give it a random name. + * + * @param[in] parent_dir the parent directory where the memory pool backing + * file will be stored + * @param[in] size the maximum capacity in bytes of the pool + * @returns the newly created pool + */ + pool(const fs::path& parent_dir, std::size_t size) noexcept; + + pool(pool&& rhs) = default; + pool(const pool& other) = delete; + pool& operator=(pool&& rhs) = default; + pool& operator=(const pool& other) = delete; + + /** + * Destroy an existing pool. + */ + ~pool(); + + /** + * Returns the path to a pool's data storage in the file system. + * + * @returns If the pool was correctly created, the function returns a + * `boost::fylesystem::path` with the path to the file backing the + * pool in the file system. Otherwise, `boost::filesystem::path{}` + * is returned. + */ + fs::path path() const noexcept; + + /** + * Returns the address to a pool's data region in non-volatile memory. + * + * @returns If the pool was correctly created, the function returns a + * void pointer to the non-volatile memory region containing the + * pool's data. Otherwise, `nullptr` is returned. + */ + void* data() const noexcept; + + /** + * Returns the size of a pool's data region in non-volatile memory. + * + * @returns If the pool was correctly created, the function returns the + * size of the non-volatile memory region containing + * the pool's data. Otherwise, `0` is returned. + */ + std::size_t size() const noexcept; + + /** + * Returns whether a pool's data is actually stored in non-volatile + * memory. + * + * @returns The function returns `true` if the pool was correctly created, + * and the pool's data is stored in NVM. Otherwise, `false` is + * returned. + */ + bool is_persistent() const noexcept; + + /** + * + * Check whether a pool is valid. + * + * @returns `true` if the pool was correctly created. Otherwise it + * returns `false`. + */ + explicit operator bool() const noexcept; + + /** + * + * Check whether a pool is invalid. + * + * @returns `true` if the pool was not correctly created. Otherwise it + * returns `false`. + */ + bool operator!() const noexcept; + + /** + * + * Check whether a pool is valid. + * + * @returns `true` if the pool was correctly created. Otherwise it + * returns `false`. + */ + bool valid() const noexcept; + +private: + /// Logger instance + std::shared_ptr log_; + + /// Path to the pool file in the file system + fs::path path_; + + /// Address of the pool's non-volatile memory region + void* data_ = nullptr; + + /// Size of the pool's non-volatile memory region + std::size_t size_ = 0; + + /// Flag set if the pool file is actually stored in non-volatile memory + bool is_persistent_ = false; + + /// Flag set if the pool was created correctly + bool is_valid_ = false; +}; + +} // namespace pmdk + +#endif // GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP diff --git a/src/daemon/backend/data/CMakeLists.txt b/src/daemon/backend/data/CMakeLists.txt index 9535714be..033bb4eb4 100644 --- a/src/daemon/backend/data/CMakeLists.txt +++ b/src/daemon/backend/data/CMakeLists.txt @@ -1,3 +1,6 @@ +# PMDK backend +add_subdirectory(pmdk) + add_library(storage STATIC) target_sources(storage @@ -16,9 +19,11 @@ target_link_libraries(storage PRIVATE spdlog Boost::filesystem + pmdk_storage -ldl ) #target_include_directories(storage # PRIVATE # ) + diff --git a/src/daemon/backend/data/pmdk/CMakeLists.txt b/src/daemon/backend/data/pmdk/CMakeLists.txt new file mode 100644 index 000000000..657ee98b3 --- /dev/null +++ b/src/daemon/backend/data/pmdk/CMakeLists.txt @@ -0,0 +1,29 @@ +## +# Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain +# Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany +# +# This software was partially supported by the +# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). +# +# This software was partially supported by the +# ADA-FS project under the SPPEXA project funded by the DFG. +# +# SPDX-License-Identifier: MIT +## + +add_library(pmdk_storage + STATIC +) + +target_sources(pmdk_storage + PRIVATE + pool.cpp + PUBLIC + ${INCLUDE_DIR}/daemon/backend/data/pmdk/pool.hpp +) + +target_link_libraries(pmdk_storage + PUBLIC + PMDK::pmem + spdlog +) diff --git a/src/daemon/backend/data/pmdk/pool.cpp b/src/daemon/backend/data/pmdk/pool.cpp new file mode 100644 index 000000000..d78236c0c --- /dev/null +++ b/src/daemon/backend/data/pmdk/pool.cpp @@ -0,0 +1,217 @@ +/* + Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include +#include + +#include +#include + +namespace fs = boost::filesystem; + +namespace { + +/** + * Generate a random filename for a non-volatile memory pool using the Mersenne + * Twister PRNG. Note that the function does not verify whether the path + * returned actually exists or can be created. Neither does it verifies that + * `subdir` exists or that the user actually has permissions to create + * + * @param[in] subdir an optional parent directory to prepend to the generated + * path (Default: "") + * @returns a randomly generated path + */ +fs::path +generate_pool_path(const fs::path& subdir = "") { + + static boost::mt19937 rng; + using RngType = decltype(rng); + + const auto uuid = boost::uuids::basic_random_generator(rng)(); + + return subdir / boost::uuids::to_string(uuid); +} + +} // namespace + +namespace pmdk { + +/** + * Create a pool of non-volatile memory of a fixed `size` under + * `parent_dir`. Give it a random name. + * + * @param[in] parent_dir the parent directory where the memory pool backing + * file will be stored + * @param[in] size the maximum capacity in bytes of the pool + * @returns the newly created pool + * + * @warning The pool construction may fail for a number of reasons, but + * the constructor will not throw (though the error itself will be logged). + * Boolean operator overloads are provided so that it is simple to check + * if a pool has been correctly constructed: + * + * .. code-block:: cpp + * + * pool p{"/foo/bar", 42000}; + * + * if(!p) { + * abort("pool is invalid!") + * } + */ +pool::pool(const fs::path& parent_dir, std::size_t size) noexcept { + + // get logger instance and set it for data module and chunk storage + auto log_ = spdlog::get(GKFS_DATA_MOD->LOGGER_NAME); + assert(log_); + + if(!fs::exists(parent_dir)) { + log_->error("Error creating PMDK pool: parent directory {} " + "does not exist", parent_dir.string()); + return; + } + + if(size <= 0) { + log_->error("Error creating PMDK pool: invalid pool size {}", size); + return; + } + + fs::path pool_path = ::generate_pool_path(parent_dir); + void* pool_address = nullptr; + std::size_t pool_length = 0; + int is_pmem = 0; + + // if the pool already exists in the host file system, it might be + // a stale file or we might have a collision. Either way, abort the + // pool creation. + if(fs::exists(pool_path)) { + log_->warn("PMDK pool file {} already exists (possible collision or " + "stale file)", pool_path.string()); + return; + + } + + pool_address = ::pmem_map_file(pool_path.c_str(), size, + PMEM_FILE_CREATE | PMEM_FILE_EXCL | PMEM_FILE_SPARSE, + 0666, &pool_length, &is_pmem); + + if(pool_address == nullptr) { + log_->critical("Error creating PMDK pool file {}: {}", + pool_path.string(), ::strerror(errno)); + return; + } + + path_ = pool_path; + data_ = pool_address; + size_ = pool_length; + is_persistent_ = is_pmem; + is_valid_ = true; +} + +/** + * Destroy an existing pool. + */ +pool::~pool() { + if(data_ != nullptr) { + ::pmem_unmap(data_, size_); + } +} + +/** + * Returns the path to a pool's data storage in the file system. + * + * @returns If the pool was correctly created, the function returns a + * `boost::fylesystem::path` with the path to the file backing the + * pool in the file system. Otherwise, `boost::filesystem::path{}` + * is returned. + */ +fs::path +pool::path() const noexcept { + return path_; +} + +/** + * Returns the address to a pool's data region in non-volatile memory. + * + * @returns If the pool was correctly created, the function returns a + * void pointer to the non-volatile memory region containing the + * pool's data. Otherwise, `nullptr` is returned. + */ +void* +pool::data() const noexcept { + return data_; +} + +/** + * Returns the size of a pool's data region in non-volatile memory. + * + * @returns If the pool was correctly created, the function returns the + * size of the non-volatile memory region containing + * the pool's data. Otherwise, `0` is returned. + */ +std::size_t +pool::size() const noexcept { + return size_; +} + +/** + * Returns whether a pool's data is actually stored in non-volatile + * memory. + * + * @returns The function returns `true` if the pool was correctly created, + * and the pool's data is stored in NVM. Otherwise, `false` is + * returned. + */ +bool +pool::is_persistent() const noexcept { + return is_persistent_; +} + +/** + * + * Check whether a pool is valid. + * + * @returns `true` if the pool was correctly created. Otherwise it + * returns `false`. + */ +pool::operator bool() const noexcept { + return valid(); +} + +/** + * + * Check whether a pool is invalid. + * + * @returns `true` if the pool was not correctly created. Otherwise it + * returns `false`. + */ +bool +pool::operator!() const noexcept { + return !valid(); +} + +/** + * + * Check whether a pool is valid. + * + * @returns `true` if the pool was correctly created. Otherwise it + * returns `false`. + */ +bool +pool::valid() const noexcept { + return is_valid_; +} + +} // namespace pmdk diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 08a6f139e..226876d71 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -34,11 +34,14 @@ target_link_libraries(catch2_main add_executable(tests test_example_00.cpp test_example_01.cpp + test_storage_pmdk.cpp ) target_link_libraries(tests catch2_main fmt::fmt + pmdk_storage + Boost::filesystem ) # Catch2's contrib folder includes some helper functions diff --git a/tests/unit/test_storage_pmdk.cpp b/tests/unit/test_storage_pmdk.cpp new file mode 100644 index 000000000..d1e13eece --- /dev/null +++ b/tests/unit/test_storage_pmdk.cpp @@ -0,0 +1,175 @@ +/* + Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain + Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany + + This software was partially supported by the + EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). + + This software was partially supported by the + ADA-FS project under the SPPEXA project funded by the DFG. + + SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include + +namespace fs = boost::filesystem; + + +// FIXME: temporary solution to have correct loggers for tests +#include + +#include +#include + + +namespace { + +void +patch_gkfs_loggers(const std::vector& loggers_name, + spdlog::level::level_enum level, const std::string& path) { + + /* Create common sink */ + auto file_sink = std::make_shared(path); + + /* Create and configure loggers */ + auto loggers = std::list>(); + for (const auto& name: loggers_name) { + + if(spdlog::get(name)) { + continue; + } + + auto logger = std::make_shared(name, file_sink); + logger->flush_on(spdlog::level::trace); + loggers.push_back(logger); + } + + /* register loggers */ + for (const auto& logger: loggers) { + spdlog::register_logger(logger); + } + + // set logger format + spdlog::set_pattern("[%C-%m-%d %H:%M:%S.%f] %P [%L][%n] %v"); + + spdlog::set_level(level); +} + +} // namespace + +// end of temporary solution + +namespace { + +fs::path +create_temporary_directory() { + auto tmpdir = fs::temp_directory_path() / fs::unique_path(); + + boost::system::error_code ec; + + if(!fs::create_directory(tmpdir, ec)) { + throw std::runtime_error(ec.message()); + } + + return tmpdir; +} + +} // namespace + + +SCENARIO( "PMDK pools can be created", "[pmdk_storage_pool]" ) { + + + auto logger_names = std::vector{ + "main", + "MetadataDB", + "DataModule", + }; + + ::patch_gkfs_loggers(logger_names, spdlog::level::debug, "/dev/stdout"); + + GIVEN( "A valid parent directory " ) { + + WHEN( "Size is a positive integer" ) { + + std::size_t pool_size = 420; + auto tmpdir = create_temporary_directory(); + + pmdk::pool p(tmpdir, pool_size); + + THEN( "The pool object is valid " ) { + REQUIRE(p); + REQUIRE(p.valid()); + REQUIRE(p.size() == pool_size); + REQUIRE(p.data() != nullptr); + } + + AND_THEN( "The mapping file exists and has the correct size" ) { + REQUIRE(fs::exists(p.path())); + REQUIRE(fs::file_size(p.path()) == pool_size); + } + } + + WHEN( "Size is zero" ) { + + auto tmpdir = create_temporary_directory(); + + pmdk::pool p(tmpdir, 0); + + THEN( "The pool object is invalid " ) { + REQUIRE(!p); + REQUIRE(!p.valid()); + + AND_THEN( "Internal members are default initialized" ) { + REQUIRE(p.path().empty()); + REQUIRE(p.data() == nullptr); + REQUIRE(p.size() == 0); + } + } + } + + WHEN( "Size is negative" ) { + + auto tmpdir = create_temporary_directory(); + + pmdk::pool p(tmpdir, -1); + + THEN( "The pool object is invalid " ) { + REQUIRE(!p); + REQUIRE(!p.valid()); + + AND_THEN( "Internal members are default initialized" ) { + REQUIRE(p.path().empty()); + REQUIRE(p.data() == nullptr); + REQUIRE(p.size() == 0); + } + } + } + } + + GIVEN( "An invalid parent directory " ) { + + WHEN( "Parent directory does not exist" ) { + + std::size_t pool_size = 420; + auto tmpdir = create_temporary_directory(); + + pmdk::pool p("/foo/bar/", pool_size); + + THEN( "The pool object is invalid " ) { + REQUIRE(!p); + REQUIRE(!p.valid()); + + AND_THEN( "Internal members are default initialized" ) { + REQUIRE(p.path().empty()); + REQUIRE(p.data() == nullptr); + REQUIRE(p.size() == 0); + } + } + } + } +} -- GitLab