# Requires CMake version 3.16
cmake_minimum_required(VERSION 3.16)

# Set the project name and the language
# CXX means C++
project(panic LANGUAGES CXX)

# Uses C++11
set(CMAKE_CXX_STANDARD 11)

# This makes it so it uses C++11, and fails if not found.
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Makes sure it uses basic options
# -std=c++11 instead of -std=gnu++11
set(CMAKE_CXX_EXTENSIONS OFF)

#---------------------------------------------------------------------------------------------------------------------------
# OPENMP CONFIGURATION
#---------------------------------------------------------------------------------------------------------------------------

# OpenMP is disabled by default.
# Enable with:
# cmake -S . -B build -DPANIC_ENABLE_OPENMP=ON
option(PANIC_ENABLE_OPENMP "Enable OpenMP support" OFF)

# Number of OpenMP threads.
# 0 means OpenMP decides the default.
# Example that overrides default is: "-DPANIC_OMP_NUM_THREADS=":
# cmake -S . -B build -DPANIC_ENABLE_OPENMP=ON -DPANIC_OMP_NUM_THREADS=4
set(PANIC_OMP_NUM_THREADS "0" CACHE STRING "Number of OpenMP threads. 0 means OpenMP default.")

#---------------------------------------------------------------------------------------------------------------------------
# SOURCE FILES
#---------------------------------------------------------------------------------------------------------------------------

# This finds all the .cpp files in the src/ folder
# and its subfolders.
# This is saved in the variable PANIC_SOURCES
file(GLOB_RECURSE PANIC_SOURCES CONFIGURE_DEPENDS
    src/*.cpp
)

#---------------------------------------------------------------------------------------------------------------------------
# EXECUTABLE
#---------------------------------------------------------------------------------------------------------------------------

# Creates an executable called "panic"
# It's built from main.cpp and all src/
add_executable(panic
    main.cpp
    ${PANIC_SOURCES}
)

#---------------------------------------------------------------------------------------------------------------------------
# INCLUDE DIRECTORIES
#---------------------------------------------------------------------------------------------------------------------------

# Tells the compiler where to look for header files.
# This makes includes like <core/types.hpp> work.
target_include_directories(panic PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

#---------------------------------------------------------------------------------------------------------------------------
# OPENMP BUILD SETTINGS
#---------------------------------------------------------------------------------------------------------------------------

# If the user enabled OpenMP with:
#   -DPANIC_ENABLE_OPENMP=ON
if(PANIC_ENABLE_OPENMP)

    # Ask CMake to search for OpenMP support for the compiler.
    # If found, CMake creates the target:
    #   OpenMP::OpenMP_CXX
    # This target contains the needed compiler and linker flags.
    find_package(OpenMP)

    # Check if CMake found OpenMP for C++.
    if(OpenMP_CXX_FOUND)

        # Link the panic executable with OpenMP.
        # This adds the correct compiler/linker options, for example -fopenmp.
        target_link_libraries(panic PRIVATE OpenMP::OpenMP_CXX)

        # Define preprocessor macros that the C++ code can read.
        #
        # This makes the compiler behave as if every .cpp file had:
        #   #define PANIC_USE_OPENMP 1
        #   #define PANIC_OMP_NUM_THREADS <value from CMake>
        #
        # Example:
        #   -DPANIC_OMP_NUM_THREADS=4
        #
        # becomes:
        #   #define PANIC_OMP_NUM_THREADS 4
        target_compile_definitions(panic PRIVATE
            PANIC_USE_OPENMP=1
            PANIC_OMP_NUM_THREADS=${PANIC_OMP_NUM_THREADS}
            PANIC_OMP_ALLOW_NESTED=0
        )

    else()

        # The user asked for OpenMP, but CMake could not find it.
        # So we warn the user and build PANIC without OpenMP instead.
        message(WARNING "OpenMP requested, but OpenMP was not found. Building without OpenMP.")

        # Tell the C++ code that OpenMP is disabled.
        target_compile_definitions(panic PRIVATE
            PANIC_USE_OPENMP=0
            PANIC_OMP_NUM_THREADS=0
            PANIC_OMP_ALLOW_NESTED=0
        )

    endif()

else()

    # The user did not enable OpenMP.
    # So PANIC builds as normal serial/portable code.
    target_compile_definitions(panic PRIVATE
        PANIC_USE_OPENMP=0
        PANIC_OMP_NUM_THREADS=0
    )

endif()