############# CMake versioning and backward compatibility ##### cmake_minimum_required (VERSION 3.12) if(POLICY CMP0017) cmake_policy(SET CMP0017 OLD) endif(POLICY CMP0017) set(CMAKE_DISABLE_SOURCE_CHANGES ON) set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) # This policy has to do with variables called _ROOT # and possible collisions with module-finding. cmake_policy(SET CMP0074 OLD) enable_testing() ############ Include paths for CMake #### set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/../cmake/modules") set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_SOURCE_DIR}/../cmake/SCHISMCompile.cmake") include(MPIWrap) include(MakeDefineOption) include(SCHISMTest) message(STATUS "\n################ Begin SCHISM Configuration ################" ) message(STATUS "In-source builds not allowed") set(comp_lang_list C Fortran) project(SCHISM LANGUAGES ${comp_lang_list}) add_definitions("-DSCHISM") ########### Announce compiler ##### message(STATUS "\n### Your compiler is ${CMAKE_Fortran_COMPILER}") ########### Build types are Release, Debug and RelWithDebInfo (Release with debug info) ##### if (NOT CMAKE_BUILD_TYPE) message(STATUS "\n### No CMAKE_BUILD_TYPE selected in command or cache, default to Release. \nAlternatives are Debug and RelWithDebInfo") set(CMAKE_BUILD_TYPE "Release") endif() ########### C Preprocessor ##### # The thought is to enable this globally, since it is needed for all # of SCHISM and several Utilities if (NOT DEFINED C_PREPROCESS_FLAG) message(FATAL_ERROR "Preprocessor flag (e.g. -cpp for intel, -MPreprocess for PGI0 is not set") endif() add_compile_options(${C_PREPROCESS_FLAG}) ######### Algorithmic switches and build options involving functionality message(STATUS "\n### Processing algorithmic switches and build options involving functionality for main project") define_opt(NO_PARMETIS "Diable ParMETIS" OFF) define_opt(DEBUG "Enable diagnostics (slow and not suitable for production simulations" OFF) define_opt(USE_ANALYSIS "Triggers detailed calculations and output options" OFF) define_opt(INCLUDE_TIMING "Add timing profile instrumentation to simulation" OFF) define_opt(OLDIO "Old nc output option" OFF) define_opt(PREC_EVAP "Use precipitation/evaporation option" OFF) define_opt(USE_BULK_FAIRALL "Enable Fairall scheme" OFF) define_opt(USE_PAHM "Enable USE_PAHM scheme" OFF) define_opt(USE_HA "Enable Harmonic Analysis output" OFF) define_opt(USE_SIMPLE_WIND "Simplified wind data interface" OFF) define_opt(USE_GOTM "Enable compiling with GOTM turbulence closure" OFF) define_opt(USE_MARSH "Enable Marsh module" OFF) define_opt(DEBUG "Enable debug mode" OFF) define_opt(USE_GEN "Enable generic tracer module" OFF) define_opt(USE_AGE "Enable age tracer module" OFF) define_opt(ICM_PH "Enable pH module in ICM" OFF) define_opt(USE_DVD "Enable DVD module" OFF) if(NOT DEFINED TVD_LIM) message(WARNING "TVD_LIM must be provided, either in the cache. It must be one of SB, VL, MM or OS for Superbee, Van Leer, Minmod, or Osher. Default is VL") endif() set(TVD_LIM VL CACHE STRING "Flux limiter. SB, VL, MM or OS for Superbee, Van Leer, Minmod, or Osher") list(APPEND def_tags _TVD-${TVD_LIM}) string(CONCAT all_def_tags ${def_tags}) string(REPLACE USE_ "" def_tag_rev ${all_def_tags}) string(REPLACE INCLUDE_ "" def_tag_rev ${def_tag_rev}) message(STATUS "Build definition tags set to ${def_tag_rev}") ########### MPI Library ######## # The typical pattern with cmake is to use the mpi wrapper (e.g. mpif90) # to infer flags and locations for the compiler message(STATUS "\n### Configuring MPI Library") if ($ENV{MPI_VERSION}) set(MPIVERSION_DEFAULT $ENV{MPI_VERSION}) else ($ENV{MPI_VERSION}) set(MPIVERSION_DEFAULT 2) endif() set(MPIVERSION ${MPIVERSION_DEFAULT} CACHE STRING "Version of MPI API (1 or 2)") find_package(MPI REQUIRED) message(STATUS "MPIVERSION = ${MPIVERSION}") add_compile_definitions(MPIVERSION=${MPIVERSION}) #set_property(GLOBAL APPEND PROPERTY DEFINE-LIST "MPIVERSION=${MPIVERSION}") add_definitions(${MPI_Fortran_COMPILE_FLAGS}) if (CMAKE_Fortran_FLAGS) set(CMAKE_Fortran_FLAGS ${CMAKE_Fortran_FLAGS} ${MPI_Fortran_COMPILE_FLAGS}) endif (CMAKE_Fortran_FLAGS) include_directories(${MPI_Fortran_INCLUDE_PATH}) add_definitions(${MPI_C_COMPILE_FLAGS}) if (CMAKE_C_FLAGS) set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} ${MPI_C_COMPILE_FLAGS}) endif (CMAKE_C_FLAGS) include_directories(${MPI_C_INCLUDE_PATH}) ########### NetCDF Dependency is handled here because so many libraries use it ############## message(STATUS "\n### Configuring NetCDF ") #set(NetCDF_DIR "/usr/local/dms/pkg/netcdf/4.1.3-intel12.0-parallel") if( NOT DEFINED NetCDF_DIR AND DEFINED NETCDF_DIR) message(WARNING "Note the mixed case of NetCDF_DIR if you put it in your cache. This CMake variable is mixed case, different from the typical environment NETCDF_DIR. Proceeding anyway.") set(NetCDF_C_DIR ${NETCDF_C_DIR}) endif() if( NOT DEFINED NetCDF_C_DIR AND ($ENV{NETCDF_C_DIR} MATCHES ".+") ) message(STATUS "Using NETCDF_C_DIR location from environment.") set(NetCDF_C_DIR $ENV{NETCDF_C_DIR}) endif() if( NOT DEFINED NetCDF_FORTRAN_DIR AND ($ENV{NETCDF_FORTRAN_DIR} MATCHES ".+") ) message(STATUS "Using NETCDF_FORTRAN_DIR location from environment.") set(NetCDF_FORTRAN_DIR $ENV{NETCDF_FORTRAN_DIR}) endif() find_package(NetCDF REQUIRED COMPONENTS ${comp_lang_list}) if(NetCDF_NEEDS_HDF5) set( HDF5_USE_STATIC_LIBRARIES 1 ) find_package(HDF5 COMPONENTS C REQUIRED) # link_directories is bad cmake form, and was used because I would have had to add a lot to 2.6 to get the magic # these next couple lines can be removed if we uniformly require cmake 2.8 set( HDF_LIB_NAMES "hdf5_hl;hdf5;z" ) link_directories( ${HDF5_LIBRARY_DIRS} ) if(HDF5_FOUND) message(STATUS "HDF5 found") endif(HDF5_FOUND) endif(NetCDF_NEEDS_HDF5) include_directories( ${NetCDF_INCLUDE_DIRS} ) set (NetCDFLIBS ${NetCDF_LIBRARIES} ${HDF_LIB_NAMES}) # this might help to use old or pre-compiled GOTM versions: #if (USE_GOTM) # if (NOT DEFINED GOTM_DIR) # if( DEFINED $ENV{GOTM_DIR} ) # set( GOTM_DIR ${ENV{GOTM_DIR} CACHE PATH "Path to GOTM") # else( DEFINED ${ENV{GOTM_DIR}) # message(STATUS "GOTM_DIR not in the environment, setting to local copy -- should be pre built") # set(GOTM_DIR "${PROJECT_SOURCE_DIR}/GOTM3.2.5" CACHE PATH "Path to GOTM Library") # endif( DEFINED ${ENV{GOTM_DIR} ) # endif(NOT DEFINED GOTM_DIR) # find_package(GOTM REQUIRED) # set(GOTMLIBS ${GOTM_LIBRARIES} ) # message("GOTM_INCLUDE_DIRS: ${GOTM_INCLUDE_DIRS}") # include_directories(${GOTM_INCLUDE_DIRS}) #endif(USE_GOTM) ########### Put each type of output (exe, libraries, modules) in the normal places ### This file is untested for compilers with no output module directory option message(STATUS "\n### Assigning output directories for binaries (bin), modules (include) and libraries (lib)") if( CMAKE_Fortran_MODDIR_FLAG) SET( CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/include CACHE PATH "Output location for include files and fortran modules") include_directories("${CMAKE_Fortran_MODULE_DIRECTORY}") endif(CMAKE_Fortran_MODDIR_FLAG) set ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin CACHE PATH "Output Directory for executables." ) set ( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib CACHE PATH "Output Directory for all static libraries." ) set ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib CACHE PATH "Output Directory for all shared libraries." ) ########### Process libraries ###### message(STATUS "\n### Adding enabled libraries to project") ###### # Macro for adding a library module to avoid boilerplate: # name: directory for module (e.g. EcoSim) # option_name: compiler -D definition (e.g. USE_ECO) # default: ON/OFF Should generally be off except Hydro macro( add_module name option_name default) option(${option_name} "Use ${lib_name} module" ${default}) if (${option_name}) list(APPEND all_use_mod_defs "${option_name}") list(APPEND schismmoddirs ${name}) endif(${option_name}) endmacro(add_module) # Create list of modules add_module(WWMIII USE_WWM OFF) add_module(WW3 USE_WW3 OFF) add_module(COSINE USE_COSINE OFF) add_module(ICM USE_ICM OFF) add_module(FIB USE_FIB OFF) add_module(Ice USE_ICE OFF) add_module(Multi_ice USE_MICE OFF) add_module(Fabm USE_FABM OFF) add_module(EcoSim USE_ECO OFF) add_module(Sediment USE_SED OFF) add_module(Sed2d USE_SED2D OFF) add_module(Hydro USE_HYDRO ON) add_module(Core USE_SCHISM ON) if(NOT NO_PARMETIS) set(PARMETIS_VER ParMetis-4.0.3 CACHE STRING "Version and relative path to Parmetis library inside /src.") set(PARMETIS_DIR "${CMAKE_SOURCE_DIR}/${PARMETIS_VER}/" CACHE PATH "Path to ParMetis which defaults to /src/PARMETIS_VER in the schism source directory. Support for other locations not tested." FORCE) add_subdirectory( ${PARMETIS_VER} ) endif() # Now recurse them and process the contents. # In the process, we accumulate a (global) list of compile options and libraries foreach (moddir ${schismmoddirs}) add_subdirectory( ${moddir} ) #if(EXISTS "${PROJECT_SOURCE_DIR}/../test/unittest/${moddir}/CMakeLists.txt") # add_subdirectory( "${PROJECT_SOURCE_DIR}/../test/unittest/${moddir}" "${PROJECT_BINARY_DIR}/unittest/${moddir}" ) # endif() message(STATUS "Added ${moddir}") endforeach() ######## Executable Name # Create string to append to executable name with module names for the executable name string(CONCAT mod_tag ${all_use_mod_defs}) string(REPLACE USE_ _ mod_tag_rev ${mod_tag}) string(REPLACE _HYDRO_SCHISM "" mod_tag_rev ${mod_tag_rev}) ######## Tests ################## # Note this is fine for the unit test directory but it may not be what we want because it doesn't pick and # choose the subdirectories according to what modules got selected #add_subdirectory(${PROJECT_SOURCE_DIR}/../test/unittest/${moddir} ${PROJECT_BINARY_DIR}/unittest/${moddir}) ######## GOTM ############ # call cmake with -DUSE_GOTM=ON -DGOTM_BASE=[gotm code directory] # if(USE_GOTM) find_path(GOTM_BASE src/gotm/gotm.F90 DOC "GOTM source directory") if(GOTM_BASE) set(GOTM_BUILD_LIBRARIES_ONLY ON) set(GOTM_USE_FABM OFF CACHE BOOL "use GOTM without FABM") set(GOTM_USE_FLEXIBLE_OUTPUT OFF CACHE BOOL "use GOTM without flexible output") add_subdirectory(${GOTM_BASE}/src gotm) set(GOTM_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/gotm/modules) set(GOTM_LIBRARIES turbulence util) add_dependencies(hydro ${GOTM_LIBRARIES}) set(GOTMLIBS ${GOTM_LIBRARIES} ) set_property(TARGET hydro APPEND PROPERTY INCLUDE_DIRECTORIES "${GOTM_INCLUDE_DIRS}") endif(GOTM_BASE) endif(USE_GOTM) ######## Main executable ####### message(STATUS "\n### Configuring Driver") add_subdirectory( Driver ) get_property(all_define_options GLOBAL PROPERTY DEFINE-LIST) message(STATUS "All defines: ${all_define_options}") # Now that the list of global options are accumulated, apply it on all the directories foreach (moddir ${schismmoddirs} "Driver") set_property( DIRECTORY ${moddir} APPEND PROPERTY COMPILE_DEFINITIONS ${all_define_options} ${all_use_mod_defs}) endforeach() ######## Utilities ######## message(STATUS "\n### Configuring Utilities") add_subdirectory( Utility )