Search code examples
c++cmakenetcdfnetcdf4

Create CMake for NetCDF C++


I am trying to create a CMake file for my project which uses NetCDF. I am very new at CMake (this is my first try), so I apologize if some of this stuff is evident.

To install NetCDF I followed the steps in the git guide shown here

I believe I did the steps correctly. I am trying to use the NetCDF C++ library, but I also had to install the C library for compilation purposes. I did this by using:

sudo apt install libnetcdf-dev

When I run the following command, I receive appropriate output (according to the git guide):

nc-config --has-nc4

So far so good... I hope. Here is my CMakeLists.Txt:

cmake_minimum_required(VERSION 3.16)

project(orbit LANGUAGES CXX)

# ##############################################################################
# Conan Packages
# ##############################################################################

set(CONAN_EXTRA_REQUIRES "")  set(CONAN_EXTRA_OPTIONS "")

list(APPEND CONAN_EXTRA_REQUIRES boost/1.73.0) list(APPEND CONAN_EXTRA_REQUIRES eigen/3.3.7)

if(BUILD_SHARED_LIBS)   list(APPEND CONAN_EXTRA_OPTIONS "Pkg:shared=True") endif()

include(cmake/Conan.cmake) run_conan()

# ############################################################################## 
find_file(CMAKE_PREFIX_PATH netCDFCxxConfig.cmake) 
find_package (NetCDF REQUIRED) include_directories(${NETCDF_INCLUDES})

# set(SOURCE test.cpp player.cpp player.hpp)

# include_directories(include)

# Search all .cpp files 
file(GLOB_RECURSE SOURCE_FILES "*.cpp")

add_executable(test ${SOURCE_FILES})

target_link_libraries(test 
                      PRIVATE
                          CONAN_PKG::boost
                          CONAN_PKG::eigen

                          ${NETCDF_LIBRARIES_CXX})

And here is the error output:

CMake Error at CMakeLists.txt:24 (find_package):
  By not providing "FindNetCDF.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "NetCDF", but
  CMake did not find one.

  Could not find a package configuration file provided by "NetCDF" with any
  of the following names:

    NetCDFConfig.cmake
    netcdf-config.cmake

  Add the installation prefix of "NetCDF" to CMAKE_PREFIX_PATH or set
  "NetCDF_DIR" to a directory containing one of the above files.  If "NetCDF"
  provides a separate development package or SDK, be sure it has been
  installed.

My understanding is that this error comes from me not doing the following line from the git guide correctly:

Make sure that either nc-config is in your PATH, or that the location of netCDFConfig.cmake is in CMAKE_PREFIX_PATH.

I have tried adding the nc-config to my PATH, by running:

export PATH="nc-config:$PATH"

But this does not resolve the issue...

Additionally, I have tried to find a netCDFConfig.cmake file in my computer, however it does not seem to exist. I do have a netCDFCxxConfig.cmake, but I am not sure if this is the same, or how I could go about using it here.

Does anyone have any experience with this issue, and know how to resolve it? Any help would be greatly appreciated, and I do apologize if such a solution has been provided in the past.

Edit:

I was able to get CMake to finally find the file, but now it gets lost looking for another one... Here is the file it was not finding in my original post:

# NetCDF CXX Configuration Summary

####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was netCDFCxxConfig.cmake.in                            ########

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)

macro(set_and_check _var _file)
  set(${_var} "${_file}")
  if(NOT EXISTS "${_file}")
    message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
  endif()
endmacro()

macro(check_required_components _NAME)
  foreach(comp ${${_NAME}_FIND_COMPONENTS})
    if(NOT ${_NAME}_${comp}_FOUND)
      if(${_NAME}_FIND_REQUIRED_${comp})
        set(${_NAME}_FOUND FALSE)
      endif()
    endif()
  endforeach()
endmacro()

####################################################################################

include(CMakeFindDependencyMacro)

if (1)
  if(EXISTS "")
    set(netCDF_ROOT "")
  endif()
  if(EXISTS "/usr/lib/x86_64-linux-gnu/cmake/netCDF")
    set(netCDF_DIR "/usr/lib/x86_64-linux-gnu/cmake/netCDF")
  endif()
  find_dependency(netCDF)
  set(NETCDF_C_LIBRARY ${netCDF_LIBRARIES})
  set(NETCDF_C_INCLUDE_DIR ${netCDF_INCLUDE_DIR})
else()
  set(NETCDF_C_LIBRARY "netcdf")
  set(NETCDF_C_INCLUDE_DIR "/usr/include")
endif()

if (NOT TARGET netCDF::netcdf)
  add_library(netCDF::netcdf UNKNOWN IMPORTED)
  set_target_properties(netCDF::netcdf PROPERTIES
    IMPORTED_LOCATION "${NETCDF_C_LIBRARY}"
    INTERFACE_INCLUDE_DIRECTORIES "${NETCDF_C_INCLUDE_DIR}"
  )
endif()

include("${CMAKE_CURRENT_LIST_DIR}/netcdf-cxx4Targets.cmake")

This last line is where it all sort of goes wrong. Here is where it has issues finding the netcdf-cxx4Targets.cmake.

The file I have just posted is in the directory: netcd-cxx4/build netcdf-cxx4Targets.cmake is in the directory:

netcd-cxx4/build/CMakeFiles/Export/lib/cmake/netCDF

So the first should be able to find the other?


Solution

  • The netCDFCxxConfig.cmake file is what you want to use. From quickly looking at the GitHub repository, there is a template for this file (netCDFCxxConfig.cmake.in), but not one for netCDFConfig.cmake.in. Therefore, my conclusion is the maintainers probably changed the config file name at some point, and forgot to update their README documentation to netCDFCxxConfig.cmake.

    You can add the location of the netCDFCxxConfig.cmake file to the CMAKE_PREFIX_PATH list variable in your CMake file. Then, link to the imported target netCDF::netcdf defined in the netCDFCxxConfig.cmake file.

    ...
    
    # ############################################################################## 
    # Don't do this.
    find_file(CMAKE_PREFIX_PATH netCDFCxxConfig.cmake)
    # Instead, append the path to the config file using the 'list' command.
    list(APPEND CMAKE_PREFIX_PATH "/path/to/installed/netcdf")
    
    # Look for the 'netCDFCxx' package, since that is what the config file is called.
    find_package (netCDFCxx REQUIRED) 
    
    # Probably don't need this if we use the imported target below.
    include_directories(${NETCDF_INCLUDES})
    
    # set(SOURCE test.cpp player.cpp player.hpp)
    
    # include_directories(include)
    
    # Search all .cpp files 
    file(GLOB_RECURSE SOURCE_FILES "*.cpp")
    
    add_executable(test ${SOURCE_FILES})
    
    # Link to the imported target 'netCDF::netcdf' here instead.
    target_link_libraries(test 
                          PRIVATE
                              CONAN_PKG::boost
                              CONAN_PKG::eigen
                              netCDF::netcdf)