cmake_minimum_required(VERSION 3.12)
set(KAHYPAR_USE_MINIMAL_BOOST ON)

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)

project(KaHyPar CXX C)
set(PROJECT_VENDOR "Sebastian Schlag")
set(PROJECT_CONTACT "kahypar@sebastianschlag.de")
set(PROJECT_URL "http://www.kahypar.org")
set(PROJECT_DESCRIPTION "KaHyPar: Karlsruhe Hypergraph Partitioning")

set(CMAKE_CXX_STANDARD 17)

include_directories(${PROJECT_SOURCE_DIR})

find_package(Threads REQUIRED)
message(STATUS "Found Threads: ${CMAKE_THREAD_LIBS_INIT}")

if (NOT CMAKE_BUILD_TYPE OR
((NOT CMAKE_BUILD_TYPE STREQUAL "Debug") AND
(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") AND
(NOT CMAKE_BUILD_TYPE STREQUAL "Release") AND
(NOT CMAKE_BUILD_TYPE STREQUAL "RELEASE") AND
(NOT CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") AND
(NOT CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO")))
    message(FATAL_ERROR "CMAKE_BUILD_TYPE not set correctly. Options are: Release|RELEASE, Debug|DEBUG, RelWithDebInfo|RELWITHDEBINFO.")
endif ()

# add third-party algorithms to project
include_directories(external_tools)
include_directories(external_tools/kahypar-shared-resources)

option(KAHYPAR_PYTHON_INTERFACE
        "Enable building the python interface" OFF)

option(KAHYPAR_USE_GCOV
        "Compile and run tests with gcov for coverage analysis." OFF)

option(KAHYPAR_DISABLE_ASSERTIONS
        "Disable KaHyPar's internal assertions." OFF)

option(KAHYPAR_USE_STANDARD_ASSERTIONS
        "Use standard C++ asserts instead of custom assertions." OFF)

option(KAHYPAR_USE_CPPCHECK
        "Enable static analysis via cppcheck" OFF)

if (KAHYPAR_DISABLE_ASSERTIONS)
    add_compile_definitions(KAHYPAR_DISABLE_ASSERTIONS)
endif (KAHYPAR_DISABLE_ASSERTIONS)

if (KAHYPAR_USE_STANDARD_ASSERTIONS)
    add_compile_definitions(KAHYPAR_USE_STANDARD_ASSERTIONS)
endif (KAHYPAR_USE_STANDARD_ASSERTIONS)

# definitions for input validation
option(KAHYPAR_INPUT_VALIDATION
        "Validate that the input is a correct hypergraph (both for CLI and C interface)." ON)

option(KAHYPAR_INPUT_VALIDATION_PROMOTE_WARNINGS_TO_ERRORS
        "During input validation, consider even recoverable issues as a fatal error." OFF)

if (KAHYPAR_INPUT_VALIDATION)
    add_compile_definitions(KAHYPAR_INPUT_VALIDATION)
endif (KAHYPAR_INPUT_VALIDATION)

if (KAHYPAR_INPUT_VALIDATION_PROMOTE_WARNINGS_TO_ERRORS)
    add_compile_definitions(KAHYPAR_INPUT_VALIDATION_PROMOTE_WARNINGS_TO_ERRORS)
endif (KAHYPAR_INPUT_VALIDATION_PROMOTE_WARNINGS_TO_ERRORS)

# defintions for heavy asserts
option(KAHYPAR_ENABLE_HEAVY_DATA_STRUCTURE_ASSERTIONS
        "Enable costly assertions for data structures." ON)

option(KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS
        "Enable costly assertions in preprocessing phase." ON)

option(KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS
        "Enable costly assertions in coarsening phase." ON)

option(KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS
        "Enable costly assertions in initial partitioning phase." ON)

option(KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS
        "Enable costly assertions in refinement phase." ON)

if (KAHYPAR_ENABLE_HEAVY_DATA_STRUCTURE_ASSERTIONS)
    add_compile_definitions(KAHYPAR_ENABLE_HEAVY_DATA_STRUCTURE_ASSERTIONS)
endif (KAHYPAR_ENABLE_HEAVY_DATA_STRUCTURE_ASSERTIONS)

if (KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS)
    add_compile_definitions(KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS)
endif (KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS)

if (KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS)
    add_compile_definitions(KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS)
endif (KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS)

if (KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS)
    add_compile_definitions(KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS)
endif (KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS)

if (KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS)
    add_compile_definitions(KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS)
endif (KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS)

add_compile_definitions(KAHYPAR_BUILD)

if (KAHYPAR_USE_MINIMAL_BOOST)
    # glob boost sources
    file(GLOB MINI_BOOST_SOURCES ./external_tools/boost/libs/program_options/src/*.cpp)

    add_library(mini_boost STATIC ${MINI_BOOST_SOURCES})
    set_target_properties(mini_boost PROPERTIES LINKER_LANGUAGE CXX)
    target_include_directories(mini_boost PUBLIC ./external_tools/boost/)
endif ()


if (NOT MSVC)
    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra ")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused ")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmaybe-uninitialized")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wfatal-errors")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-qual")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wredundant-decls")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
        #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnoexcept")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPARANOID ")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weffc++")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function")
    endif ()

    include(CheckCXXCompilerFlag)
    check_cxx_compiler_flag(-mcrc32 KAHYPAR_HAS_CRC32)
    if (KAHYPAR_HAS_CRC32)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcrc32")
    endif ()

    if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  -std=c++1y")
    endif ()

    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pthread -g3")

    if (CMAKE_SYSTEM_NAME MATCHES "Darwin" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm64")
        # M1 doesn't seem to support -mtune=native -march=native
#        set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
        set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g3 ")
    else ()
        set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -mtune=native -march=native")
        set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -mtune=native -march=native -g3 ")
    endif ()

    if (DEFINED ENV{TRAVIS_ENV})
        set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mno-avx")
    endif ()

    if (ENABLE_PROFILE MATCHES ON)
        message(STATUS "Profiling activated")
        set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLE_PROFILE")
        set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g3 -DENABLE_PROFILE -fno-omit-frame-pointer")
        set(PROFILE_FLAGS "-lprofiler")
    endif ()

    # disable warnings for the register keyword which is deprecated but used in the python 2.7 bindings
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-register")

elseif (MSVC)
    string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
    string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
    # Force to always compile with W4
    if (CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
        string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    else ()
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
    endif ()
    # raise warnings as errors
    #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")


    # https://msdn.microsoft.com/en-us/library/ms173499.aspx
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")

    # disable all warnings to see whether we can now build in below 1h on appveyor
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /w")
    ### disable verbose warnings:
    # warning C4589: Constructor of abstract class '...' ignores initializer for
    # virtual base class '...' (false positive warnings)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4589")
    # warning C4505: 'function' : unreferenced local function has been removed
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4505")
    # warning C4127: conditional expression is constant
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4127")
    # warning C4458: declaration of '...' hides class member
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4458")
    # warning C4459: declaration of '...' hides global declaration
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4459")
    # warning C4702: unreachable code
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4702")
    # warning C4250: ABC inherits XYZ via dominance
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4250")
    # warning C4503: decorated name length exceeded, name was truncated
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4503")
    # disable lots of warnings about "unsecure" C runtime function
    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
    # disable "The POSIX name for this item is deprecated. Instead, use the ISO C
    # and C++ conformant name.", Nope. We will not.
    add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
    # disable lots of warnings about "unsecure" STL functions
    add_definitions(-D_SCL_SECURE_NO_WARNINGS)
    # windef.h bizzarly defines min and max as macros, unless this is defined.
    add_definitions(-DNOMINMAX)
endif ()

message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
message(STATUS "CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}")
message(STATUS "CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}")

add_subdirectory(lib)
#add_subdirectory(kahypar/application)

