chore: Update CONTRIBUTING.md with section for code reviews (#1495)
[FMS.git] / cmake / FindNetCDF.cmake
blob1439ae8486c4c5953039a69c59a79cde71ae0116
1 # (C) Copyright 2011- ECMWF.
3 # This software is licensed under the terms of the Apache Licence Version 2.0
4 # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 # In applying this licence, ECMWF does not waive the privileges and immunities
6 # granted to it by virtue of its status as an intergovernmental organisation nor
7 # does it submit to any jurisdiction.
9 # Try to find NetCDF includes and library.
10 # Supports static and shared libaries and allows each component to be found in sepearte prefixes.
12 # This module defines
14 #   - NetCDF_FOUND                - System has NetCDF
15 #   - NetCDF_INCLUDE_DIRS         - the NetCDF include directories
16 #   - NetCDF_VERSION              - the version of NetCDF
17 #   - NetCDF_CONFIG_EXECUTABLE    - the netcdf-config executable if found
18 #   - NetCDF_PARALLEL             - Boolean True if NetCDF4 has parallel IO support via hdf5 and/or pnetcdf
19 #   - NetCDF_HAS_PNETCDF          - Boolean True if NetCDF4 has pnetcdf support
21 # Deprecated Defines
22 #   - NetCDF_LIBRARIES            - [Deprecated] Use NetCDF::NetCDF_<LANG> targets instead.
25 # Following components are available:
27 #   - C                           - C interface to NetCDF          (netcdf)
28 #   - CXX                         - CXX4 interface to NetCDF       (netcdf_c++4)
29 #   - Fortran                     - Fortran interface to NetCDF    (netcdff)
31 # For each component the following are defined:
33 #   - NetCDF_<comp>_FOUND         - whether the component is found
34 #   - NetCDF_<comp>_LIBRARIES     - the libraries for the component
35 #   - NetCDF_<comp>_LIBRARY_SHARED - Boolean is true if libraries for component are shared
36 #   - NetCDF_<comp>_INCLUDE_DIRS  - the include directories for specified component
37 #   - NetCDF::NetCDF_<comp>       - target of component to be used with target_link_libraries()
39 # The following paths will be searched in order if set in CMake (first priority) or environment (second priority)
41 #   - NetCDF_ROOT                 - root of NetCDF installation
42 #   - NetCDF_PATH                 - root of NetCDF installation
44 # The search process begins with locating NetCDF Include headers.  If these are in a non-standard location,
45 # set one of the following CMake or environment variables to point to the location:
47 #  - NetCDF_INCLUDE_DIR or NetCDF_${comp}_INCLUDE_DIR
48 #  - NetCDF_INCLUDE_DIRS or NetCDF_${comp}_INCLUDE_DIR
50 # Notes:
52 #   - Use "NetCDF::NetCDF_<LANG>" targets only.  NetCDF_LIBRARIES exists for backwards compatibility and should not be used.
53 #     - These targets have all the knowledge of include directories and library search directories, and a single
54 #       call to target_link_libraries will provide all these transitive properties to your target.  Normally all that is
55 #       needed to build and link against NetCDF is, e.g.:
56 #           target_link_libraries(my_c_tgt PUBLIC NetCDF::NetCDF_C)
57 #   - "NetCDF" is always the preferred naming for this package, its targets, variables, and environment variables
58 #     - For compatibility, some variables are also set/checked using alternate names NetCDF4, NETCDF, or NETCDF4
59 #     - Environments relying on these older environment variable names should move to using a "NetCDF_ROOT" environment variable
60 #   - Preferred component capitalization follows the CMake LANGUAGES variables: i.e., C, Fortran, CXX
61 #     - For compatibility, alternate capitalizations are supported but should not be used.
62 #   - If no components are defined, all components will be searched
65 list( APPEND _possible_components C CXX Fortran )
67 ## Include names for each component
68 set( NetCDF_C_INCLUDE_NAME          netcdf.h )
69 set( NetCDF_CXX_INCLUDE_NAME        netcdf )
70 set( NetCDF_Fortran_INCLUDE_NAME    netcdf.mod )
72 ## Library names for each component
73 set( NetCDF_C_LIBRARY_NAME          netcdf )
74 set( NetCDF_CXX_LIBRARY_NAME        netcdf_c++4 )
75 set( NetCDF_Fortran_LIBRARY_NAME    netcdff )
77 ## Enumerate search components
78 foreach( _comp ${_possible_components} )
79   string( TOUPPER "${_comp}" _COMP )
80   set( _arg_${_COMP} ${_comp} )
81   set( _name_${_COMP} ${_comp} )
82 endforeach()
84 set( _search_components C)
85 foreach( _comp ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS} )
86   string( TOUPPER "${_comp}" _COMP )
87   set( _arg_${_COMP} ${_comp} )
88   list( APPEND _search_components ${_name_${_COMP}} )
89   if( NOT _name_${_COMP} )
90     message(SEND_ERROR "Find${CMAKE_FIND_PACKAGE_NAME}: COMPONENT ${_comp} is not a valid component. Valid components: ${_possible_components}" )
91   endif()
92 endforeach()
93 list( REMOVE_DUPLICATES _search_components )
95 ## Search hints for finding include directories and libraries
96 foreach( _comp IN ITEMS "_" "_C_" "_Fortran_" "_CXX_" )
97   foreach( _name IN ITEMS NetCDF4 NetCDF NETCDF4 NETCDF )
98     foreach( _var IN ITEMS ROOT PATH )
99       list(APPEND _search_hints ${${_name}${_comp}${_var}} $ENV{${_name}${_comp}${_var}} )
100       list(APPEND _include_search_hints
101                 ${${_name}${_comp}INCLUDE_DIR} $ENV{${_name}${_comp}INCLUDE_DIR}
102                 ${${_name}${_comp}INCLUDE_DIRS} $ENV{${_name}${_comp}INCLUDE_DIRS} )
103     endforeach()
104   endforeach()
105 endforeach()
106 #Old-school HPC module env variable names
107 foreach( _name IN ITEMS NetCDF4 NetCDF NETCDF4 NETCDF )
108   foreach( _comp IN ITEMS "_C" "_Fortran" "_CXX" )
109     list(APPEND _search_hints ${${_name}}         $ENV{${_name}})
110     list(APPEND _search_hints ${${_name}${_comp}} $ENV{${_name}${_comp}})
111   endforeach()
112 endforeach()
114 ## Find headers for each component
115 set(NetCDF_INCLUDE_DIRS)
116 set(_new_search_components)
117 foreach( _comp IN LISTS _search_components )
118   if(NOT ${PROJECT_NAME}_NetCDF_${_comp}_FOUND)
119       list(APPEND _new_search_components ${_comp})
120   endif()
121   find_file(NetCDF_${_comp}_INCLUDE_FILE
122     NAMES ${NetCDF_${_comp}_INCLUDE_NAME}
123     DOC "NetCDF ${_comp} include directory"
124     HINTS ${_include_search_hints} ${_search_hints}
125     PATH_SUFFIXES include include/netcdf
126   )
127   mark_as_advanced(NetCDF_${_comp}_INCLUDE_FILE)
128   message(DEBUG "NetCDF_${_comp}_INCLUDE_FILE: ${NetCDF_${_comp}_INCLUDE_FILE}")
129   if( NetCDF_${_comp}_INCLUDE_FILE )
130     get_filename_component(NetCDF_${_comp}_INCLUDE_FILE ${NetCDF_${_comp}_INCLUDE_FILE} ABSOLUTE)
131     get_filename_component(NetCDF_${_comp}_INCLUDE_DIR ${NetCDF_${_comp}_INCLUDE_FILE} DIRECTORY)
132     list(APPEND NetCDF_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIR})
133   endif()
134 endforeach()
135 if(NetCDF_INCLUDE_DIRS)
136     list(REMOVE_DUPLICATES NetCDF_INCLUDE_DIRS)
137 endif()
138 set(NetCDF_INCLUDE_DIRS "${NetCDF_INCLUDE_DIRS}" CACHE STRING "NetCDF Include directory paths" FORCE)
140 ## Find n*-config executables for search components
141 foreach( _comp IN LISTS _search_components )
142   if( _comp MATCHES "^(C)$" )
143     set(_conf "c")
144   elseif( _comp MATCHES "^(Fortran)$" )
145     set(_conf "f")
146   elseif( _comp MATCHES "^(CXX)$" )
147     set(_conf "cxx4")
148   endif()
149   find_program( NetCDF_${_comp}_CONFIG_EXECUTABLE
150       NAMES n${_conf}-config
151     HINTS ${NetCDF_INCLUDE_DIRS} ${_include_search_hints} ${_search_hints}
152     PATH_SUFFIXES bin Bin ../bin ../../bin
153       DOC "NetCDF n${_conf}-config helper" )
154     message(DEBUG "NetCDF_${_comp}_CONFIG_EXECUTABLE: ${NetCDF_${_comp}_CONFIG_EXECUTABLE}")
155 endforeach()
157 set(_C_libs_flag --libs)
158 set(_Fortran_libs_flag --flibs)
159 set(_CXX_libs_flag --libs)
160 set(_C_includes_flag --includedir)
161 set(_Fortran_includes_flag --includedir)
162 set(_CXX_includes_flag --includedir)
163 function(netcdf_config exec flag output_var)
164   set(${output_var} False PARENT_SCOPE)
165   if( exec )
166     execute_process( COMMAND ${exec} ${flag} RESULT_VARIABLE _ret OUTPUT_VARIABLE _val)
167     if( _ret EQUAL 0 )
168       string( STRIP ${_val} _val )
169       set( ${output_var} ${_val} PARENT_SCOPE )
170     endif()
171   endif()
172 endfunction()
174 ## Find libraries for each component
175 set( NetCDF_LIBRARIES )
176 foreach( _comp IN LISTS _search_components )
177   string( TOUPPER "${_comp}" _COMP )
179   find_library( NetCDF_${_comp}_LIBRARY
180     NAMES ${NetCDF_${_comp}_LIBRARY_NAME}
181     DOC "NetCDF ${_comp} library"
182     HINTS ${NetCDF_${_comp}_INCLUDE_DIRS} ${_search_hints}
183     PATH_SUFFIXES lib64 lib ../lib64 ../lib ../../lib64 ../../lib )
184   mark_as_advanced( NetCDF_${_comp}_LIBRARY )
185   get_filename_component(NetCDF_${_comp}_LIBRARY ${NetCDF_${_comp}_LIBRARY} ABSOLUTE)
186   set(NetCDF_${_comp}_LIBRARY ${NetCDF_${_comp}_LIBRARY} CACHE STRING "NetCDF ${_comp} library" FORCE)
187   message(DEBUG "NetCDF_${_comp}_LIBRARY: ${NetCDF_${_comp}_LIBRARY}")
189   if( NetCDF_${_comp}_LIBRARY )
190     if( NetCDF_${_comp}_LIBRARY MATCHES ".a$" )
191       set( NetCDF_${_comp}_LIBRARY_SHARED FALSE )
192       set( _library_type STATIC)
193     else()
194       list( APPEND NetCDF_LIBRARIES ${NetCDF_${_comp}_LIBRARY} )
195       set( NetCDF_${_comp}_LIBRARY_SHARED TRUE )
196       set( _library_type SHARED)
197     endif()
198   endif()
200   #Use nc-config to set per-component LIBRARIES variable if possible
201   netcdf_config( ${NetCDF_${_comp}_CONFIG_EXECUTABLE} ${_${_comp}_libs_flag} _val )
202   if( _val )
203     set( NetCDF_${_comp}_LIBRARIES ${_val} )
204     if(NOT NetCDF_${_comp}_LIBRARY_SHARED AND NOT NetCDF_${_comp}_FOUND) #Static targets should use nc_config to get a proper link line with all necessary static targets.
205       list( APPEND NetCDF_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} )
206     endif()
207   else()
208     set( NetCDF_${_comp}_LIBRARIES ${NetCDF_${_comp}_LIBRARY} )
209     if(NOT NetCDF_${_comp}_LIBRARY_SHARED)
210       message(SEND_ERROR "Unable to properly find NetCDF.  Found static libraries at: ${NetCDF_${_comp}_LIBRARY} but could not run nc-config: ${NetCDF_CONFIG_EXECUTABLE}")
211     endif()
212   endif()
214   #Use nc-config to set per-component INCLUDE_DIRS variable if possible
215   netcdf_config( ${NetCDF_${_comp}_CONFIG_EXECUTABLE} ${_${_comp}_includes_flag} _val )
216   if( _val )
217     string( REPLACE " " ";" _val ${_val} )
218     set( NetCDF_${_comp}_INCLUDE_DIRS ${_val} )
219   else()
220     set( NetCDF_${_comp}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIR} )
221   endif()
223   if( NetCDF_${_comp}_LIBRARIES AND NetCDF_${_comp}_INCLUDE_DIRS )
224     set( ${CMAKE_FIND_PACKAGE_NAME}_${_arg_${_COMP}}_FOUND TRUE )
225     if (NOT TARGET NetCDF::NetCDF_${_comp})
226       add_library(NetCDF::NetCDF_${_comp} ${_library_type} IMPORTED)
227       set_target_properties(NetCDF::NetCDF_${_comp} PROPERTIES
228         IMPORTED_LOCATION ${NetCDF_${_comp}_LIBRARY}
229         INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_${_comp}_INCLUDE_DIRS}"
230         INTERFACE_LINK_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} )
231     endif()
232   endif()
233 endforeach()
234 if(NetCDF_LIBRARIES AND NetCDF_${_comp}_LIBRARY_SHARED)
235     list(REMOVE_DUPLICATES NetCDF_LIBRARIES)
236 endif()
237 set(NetCDF_LIBRARIES "${NetCDF_LIBRARIES}" CACHE STRING "NetCDF library targets" FORCE)
239 ## Find version via netcdf-config if possible
240 if (NetCDF_INCLUDE_DIRS)
241   if( NetCDF_C_CONFIG_EXECUTABLE )
242     netcdf_config( ${NetCDF_C_CONFIG_EXECUTABLE} --version _vers )
243     if( _vers )
244       string(REGEX REPLACE ".* ((([0-9]+)\\.)+([0-9]+)).*" "\\1" NetCDF_VERSION "${_vers}" )
245     endif()
246   else()
247     foreach( _dir IN LISTS NetCDF_INCLUDE_DIRS)
248       if( EXISTS "${_dir}/netcdf_meta.h" )
249         file(STRINGS "${_dir}/netcdf_meta.h" _netcdf_version_lines
250         REGEX "#define[ \t]+NC_VERSION_(MAJOR|MINOR|PATCH|NOTE)")
251         string(REGEX REPLACE ".*NC_VERSION_MAJOR *\([0-9]*\).*" "\\1" _netcdf_version_major "${_netcdf_version_lines}")
252         string(REGEX REPLACE ".*NC_VERSION_MINOR *\([0-9]*\).*" "\\1" _netcdf_version_minor "${_netcdf_version_lines}")
253         string(REGEX REPLACE ".*NC_VERSION_PATCH *\([0-9]*\).*" "\\1" _netcdf_version_patch "${_netcdf_version_lines}")
254         string(REGEX REPLACE ".*NC_VERSION_NOTE *\"\([^\"]*\)\".*" "\\1" _netcdf_version_note "${_netcdf_version_lines}")
255         set(NetCDF_VERSION "${_netcdf_version_major}.${_netcdf_version_minor}.${_netcdf_version_patch}${_netcdf_version_note}")
256         unset(_netcdf_version_major)
257         unset(_netcdf_version_minor)
258         unset(_netcdf_version_patch)
259         unset(_netcdf_version_note)
260         unset(_netcdf_version_lines)
261       endif()
262     endforeach()
263   endif()
264 endif ()
266 ## Detect additional package properties
267 netcdf_config(${NetCDF_C_CONFIG_EXECUTABLE} --has-parallel4 _val)
268 if( NOT _val MATCHES "^(yes|no)$" )
269   netcdf_config(${NetCDF_C_CONFIG_EXECUTABLE} --has-parallel _val)
270 endif()
271 if( _val MATCHES "^(yes)$" )
272   set(NetCDF_PARALLEL TRUE CACHE STRING "NetCDF has parallel IO capability via pnetcdf or hdf5." FORCE)
273 else()
274   set(NetCDF_PARALLEL FALSE CACHE STRING "NetCDF has no parallel IO capability." FORCE)
275 endif()
277 ## Finalize find_package
278 include(FindPackageHandleStandardArgs)
280 if(NOT NetCDF_FOUND OR _new_search_components)
281     find_package_handle_standard_args( ${CMAKE_FIND_PACKAGE_NAME}
282         REQUIRED_VARS NetCDF_INCLUDE_DIRS NetCDF_LIBRARIES
283         VERSION_VAR NetCDF_VERSION
284         HANDLE_COMPONENTS )
285 endif()
287 foreach( _comp IN LISTS _search_components )
288     if( NetCDF_${_comp}_FOUND )
289         #Record found components to avoid duplication in NetCDF_LIBRARIES for static libraries
290         set(NetCDF_${_comp}_FOUND ${NetCDF_${_comp}_FOUND} CACHE BOOL "NetCDF ${_comp} Found" FORCE)
291         #Set a per-package, per-component found variable to communicate between multiple calls to find_package()
292         set(${PROJECT_NAME}_NetCDF_${_comp}_FOUND True)
293     endif()
294 endforeach()
296 if( ${CMAKE_FIND_PACKAGE_NAME}_FOUND AND NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY AND _new_search_components)
297   message( STATUS "Find${CMAKE_FIND_PACKAGE_NAME} defines targets:" )
298   message( STATUS "  - NetCDF_VERSION [${NetCDF_VERSION}]")
299   message( STATUS "  - NetCDF_PARALLEL [${NetCDF_PARALLEL}]")
300   foreach( _comp IN LISTS _new_search_components )
301     string( TOUPPER "${_comp}" _COMP )
302     message( STATUS "  - NetCDF_${_comp}_CONFIG_EXECUTABLE [${NetCDF_${_comp}_CONFIG_EXECUTABLE}]")
303     if( ${CMAKE_FIND_PACKAGE_NAME}_${_arg_${_COMP}}_FOUND )
304       get_filename_component(_root ${NetCDF_${_comp}_INCLUDE_DIR}/.. ABSOLUTE)
305       if( NetCDF_${_comp}_LIBRARY_SHARED )
306         message( STATUS "  - NetCDF::NetCDF_${_comp} [SHARED] [Root: ${_root}] Lib: ${NetCDF_${_comp}_LIBRARY} ")
307       else()
308         message( STATUS "  - NetCDF::NetCDF_${_comp} [STATIC] [Root: ${_root}] Lib: ${NetCDF_${_comp}_LIBRARY} ")
309       endif()
310     endif()
311   endforeach()
312 endif()
314 foreach( _prefix NetCDF NetCDF4 NETCDF NETCDF4 ${CMAKE_FIND_PACKAGE_NAME} )
315   set( ${_prefix}_INCLUDE_DIRS ${NetCDF_INCLUDE_DIRS} )
316   set( ${_prefix}_LIBRARIES    ${NetCDF_LIBRARIES})
317   set( ${_prefix}_VERSION      ${NetCDF_VERSION} )
318   set( ${_prefix}_FOUND        ${${CMAKE_FIND_PACKAGE_NAME}_FOUND} )
319   set( ${_prefix}_CONFIG_EXECUTABLE ${NetCDF_CONFIG_EXECUTABLE} )
320   set( ${_prefix}_PARALLEL ${NetCDF_PARALLEL} )
322   foreach( _comp ${_search_components} )
323     string( TOUPPER "${_comp}" _COMP )
324     set( _arg_comp ${_arg_${_COMP}} )
325     set( ${_prefix}_${_comp}_FOUND     ${${CMAKE_FIND_PACKAGE_NAME}_${_arg_comp}_FOUND} )
326     set( ${_prefix}_${_COMP}_FOUND     ${${CMAKE_FIND_PACKAGE_NAME}_${_arg_comp}_FOUND} )
327     set( ${_prefix}_${_arg_comp}_FOUND ${${CMAKE_FIND_PACKAGE_NAME}_${_arg_comp}_FOUND} )
329     set( ${_prefix}_${_comp}_LIBRARIES     ${NetCDF_${_comp}_LIBRARIES} )
330     set( ${_prefix}_${_COMP}_LIBRARIES     ${NetCDF_${_comp}_LIBRARIES} )
331     set( ${_prefix}_${_arg_comp}_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} )
333     set( ${_prefix}_${_comp}_INCLUDE_DIRS     ${NetCDF_${_comp}_INCLUDE_DIRS} )
334     set( ${_prefix}_${_COMP}_INCLUDE_DIRS     ${NetCDF_${_comp}_INCLUDE_DIRS} )
335     set( ${_prefix}_${_arg_comp}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIRS} )
336   endforeach()
337 endforeach()