Skip to content

Commit

Permalink
Restructure netCDF find modules to use modern import target (#2054)
Browse files Browse the repository at this point in the history
TYPE: enhancement

KEYWORDS: netCDF, cmake, compilation

SOURCE: internal

DESCRIPTION OF CHANGES:
Problem:
The current iteration of the cmake build uses the old-style of finding
modules. This limits the usability of transitive properties as well as
the native netCDF cmake build which provide imported targets.

See
https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html#find-modules
for more information on module writing.

Solution:
Augment the output of the provided find module to supply an imported
target that fully describes the netCDF library. Additionally, in
rewriting how targets in WRF reference netCDF remove unnecessary linking
to the library. Ensure the provided import target and flags of the find
module matches the netCDF[-Fortran].cmake.in outputs verbatim thus
emulating the native netCDF build for additional robustness.

LIST OF MODIFIED FILES: 
M       CMakeLists.txt
M       cmake/modules/FindnetCDF-Fortran.cmake
M       cmake/modules/FindnetCDF.cmake
M       external/CMakeLists.txt
M       external/RSL_LITE/CMakeLists.txt
M       external/atm_ocn/CMakeLists.txt
M       external/esmf_time_f90/CMakeLists.txt
M       external/fftpack/fftpack5/CMakeLists.txt
M       external/io_adios2/CMakeLists.txt
M       external/io_esmf/CMakeLists.txt
M       external/io_grib1/CMakeLists.txt
M       external/io_grib1/MEL_grib1/CMakeLists.txt
M       external/io_grib1/WGRIB/CMakeLists.txt
M       external/io_grib1/grib1_util/CMakeLists.txt
M       external/io_grib2/bacio-1.3/CMakeLists.txt
M       external/io_grib2/g2lib/CMakeLists.txt
M       external/io_grib_share/CMakeLists.txt
M       external/io_netcdf/CMakeLists.txt
M       external/io_netcdfpar/CMakeLists.txt


RELEASE NOTE: 
Restructure netCDF find modules to use modern import target
  • Loading branch information
islas authored Oct 14, 2024
1 parent f68f0b9 commit 1e96a7e
Show file tree
Hide file tree
Showing 27 changed files with 237 additions and 212 deletions.
33 changes: 16 additions & 17 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,19 @@ endif()
find_package( netCDF REQUIRED )
find_package( netCDF-Fortran REQUIRED )

# Make use of version checking here and not in find_package for previous versions that did not use cmake
if ( ( NOT netCDF_VERSION GREATER_EQUAL "4.1.3" ) OR ( NOT netCDF-Fortran_VERSION GREATER_EQUAL "4.1.3" ) )
message( FATAL "Please make sure NETCDF versions are 4.1.3 or later. " )
# Make use of version checking here and not in find_package for WRF control allowing older versions if requested
if ( NOT ${FORCE_NETCDF_CLASSIC} )
if ( NOT netCDF_VERSION GREATER_EQUAL "4.1.3" )
set( NC4_MISSING_REASON "(version < 4.1.3)" )
elseif( NOT ${netCDF_HAS_NC4} )
set( NC4_MISSING_REASON "(not build with nc4)" )
endif()

if ( DEFINED NC4_MISSING_REASON )
message( STATUS "netCDF found does not support NC4 features ${NC4_MISSING_REASON}, forcing use of classic netcdf" )
message( STATUS " To disable this message, make sure netCDF used has nc4 capabilities or specify FORCE_NETCDF_CLASSIC" )
set( FORCE_NETCDF_CLASSIC ON CACHE BOOL "Required by netCDF found" FORCE )
endif()
endif()

find_package( pnetCDF QUIET )
Expand Down Expand Up @@ -682,7 +692,7 @@ else()
endif()

# If force classic or no nc-4 support enable classic
if ( ${FORCE_NETCDF_CLASSIC} OR ( NOT ${netCDF_NC4} ) )
if ( ${FORCE_NETCDF_CLASSIC} OR ( NOT ${netCDF_HAS_NC4} ) )
list( APPEND PROJECT_COMPILE_DEFINITIONS NETCDF_classic=1 )
endif()
if ( ${WRFIO_NCD_NO_LARGE_FILE_SUPPORT} OR ( NOT ${netCDF_LARGE_FILE_SUPPORT} ) )
Expand All @@ -691,7 +701,7 @@ endif()
# May need a check for WRFIO_ncdpar_LARGE_FILE_SUPPORT

# Now set the opposite in different defines, because why not :)
if ( ( NOT ${FORCE_NETCDF_CLASSIC} ) AND ${netCDF_NC4} )
if ( ( NOT ${FORCE_NETCDF_CLASSIC} ) AND ${netCDF_HAS_NC4} )
list( APPEND PROJECT_COMPILE_DEFINITIONS USE_NETCDF4_FEATURES=1 )
endif()
if ( ( NOT ${WRFIO_NCD_NO_LARGE_FILE_SUPPORT} ) AND ${netCDF_LARGE_FILE_SUPPORT} )
Expand Down Expand Up @@ -895,8 +905,6 @@ target_include_directories(
${PROJECT_SOURCE_DIR}/external/io_int

# Found Packages not handled through :: imported target
${netCDF_INCLUDE_DIRS}
${netCDF-Fortran_INCLUDE_DIRS}
${pnetCDF_INCLUDE_DIRS}
)

Expand Down Expand Up @@ -938,19 +946,10 @@ set_target_properties(
EXPORT_PROPERTIES Fortran_MODULE_DIRECTORY
)

# Because of the way netCDF provides its info and the way cmake auto-gens RPATH, we need to help it along
target_link_directories(
${PROJECT_NAME}_Core
PUBLIC
${netCDF_LIBRARY_DIR}
${netCDF-Fortran_LIBRARY_DIR}
)


target_link_libraries( ${PROJECT_NAME}_Core
PUBLIC
${netCDF_LIBRARIES}
${netCDF-Fortran_LIBRARIES}
netCDF::netcdff
${pnetCDF_LIBRARIES}
$<$<BOOL:${USE_MPI}>:$<TARGET_NAME_IF_EXISTS:MPI::MPI_Fortran>>
$<$<BOOL:${USE_OPENMP}>:$<TARGET_NAME_IF_EXISTS:OpenMP::OpenMP_Fortran>>
Expand Down
75 changes: 62 additions & 13 deletions cmake/modules/FindnetCDF-Fortran.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ else()
execute_process( COMMAND ${NETCDF-FORTRAN_PROGRAM} --prefix OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF-Fortran_PREFIX )
execute_process( COMMAND ${NETCDF-FORTRAN_PROGRAM} --flibs OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF-Fortran_FLIBS )
execute_process( COMMAND ${NETCDF-FORTRAN_PROGRAM} --version OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF-Fortran_VERSION_RAW )
execute_process( COMMAND ${NETCDF-FORTRAN_PROGRAM} --has-nc4 OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF-Fortran_NC4_YES )

# check for large file support
find_file( netCDF-Fortran_INCLUDE_FILE netcdf.inc ${netCDF-Fortran_INCLUDE_DIR} )
Expand All @@ -59,31 +58,81 @@ else()
string( REPLACE " " ";" netCDF-Fortran_VERSION_LIST ${netCDF-Fortran_VERSION_RAW} )
list( GET netCDF-Fortran_VERSION_LIST -1 netCDF-Fortran_VERSION )

# Convert to YES/NO - Note cannot be generator expression if you want to use it during configuration time
string( TOUPPER ${netCDF-Fortran_NC4_YES} netCDF-Fortran_NC4 )
# These do not pull all options available from nc-config out, but rather mirrors what is available from netCDFConfig.cmake.in
set(
netCDF-Fortran_QUERY_YES_OPTIONS
dap
nc2
nc4
f90
f03
)

foreach( NF_QUERY ${netCDF-Fortran_QUERY_YES_OPTIONS} )
execute_process( COMMAND ${NETCDF-FORTRAN_PROGRAM} --has-${NF_QUERY} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF-Fortran_${NF_QUERY}_LOWERCASE )
if ( NOT "${netCDF-Fortran_${NF_QUERY}_LOWERCASE}" )
# might be empty
set( netCDF-Fortran_${NF_QUERY}_LOWERCASE no )
endif()
string( TOUPPER ${NF_QUERY} NF_QUERY_UPPERCASE )
string( TOUPPER ${netCDF-Fortran_${NF_QUERY}_LOWERCASE} NF_ANSWER_UPPERCASE )
# Convert to netCDF-Fortran_HAS_* = YES/NO - Note this cannot be generator expression if you want to use it during configuration time
set( netCDF-Fortran_HAS_${NF_QUERY_UPPERCASE} ${NF_ANSWER_UPPERCASE} )
endforeach()

set( netCDF-Fortran_DEFINITIONS )
set( netCDF-Fortran_LIBRARY_DIR ${netCDF-Fortran_PREFIX}/lib )

# A bug in previous netcdf-fortran cmake builds, extract from flibs
string( REGEX MATCH "^-L([^ ]*)" netCDF-Fortran_LIBRARY_LINK_LOCATION ${netCDF-Fortran_FLIBS} )
set( netCDF-Fortran_LIBRARY_DIR ${CMAKE_MATCH_1} )

set( netCDF-Fortran_DEFINITIONS )
set( netCDF-Fortran_LIBRARIES
$<$<LINK_LANGUAGE:Fortran>:${netCDF-Fortran_FLIBS}>
)

# Because we may need this for in-situ manual preprocessing do not use genex
set( netCDF-Fortran_INCLUDE_DIRS ${netCDF-Fortran_INCLUDE_DIR} )
endif()

find_package( PkgConfig )
# Find the actual name of the library
find_library(
netCDF-Fortran_LIBRARY
netcdff
PATHS ${netCDF-Fortran_LIBRARY_DIR}
NO_DEFAULT_PATH
)
endif()

include(FindPackageHandleStandardArgs)

# handle the QUIETLY and REQUIRED arguments and set netCDF-Fortran_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(
netCDF-Fortran DEFAULT_MSG
netCDF-Fortran_INCLUDE_DIRS
netCDF-Fortran_FLIBS
netCDF-Fortran_VERSION
)
netCDF-Fortran
FOUND_VAR netCDF-Fortran_FOUND
REQUIRED_VARS
netCDF-Fortran_INCLUDE_DIRS
netCDF-Fortran_LIBRARIES
netCDF-Fortran_VERSION
VERSION_VAR netCDF-Fortran_VERSION
HANDLE_VERSION_RANGE
)

