From 21e859adf65647c4aa7635beed619f8adeee3f11 Mon Sep 17 00:00:00 2001 From: anton-seaice Date: Mon, 13 Jan 2025 14:52:56 +1100 Subject: [PATCH] building access cice library --- cmake/AccessCiceCmeps.cmake.in | 9 +++ cmake/CMakeLists.txt | 107 +++++++++++++++++++++----- cmake/FindESMF.cmake | 135 +++++++++++++++++++++++++++++++++ cmake/FindFoX.cmake | 56 -------------- 4 files changed, 233 insertions(+), 74 deletions(-) create mode 100644 cmake/AccessCiceCmeps.cmake.in create mode 100755 cmake/FindESMF.cmake delete mode 100644 cmake/FindFoX.cmake diff --git a/cmake/AccessCiceCmeps.cmake.in b/cmake/AccessCiceCmeps.cmake.in new file mode 100644 index 000000000..dabecdd91 --- /dev/null +++ b/cmake/AccessCiceCmeps.cmake.in @@ -0,0 +1,9 @@ +@PACKAGE_INIT@ + + +find_package(NetCDF 4.7.3 REQUIRED Fortran) +find_package(PIO 2.5.3 REQUIRED COMPONENTS C Fortran) + +include("${CMAKE_CURRENT_LIST_DIR}/AccessCiceCmepsTargets.cmake") + +check_required_components(AccessCiceCmeps) \ No newline at end of file diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 19102b09f..70db3deaf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -4,13 +4,35 @@ cmake_minimum_required(VERSION 3.18) # Basic project definition # #]==============================================================================] -project(CICE6 DESCRIPTION "CICE6" LANGUAGES C Fortran) +project(CICE + DESCRIPTION "CICE Sea Ice Model" + HOMEPAGE_URL https://github.com/ciCE-Consortium/cice + LANGUAGES C Fortran) + +#[==============================================================================[ +# Options # +#]==============================================================================] + +# Build options +option(ACCESS3_LIB_INSTALL "Instal ACCESS3 libraries" OFF) +option(CICE_IO "CICE IO Method" "Binary") +option(CESMCOUPLED "CESMCOUPLED Build CPP" OFF) +# openmp ? + +message(STATUS "Build options") +message(STATUS " - ACCESS3_LIB_INSTALL ${ACCESS3_LIB_INSTALL}") +message(STATUS " - CICE_IO ${CICE_IO}") +message(STATUS " - CESMCOUPLED ${CESMCOUPLED}") + +#[==============================================================================[ +# Project configuration # +#]==============================================================================] list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}) +include(CMakePackageConfigHelpers) include(GNUInstallDirs) include(FortranLib) - # Common compiler flags and definitions if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU") set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fbacktrace -fconvert=big-endian -ffree-line-length-none -ffixed-line-length-none") @@ -51,22 +73,36 @@ set(CMAKE_INSTALL_MODULEDIR ${CMAKE_INSTALL_INCLUDEDIR} "Fortran module installation path (Not a cmake native variable)" ) +#[==============================================================================[ +# External packages # +#]==============================================================================] + if(ACCESS3_LIB_INSTALL) - find_package(Access3Share) - find_package(FoX 4.1.2 REQUIRED) + find_package(Access3Share) #should this have a REQUIRED? + find_package(ESMF 8.3.0 MODULE REQUIRED) +else() + find_package(MPI REQUIRED) endif() + if(CICE_IO MATCHES "^(NetCDF|PIO)$") find_package(NetCDF 4.7.3 REQUIRED Fortran) endif() if(CICE_IO MATCHES "PIO") find_package(PIO 2.5.3 REQUIRED COMPONENTS C Fortran) endif() + +#[==============================================================================[ +# Main definitions # +#]==============================================================================] + ### Targets ## CICE library add_fortran_library(cicelib mod STATIC) -target_compile_definitions(cicelib PRIVATE FORTRANUNDERSCORE ncdf) + if(CICE_IO MATCHES "^(NetCDF|PIO)$") + # which is this not just an "add_compile_definitions?" + target_compile_definitions(cicelib PRIVATE FORTRANUNDERSCORE ncdf) target_compile_definitions(cicelib PRIVATE USE_NETCDF) endif() if(ACCESS3_LIB_INSTALL) @@ -81,6 +117,7 @@ if(CICE_IO MATCHES "^(NetCDF|PIO)$") target_link_libraries(cicelib PRIVATE PIO::PIO_Fortran) endif() endif() + if(OpenMP_Fortran_FOUND) target_link_libraries(cicelib PRIVATE OpenMP::OpenMP_Fortran) endif() @@ -205,6 +242,13 @@ if(ACCESS3_LIB_INSTALL) ${CICE_CORE}/drivers/nuopc/cmeps/ice_scam.F90 ${CICE_CORE}/drivers/nuopc/cmeps/ice_shr_methods.F90 ) +else() + target_sources(cicelib PRIVATE + # CICE standalone + ${CICE_CORE}/drivers/standalone/cice/CICE_FinalMod.F90 + ${CICE_CORE}/drivers/standalone/cice/CICE_InitMod.F90 + ${CICE_CORE}/drivers/standalone/cice/CICE_RunMod.F90 + ) endif() # Select IO source files based on CICE_IO @@ -226,31 +270,58 @@ elseif(CICE_IO MATCHES "Binary") ) endif() -### Install and Export +#[==============================================================================[ +# Install or Export # +#]==============================================================================] -## Library if(ACCESS3_LIB_INSTALL) + ## Library set_target_properties(cicelib PROPERTIES - OUTPUT_NAME access-cice - EXPORT_NAME cice + OUTPUT_NAME access-cice-cmeps + EXPORT_NAME cice-cmeps ) install(TARGETS cicelib - EXPORT Access3cice_Targets - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Access3_RunTime NAMELINK_COMPONENT Access3_Development - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Access3_Development + EXPORT AccessCiceCmepsTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) # Fortran module files are a special case, as currently there is no standard # way of handling them in CMake target_include_directories(cicelib PUBLIC "$") get_target_property(cice_moddir cicelib Fortran_MODULE_DIRECTORY) install(FILES ${cice_moddir}/ice_comp_nuopc.mod - DESTINATION ${CMAKE_INSTALL_MODULEDIR}/CICE - COMPONENT Access3_Development + DESTINATION ${CMAKE_INSTALL_MODULEDIR}/access-cice ) - install(EXPORT Access3cice_Targets - FILE Access3ciceTargets.cmake - NAMESPACE Access3:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CICE + + # Make sure the dependencies get exported too + configure_package_config_file( + AccessCiceCmeps.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/AccessCiceCmepsConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/AccessCiceCmeps + ) + install(FILES ${CMAKE_SOURCE_DIR}/FindNetCDF.cmake ${CMAKE_SOURCE_DIR}/FindPIO.cmake ${CMAKE_CURRENT_BINARY_DIR}/AccessCiceCmepsConfig.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/AccessCiceCmeps + COMPONENT AccessCiceCmeps + ) + # install(EXPORT AccessCiceCmepsTargets + # FILE AccessCiceCmepsTargets.cmake + # NAMESPACE AccessCiceCmeps:: + # DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/AccessCiceCmeps + # ) +else() + set_target_properties(cicelib PROPERTIES + OUTPUT_NAME cicelib-standalone + EXPORT_NAME cicelib + ) + add_executable(CICE ${CICE_CORE}/drivers/standalone/cice/CICE.F90) + target_link_libraries(CICE PRIVATE cicelib) + + set_target_properties(CICE PROPERTIES + LINKER_LANGUAGE Fortran + OUTPUT_NAME cice ) + install(TARGETS CICE + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) endif() diff --git a/cmake/FindESMF.cmake b/cmake/FindESMF.cmake new file mode 100755 index 000000000..5ba7003bd --- /dev/null +++ b/cmake/FindESMF.cmake @@ -0,0 +1,135 @@ +# - Try to find ESMF +# +# Requires setting ESMFMKFILE to the filepath of esmf.mk. If this is NOT set, +# then ESMF_FOUND will always be FALSE. If ESMFMKFILE exists, then ESMF_FOUND=TRUE +# and all ESMF makefile variables will be set in the global scope. Optionally, +# set ESMF_MKGLOBALS to a string list to filter makefile variables. For example, +# to globally scope only ESMF_LIBSDIR and ESMF_APPSDIR variables, use this CMake +# command in CMakeLists.txt: +# +# set(ESMF_MKGLOBALS "LIBSDIR" "APPSDIR") + + +# Add the ESMFMKFILE path to the cache if defined as system env variable +if(DEFINED ENV{ESMFMKFILE} AND NOT DEFINED ESMFMKFILE) + set(ESMFMKFILE $ENV{ESMFMKFILE} CACHE FILEPATH "Path to ESMF mk file") +endif() + +# If it's not explicitly set try to find esmf.mk file in default locations (ESMF_ROOT, CMAKE_PREFIX_PATH, etc) +if(NOT DEFINED ESMFMKFILE) + find_path(ESMFMKFILE_PATH esmf.mk PATH_SUFFIXES lib lib64) + if(ESMFMKFILE_PATH) + set(ESMFMKFILE ${ESMFMKFILE_PATH}/esmf.mk) + message(STATUS "Found esmf.mk file ${ESMFMKFILE}") + else() + message(STATUS "ESMFMKFILE not defined. This is the path to esmf.mk file. \ +Without this filepath, ESMF_FOUND will always be FALSE.") + endif() +endif() + +# Only parse the mk file if it is found +if(EXISTS ${ESMFMKFILE}) + # Read the mk file + file(STRINGS "${ESMFMKFILE}" esmfmkfile_contents) + # Parse each line in the mk file + foreach(str ${esmfmkfile_contents}) + # Only consider uncommented lines + string(REGEX MATCH "^[^#]" def ${str}) + # Line is not commented + if(def) + # Extract the variable name + string(REGEX MATCH "^[^=]+" esmf_varname ${str}) + # Extract the variable's value + string(REGEX MATCH "=.+$" esmf_vardef ${str}) + # Only for variables with a defined value + if(esmf_vardef) + # Get rid of the assignment string + string(SUBSTRING ${esmf_vardef} 1 -1 esmf_vardef) + # Remove whitespace + string(STRIP ${esmf_vardef} esmf_vardef) + # A string or single-valued list + if(NOT DEFINED ESMF_MKGLOBALS) + # Set in global scope + set(${esmf_varname} ${esmf_vardef}) + # Don't display by default in GUI + mark_as_advanced(esmf_varname) + else() # Need to filter global promotion + foreach(m ${ESMF_MKGLOBALS}) + string(FIND ${esmf_varname} ${m} match) + # Found the string + if(NOT ${match} EQUAL -1) + # Promote to global scope + set(${esmf_varname} ${esmf_vardef}) + # Don't display by default in the GUI + mark_as_advanced(esmf_varname) + # No need to search for the current string filter + break() + endif() + endforeach() + endif() + endif() + endif() + endforeach() + + # Construct ESMF_VERSION from ESMF_VERSION_STRING_GIT + # ESMF_VERSION_MAJOR and ESMF_VERSION_MINOR are defined in ESMFMKFILE + set(ESMF_VERSION 0) + set(ESMF_VERSION_PATCH ${ESMF_VERSION_REVISION}) + set(ESMF_BETA_RELEASE FALSE) + if(ESMF_VERSION_BETASNAPSHOT MATCHES "^('T')$") + set(ESMF_BETA_RELEASE TRUE) + string(REGEX REPLACE ".*beta_snapshot_*\([0-9]*\).*" "\\1" ESMF_BETA_SNAPSHOT "${ESMF_VERSION_STRING_GIT}") + message(STATUS "Detected ESMF Beta snapshot ${ESMF_BETA_SNAPSHOT}") + endif() + set(ESMF_VERSION "${ESMF_VERSION_MAJOR}.${ESMF_VERSION_MINOR}.${ESMF_VERSION_PATCH}") + + separate_arguments(ESMF_F90COMPILEPATHS NATIVE_COMMAND ${ESMF_F90COMPILEPATHS}) + foreach(ITEM ${ESMF_F90COMPILEPATHS}) + string(REGEX REPLACE "^-I" "" ITEM "${ITEM}") + list(APPEND tmp ${ITEM}) + endforeach() + set(ESMF_F90COMPILEPATHS ${tmp}) + + # Look for static library, if not found try dynamic library + find_library(esmf_lib NAMES libesmf.a PATHS ${ESMF_LIBSDIR}) + if(esmf_lib MATCHES "esmf_lib-NOTFOUND") + unset(esmf_lib) + message(STATUS "Static ESMF library not found, searching for dynamic library instead") + find_library(esmf_lib NAMES esmf_fullylinked libesmf.so PATHS ${ESMF_LIBSDIR}) + if(esmf_lib MATCHES "esmf_lib-NOTFOUND") + unset(esmf_lib) + message(STATUS "Neither the dynamic nor the static ESMF library was found") + else() + set(_library_type SHARED) + endif() + else() + set(_library_type STATIC) + endif() + + string(STRIP "${ESMF_F90ESMFLINKRPATHS} ${ESMF_F90ESMFLINKPATHS} ${ESMF_F90LINKPATHS} ${ESMF_F90LINKLIBS} ${ESMF_F90LINKOPTS}" ESMF_INTERFACE_LINK_LIBRARIES) + set(ESMF_LIBRARY_LOCATION ${esmf_lib}) + +else() + + message(WARNING "ESMFMKFILE ${ESMFMKFILE} does not exist") + +endif() + +## Finalize find_package +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + ${CMAKE_FIND_PACKAGE_NAME} + REQUIRED_VARS ESMF_LIBRARY_LOCATION + ESMF_INTERFACE_LINK_LIBRARIES + ESMF_F90COMPILEPATHS + VERSION_VAR ESMF_VERSION) + +## If ESMF is found create imported library target +if(ESMF_FOUND) + add_library(esmf ${_library_type} IMPORTED) + set_target_properties(esmf PROPERTIES + IMPORTED_LOCATION "${ESMF_LIBRARY_LOCATION}" + INTERFACE_INCLUDE_DIRECTORIES "${ESMF_F90COMPILEPATHS}" + INTERFACE_LINK_LIBRARIES "${ESMF_INTERFACE_LINK_LIBRARIES}") +endif() diff --git a/cmake/FindFoX.cmake b/cmake/FindFoX.cmake deleted file mode 100644 index b09bb35c9..000000000 --- a/cmake/FindFoX.cmake +++ /dev/null @@ -1,56 +0,0 @@ -# We will use pkgconfig to find the library -find_package(PkgConfig REQUIRED) - -## Prepare arguments to pass to pkg_search_module - -# QUIET -set(_quiet_arg) -if (FoX_FIND_QUIETLY) - list(APPEND _quiet_arg QUIET) -endif () - -# REQUIRED -set(_required_arg) -if (FoX_FIND_REQUIRED) - list(APPEND _required_arg REQUIRED) -endif () - -# Construct the moduleSpec to search for -if (DEFINED FoX_FIND_VERSION_RANGE) - # Can only parse the minimum requirement - list(APPEND PKG_MODULE_SPECS "fox>=${FoX_FIND_VERSION_MIN}") -elseif ({FoX_FIND_VERSION_EXACT) - # Requesting exact version - list(APPEND PKG_MODULE_SPECS "fox=${FoX_FIND_VERSION}") -elseif (DEFINED FoX_FIND_VERSION) - # Otherwise treat the request as minimum requirement - list(APPEND PKG_MODULE_SPECS "fox>=${FoX_FIND_VERSION}") -else () - # Fallthrough if no version is required - list(APPEND PKG_MODULE_SPECS "fox") -endif () - -## Call pkg-config -if (CMAKE_VERSION VERSION_LESS 3.28) - # https://gitlab.kitware.com/cmake/cmake/-/issues/25228 - set(ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS} 1) -endif () -if (CMAKE_VERSION VERSION_LESS 3.22) - # Back-porting - # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6345 - set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} 1) -endif () -pkg_search_module(FoX - ${_required_arg} ${_quiet_arg} - IMPORTED_TARGET - ${PKG_MODULE_SPECS}) - -## Create alias if package was found by pkg-config -if (FoX_FOUND) - add_library(FoX::FoX ALIAS PkgConfig::FoX) -endif () - -# Sanitize local variables -set(PKG_MODULE_SPECS) -set(_quiet_arg) -set(_required_arg)