cmake_minimum_required(VERSION 3.10)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMakeModules/")

project(hark-lib)
set(PROJECT_VERSION "3.0.0")
set(SHORT_PACKAGE "HARKLIB")

set(OPTIONAL_LIBRARIES "")

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE)

option(USE_DETAIL_DEBUG "[For developer] Full dumps." OFF)

if(USE_DETAIL_DEBUG)
    add_definitions(-DVERBOSE_DEBUG)
endif(USE_DETAIL_DEBUG)

option(USE_EXTERNAL_BLAS "[TEST OPTION] If you want to change the processing of Eigen to an external library, usually use USE_LIB_OPENBLAS=ON or USE_LIB_MKL=ON. Use this option only if you understand Eigen's architecture. Enables the use of external BLAS level 2 and 3 routines." ON)
option(USE_EXTERNAL_LAPACKE "[TEST OPTION] If you want to change the processing of Eigen to an external library, usually use USE_LIB_OPENBLAS=ON or USE_LIB_MKL=ON. Use this option only if you understand Eigen's architecture. Enables the use of external LAPACK routines via LAPACKE interface." ON)
option(USE_EXTERNAL_LAPACKE_STRICT "[TEST OPTION] If you want to change the processing of Eigen to an external library, usually use USE_LIB_OPENBLAS=ON or USE_LIB_MKL=ON. Use this option only if you understand Eigen's architecture. Same as USE_EXTERNAL_LAPACKE but algorithms of lower numerical robustness are disabled." ON)
option(USE_EXTERNAL_MKL_VML "[TEST OPTION] If you want to change the processing of Eigen to an external library, usually use USE_LIB_OPENBLAS=ON or USE_LIB_MKL=ON. Use this option only if you understand Eigen's architecture. Enables the use of Intel VML (vector operations)." ON)
option(USE_EXTERNAL_MKL_DIRECT_CALL "[TEST OPTION] If you want to change the processing of Eigen to an external library, usually use USE_LIB_OPENBLAS=ON or USE_LIB_MKL=ON. Use this option only if you understand Eigen's architecture. The main effect is to enable MKL direct feature." ON)

option(USE_LIB_EIGEN "Clarify that Eigen should also be used when using an external library for only some operations. If no USE_LIB_* option is specified, or if only USE_LIB_EIGEN=ON is specified, Eigen will be used for all operations." OFF)
option(USE_LIB_OPENBLAS "Switch all operations performed by Eigen to OpenBLAS. If you want to use the external library only for some operations such as BLAS, LAPACK, and Vector operations, use USE_LIB_EIGEN=ON together and specify the details with the USE_EXTERNAL_* option." OFF)
option(USE_LIB_MKL "Switch all operations performed by Eigen to Intel MKL. If you want to use the external library only for some operations such as BLAS, LAPACK, and Vector operations, use USE_LIB_EIGEN=ON together and specify the details with the USE_EXTERNAL_* option." OFF)

if((NOT USE_LIB_OPENBLAS) AND (NOT USE_LIB_MKL))
    message(STATUS "[Eigen mode] Use \"Eigen\" for operations.")
elseif((NOT USE_LIB_EIGEN) AND USE_LIB_OPENBLAS AND (NOT USE_LIB_MKL))
    message(STATUS "[OpenBLAS mode] Use \"OpenBLAS\" for operations.")
    set(BLA_VENDOR OpenBLAS)
    find_package(BLAS)
    find_package(LAPACK)
    if(BLAS_FOUND AND LAPACK_FOUND)
        set(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
        add_definitions(-DEIGEN_USE_BLAS -DEIGEN_USE_LAPACKE -DEIGEN_USE_LAPACKE_STRICT)
    else(BLAS_FOUND AND LAPACK_FOUND)
        message(FATAL_ERROR "The BLAS and LAPACK were specified to use the external library OpenBLAS, but the BLAS and/or LAPACK libraries were not found.")
    endif(BLAS_FOUND AND LAPACK_FOUND)
elseif((NOT USE_LIB_EIGEN) AND (NOT USE_LIB_OPENBLAS) AND USE_LIB_MKL)
    message(STATUS "[Intel MKL mode] Use \"Intel MKL\" for operations.")
    set(BLA_VENDOR Intel10_64lp)
    find_package(BLAS)
    find_package(LAPACK)
    if(BLAS_FOUND AND LAPACK_FOUND)
        set(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES})
        add_definitions(-DEIGEN_USE_BLAS -DEIGEN_USE_LAPACKE -DEIGEN_USE_LAPACKE_STRICT)
        add_definitions(-DEIGEN_USE_MKL -DEIGEN_USE_MKL_VML -DEIGEN_MKL_DIRECT_CALL)
    else(BLAS_FOUND AND LAPACK_FOUND)
        message(FATAL_ERROR "The BLAS and LAPACK were specified to use the external library Intel MKL, but the BLAS and/or LAPACK libraries were not found.")
    endif(BLAS_FOUND AND LAPACK_FOUND)
