diff --git a/.gitignore b/.gitignore index 9b6da25..c256076 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,4 @@ *~ -/@cmake/ -/cmake/ -/cmake@/ /@env/ /env/ /env@/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ac9f5a..1c57aff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.13) +cmake_minimum_required (VERSION 3.24) cmake_policy (SET CMP0053 NEW) cmake_policy (SET CMP0054 NEW) cmake_policy (SET CMP0132 NEW) @@ -6,52 +6,30 @@ cmake_policy (SET CMP0132 NEW) project ( QFED VERSION 3.0.0 - LANGUAGES Fortran CXX C) # Note - CXX is required for ESMF + LANGUAGES Fortran C +) if ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") message(SEND_ERROR "In-source builds are disabled. Please issue cmake command in separate build directory.") endif ("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") -# Set the default build type to release -if (NOT CMAKE_BUILD_TYPE) - message (STATUS "Setting build type to 'Release' as none was specified.") - set (CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property (CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Release" "Aggressive") -endif () - -# Should find a better place for this - used in Chem component -#set (ACG_FLAGS -v) +list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") # mepo can now clone subrepos in three styles -set (ESMA_CMAKE_DIRS - cmake - @cmake - cmake@ - ) -foreach (dir IN LISTS ESMA_CMAKE_DIRS) +set (ESMA_ENV_DIRS + env + @env + env@ +) +foreach (dir IN LISTS ESMA_ENV_DIRS) if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${dir}) - list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/${dir}") + add_subdirectory (${dir}) endif () endforeach () -include (esma) - -ecbuild_declare_project() - -# Generic DFLAGS -# These should be relocated and/or eliminated. -add_definitions(-Dsys${CMAKE_SYSTEM_NAME} -DESMA64) -add_definitions(${MPI_Fortran_COMPILE_FLAGS}) -include_directories(${MPI_Fortran_INCLUDE_PATH}) - -esma_mepo_style(env env_dir) -esma_add_subdirectory (${env_dir}) - # Recursively build source tree -esma_add_subdirectory (src) +add_subdirectory (src) # https://www.scivision.dev/cmake-auto-gitignore-build-dir/ # --- auto-ignore build directory @@ -65,5 +43,3 @@ install( DESTINATION ${CMAKE_INSTALL_PREFIX} ) -# Adds ability to tar source -include(esma_cpack) diff --git a/cmake/UseF2Py.cmake b/cmake/UseF2Py.cmake new file mode 100644 index 0000000..fb4bac3 --- /dev/null +++ b/cmake/UseF2Py.cmake @@ -0,0 +1,131 @@ +# Copyright (c) 2024, Henry Schreiner +# Developed under NSF AWARD OAC-2209877 and by the respective contributors. +# All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +if(CMAKE_VERSION VERSION_LESS 3.17) + message(FATAL_ERROR "CMake 3.17+ required") +endif() + +include_guard(GLOBAL) + +if(TARGET Python::NumPy) + set(_Python Python CACHE INTERNAL "" FORCE) +elseif(TARGET Python3::NumPy) + set(_Python Python3 CACHE INTERNAL "" FORCE) +else() + message(FATAL_ERROR "You must find Python or Python3 with the NumPy component before including F2PY!") +endif() + +execute_process( + COMMAND "${${_Python}_EXECUTABLE}" -c + "import numpy.f2py; print(numpy.f2py.get_include())" + OUTPUT_VARIABLE F2PY_inc_output + ERROR_VARIABLE F2PY_inc_error + RESULT_VARIABLE F2PY_inc_result + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + +if(NOT F2PY_inc_result EQUAL 0) + message(FATAL_ERROR "Can't find f2py, got ${F2PY_inc_output} ${F2PY_inc_error}") +endif() + +set(F2PY_INCLUDE_DIR "${F2PY_inc_output}" CACHE STRING "" FORCE) +set(F2PY_OBJECT_FILES "${F2PY_inc_output}/fortranobject.c;${F2PY_inc_output}/fortranobject.h" CACHE STRING "" FORCE) +mark_as_advanced(F2PY_INCLUDE_DIR F2PY_OBJECT_FILES) + +add_library(F2Py::Headers IMPORTED GLOBAL INTERFACE) +target_include_directories(F2Py::Headers INTERFACE "${F2PY_INCLUDE_DIR}") + +function(f2py_object_library NAME TYPE) + add_library(${NAME} ${TYPE} "${F2PY_INCLUDE_DIR}/fortranobject.c") + target_link_libraries(${NAME} PUBLIC ${_Python}::NumPy F2Py::Headers) + if("${TYPE}" STREQUAL "OBJECT") + set_property(TARGET ${NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) + endif() +endfunction() + +function(f2py_generate_module NAME) + cmake_parse_arguments( + PARSE_ARGV 1 + F2PY + "NOLOWER;F77;F90" + "OUTPUT_DIR;OUTPUT_VARIABLE" + "F2PY_ARGS" + ) + set(ALL_FILES ${F2PY_UNPARSED_ARGUMENTS}) + + if(NOT ALL_FILES) + message(FATAL_ERROR "One or more input files must be specified") + endif() + + if(NOT F2PY_OUTPUT_DIR) + set(F2PY_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + endif() + + if(NAME MATCHES "\\.pyf$") + set(_file_arg "${NAME}") + get_filename_component(NAME "${NAME}" NAME_WE) + else() + set(_file_arg -m ${NAME}) + endif() + + if(F2PY_F77 AND F2PY_F90) + message(FATAL_ERROR "Can't specify F77 and F90") + elseif(NOT F2PY_F77 AND NOT F2PY_F90) + set(HAS_F90_FILE FALSE) + + foreach(file IN LISTS ALL_FILES) + if("${file}" MATCHES "\\.f90$") + set(HAS_F90_FILE TRUE) + break() + endif() + endforeach() + + if(HAS_F90_FILE) + set(F2PY_F90 ON) + else() + set(F2PY_F77 ON) + endif() + endif() + + if(F2PY_F77) + set(wrapper_files ${NAME}-f2pywrappers.f) + else() + set(wrapper_files ${NAME}-f2pywrappers.f ${NAME}-f2pywrappers2.f90) + endif() + + if(F2PY_NOLOWER) + set(lower "--no-lower") + else() + set(lower "--lower") + endif() + + set(abs_all_files) + foreach(file IN LISTS ALL_FILES) + if(IS_ABSOLUTE "${file}") + list(APPEND abs_all_files "${file}") + else() + list(APPEND abs_all_files "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + endforeach() + + add_custom_command( + OUTPUT ${NAME}module.c ${wrapper_files} + DEPENDS ${ALL_FILES} + VERBATIM + COMMAND + "${${_Python}_EXECUTABLE}" -m numpy.f2py + "${abs_all_files}" ${_file_arg} ${lower} ${F2PY_F2PY_ARGS} + COMMAND + "${CMAKE_COMMAND}" -E touch ${wrapper_files} + WORKING_DIRECTORY "${F2PY_OUTPUT_DIR}" + COMMENT + "F2PY making ${NAME} wrappers" + ) + + if(F2PY_OUTPUT_VARIABLE) + set(${F2PY_OUTPUT_VARIABLE} ${NAME}module.c ${wrapper_files} PARENT_SCOPE) + endif() +endfunction() diff --git a/components.yaml b/components.yaml index 3fa6937..2ff730c 100644 --- a/components.yaml +++ b/components.yaml @@ -8,19 +8,8 @@ env: tag: v4.29.1 develop: main -cmake: - local: ./@cmake - remote: ../ESMA_cmake.git - tag: v4.8.1 - develop: develop - -ecbuild: - local: ./@cmake/@ecbuild - remote: ../ecbuild.git - tag: geos/v1.2.0 - GMAOpyobs: local: ./src/Shared/@GMAOpyobs remote: ../GMAOpyobs.git - tag: feature/#17/adasilva/plume_rise + branch: feature/mathomp4/plume-no-esma diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1854dff..408f8eb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,14 +1,14 @@ -esma_add_subdirectory (Shared) -esma_add_subdirectory (plumerise) +add_subdirectory (Shared) +add_subdirectory (plumerise) file (GLOB qfed_files qfed/*.py) install ( - FILES ${qfed_files} + FILES ${qfed_files} DESTINATION lib/Python/qfed ) install ( - PROGRAMS qfed_l3a.py qfed_l3b.py + PROGRAMS qfed_l3a.py qfed_l3b.py DESTINATION bin ) diff --git a/src/Shared/CMakeLists.txt b/src/Shared/CMakeLists.txt index 7b282cb..be58032 100644 --- a/src/Shared/CMakeLists.txt +++ b/src/Shared/CMakeLists.txt @@ -1,3 +1,11 @@ -esma_add_subdirectories ( +# mepo can now clone subrepos in three styles +set (GMAOPYOBS_DIRS GMAOpyobs - ) + @GMAOpyobs + GMAOpyobs@ +) +foreach (dir IN LISTS GMAOPYOBS_DIRS) + if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${dir}) + add_subdirectory (${dir}) + endif () +endforeach () diff --git a/src/plumerise/f2py/CMakeLists.txt b/src/plumerise/f2py/CMakeLists.txt index 8732d63..82c9a2e 100644 --- a/src/plumerise/f2py/CMakeLists.txt +++ b/src/plumerise/f2py/CMakeLists.txt @@ -2,49 +2,54 @@ # Cmake rules for creating python modules with f2py and # -# The OVERRIDE tells esma_set_this() to name the library as -# what we set here rather than the name of the directory - -esma_set_this ( OVERRIDE plumerise ) - # cmake requirements # ------------------ - find_package(F2PY3 REQUIRED) +find_package(OpenMP REQUIRED COMPONENTS Fortran) + +# This setting is needed on macOS to ensure +# that the desired Python is found (i.e., if +# a user has installed their own Python, it +# should be favored over the system Python or +# one from Homebrew, etc.) +set (CMAKE_FIND_FRAMEWORK LAST) + +find_package( + Python + COMPONENTS Interpreter Development.Module NumPy + REQUIRED) -# Libray -# ------ - esma_add_library (${this} - SRCS LockePlume_Mod.F90 - rconstants.F90 - FreitasPlume_Mod.F90 - qsat_Mod.F90 - ) +include(UseF2Py) + +# Library: plumerise +# ------------------ +add_library (plumerise + LockePlume_Mod.F90 + rconstants.F90 + FreitasPlume_Mod.F90 + qsat_Mod.F90 +) +install(TARGETS plumerise DESTINATION lib/Python/plumerise) # Module: FreitasPlume # -------------------- - esma_add_f2py3_module(FreitasPlume_ - SOURCES FreitasPlume_py.F90 - DESTINATION lib/Python/plumerise - LIBRARIES plumerise - INCLUDEDIRS ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR}/lib - ${include_${this}} - USE_OPENMP - ) - add_dependencies(FreitasPlume_ ${this}) +f2py_object_library(FreitasPlume_object OBJECT) +f2py_generate_module(FreitasPlume_ FreitasPlume_py.F90 OUTPUT_VARIABLE FreitasPlume_files) +python_add_library(FreitasPlume_ MODULE "${FreitasPlume_files}" WITH_SOABI) +target_link_libraries(FreitasPlume_ PRIVATE Python::NumPy) +target_link_libraries(FreitasPlume_ PRIVATE FreitasPlume_object) +target_link_libraries(FreitasPlume_ PRIVATE plumerise) +target_link_libraries(FreitasPlume_ PRIVATE OpenMP::OpenMP_Fortran) +install(TARGETS FreitasPlume_ DESTINATION lib/Python/plumerise) # Module: Locke # ------------- - esma_add_f2py3_module(LockePlume_ - SOURCES LockePlume_py.F90 - DESTINATION lib/Python/plumerise - LIBRARIES plumerise - INCLUDEDIRS ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_BINARY_DIR}/lib - ${include_${this}} - USE_OPENMP - ) - add_dependencies(LockePlume_ ${this}) - - + +f2py_object_library(LockePlume_object OBJECT) +f2py_generate_module(LockePlume_ LockePlume_py.F90 OUTPUT_VARIABLE LockePlume_files) +python_add_library(LockePlume_ MODULE "${LockePlume_files}" WITH_SOABI) +target_link_libraries(LockePlume_ PRIVATE Python::NumPy) +target_link_libraries(LockePlume_ PRIVATE LockePlume_object) +target_link_libraries(LockePlume_ PRIVATE plumerise) +target_link_libraries(LockePlume_ PRIVATE OpenMP::OpenMP_Fortran) +install(TARGETS LockePlume_ DESTINATION lib/Python/plumerise)