# Note that the name of the target is the target library name as specified by the netCDF cmake build,
# NOT the netCDF repository name, I've kept this consistent to the provided netCDF builds rather
# than the convention of *_<LANG> to specify multiple components. This also helps account for the
# fact that the netCDF langauge-specific projects are separate projects
if ( netCDF-Fortran_FOUND AND NOT TARGET netCDF::netcdff )
find_package( netCDF REQUIRED )

add_library( netCDF::netcdff UNKNOWN IMPORTED )
set_target_properties(
netCDF::netcdff
PROPERTIES
IMPORTED_LOCATION "${netCDF-Fortran_LIBRARY}"
IMPORTED_LINK_INTERFACE_LANGUAGES Fortran
INTERFACE_INCLUDE_DIRECTORIES "${netCDF-Fortran_INCLUDE_DIRS}"
)
target_link_libraries( netCDF::netcdff INTERFACE netCDF::netcdf )
endif()

mark_as_advanced( netCDF-Fortran_FLIBS netCDF-Fortran_PREFIX netCDF-Fortran_LIBRARY_DIR )
mark_as_advanced( netCDF-Fortran_FLIBS netCDF-Fortran_PREFIX netCDF-Fortran_LIBRARY_DIR )
158 changes: 139 additions & 19 deletions cmake/modules/FindnetCDF.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,36 @@ else()
execute_process( COMMAND ${NETCDF_PROGRAM} --prefix OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_PREFIX )
execute_process( COMMAND ${NETCDF_PROGRAM} --libs OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_CLIBS )
execute_process( COMMAND ${NETCDF_PROGRAM} --version OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_VERSION_RAW )
execute_process( COMMAND ${NETCDF_PROGRAM} --has-nc4 OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_NC4_YES )
execute_process( COMMAND ${NETCDF_PROGRAM} --has-pnetcdf OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_PNETCDF_YES )
execute_process( COMMAND ${NETCDF_PROGRAM} --has-parallel OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_PARALLEL_YES )

