CMake netCDF Compatibility with WPS (#2121)
[WRF.git] / cmake / modules / FindnetCDF.cmake
blob896acaba00d7cd8ff15c4f9eef798c48f269809b
1 # Find netcdf
2 # Eventually replace with netCDF's actual config if using that
3 # Once found this file will define:
4 #  netCDF_FOUND - System has netcdf
5 #  netCDF_INCLUDE_DIRS - The netcdf include directories
6 #  netCDF_LIBRARIES - The libraries needed to use netcdf
7 #  netCDF_DEFINITIONS - Compiler switches required for using netcdf
9 # list( REMOVE_ITEM CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} )
10 # find_package( netCDF )
11 # list( APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} )
13 # exit early if we don't even need to be here
14 if ( netCDF_FOUND )
15   return()
16 endif()
19 ###############################################################################
20 # First try to find using netCDF native cmake build
21 # TODO : Enable this when netCDF native cmake build works well as an imported package
22 # find_package( netCDF CONFIG )
23 # if ( netCDF_FOUND )
24 #   message( STATUS "Found netCDF through native cmake build" )
25 #   return()
26 # endif()
27 ###############################################################################
30 # else
31 # Use nc-config
32 find_program( 
33                 NETCDF_PROGRAM
34                 nc-config
35                 QUIET
36                 )
38 if ( ${NETCDF_PROGRAM} MATCHES "-NOTFOUND$" )
39   message( STATUS "No nc-config found" )
40 else()
41   message( STATUS "Found NETCDF_PROGRAM : ${NETCDF_PROGRAM}" )
43   execute_process( COMMAND ${NETCDF_PROGRAM} --includedir   OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_INCLUDE_DIR )
44   execute_process( COMMAND ${NETCDF_PROGRAM} --libdir       OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_LIBRARY_DIR )
45   execute_process( COMMAND ${NETCDF_PROGRAM} --prefix       OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_PREFIX )
46   execute_process( COMMAND ${NETCDF_PROGRAM} --libs         OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_CLIBS   )
47   execute_process( COMMAND ${NETCDF_PROGRAM} --version      OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_VERSION_RAW )
49   # These do not pull all options available from nc-config out, but rather mirrors what is available from netCDFConfig.cmake.in
50   set(
51       netCDF_QUERY_YES_OPTIONS
52       dap
53       dap2
54       dap4
55       nc2
56       nc4
57       hdf5
58       hdf4
59       pnetcdf
60       parallel
62       # These are not part of the config but used in this to provide the properly linking
63       szlib
64       zstd
65       )
67   foreach( NC_QUERY ${netCDF_QUERY_YES_OPTIONS} )
68     execute_process( COMMAND ${NETCDF_PROGRAM} --has-${NC_QUERY} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE netCDF_${NC_QUERY}_LOWERCASE )
69     if ( NOT "${netCDF-Fortran_${NF_QUERY}_LOWERCASE}" )
70       # might be empty
71       set( netCDF-Fortran_${NF_QUERY}_LOWERCASE no )
72     endif()
73     string( TOUPPER ${NC_QUERY}                     NC_QUERY_UPPERCASE )
74     string( TOUPPER ${netCDF_${NC_QUERY}_LOWERCASE} NC_ANSWER_UPPERCASE )
75     # Convert to netCDF_HAS_* = YES/NO - Note this cannot be generator expression if you want to use it during configuration time
76     set( netCDF_HAS_${NC_QUERY_UPPERCASE} ${NC_ANSWER_UPPERCASE} )
77   endforeach()
79   # check for large file support
80   find_file( netCDF_INCLUDE_FILE netcdf.h ${netCDF_INCLUDE_DIR} )
81   file( READ ${netCDF_INCLUDE_FILE} netCDF_INCLUDE_FILE_STR )
82   string( FIND "${netCDF_INCLUDE_FILE_STR}" "NC_FORMAT_64BIT_DATA" netCDF_LARGE_FILE_SUPPORT_FOUND )
83   if ( ${netCDF_LARGE_FILE_SUPPORT_FOUND} EQUAL -1 )
84     set( netCDF_LARGE_FILE_SUPPORT "NO" )
85   else()
86     set( netCDF_LARGE_FILE_SUPPORT "YES" )
87   endif()
89   # Sanitize version
90   string( REPLACE " " ";" netCDF_VERSION_LIST ${netCDF_VERSION_RAW} )
91   list( GET netCDF_VERSION_LIST -1 netCDF_VERSION )
93   set( netCDF_DEFINITIONS  )
94   set( netCDF_LIBRARIES
95       # All supported language variants will need this regardless - this may conflict with the RPATH in any
96       # supplemental packages so be careful to use compatible langauge versions of netCDF
97       $<$<OR:$<LINK_LANGUAGE:C>,$<LINK_LANGUAGE:Fortran>>:${netCDF_CLIBS}>
98       )
99   # Because we may need this for in-situ manual preprocessing do not use genex
100   set( netCDF_INCLUDE_DIRS ${netCDF_INCLUDE_DIR} )
102   # Find the actual name of the library
103   find_library(
104                 netCDF_LIBRARY
105                 netcdf
106                 PATHS ${netCDF_LIBRARY_DIR}
107                 NO_DEFAULT_PATH
108                 )
109   if( ${netCDF_LIBRARY} MATCHES ".a$" )
110     set( netCDF_STATIC TRUE  )
111     set( netCDF_SHARED FALSE )
112   else()
113     set( netCDF_STATIC FALSE  )
114     set( netCDF_SHARED TRUE )
115   endif()
116 endif()
118 include(FindPackageHandleStandardArgs)
120 # handle the QUIETLY and REQUIRED arguments and set netCDF_FOUND to TRUE
121 # if all listed variables are TRUE
122 find_package_handle_standard_args(
123                                   netCDF
124                                   FOUND_VAR netCDF_FOUND
125                                   REQUIRED_VARS
126                                     netCDF_INCLUDE_DIRS
127                                     netCDF_LIBRARIES
128                                     netCDF_VERSION
129                                   VERSION_VAR netCDF_VERSION
130                                   HANDLE_VERSION_RANGE
131                                 )
133 # Note that the name of the target is the target library name as specified by the netCDF cmake build,
134 # NOT the netCDF repository name, I've kept this consistent to the provided netCDF builds rather
135 # than the convention of *_<LANG> to specify multiple components. This also helps account for the
136 # fact that the netCDF langauge-specific projects are separate projects
137 if ( netCDF_FOUND AND NOT TARGET netCDF::netcdf )
138   add_library( netCDF::netcdf UNKNOWN IMPORTED )
139   set_target_properties(
140                         netCDF::netcdf
141                         PROPERTIES
142                           IMPORTED_LOCATION                   "${netCDF_LIBRARY}"
143                           IMPORTED_LINK_INTERFACE_LANGUAGES   C
144                           INTERFACE_INCLUDE_DIRECTORIES      "${netCDF_INCLUDE_DIRS}"
145                         )
147   # I believe this is not required as the API will wrap usage of these
148   # libnetcdf should provide the rpath dependency linking if not static
149   # This is untested! Probably missing a lot of stuff
150   if ( ${netCDF_STATIC} )
151     if ( ${netCDF_HAS_HDF4} OR ${netCDF_HAS_HDF5} )
152       if ( ${netCDF_HAS_PARALLEL} )
153         set( HDF5_PREFER_PARALLEL TRUE )
154       endif()
156       find_package( HDF5 COMPONENTS C HL REQUIRED )
157       target_link_libraries( netCDF::netcdf INTERFACE HDF5::HDF5 )
158       
159       find_package( ZLIB REQUIRED )
160       target_link_libraries( netCDF::netcdf INTERFACE ZLIB::ZLIB )
161     endif()
163     # If available do find it and link in
164     find_package( ZLIB QUIET )
165     if ( ${ZLIB_FOUND} )
166       target_link_libraries( netCDF::netcdf INTERFACE ZLIB::ZLIB )
167     endif()
169     if ( ${netCDF_HAS_SZLIB} )
170       # Currently no standard way to find szlib, and netCDF does not export its module out soooo
171       message( WARNING "No standard way to locate szlib, will attempt to link with -lsz" )
172       target_link_libraries( netCDF::netcdf INTERFACE sz )
173     endif()
175     if ( ${netCDF_HAS_ZSTD} )
176       find_package( PkgConfig )
177       pkg_check_modules( PC_ZSTD QUIET zstd )
178       target_link_libraries( netCDF::netcdf INTERFACE ${PC_ZSTD_LINK_LIBRARIES} )
179     endif()
181     # HAS_BZ2 is not defined right now
182     # if ( ${netCDF_HAS_BZ2} )
183     find_package( BZip2 QUIET )
184     if ( ${BZIP2_FOUND} )
185       target_link_libraries( netCDF::netcdf INTERFACE BZip2::BZip2 )
186     endif()
187     # endif()
189     # HAS_LIBXML2 is not defined right now
190     find_package( LibXml2 QUIET )
191     if( LibXml2_FOUND )
192       target_link_libraries( netCDF::netcdf INTERFACE LibXml2::LibXml2 )
193     endif()  
195     if ( ${netCDF_HAS_PARALLEL} )
196       find_package( MPI COMPONENTS C REQUIRED )
197       target_link_libraries( netCDF::netcdf INTERFACE MPI::MPI_C )
198     endif()
200     # Always linked
201     find_package( CURL REQUIRED )
202     find_library( MATH_LIB NAMES m )
203     target_link_libraries(
204                           netCDF::netcdf
205                           INTERFACE
206                             ${CMAKE_DL_LIBS}
207                             CURL::libcurl
208                             ${MATH_LIB}
209                           )
210   endif()
212 endif()
215 mark_as_advanced( netCDF_CLIBS netCDF_PREFIX netCDF_LIBRARY_DIR )