Last active
March 5, 2023 06:05
-
-
Save scivision/dd0e7aa18ba1397b0274c82603e4650c to your computer and use it in GitHub Desktop.
Use h5fortran via ExternalProject
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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