else()
    message(STATUS "[Mixed mode] Use an external library based on the options you specify.")
    if((NOT USE_LIB_OPENBLAS) AND USE_LIB_MKL)
        add_definitions(-DEIGEN_USE_MKL)
        set(BLA_VENDOR Intel10_64lp)
        if(USE_EXTERNAL_BLAS)
            find_package(BLAS)
            if(BLAS_FOUND)
                set(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${BLAS_LIBRARIES})
                add_definitions(-DEIGEN_USE_BLAS)
            else(BLAS_FOUND)
                message(FATAL_ERROR "The BLAS was specified to use the external library Intel MKL, but the BLAS library was not found.")
            endif(BLAS_FOUND)
        endif(USE_EXTERNAL_BLAS)
        if(USE_EXTERNAL_LAPACKE)
            find_package(LAPACK)
            if(LAPACK_FOUND)
                set(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${LAPACK_LIBRARIES})
                add_definitions(-DEIGEN_USE_LAPACKE)
                if(USE_EXTERNAL_LAPACKE_STRICT)
                    add_definitions(-DEIGEN_USE_LAPACKE_STRICT)
                endif(USE_EXTERNAL_LAPACKE_STRICT)
            else(LAPACK_FOUND)
                message(FATAL_ERROR "The LAPACK was specified to use the external library Intel MKL, but the LAPACK library was not found.")
            endif(LAPACK_FOUND)
        endif(USE_EXTERNAL_LAPACKE)
        if(USE_EXTERNAL_MKL_VML)
            add_definitions(-DEIGEN_USE_MKL_VML)
        endif(USE_EXTERNAL_MKL_VML)
        if(USE_EXTERNAL_MKL_DIRECT_CALL)
            add_definitions(-DEIGEN_MKL_DIRECT_CALL)
        else(USE_EXTERNAL_MKL_DIRECT_CALL)
            add_definitions(-DEIGEN_MKL_NO_DIRECT_CALL)
        endif(USE_EXTERNAL_MKL_DIRECT_CALL)
    elseif(USE_LIB_OPENBLAS AND (NOT USE_LIB_MKL))
        set(BLA_VENDOR OpenBLAS)
        if(USE_EXTERNAL_BLAS)
            find_package(BLAS)
            if(BLAS_FOUND)
                set(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${BLAS_LIBRARIES})
                add_definitions(-DEIGEN_USE_BLAS)
            else(BLAS_FOUND)
                message(FATAL_ERROR "The BLAS was specified to use the external library OpenBLAS, but the BLAS library was not found.")
            endif(BLAS_FOUND)
        endif(USE_EXTERNAL_BLAS)
        if(USE_EXTERNAL_LAPACKE)
            find_package(LAPACK)
            if(LAPACK_FOUND)
                set(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${LAPACK_LIBRARIES})
                add_definitions(-DEIGEN_USE_LAPACKE)
                if(USE_EXTERNAL_LAPACKE_STRICT)
                    add_definitions(-DEIGEN_USE_LAPACKE_STRICT)
                endif(USE_EXTERNAL_LAPACKE_STRICT)
            else(LAPACK_FOUND)
                message(FATAL_ERROR "The LAPACK was specified to use the external library OpenBLAS, but the LAPACK library was not found.")
            endif(LAPACK_FOUND)
        endif(USE_EXTERNAL_LAPACKE)
    else()
        message(FATAL_ERROR "Both OpenBLAS and Intel MKL are selected. Please select only one. If the cache remains, explicitly set options to OFF to clear it, or delete the temporary files with the \"rm -rf ./*\" command and then re-execute cmake.")
    endif()
endif()

find_package(Eigen3 REQUIRED NO_MODULE)

find_package(LibHarkio3 REQUIRED)
set(OPTIONAL_INCLUDES ${LIBHARKIO3_INCLUDE_DIR})
set(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${LIBHARKIO3_LIBRARY})

add_subdirectory(include)
add_subdirectory(src)
#add_subdirectory(samples)

#set(INCLUDE_INSTALL_DIR "hoge")

include(CMakePackageConfigHelpers)
configure_package_config_file(${PROJECT_NAME}-config.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
  INSTALL_DESTINATION lib/${PROJECT_NAME}/cmake
  PATH_VARS PROJECT_NAME)
#  PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR)

write_basic_package_version_file(
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake
  VERSION ${PROJECT_VERSION}
  COMPATIBILITY SameMajorVersion)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
              ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake
        DESTINATION lib/${PROJECT_NAME}/cmake )

export(EXPORT ${PROJECT_NAME}
    FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.cmake"
)

# uninstall target
configure_file(
  "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
  "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
  IMMEDIATE @ONLY)

add_custom_target(uninstall
  COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
