From c1e4ac5193113ff4a9ad2a58cfe00d2a8ca1dc0a Mon Sep 17 00:00:00 2001 From: Andy Stokely Date: Sun, 26 Oct 2025 16:53:08 -0600 Subject: [PATCH] Add CMake support for building and setting up the MPAS test core This commit introduces full CMake integration for the MPAS test core, including automatic setup, linking, and test data management. The new CMake functions handle downloading and extracting required input files if they are not already present, ensuring a fully self-contained test environment. These changes simplify development and make it possible to build and run the test core directly through CMake. --- CMakeLists.txt | 1 + cmake/Functions/MPAS_Functions.cmake | 10 +- cmake/Functions/setup_mpas_test_core.cmake | 143 +++++++++++++++++++++ src/core_test/CMakeLists.txt | 31 +++++ 4 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 cmake/Functions/setup_mpas_test_core.cmake create mode 100644 src/core_test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e7e010394d..27763d92e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.12) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Functions/MPAS_Functions.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Functions/setup_mpas_test_core.cmake) get_mpas_version(MPAS_VERSION) project(MPAS LANGUAGES C Fortran VERSION ${MPAS_VERSION} DESCRIPTION "MPAS - Model for Prediction Across Scales") diff --git a/cmake/Functions/MPAS_Functions.cmake b/cmake/Functions/MPAS_Functions.cmake index fe76556225..55dde6c009 100644 --- a/cmake/Functions/MPAS_Functions.cmake +++ b/cmake/Functions/MPAS_Functions.cmake @@ -203,7 +203,15 @@ function(mpas_core_target) #Per-core generated output and tables directory location set(CORE_DATADIR ${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${ARG_TARGET}) - file(MAKE_DIRECTORY ${CORE_DATADIR}) + # Special handling for core_test to setup test data + if (${ARG_TARGET} STREQUAL "core_test") + set(CORE_DATADIR ${CMAKE_BINARY_DIR}/test) + setup_mpas_test_core() + set_target_properties(mpas_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CORE_DATADIR}) + endif() + if (NOT EXISTS ${CORE_DATADIR}) + file(MAKE_DIRECTORY ${CORE_DATADIR}) + endif() #Process registry and generate includes, namelists, and streams get_git_version(git_version) diff --git a/cmake/Functions/setup_mpas_test_core.cmake b/cmake/Functions/setup_mpas_test_core.cmake new file mode 100644 index 0000000000..6383e85ccc --- /dev/null +++ b/cmake/Functions/setup_mpas_test_core.cmake @@ -0,0 +1,143 @@ +#------------------------------------------------------------------------------ +# download_mpas_test_data(dst_dir) +# +# Downloads the MPAS test data tarball to the specified destination directory. +# If the tarball already exists, it is not re-downloaded. +#------------------------------------------------------------------------------ +function(download_mpas_test_data dst_dir) + set(url "https://www2.mmm.ucar.edu/mpas_test_data/mpas_test_data.tar.gz") + set(output_file "${dst_dir}/mpas_test_data.tar.gz") + + file(MAKE_DIRECTORY "${dst_dir}") + + message(STATUS "Downloading MPAS test data from ${url}") + + execute_process( + COMMAND wget -O "${output_file}" "${url}" + WORKING_DIRECTORY "${dst_dir}" + RESULT_VARIABLE result + ) + + if(result EQUAL 0) + message(STATUS "MPAS test data saved to: ${output_file}") + else() + message(FATAL_ERROR "Failed to download MPAS test data (wget exit code: ${result})") + endif() +endfunction() + + +#------------------------------------------------------------------------------ +# untar_tarball(tarball_path dest_dir) +# +# Extracts a tarball into the specified destination directory. +#------------------------------------------------------------------------------ +function(untar_tarball tarball_path dest_dir) + if(NOT EXISTS "${tarball_path}") + message(FATAL_ERROR "Tarball not found: ${tarball_path}") + endif() + + file(MAKE_DIRECTORY "${dest_dir}") + + message(STATUS "Extracting ${tarball_path} → ${dest_dir}") + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xzf "${tarball_path}" + WORKING_DIRECTORY "${dest_dir}" + RESULT_VARIABLE untar_result + ) + + if(NOT untar_result EQUAL 0) + message(FATAL_ERROR "Failed to extract ${tarball_path} (exit code ${untar_result})") + else() + message(STATUS "Successfully extracted ${tarball_path} to ${dest_dir}") + endif() +endfunction() + + +#------------------------------------------------------------------------------ +# mpas_link_file_force(src dst) +# +# Creates a symbolic link from `src` to `dst`, overwriting if it exists. +#------------------------------------------------------------------------------ +function(mpas_link_file_force src dst) + if(NOT EXISTS "${src}") + message(FATAL_ERROR "Link source does not exist: ${src}") + endif() + + if(EXISTS "${dst}" OR IS_SYMLINK "${dst}") + file(REMOVE "${dst}") + endif() + + file(CREATE_LINK "${src}" "${dst}" SYMBOLIC) +endfunction() + + +#------------------------------------------------------------------------------ +# mpas_link_directory(src_dir dst_dir) +# +# Creates symbolic links in `dst_dir` for all files in `src_dir` (non-recursive). +#------------------------------------------------------------------------------ +function(mpas_link_directory src_dir dst_dir) + if(NOT IS_DIRECTORY "${src_dir}") + message(FATAL_ERROR "mpas_link_directory: Source is not a directory: ${src_dir}") + endif() + + file(MAKE_DIRECTORY "${dst_dir}") + file(GLOB files CONFIGURE_DEPENDS LIST_DIRECTORIES false "${src_dir}/*") + + foreach(file_path IN LISTS files) + get_filename_component(filename "${file_path}" NAME) + mpas_link_file_force("${file_path}" "${dst_dir}/${filename}") + endforeach() +endfunction() + + +#------------------------------------------------------------------------------ +# setup_mpas_test_core() +# +# Prepares the MPAS test core environment: +# - Downloads and extracts MPAS test data if missing. +# - Symlinks all extracted test data into the test directory. +#------------------------------------------------------------------------------ +function(setup_mpas_test_core) + set(dst_dir "${CMAKE_BINARY_DIR}/test") + + file(MAKE_DIRECTORY "${dst_dir}") + message(STATUS "Setting up MPAS test core in: ${dst_dir}") + + #-------------------------------------------------------------------------- + # Download test data tarball (if missing) + #-------------------------------------------------------------------------- + set(tarball_path "${dst_dir}/mpas_test_data.tar.gz") + if(EXISTS "${tarball_path}") + message(STATUS "MPAS test data tarball already exists: ${tarball_path}") + else() + message(STATUS "Downloading MPAS test data to: ${tarball_path}") + file(DOWNLOAD + "https://www2.mmm.ucar.edu/mpas_test_data/mpas_test_data.tar.gz" + "${tarball_path}" + SHOW_PROGRESS + STATUS status + LOG log + ) + list(GET status 0 status_code) + if(NOT status_code EQUAL 0) + message(FATAL_ERROR "Failed to download MPAS test data: ${log}") + endif() + endif() + + #-------------------------------------------------------------------------- + # Extract the test data + #-------------------------------------------------------------------------- + message(STATUS "Extracting MPAS test data...") + untar_tarball("${tarball_path}" "${dst_dir}") + + #-------------------------------------------------------------------------- + # Link extracted data into the test directory + #-------------------------------------------------------------------------- + set(extracted_dir "${dst_dir}/mpas_test_data") + if(EXISTS "${extracted_dir}") + mpas_link_directory("${extracted_dir}" "${dst_dir}") + endif() + + message(STATUS "MPAS test core setup complete.") +endfunction() diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt new file mode 100644 index 0000000000..9790814b72 --- /dev/null +++ b/src/core_test/CMakeLists.txt @@ -0,0 +1,31 @@ +include(${CMAKE_SOURCE_DIR}/cmake/Functions/setup_mpas_test_core.cmake) + +set(test_core_inc + block_dimension_routines.inc + core_variables.inc + define_packages.inc + domain_variables.inc + namelist_call.inc + namelist_defines.inc + setup_immutable_streams.inc + structs_and_variables.inc) + +## core_init_atosphere +set(test_core_srcs + mpas_test_core.F + mpas_test_core_field_tests.F + mpas_test_core_halo_exch.F + mpas_halo_testing.F + mpas_test_core_interface.F + mpas_test_core_sorting.F + mpas_test_openacc.F + mpas_test_core_string_utils.F + mpas_test_core_dmpar.F + mpas_test_core_timekeeping_tests.F + mpas_test_core_streams.F + mpas_test_core_stream_list.F + mpas_test_core_stream_inquiry.F +) + +add_library(core_test ${test_core_srcs}) +mpas_core_target(CORE test TARGET core_test INCLUDES ${test_core_inc})