# These do not pull all options available from nc-config out, but rather mirrors what is available from netCDFConfig.cmake.in
set(
netCDF_QUERY_YES_OPTIONS
dap
dap2
dap4
nc2
nc4
hdf5
hdf4
pnetcdf
parallel

# These are not part of the config but used in this to provide the properly linking
szlib
zstd
)

foreach( NC_QUERY ${netCDF_QUERY_YES_OPTIONS} )
execute_process( COMMAND ${NETCDF_PROGRAM} --has-${NC_QUERY} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_${NC_QUERY}_LOWERCASE )
if ( NOT "${netCDF-Fortran_${NF_QUERY}_LOWERCASE}" )
# might be empty
set( netCDF-Fortran_${NF_QUERY}_LOWERCASE no )
endif()
string( TOUPPER ${NC_QUERY} NC_QUERY_UPPERCASE )
string( TOUPPER ${netCDF_${NC_QUERY}_LOWERCASE} NC_ANSWER_UPPERCASE )
# Convert to netCDF_HAS_* = YES/NO - Note this cannot be generator expression if you want to use it during configuration time
set( netCDF_HAS_${NC_QUERY_UPPERCASE} ${NC_ANSWER_UPPERCASE} )
endforeach()

# check for large file support
find_file( netCDF_INCLUDE_FILE netcdf.h ${netCDF_INCLUDE_DIR} )
Expand All @@ -63,33 +90,126 @@ else()
string( REPLACE " " ";" netCDF_VERSION_LIST ${netCDF_VERSION_RAW} )
list( GET netCDF_VERSION_LIST -1 netCDF_VERSION )

