cmake_minimum_required(VERSION 3.18)

project(hpc_stencil_demo LANGUAGES CXX)

option(ENABLE_MPI "Build MPI executable" ON)
option(ENABLE_TESTS "Build tests" ON)
option(ENABLE_BENCHMARKS "Enable benchmark CTest labels" ON)
option(ENABLE_MPI_OVERSUBSCRIBE "Allow MPI tests to oversubscribe small CI runners" ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_library(stencil_core
  src/stencil.cpp
)
target_include_directories(stencil_core
  PUBLIC
    ${PROJECT_SOURCE_DIR}/include
)
target_compile_options(stencil_core
  PRIVATE
    $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wall -Wextra -Wpedantic>
)

if(ENABLE_MPI)
  find_package(MPI REQUIRED)

  add_executable(stencil_mpi
    src/main_mpi.cpp
  )
  target_link_libraries(stencil_mpi
    PRIVATE
      stencil_core
      MPI::MPI_CXX
  )
endif()

if(ENABLE_TESTS)
  enable_testing()

  add_executable(stencil_unit_tests
    tests/test_stencil.cpp
  )
  target_link_libraries(stencil_unit_tests
    PRIVATE
      stencil_core
  )

  add_test(NAME stencil_unit_tests COMMAND stencil_unit_tests)

  if(ENABLE_MPI)
    set(HPC_DEMO_MPIEXEC_PREFLAGS "")
    if(ENABLE_MPI_OVERSUBSCRIBE)
      list(APPEND HPC_DEMO_MPIEXEC_PREFLAGS "--oversubscribe")
    endif()

    function(add_hpc_demo_mpi_test test_name ranks)
      add_test(
        NAME ${test_name}
        COMMAND
          ${MPIEXEC_EXECUTABLE}
          ${MPIEXEC_NUMPROC_FLAG} ${ranks}
          ${HPC_DEMO_MPIEXEC_PREFLAGS}
          $<TARGET_FILE:stencil_mpi>
          ${ARGN}
      )
      set_tests_properties(${test_name}
        PROPERTIES
          ENVIRONMENT "OMPI_ALLOW_RUN_AS_ROOT=1;OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1"
      )
    endfunction()

    add_hpc_demo_mpi_test(stencil_mpi_smoke 2 --size 1000 --steps 20)
  endif()

  if(ENABLE_BENCHMARKS AND ENABLE_MPI)
    add_hpc_demo_mpi_test(benchmark_stencil_mpi 4 --size 200000 --steps 200)
    set_tests_properties(benchmark_stencil_mpi PROPERTIES LABELS benchmark)
  endif()
endif()

install(TARGETS stencil_core
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
)

if(ENABLE_MPI)
  install(TARGETS stencil_mpi RUNTIME DESTINATION bin)
endif()

install(DIRECTORY include/ DESTINATION include)
