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.
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
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
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} )
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}" )
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} )
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}})
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})
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
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})
135 if(NetCDF_INCLUDE_DIRS)
136 list(REMOVE_DUPLICATES NetCDF_INCLUDE_DIRS)
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)$" )
144 elseif( _comp MATCHES "^(Fortran)$" )
146 elseif( _comp MATCHES "^(CXX)$" )
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}")
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)
166 execute_process( COMMAND ${exec} ${flag} RESULT_VARIABLE _ret OUTPUT_VARIABLE _val)
168 string( STRIP ${_val} _val )
169 set( ${output_var} ${_val} PARENT_SCOPE )
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)
194 list( APPEND NetCDF_LIBRARIES ${NetCDF_${_comp}_LIBRARY} )
195 set( NetCDF_${_comp}_LIBRARY_SHARED TRUE )
196 set( _library_type SHARED)
200 #Use nc-config to set per-component LIBRARIES variable if possible
201 netcdf_config( ${NetCDF_${_comp}_CONFIG_EXECUTABLE} ${_${_comp}_libs_flag} _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} )
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}")
214 #Use nc-config to set per-component INCLUDE_DIRS variable if possible
215 netcdf_config( ${NetCDF_${_comp}_CONFIG_EXECUTABLE} ${_${_comp}_includes_flag} _val )
217 string( REPLACE " " ";" _val ${_val} )
218 set( NetCDF_${_comp}_INCLUDE_DIRS ${_val} )
220 set( NetCDF_${_comp}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIR} )
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} )
234 if(NetCDF_LIBRARIES AND NetCDF_${_comp}_LIBRARY_SHARED)
235 list(REMOVE_DUPLICATES NetCDF_LIBRARIES)
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 )
244 string(REGEX REPLACE ".* ((([0-9]+)\\.)+([0-9]+)).*" "\\1" NetCDF_VERSION "${_vers}" )
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)
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)
271 if( _val MATCHES "^(yes)$" )
272 set(NetCDF_PARALLEL TRUE CACHE STRING "NetCDF has parallel IO capability via pnetcdf or hdf5." FORCE)
274 set(NetCDF_PARALLEL FALSE CACHE STRING "NetCDF has no parallel IO capability." FORCE)
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
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)
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} ")
308 message( STATUS " - NetCDF::NetCDF_${_comp} [STATIC] [Root: ${_root}] Lib: ${NetCDF_${_comp}_LIBRARY} ")
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} )