# Convert to YES/NO - Note cannot be generator expression if you want to use it during configuration time
string( TOUPPER ${netCDF_NC4_YES} netCDF_NC4 )
string( TOUPPER ${netCDF_PNETCDF_YES} netCDF_PNETCDF )
string( TOUPPER ${netCDF_PARALLEL_YES} netCDF_PARALLEL )

set( netCDF_DEFINITIONS )

set( netCDF_LIBRARIES
# All supported language variants will need this regardless - this may conflict with the RPATH in any
# supplemental packages so be careful to use compatible langauge versions of netCDF
$<$<OR:$<LINK_LANGUAGE:C>,$<LINK_LANGUAGE:Fortran>>:${netCDF_CLIBS}>
)
# Because we may need this for in-situ manual preprocessing do not use genex
set( netCDF_INCLUDE_DIRS ${netCDF_INCLUDE_DIR} )
endif()

find_package( PkgConfig )
# Find the actual name of the library
find_library(
netCDF_LIBRARY
netcdf
PATHS ${netCDF_LIBRARY_DIR}
NO_DEFAULT_PATH
)
if( ${netCDF_LIBRARY} MATCHES ".a$" )
set( netCDF_STATIC TRUE )
set( netCDF_SHARED FALSE )
else()
set( netCDF_STATIC FALSE )
set( netCDF_SHARED TRUE )
endif()
endif()

include(FindPackageHandleStandardArgs)

# handle the QUIETLY and REQUIRED arguments and set netCDF_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args( netCDF DEFAULT_MSG
netCDF_INCLUDE_DIRS
netCDF_LIBRARY_DIR
netCDF_CLIBS
netCDF_VERSION
)

mark_as_advanced( netCDF_CLIBS netCDF_PREFIX netCDF_LIBRARY_DIR )
find_package_handle_standard_args(
netCDF
FOUND_VAR netCDF_FOUND
REQUIRED_VARS
netCDF_INCLUDE_DIRS
netCDF_LIBRARIES
netCDF_VERSION
VERSION_VAR netCDF_VERSION
HANDLE_VERSION_RANGE
)

# Note that the name of the target is the target library name as specified by the netCDF cmake build,
# NOT the netCDF repository name, I've kept this consistent to the provided netCDF builds rather
# than the convention of *_<LANG> to specify multiple components. This also helps account for the
# fact that the netCDF langauge-specific projects are separate projects
if ( netCDF_FOUND AND NOT TARGET netCDF::netcdf )
add_library( netCDF::netcdf UNKNOWN IMPORTED )
set_target_properties(
netCDF::netcdf
PROPERTIES
IMPORTED_LOCATION "${netCDF_LIBRARY}"
IMPORTED_LINK_INTERFACE_LANGUAGES C
INTERFACE_INCLUDE_DIRECTORIES "${netCDF_INCLUDE_DIRS}"
)

# I believe this is not required as the API will wrap usage of these
# libnetcdf should provide the rpath dependency linking if not static
# This is untested! Probably missing a lot of stuff
if ( ${netCDF_STATIC} )
if ( ${netCDF_HAS_HDF4} OR ${netCDF_HAS_HDF5} )
if ( ${netCDF_HAS_PARALLEL} )
set( HDF5_PREFER_PARALLEL TRUE )
endif()

find_package( HDF5 COMPONENTS C HL REQUIRED )
target_link_libraries( netCDF::netcdf INTERFACE HDF5::HDF5 )

find_package( ZLIB REQUIRED )
target_link_libraries( netCDF::netcdf INTERFACE ZLIB::ZLIB )
endif()

# If available do find it and link in
find_package( ZLIB QUIET )
if ( ${ZLIB_FOUND} )
target_link_libraries( netCDF::netcdf INTERFACE ZLIB::ZLIB )
endif()

if ( ${netCDF_HAS_SZLIB} )
# Currently no standard way to find szlib, and netCDF does not export its module out soooo
message( WARNING "No standard way to locate szlib, will attempt to link with -lsz" )
target_link_libraries( netCDF::netcdf INTERFACE sz )
endif()

if ( ${netCDF_HAS_ZSTD} )
find_package( PkgConfig )
pkg_check_modules( PC_ZSTD QUIET zstd )
target_link_libraries( netCDF::netcdf INTERFACE ${PC_ZSTD_LINK_LIBRARIES} )
endif()

# HAS_BZ2 is not defined right now
# if ( ${netCDF_HAS_BZ2} )
find_package( BZip2 QUIET )
if ( ${BZIP2_FOUND} )
target_link_libraries( netCDF::netcdf INTERFACE BZip2::BZip2 )
endif()
# endif()

# HAS_LIBXML2 is not defined right now
find_package( LibXml2 QUIET )
if( LibXml2_FOUND )
target_link_libraries( netCDF::netcdf INTERFACE LibXml2::LibXml2 )
endif()

if ( ${netCDF_HAS_PARALLEL} )
find_package( MPI COMPONENTS C REQUIRED )
target_link_libraries( netCDF::netcdf INTERFACE MPI::MPI_C )
endif()

# Always linked
find_package( CURL REQUIRED )
find_library( MATH_LIB NAMES m )
target_link_libraries(
netCDF::netcdf
INTERFACE
${CMAKE_DL_LIBS}
CURL::libcurl
${MATH_LIB}
)
endif()

endif()


mark_as_advanced( netCDF_CLIBS netCDF_PREFIX netCDF_LIBRARY_DIR )
2 changes: 1 addition & 1 deletion external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ add_subdirectory( esmf_time_f90 )
add_subdirectory( io_netcdf )
#!TODO We should collapse all these files into #ifdefs even if they are compiled
# multiple times with different defs for the same configuration
if ( ${netCDF_PARALLEL} AND ${USE_MPI} )
if ( ${netCDF_HAS_PARALLEL} AND ${USE_MPI} )
message( STATUS "Adding [io_netcdfpar] to configuration" )
add_subdirectory( io_netcdfpar )
endif()
Expand Down
6 changes: 0 additions & 6 deletions external/RSL_LITE/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,10 @@ set_target_properties(

target_link_libraries( ${FOLDER_COMPILE_TARGET}
PRIVATE
${netCDF_LIBRARIES}
$<$<BOOL:${USE_MPI}>:$<TARGET_NAME_IF_EXISTS:MPI::MPI_Fortran>>
$<$<BOOL:${USE_OPENMP}>:$<TARGET_NAME_IF_EXISTS:OpenMP::OpenMP_Fortran>>
)

target_include_directories( ${FOLDER_COMPILE_TARGET}
PRIVATE
${netCDF_INCLUDE_DIRS}
)

install(
TARGETS ${FOLDER_COMPILE_TARGET}
EXPORT ${EXPORT_NAME}Targets
Expand Down
Loading

0 comments on commit 1e96a7e

Please sign in to comment.