Skip to content

Instantly share code, notes, and snippets.

@scivision
Last active March 5, 2023 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scivision/dd0e7aa18ba1397b0274c82603e4650c to your computer and use it in GitHub Desktop.
Save scivision/dd0e7aa18ba1397b0274c82603e4650c to your computer and use it in GitHub Desktop.
Use h5fortran via ExternalProject
cmake_minimum_required(VERSION 3.19...3.26)
project(H5fortran_example LANGUAGES C Fortran)
enable_testing()
include(GNUInstallDirs)
option(h5fortran_BUILD_TESTING "h5fortran internal tests")
set(h5fortran_VERSION "v4.10.2")
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_TLS_VERIFY true)
set_directory_properties(PROPERTIES EP_UPDATE_DISCONNECTED true)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
# will not take effect without FORCE
# CMAKE_BINARY_DIR in case it's used from FetchContent
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR} CACHE PATH "Install top-level directory" FORCE)
endif()
# --- build h5fortran (requires HDF5 library)
include(h5fortran.cmake)
# Example main program using h5fortran
add_executable(demo main.f90)
target_link_libraries(demo PRIVATE h5fortran::h5fortran)
add_test(NAME DemoH5fortran COMMAND demo)
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindHDF5
---------
by Michael Hirsch www.scivision.dev
Finds HDF5 library for C, CXX, Fortran. Serial or parallel HDF5.
Environment variable ``HDF5MPI_ROOT`` or CMake variable HDF5MPI_ROOT can
specify the location of the HDF5-MPI parallel library.
Result Variables
^^^^^^^^^^^^^^^^
``HDF5_FOUND``
HDF5 libraries were found
``HDF5_INCLUDE_DIRS``
HDF5 include directory
``HDF5_LIBRARIES``
HDF5 library files
``HDF5_<lang>_COMPILER_EXECUTABLE``
wrapper compiler for HDF5
``HDF5_HAVE_PARALLEL``
HDF5 links the MPI library (thus user program must link MPI as well)
Components
==========
``C``
C is normally available for all HDF5 library installs
``CXX``
C++ is an optional feature that not all HDF5 library installs are built with
``Fortran``
Fortran is an optional feature that not all HDF5 library installs are built with
``parallel``
checks that the optional MPI parallel HDF5 layer is enabled. NOTE: if HDF5_parallel_FOUND is true,
the user program MUST link MPI::MPI_C and/or MPI::MPI_Fortran.
``HL``
always implied and silently accepted to keep compatibility with factory FindHDF5.cmake
Targets
^^^^^^^
``HDF5::HDF5``
HDF5 Imported Target
#]=======================================================================]
include(CheckSymbolExists)
include(CheckCSourceCompiles)
include(CheckFortranSourceCompiles)
function(get_flags exec outvar)
execute_process(COMMAND ${exec} -show
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE ret
RESULT_VARIABLE code
TIMEOUT 10
ERROR_QUIET
)
if(code EQUAL 0)
set(${outvar} ${ret} PARENT_SCOPE)
endif()
endfunction(get_flags)
function(pop_flag raw flag outvar)
# this gives the argument to flags to get their paths like -I or -l or -L
set(_v)
string(REGEX MATCHALL "(^| )${flag} *([^\" ]+|\"[^\"]+\")" _vars "${raw}")
foreach(_p IN LISTS _vars)
string(REGEX REPLACE "(^| )${flag} *" "" _p "${_p}")
list(APPEND _v "${_p}")
endforeach()
set(${outvar} ${_v} PARENT_SCOPE)
endfunction(pop_flag)
macro(find_mpi)
# non-cache set by FindMPI are not visible outside function -- need macro just to see within that function
set(mpi_comp C)
if(Fortran IN_LIST HDF5_FIND_COMPONENTS)
list(APPEND mpi_comp Fortran)
endif()
if(HDF5_FIND_REQUIRED)
find_package(MPI COMPONENTS ${mpi_comp} REQUIRED)
else()
find_package(MPI COMPONENTS ${mpi_comp})
endif()
endmacro(find_mpi)
macro(detect_config)
set(CMAKE_REQUIRED_INCLUDES ${HDF5_C_INCLUDE_DIR})
find_file(h5_conf
NAMES H5pubconf.h H5pubconf-64.h
HINTS ${HDF5_C_INCLUDE_DIR}
NO_DEFAULT_PATH
)
if(NOT h5_conf)
set(HDF5_C_FOUND false)
return()
endif()
# check HDF5 features that require link of external libraries.
check_symbol_exists(H5_HAVE_FILTER_SZIP ${h5_conf} hdf5_have_szip)
check_symbol_exists(H5_HAVE_FILTER_DEFLATE ${h5_conf} hdf5_have_zlib)
# Always check for HDF5 MPI support because HDF5 link fails if MPI is linked into HDF5.
check_symbol_exists(H5_HAVE_PARALLEL ${h5_conf} HDF5_HAVE_PARALLEL)
set(HDF5_parallel_FOUND false)
if(HDF5_HAVE_PARALLEL)
find_mpi()
if(NOT MPI_FOUND)
return()
endif()
set(HDF5_parallel_FOUND true)
endif()
# get version
# from CMake/Modules/FindHDF5.cmake
file(STRINGS ${h5_conf} _def
REGEX "^[ \t]*#[ \t]*define[ \t]+H5_VERSION[ \t]+" )
if("${_def}" MATCHES
"H5_VERSION[ \t]+\"([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?\"" )
set(HDF5_VERSION "${CMAKE_MATCH_1}" )
if(CMAKE_MATCH_3)
set(HDF5_VERSION ${HDF5_VERSION}.${CMAKE_MATCH_3})
endif()
endif()
# avoid picking up incompatible zlib over the desired zlib
if(CMAKE_VERSION VERSION_LESS 3.20)
get_filename_component(zlib_dir ${HDF5_C_INCLUDE_DIR} DIRECTORY)
else()
cmake_path(GET HDF5_C_INCLUDE_DIR PARENT_PATH zlib_dir)
endif()
if(NOT ZLIB_ROOT)
set(ZLIB_ROOT "${HDF5_ROOT};${zlib_dir}")
endif()
if(hdf5_have_zlib)
if(HDF5_FIND_REQUIRED)
find_package(ZLIB REQUIRED)
else()
find_package(ZLIB)
endif()
if(NOT ZLIB_FOUND)
return()
endif()
if(hdf5_have_szip)
# Szip even though not used by default.
# If system HDF5 dynamically links libhdf5 with szip, our builds will fail if we don't also link szip.
# however, we don't require SZIP for this case as other HDF5 libraries may statically link SZIP.
find_library(SZIP_LIBRARY
NAMES szip sz
NAMES_PER_DIR
HINTS ${SZIP_ROOT} ${ZLIB_ROOT}
DOC "SZIP API"
)
find_path(SZIP_INCLUDE_DIR
NAMES szlib.h
HINTS ${SZIP_ROOT} ${ZLIB_ROOT}
DOC "SZIP header"
)
if(NOT SZIP_LIBRARY AND SZIP_INCLUDE_DIR)
return()
endif()
list(APPEND CMAKE_REQUIRED_INCLUDES ${SZIP_INCLUDE_DIR})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${SZIP_LIBRARY})
endif()
list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${ZLIB_LIBRARIES})
endif()
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS})
find_package(Threads)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
if(UNIX)
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
endif()
endmacro(detect_config)
function(find_hdf5_fortran)
# NOTE: the "lib*" are for Windows Intel compiler, even for self-built HDF5.
# CMake won't look for lib prefix automatically.
if(parallel IN_LIST HDF5_FIND_COMPONENTS AND NOT HDF5_parallel_FOUND)
# this avoids expensive Fortran find when MPI isn't linked properly
return()
endif()
hdf5_fortran_wrap(hdf5_lib_dirs hdf5_inc_dirs)
if(MSVC)
set(CMAKE_FIND_LIBRARY_PREFIXES lib)
endif()
set(_names hdf5_fortran)
set(_hl_names hdf5_hl_fortran hdf5hl_fortran)
set(_hl_stub_names hdf5_hl_f90cstub)
set(_stub_names hdf5_f90cstub)
# distro names (Ubuntu)
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
list(APPEND _names hdf5_openmpi_fortran hdf5_mpich_fortran)
list(APPEND _hl_names hdf5_openmpihl_fortran hdf5_mpichhl_fortran)
else()
list(APPEND _names hdf5_serial_fortran)
list(APPEND _hl_names hdf5_serialhl_fortran)
endif()
# Debug names
if(MSVC)
list(APPEND _names hdf5_fortran_D)
list(APPEND _hl_names hdf5_hl_fortran_D)
list(APPEND _hl_stub_names hdf5_hl_f90cstub_D)
list(APPEND _stub_names hdf5_f90cstub_D)
else()
list(APPEND _names hdf5_fortran_debug)
list(APPEND _hl_names hdf5_hl_fortran_debug)
list(APPEND _hl_stub_names hdf5_hl_f90cstub_debug)
list(APPEND _stub_names hdf5_f90cstub_debug)
endif()
find_library(HDF5_Fortran_LIBRARY
NAMES ${_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "HDF5 Fortran API"
)
find_library(HDF5_Fortran_HL_LIBRARY
NAMES ${_hl_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "HDF5 Fortran HL high-level API"
)
# not all platforms have this stub
find_library(HDF5_Fortran_HL_stub
NAMES ${_hl_stub_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "Fortran C HL interface, not all HDF5 implementations have/need this"
)
find_library(HDF5_Fortran_stub
NAMES ${_stub_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "Fortran C interface, not all HDF5 implementations have/need this"
)
set(HDF5_Fortran_LIBRARIES ${HDF5_Fortran_HL_LIBRARY} ${HDF5_Fortran_LIBRARY})
if(HDF5_Fortran_HL_stub AND HDF5_Fortran_stub)
list(APPEND HDF5_Fortran_LIBRARIES ${HDF5_Fortran_HL_stub} ${HDF5_Fortran_stub})
endif()
if(HDF5_ROOT)
find_path(HDF5_Fortran_INCLUDE_DIR
NAMES hdf5.mod
NO_DEFAULT_PATH
HINTS ${HDF5_C_INCLUDE_DIR} ${HDF5_ROOT}
DOC "HDF5 Fortran module path"
)
else()
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
# HDF5-MPI system library presents a unique challenge, as when non-MPI HDF5 is
# also installed, which is typically necessary for other system libraries, the
# HDF5-MPI compiler wrapper often includes that wrong non-MPI include dir first.
# The most general approach seemed to be the following:
# search in a for loop and do a link check.
if(NOT HDF5_Fortran_INCLUDE_DIR)
foreach(i IN LISTS HDF5_C_INCLUDE_DIR hdf5_inc_dirs)
find_path(HDF5_Fortran_INCLUDE_DIR
NAMES hdf5.mod
NO_DEFAULT_PATH
HINTS ${i}
DOC "HDF5 Fortran module path"
)
message(VERBOSE "FindHDF5: trying hdf5.mod in ${i} - got: ${HDF5_Fortran_INCLUDE_DIR}")
if(HDF5_Fortran_INCLUDE_DIR)
check_fortran_links()
if(HDF5_Fortran_links)
break()
else()
unset(HDF5_Fortran_INCLUDE_DIR CACHE)
unset(HDF5_Fortran_links CACHE)
endif()
endif()
endforeach()
endif()
if(NOT HDF5_Fortran_INCLUDE_DIR)
# last resort, might give incompatible non-MPI hdf5.mod
find_path(HDF5_Fortran_INCLUDE_DIR
NAMES hdf5.mod
HINTS ${HDF5_C_INCLUDE_DIR} ${hdf5_inc_dirs}
PATHS ${hdf5_binpref}
PATH_SUFFIXES ${hdf5_msuf}
DOC "HDF5 Fortran module path"
)
endif()
else()
find_path(HDF5_Fortran_INCLUDE_DIR
NAMES hdf5.mod
HINTS ${HDF5_C_INCLUDE_DIR} ${hdf5_inc_dirs}
PATHS ${hdf5_binpref}
PATH_SUFFIXES ${hdf5_msuf}
DOC "HDF5 Fortran module path"
)
endif()
endif()
if(HDF5_Fortran_LIBRARY AND HDF5_Fortran_HL_LIBRARY AND HDF5_Fortran_INCLUDE_DIR)
set(HDF5_Fortran_LIBRARIES ${HDF5_Fortran_LIBRARIES} PARENT_SCOPE)
set(HDF5_Fortran_FOUND true PARENT_SCOPE)
set(HDF5_HL_FOUND true PARENT_SCOPE)
endif()
endfunction(find_hdf5_fortran)
function(find_hdf5_cxx)
hdf5_cxx_wrap(hdf5_lib_dirs hdf5_inc_dirs)
if(MSVC)
set(CMAKE_FIND_LIBRARY_PREFIXES lib)
endif()
set(_names hdf5_cpp)
set(_hl_names hdf5_hl_cpp)
# distro names (Ubuntu)
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
list(APPEND _names hdf5_openmpi_cpp hdf5_mpich_cpp)
list(APPEND _hl_names hdf5_openmpi_hl_cpp hdf5_mpich_hl_cpp)
else()
list(APPEND _names hdf5_serial_cpp)
list(APPEND _hl_names hdf5_serial_hl_cpp)
endif()
# Debug names
if(MSVC)
list(APPEND _names hdf5_cpp_D)
list(APPEND _hl_names hdf5_hl_cpp_D)
else()
list(APPEND _names hdf5_cpp_debug)
list(APPEND _hl_names hdf5_hl_cpp_debug)
endif()
find_library(HDF5_CXX_LIBRARY
NAMES ${_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "HDF5 C++ API"
)
find_library(HDF5_CXX_HL_LIBRARY
NAMES ${_hl_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "HDF5 C++ high-level API"
)
find_path(HDF5_CXX_INCLUDE_DIR
NAMES hdf5.h
HINTS ${HDF5_C_INCLUDE_DIR} ${HDF5_ROOT} ${hdf5_inc_dirs}
PATH_SUFFIXES ${hdf5_isuf}
DOC "HDF5 C header"
)
if(HDF5_CXX_LIBRARY AND HDF5_CXX_HL_LIBRARY AND HDF5_CXX_INCLUDE_DIR)
set(HDF5_CXX_LIBRARIES ${HDF5_CXX_HL_LIBRARY} ${HDF5_CXX_LIBRARY} PARENT_SCOPE)
set(HDF5_CXX_FOUND true PARENT_SCOPE)
set(HDF5_HL_FOUND true PARENT_SCOPE)
endif()
endfunction(find_hdf5_cxx)
function(find_hdf5_c)
hdf5_c_wrap(hdf5_lib_dirs hdf5_inc_dirs)
if(MSVC)
set(CMAKE_FIND_LIBRARY_PREFIXES lib)
endif()
set(_names hdf5)
set(_hl_names hdf5_hl)
# distro names (Ubuntu)
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
list(APPEND _names hdf5_openmpi hdf5_mpich)
list(APPEND _hl_names hdf5_openmpi_hl hdf5_mpich_hl)
else()
list(APPEND _names hdf5_serial)
list(APPEND _hl_names hdf5_serial_hl)
endif()
# debug names
if(MSVC)
list(APPEND _names hdf5_D)
list(APPEND _hl_names hdf5_hl_D)
else()
list(APPEND _names hdf5_debug)
list(APPEND _hl_names hdf5_hl_debug)
endif()
# MUST have HDF5_ROOT in HINTS here since it was set in this script
find_library(HDF5_C_LIBRARY
NAMES ${_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "HDF5 C library (necessary for all languages)"
)
find_library(HDF5_C_HL_LIBRARY
NAMES ${_hl_names}
HINTS ${HDF5_ROOT} ${hdf5_lib_dirs}
PATH_SUFFIXES ${hdf5_lsuf}
NAMES_PER_DIR
DOC "HDF5 C high level interface"
)
find_path(HDF5_C_INCLUDE_DIR
NAMES hdf5.h
HINTS ${HDF5_ROOT} ${hdf5_inc_dirs}
PATH_SUFFIXES ${hdf5_isuf}
DOC "HDF5 C header"
)
if(HDF5_C_HL_LIBRARY AND HDF5_C_LIBRARY AND HDF5_C_INCLUDE_DIR)
set(HDF5_C_LIBRARIES ${HDF5_C_HL_LIBRARY} ${HDF5_C_LIBRARY} PARENT_SCOPE)
set(HDF5_C_FOUND true PARENT_SCOPE)
set(HDF5_HL_FOUND true PARENT_SCOPE)
endif()
endfunction(find_hdf5_c)
function(hdf5_fortran_wrap lib_var inc_var)
set(lib_dirs)
set(inc_dirs)
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
set(wrapper_names h5pfc h5pfc.openmpi h5pfc.mpich)
else()
set(wrapper_names h5fc)
endif()
if(HDF5_ROOT)
find_program(HDF5_Fortran_COMPILER_EXECUTABLE
NAMES ${wrapper_names}
NAMES_PER_DIR
NO_DEFAULT_PATH
HINTS ${HDF5_ROOT}
PATH_SUFFIXES ${hdf5_binsuf}
)
else()
find_program(HDF5_Fortran_COMPILER_EXECUTABLE
NAMES ${wrapper_names}
NAMES_PER_DIR
PATHS ${hdf5_binpref}
PATH_SUFFIXES ${hdf5_binsuf}
)
endif()
if(NOT HDF5_Fortran_COMPILER_EXECUTABLE)
return()
endif()
get_flags(${HDF5_Fortran_COMPILER_EXECUTABLE} f_raw)
if(f_raw)
pop_flag(${f_raw} -L lib_dirs)
pop_flag(${f_raw} -I inc_dirs)
if(NOT inc_dirs AND parallel IN_LIST HDF5_FIND_COMPONENTS)
get_flags(${MPI_Fortran_COMPILER} f_raw)
if(f_raw)
pop_flag(${f_raw} -I inc_dirs)
endif(f_raw)
endif()
endif(f_raw)
if(inc_dirs)
set(${inc_var} ${inc_dirs} PARENT_SCOPE)
endif()
if(lib_dirs)
set(${lib_var} ${lib_dirs} PARENT_SCOPE)
endif()
endfunction(hdf5_fortran_wrap)
function(hdf5_cxx_wrap lib_var inc_var)
set(lib_dirs)
set(inc_dirs)
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
set(wrapper_names h5c++.openmpi h5c++.mpich)
else()
set(wrapper_names h5c++)
endif()
if(HDF5_ROOT)
find_program(HDF5_CXX_COMPILER_EXECUTABLE
NAMES ${wrapper_names}
NAMES_PER_DIR
NO_DEFAULT_PATH
HINTS ${HDF5_ROOT}
PATH_SUFFIXES ${hdf5_binsuf}
)
else()
find_program(HDF5_CXX_COMPILER_EXECUTABLE
NAMES ${wrapper_names}
NAMES_PER_DIR
PATHS ${hdf5_binpref}
PATH_SUFFIXES ${hdf5_binsuf}
)
endif()
if(NOT HDF5_CXX_COMPILER_EXECUTABLE)
return()
endif()
get_flags(${HDF5_CXX_COMPILER_EXECUTABLE} cxx_raw)
if(cxx_raw)
pop_flag(${cxx_raw} -L lib_dirs)
pop_flag(${cxx_raw} -I inc_dirs)
endif(cxx_raw)
if(inc_dirs)
set(${inc_var} ${inc_dirs} PARENT_SCOPE)
endif()
if(lib_dirs)
set(${lib_var} ${lib_dirs} PARENT_SCOPE)
endif()
endfunction(hdf5_cxx_wrap)
function(hdf5_c_wrap lib_var inc_var)
set(lib_dirs)
set(inc_dirs)
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
set(wrapper_names h5pcc h5pcc.openmpi h5pcc.mpich)
else()
set(wrapper_names h5cc)
endif()
if(HDF5_ROOT)
find_program(HDF5_C_COMPILER_EXECUTABLE
NAMES ${wrapper_names}
NAMES_PER_DIR
NO_DEFAULT_PATH
HINTS ${HDF5_ROOT}
PATH_SUFFIXES ${hdf5_binsuf}
)
else()
find_program(HDF5_C_COMPILER_EXECUTABLE
NAMES ${wrapper_names}
NAMES_PER_DIR
PATHS ${hdf5_binpref}
PATH_SUFFIXES ${hdf5_binsuf}
)
endif()
if(NOT HDF5_C_COMPILER_EXECUTABLE)
return()
endif()
get_flags(${HDF5_C_COMPILER_EXECUTABLE} c_raw)
if(c_raw)
pop_flag(${c_raw} -L lib_dirs)
pop_flag(${c_raw} -I inc_dirs)
if(NOT inc_dirs AND parallel IN_LIST HDF5_FIND_COMPONENTS)
get_flags(${MPI_C_COMPILER} c_raw)
if(c_raw)
pop_flag(${c_raw} -I inc_dirs)
endif(c_raw)
endif()
endif(c_raw)
if(inc_dirs)
set(${inc_var} ${inc_dirs} PARENT_SCOPE)
endif()
if(lib_dirs)
set(${lib_var} ${lib_dirs} PARENT_SCOPE)
endif()
endfunction(hdf5_c_wrap)
function(check_c_links)
list(INSERT CMAKE_REQUIRED_LIBRARIES 0 ${HDF5_C_LIBRARIES})
set(CMAKE_REQUIRED_INCLUDES ${HDF5_C_INCLUDE_DIR})
if(HDF5_parallel_FOUND)
find_mpi()
list(APPEND CMAKE_REQUIRED_INCLUDES ${MPI_C_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${MPI_C_LIBRARIES})
check_symbol_exists(H5Pset_fapl_mpio hdf5.h HAVE_H5Pset_fapl_mpio)
if(NOT HAVE_H5Pset_fapl_mpio)
return()
endif()
set(src [=[
#include "hdf5.h"
#include "mpi.h"
int main(void){
MPI_Init(NULL, NULL);
hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS);
H5Pset_fapl_mpio(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL);
H5Pclose(plist_id);
MPI_Finalize();
return 0;
}
]=])
else()
set(src [=[
#include "hdf5.h"
int main(void){
hid_t f = H5Fcreate("junk.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
herr_t status = H5Fclose (f);
return 0;}
]=])
endif(HDF5_parallel_FOUND)
check_c_source_compiles("${src}" HDF5_C_links)
endfunction(check_c_links)
function(check_fortran_links)
list(INSERT CMAKE_REQUIRED_LIBRARIES 0 ${HDF5_Fortran_LIBRARIES} ${HDF5_C_LIBRARIES})
set(CMAKE_REQUIRED_INCLUDES ${HDF5_Fortran_INCLUDE_DIR} ${HDF5_C_INCLUDE_DIR})
if(HDF5_parallel_FOUND)
find_mpi()
list(APPEND CMAKE_REQUIRED_INCLUDES ${MPI_Fortran_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${MPI_Fortran_LIBRARIES})
set(src "program test
use hdf5
use mpi
implicit none
integer :: ierr, mpi_id
integer(HID_T) :: fapl, xfer_id
call mpi_init(ierr)
call h5open_f(ierr)
call h5pcreate_f(H5P_FILE_ACCESS_F, fapl, ierr)
call h5pset_fapl_mpio_f(fapl, MPI_COMM_WORLD, MPI_INFO_NULL, ierr)
call h5pcreate_f(H5P_DATASET_XFER_F, xfer_id, ierr)
call h5pset_dxpl_mpio_f(xfer_id, H5FD_MPIO_COLLECTIVE_F, ierr)
call mpi_finalize(ierr)
end program")
else()
set(src "program test_minimal
use hdf5, only : h5open_f, h5close_f
use h5lt, only : h5ltmake_dataset_f
implicit none
integer :: i
call h5open_f(i)
call h5close_f(i)
end program")
endif()
check_fortran_source_compiles(${src} HDF5_Fortran_links SRC_EXT f90)
endfunction(check_fortran_links)
function(check_hdf5_link)
if(NOT HDF5_C_FOUND)
return()
endif()
if(parallel IN_LIST HDF5_FIND_COMPONENTS AND NOT HDF5_parallel_FOUND)
return()
endif()
check_c_links()
if(NOT HDF5_C_links)
return()
endif()
if(HDF5_Fortran_FOUND)
check_fortran_links()
if(NOT HDF5_Fortran_links)
return()
endif()
endif()
set(HDF5_links true PARENT_SCOPE)
endfunction(check_hdf5_link)
# === main program
set(CMAKE_REQUIRED_LIBRARIES)
if(NOT HDF5MPI_ROOT AND DEFINED ENV{HDF5MPI_ROOT})
set(HDF5MPI_ROOT $ENV{HDF5MPI_ROOT})
endif()
if(NOT HDF5_ROOT)
if(HDF5MPI_ROOT AND parallel IN_LIST HDF5_FIND_COMPONENTS)
set(HDF5_ROOT ${HDF5MPI_ROOT})
elseif(DEFINED ENV{HDF5_ROOT})
set(HDF5_ROOT $ENV{HDF5_ROOT})
endif()
endif()
# Conda causes numerous problems with finding HDF5, so exclude from search
if(DEFINED ENV{CONDA_PREFIX})
set(h5_ignore_path
$ENV{CONDA_PREFIX}/bin $ENV{CONDA_PREFIX}/lib $ENV{CONDA_PREFIX}/include
$ENV{CONDA_PREFIX}/Library/bin $ENV{CONDA_PREFIX}/Library/lib $ENV{CONDA_PREFIX}/Library/include
)
list(APPEND CMAKE_IGNORE_PATH ${h5_ignore_path})
endif()
# --- library suffixes
set(hdf5_lsuf lib hdf5/lib) # need explicit "lib" for self-built HDF5
if(NOT HDF5_ROOT)
list(INSERT hdf5_lsuf 0 hdf5/openmpi hdf5/mpich) # Ubuntu
list(INSERT hdf5_lsuf 0 openmpi/lib mpich/lib) # CentOS
if(NOT parallel IN_LIST HDF5_FIND_COMPONENTS)
list(INSERT hdf5_lsuf 0 hdf5/serial) # Ubuntu
endif()
endif()
# --- include and modules suffixes
if(BUILD_SHARED_LIBS)
set(hdf5_isuf shared include)
set(hdf5_msuf shared include)
else()
set(hdf5_isuf static include)
set(hdf5_msuf static include)
endif()
# Ubuntu
list(INSERT hdf5_isuf 0 hdf5/openmpi hdf5/mpich)
list(INSERT hdf5_msuf 0 hdf5/openmpi hdf5/mpich)
if(NOT parallel IN_LIST HDF5_FIND_COMPONENTS)
# Ubuntu
list(INSERT hdf5_isuf 0 hdf5/serial)
list(INSERT hdf5_msuf 0 hdf5/serial)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|AMD64)")
list(APPEND hdf5_isuf openmpi-x86_64 mpich-x86_64) # CentOS
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64|arm64)")
list(APPEND hdf5_isuf openmpi-aarch64 mpich-aarch64) # CentOS
endif()
if(NOT HDF5_ROOT AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
# CentOS paths
if(parallel IN_LIST HDF5_FIND_COMPONENTS)
list(INSERT hdf5_msuf 0 gfortran/modules/openmpi gfortran/modules/mpich)
else()
list(APPEND hdf5_msuf gfortran/modules)
endif()
endif()
# --- binary prefix / suffix
set(hdf5_binpref)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(hdf5_binpref /usr/lib64)
endif()
set(hdf5_binsuf bin)
if(NOT HDF5_ROOT AND parallel IN_LIST HDF5_FIND_COMPONENTS)
# CentOS paths
list(APPEND hdf5_binsuf openmpi/bin mpich/bin)
endif()
# ----
# May not help, as we'd have to foreach() a priori names, like we already do with find_library()
# find_package(hdf5 CONFIG)
# ----
# C is always needed
find_hdf5_c()
# required libraries
if(HDF5_C_FOUND)
detect_config()
endif(HDF5_C_FOUND)
if(HDF5_C_FOUND AND CXX IN_LIST HDF5_FIND_COMPONENTS)
find_hdf5_cxx()
endif()
if(HDF5_C_FOUND AND Fortran IN_LIST HDF5_FIND_COMPONENTS)
find_hdf5_fortran()
endif()
# --- configure time checks
# these checks avoid messy, confusing errors at build time
check_hdf5_link()
set(CMAKE_REQUIRED_LIBRARIES)
set(CMAKE_REQUIRED_INCLUDES)
# pop off ignored paths so rest of script can find Python
if(DEFINED CMAKE_IGNORE_PATH)
list(REMOVE_ITEM CMAKE_IGNORE_PATH "${h5_ignore_path}")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(HDF5
REQUIRED_VARS HDF5_C_LIBRARIES HDF5_links
VERSION_VAR HDF5_VERSION
HANDLE_COMPONENTS
)
if(HDF5_FOUND)
set(HDF5_INCLUDE_DIRS ${HDF5_Fortran_INCLUDE_DIR} ${HDF5_CXX_INCLUDE_DIR} ${HDF5_C_INCLUDE_DIR})
set(HDF5_LIBRARIES ${HDF5_Fortran_LIBRARIES} ${HDF5_CXX_LIBRARIES} ${HDF5_C_LIBRARIES})
if(NOT TARGET HDF5::HDF5)
add_library(HDF5::HDF5 INTERFACE IMPORTED)
set_property(TARGET HDF5::HDF5 PROPERTY INTERFACE_LINK_LIBRARIES "${HDF5_LIBRARIES}")
set_property(TARGET HDF5::HDF5 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${HDF5_INCLUDE_DIRS}")
target_include_directories(HDF5::HDF5 INTERFACE
$<$<BOOL:${hdf5_have_szip}>:${SZIP_INCLUDE_DIR}>
)
target_link_libraries(HDF5::HDF5 INTERFACE
$<$<BOOL:${hdf5_have_zlib}>:ZLIB::ZLIB>
$<$<BOOL:${hdf5_have_szip}>:${SZIP_LIBRARY}>
${CMAKE_THREAD_LIBS_INIT}
${CMAKE_DL_LIBS}
$<$<BOOL:${UNIX}>:m>
)
endif()
endif(HDF5_FOUND)
mark_as_advanced(HDF5_Fortran_LIBRARY HDF5_Fortran_HL_LIBRARY
HDF5_C_LIBRARY HDF5_C_HL_LIBRARY
HDF5_CXX_LIBRARY HDF5_CXX_HL_LIBRARY
HDF5_C_INCLUDE_DIR HDF5_CXX_INCLUDE_DIR HDF5_Fortran_INCLUDE_DIR)
include(ExternalProject)
find_package(ZLIB REQUIRED)
find_package(HDF5 COMPONENTS C Fortran HL REQUIRED)
set(h5fortran_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/include)
if(BUILD_SHARED_LIBS)
if(WIN32)
set(h5fortran_LIBRARIES ${CMAKE_INSTALL_FULL_BINDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}h5fortran${CMAKE_SHARED_LIBRARY_SUFFIX})
else()
set(h5fortran_LIBRARIES ${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}h5fortran${CMAKE_SHARED_LIBRARY_SUFFIX})
endif()
else()
set(h5fortran_LIBRARIES ${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}h5fortran${CMAKE_STATIC_LIBRARY_SUFFIX})
endif()
set(h5fortran_cmake_args
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}
-DCMAKE_PREFIX_PATH:PATH=${CMAKE_INSTALL_PREFIX}
-DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS}
-DCMAKE_BUILD_TYPE=Release
-DBUILD_TESTING:BOOL=false
)
if(HDF5_ROOT)
list(APPEND h5fortran_cmake_args -DHDF5_ROOT:PATH=${HDF5_ROOT})
endif()
ExternalProject_Add(H5FORTRAN
GIT_REPOSITORY https://github.com/geospace-code/h5fortran.git
GIT_TAG ${h5fortran_VERSION}
GIT_SHALLOW true
CMAKE_ARGS ${h5fortran_cmake_args}
BUILD_BYPRODUCTS ${h5fortran_LIBRARIES}
INACTIVITY_TIMEOUT 15
CONFIGURE_HANDLED_BY_BUILD ON
)
file(MAKE_DIRECTORY ${h5fortran_INCLUDE_DIRS})
add_library(h5fortran::h5fortran INTERFACE IMPORTED GLOBAL)
target_include_directories(h5fortran::h5fortran INTERFACE ${h5fortran_INCLUDE_DIRS})
target_link_libraries(h5fortran::h5fortran INTERFACE ${h5fortran_LIBRARIES}
HDF5::HDF5 ZLIB::ZLIB)
# race condition for linking without this
add_dependencies(h5fortran::h5fortran H5FORTRAN)
program demo
use h5fortran, only : h5write, h5read
implicit none
integer :: x, y
x = 42
call h5write('test.h5', '/x', x)
call h5read('test.h5', '/x', y)
if (y /= x) error stop "x was not written correctly or y was not read correctly"
print *, "OK: h5write, h5read from h5fortran"
end program
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment