CMAKE_MINIMUM_REQUIRED(VERSION 3.0)

FIND_PROGRAM(CMAKE_C_COMPILER NAMES $ENV{CC} gcc PATHS ENV PATH NO_DEFAULT_PATH)
FIND_PROGRAM(CMAKE_CXX_COMPILER NAMES $ENV{CXX} g++ PATHS ENV PATH NO_DEFAULT_PATH)

OPTION(USE_CORE "Core" ON)
OPTION(USE_SU2SZ "SU2 and SZ Symmetries" ON)
OPTION(USE_DMRG "DMRG" ON)
OPTION(USE_BIG_SITE "Big Site" ON)
OPTION(USE_SP_DMRG "Stochastic PDMRG" ON)
OPTION(USE_IC "Internal Contraction" ON)
OPTION(USE_SANY "Any Symmetry" OFF)
OPTION(USE_SCI "SCI" OFF)
OPTION(USE_KSYMM "K Symmetry" OFF)
OPTION(USE_COMPLEX "Complex Number" OFF)
OPTION(USE_SG "General Spin Symmetry" OFF)
OPTION(USE_SINGLE_PREC "Single Precision" OFF)
OPTION(USE_BLIS "BLIS" OFF)
OPTION(ARCH_ARM64 "MacOS arch arm64" OFF)
OPTION(APPLE_ACC_SINGLE_PREC "Fix Apple Accelerate single prec" ON)
OPTION(BUILD_LIB "Build python block2.so" OFF)
OPTION(BUILD_CLIB "Build C++ block2.so" OFF)
OPTION(BUILD_TEST "Build C++ unit test" OFF)
OPTION(BUILD_EXE "Build executable block2" OFF)
OPTION(REUSE_OBJS "Reuse core objects" ON)
OPTION(USE_PCH "Build precompiled headers" ON)
OPTION(FORCE_LIB_ABS_PATH "Using absolute path when linking libraries" ON)
# For BUILD_CLIB, local static variables may vaiolate ODR in .so and .exe.
OPTION(USE_GLOBAL_VARIABLE "Use global variable instead of local static ones" ON)
OPTION(SIMPLE_TEST "Only compile basic unit tests" OFF)

IF (NOT ${USE_DMRG})
    SET(USE_BIG_SITE OFF)
    SET(USE_SP_DMRG OFF)
ENDIF()

# Project Name (must be python module name)

SET(PROJECT_NAME block2)
SET(PROJECT_VERSION 2.0)
PROJECT(${PROJECT_NAME} VERSION ${PROJECT_VERSION})

IF (${FORCE_LIB_ABS_PATH})
    CMAKE_POLICY(SET CMP0060 NEW) # force using absolute path when linking libraries
ENDIF()

# Check Python3 and Pybind11

SET(Python_ADDITIONAL_VERSIONS 3)
FIND_PACKAGE(PythonInterp)

IF (NOT PYTHONINTERP_FOUND)
    MESSAGE(FATAL_ERROR "Python3 not found.")
ENDIF()

FIND_PACKAGE(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})

EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig; \
        print(distutils.sysconfig.get_config_var('LIBDIR'))"
        OUTPUT_VARIABLE PYTHON_LIB_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig; \
        print(distutils.sysconfig.get_config_var('INCLUDEDIR'))"
        OUTPUT_VARIABLE PYTHON_INCLUDE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)

IF (PYTHONLIBS_FOUND)
    STRING(FIND ${PYTHONLIBS_VERSION_STRING} "." PYV_L REVERSE)
    STRING(SUBSTRING ${PYTHONLIBS_VERSION_STRING} 0 ${PYV_L} PYTHONLIBS_VERSION_STRING_SHORT)
ELSE()
    SET(PYTHONLIBS_VERSION_STRING_SHORT 0.0)
ENDIF()

MESSAGE(STATUS "PYTHONLIBS_VERSION_STRING_SHORT = ${PYTHONLIBS_VERSION_STRING_SHORT}")

IF ((NOT PYTHONLIBS_FOUND) OR NOT (${PYTHONLIBS_VERSION_STRING_SHORT} EQUAL ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}))
    EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig; \
        import os; print(os.path.join(distutils.sysconfig.get_config_var('LIBDIR'), \
        distutils.sysconfig.get_config_var('LDLIBRARY')))"
        OUTPUT_VARIABLE PYTHON_LIBRARIES OUTPUT_STRIP_TRAILING_WHITESPACE)
    EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_inc; \
        print(get_python_inc())"
        OUTPUT_VARIABLE PYTHON_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE)
ENDIF()

EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import importlib.machinery;print(importlib.machinery.EXTENSION_SUFFIXES[0])"
    OUTPUT_VARIABLE PYLIB_SUFFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import pybind11;print(pybind11.get_include())"
    OUTPUT_VARIABLE PYBIND_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE)

MESSAGE(STATUS "PROJECT_NAME = ${PROJECT_NAME}")
MESSAGE(STATUS "PYTHON_VERSION_MAJOR = ${PYTHON_VERSION_MAJOR}")
MESSAGE(STATUS "PYTHON_VERSION_MINOR = ${PYTHON_VERSION_MINOR}")
MESSAGE(STATUS "PYTHON_LIBRARIES = ${PYTHON_LIBRARIES}")
MESSAGE(STATUS "PYTHON_EXECUTABLE = ${PYTHON_EXECUTABLE}")
MESSAGE(STATUS "PYTHON_EXECUTABLE_HINT = ${PYTHON_EXECUTABLE_HINT}")
MESSAGE(STATUS "PYTHON_INCLUDE_DIRS = ${PYTHON_INCLUDE_DIRS}")
MESSAGE(STATUS "PYLIB_SUFFIX = ${PYLIB_SUFFIX}")
MESSAGE(STATUS "PYBIND_INCLUDE_DIRS = ${PYBIND_INCLUDE_DIRS}")

IF (${PYTHON_EXECUTABLE_HINT})
    IF (NOT (${PYTHON_EXECUTABLE_HINT} EQUAL ${PYTHON_EXECUTABLE}))
        MESSAGE(FATAL_ERROR "Python3 used by cmake (${PYTHON_EXECUTABLE}) does not match Python3 \
            used by setup.py (${PYTHON_EXECUTABLE_HINT})!")
    ENDIF()
ENDIF()

SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED True)

IF("${EXP_TMPL}" STREQUAL "NONE")
    SET(SRCS "")
    SET(PYBIND_SRCS "")
    SET(TMPL_FLAG "")
ELSE()
    FILE(GLOB_RECURSE SRCS src/instantiation/core/*.cpp)
    FILE(GLOB_RECURSE PYBIND_SRCS src/pybind/core/*.cpp)
    IF(${USE_SU2SZ})
        FILE(GLOB_RECURSE SRCS_U src/instantiation/core_u/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_U src/pybind/core_u/*.cpp)
        SET(SRCS ${SRCS_U} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_U} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_KSYMM})
        FILE(GLOB_RECURSE SRCS_K src/instantiation/core_k/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_K src/pybind/core_k/*.cpp)
        SET(SRCS ${SRCS_K} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_K} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SG})
        FILE(GLOB_RECURSE SRCS_G src/instantiation/core_g/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_G src/pybind/core_g/*.cpp)
        SET(SRCS ${SRCS_G} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_G} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SANY})
        FILE(GLOB_RECURSE SRCS_A src/instantiation/core_a/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_A src/pybind/core_a/*.cpp)
        SET(SRCS ${SRCS_A} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_A} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_COMPLEX})
        FILE(GLOB_RECURSE PYBIND_SRCS_Z src/pybind/core_z/*.cpp)
        SET(PYBIND_SRCS ${PYBIND_SRCS_Z} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_COMPLEX} AND ${USE_SU2SZ})
        FILE(GLOB_RECURSE SRCS_UZ src/instantiation/core_uz/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_UZ src/pybind/core_uz/*.cpp)
        SET(SRCS ${SRCS_UZ} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_UZ} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_COMPLEX} AND ${USE_KSYMM})
        FILE(GLOB_RECURSE SRCS_KZ src/instantiation/core_kz/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_KZ src/pybind/core_kz/*.cpp)
        SET(SRCS ${SRCS_KZ} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_KZ} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_COMPLEX} AND ${USE_SG})
        FILE(GLOB_RECURSE SRCS_GZ src/instantiation/core_gz/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_GZ src/pybind/core_gz/*.cpp)
        SET(SRCS ${SRCS_GZ} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_GZ} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_COMPLEX} AND ${USE_SANY})
        FILE(GLOB_RECURSE SRCS_AZ src/instantiation/core_az/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_AZ src/pybind/core_az/*.cpp)
        SET(SRCS ${SRCS_AZ} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_AZ} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SINGLE_PREC})
        FILE(GLOB_RECURSE SRCS_S src/instantiation/core_s/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_S src/pybind/core_s/*.cpp)
        SET(SRCS ${SRCS_S} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_S} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SINGLE_PREC} AND ${USE_COMPLEX})
        FILE(GLOB_RECURSE PYBIND_SRCS_C src/pybind/core_c/*.cpp)
        SET(PYBIND_SRCS ${PYBIND_SRCS_C} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SINGLE_PREC} AND ${USE_SU2SZ})
        FILE(GLOB_RECURSE SRCS_US src/instantiation/core_us/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_US src/pybind/core_us/*.cpp)
        SET(SRCS ${SRCS_US} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_US} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SINGLE_PREC} AND ${USE_COMPLEX} AND ${USE_SU2SZ})
        FILE(GLOB_RECURSE SRCS_UC src/instantiation/core_uc/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_UC src/pybind/core_uc/*.cpp)
        SET(SRCS ${SRCS_UC} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_UC} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SINGLE_PREC} AND ${USE_SG})
        FILE(GLOB_RECURSE SRCS_GS src/instantiation/core_gs/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_GS src/pybind/core_gs/*.cpp)
        SET(SRCS ${SRCS_GS} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_GS} ${PYBIND_SRCS})
    ENDIF()
    IF(${USE_SINGLE_PREC} AND ${USE_COMPLEX} AND ${USE_SG})
        FILE(GLOB_RECURSE SRCS_GC src/instantiation/core_gc/*.cpp)
        FILE(GLOB_RECURSE PYBIND_SRCS_GC src/pybind/core_gc/*.cpp)
        SET(SRCS ${SRCS_GC} ${SRCS})
        SET(PYBIND_SRCS ${PYBIND_SRCS_GC} ${PYBIND_SRCS})
    ENDIF()
    SET(TMPL_FLAG "-D_EXPLICIT_TEMPLATE")
ENDIF()

IF (${USE_DMRG})
    IF (NOT ("${EXP_TMPL}" STREQUAL "NONE"))
        FILE(GLOB_RECURSE DMRG_PYBIND_SRCS src/pybind/dmrg/*.cpp)
        SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS} ${PYBIND_SRCS})
        IF(${USE_SU2SZ})
            FILE(GLOB_RECURSE DMRG_SRCS_U src/instantiation/dmrg_u/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_U src/pybind/dmrg_u/*.cpp)
            SET(SRCS ${DMRG_SRCS_U} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_U} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_KSYMM})
            FILE(GLOB_RECURSE DMRG_SRCS_K src/instantiation/dmrg_k/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_K src/pybind/dmrg_k/*.cpp)
            SET(SRCS ${DMRG_SRCS_K} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_K} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_SG})
            FILE(GLOB_RECURSE DMRG_SRCS_G src/instantiation/dmrg_g/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_G src/pybind/dmrg_g/*.cpp)
            SET(SRCS ${DMRG_SRCS_G} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_G} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_SANY})
            FILE(GLOB_RECURSE DMRG_SRCS_A src/instantiation/dmrg_a/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_A src/pybind/dmrg_a/*.cpp)
            SET(SRCS ${DMRG_SRCS_A} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_A} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_COMPLEX} AND ${USE_SU2SZ})
            FILE(GLOB_RECURSE DMRG_SRCS_UZ src/instantiation/dmrg_uz/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_UZ src/pybind/dmrg_uz/*.cpp)
            SET(SRCS ${DMRG_SRCS_UZ} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_UZ} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_COMPLEX} AND ${USE_KSYMM})
            FILE(GLOB_RECURSE DMRG_SRCS_KZ src/instantiation/dmrg_kz/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_KZ src/pybind/dmrg_kz/*.cpp)
            SET(SRCS ${DMRG_SRCS_KZ} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_KZ} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_COMPLEX} AND ${USE_SG})
            FILE(GLOB_RECURSE DMRG_SRCS_GZ src/instantiation/dmrg_gz/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_GZ src/pybind/dmrg_gz/*.cpp)
            SET(SRCS ${DMRG_SRCS_GZ} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_GZ} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_COMPLEX} AND ${USE_SANY})
            FILE(GLOB_RECURSE DMRG_SRCS_AZ src/instantiation/dmrg_az/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_AZ src/pybind/dmrg_az/*.cpp)
            SET(SRCS ${DMRG_SRCS_AZ} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_AZ} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_SINGLE_PREC} AND ${USE_SU2SZ})
            FILE(GLOB_RECURSE DMRG_SRCS_US src/instantiation/dmrg_us/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_US src/pybind/dmrg_us/*.cpp)
            SET(SRCS ${DMRG_SRCS_US} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_US} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_SINGLE_PREC} AND ${USE_COMPLEX} AND ${USE_SU2SZ})
            FILE(GLOB_RECURSE DMRG_SRCS_UC src/instantiation/dmrg_uc/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_UC src/pybind/dmrg_uc/*.cpp)
            SET(SRCS ${DMRG_SRCS_UC} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_UC} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_SINGLE_PREC} AND ${USE_SG})
            FILE(GLOB_RECURSE DMRG_SRCS_GS src/instantiation/dmrg_gs/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_GS src/pybind/dmrg_gs/*.cpp)
            SET(SRCS ${DMRG_SRCS_GS} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_GS} ${PYBIND_SRCS})
        ENDIF()
        IF(${USE_SINGLE_PREC} AND ${USE_COMPLEX} AND ${USE_SG})
            FILE(GLOB_RECURSE DMRG_SRCS_GC src/instantiation/dmrg_gc/*.cpp)
            FILE(GLOB_RECURSE DMRG_PYBIND_SRCS_GC src/pybind/dmrg_gc/*.cpp)
            SET(SRCS ${DMRG_SRCS_GC} ${SRCS})
            SET(PYBIND_SRCS ${DMRG_PYBIND_SRCS_GC} ${PYBIND_SRCS})
        ENDIF()
    ENDIF()
    SET(DMRG_FLAG "-D_USE_DMRG")
ELSE()
    SET(DMRG_FLAG "")
ENDIF()

IF (${USE_BIG_SITE})
    IF (NOT ("${EXP_TMPL}" STREQUAL "NONE"))
        IF(${USE_SU2SZ})
            FILE(GLOB_RECURSE BIG_SITE_SRCS_U src/instantiation/big_site_u/*.cpp)
            FILE(GLOB_RECURSE BIG_SITE_PYBIND_SRCS_U src/pybind/big_site_u/*.cpp)
            SET(SRCS ${BIG_SITE_SRCS_U} ${SRCS})
            SET(PYBIND_SRCS ${BIG_SITE_PYBIND_SRCS_U} ${PYBIND_SRCS})
        ENDIF()
    ENDIF()
    SET(BIG_SITE_FLAG "-D_USE_BIG_SITE")
ELSE()
    SET(BIG_SITE_FLAG "")
ENDIF()

IF (${LARGE_BOND})
    SET(BOND_FLAG "-D_LARGE_BOND")
ELSEIF (${SMALL_BOND})
    SET(BOND_FLAG "-D_SMALL_BOND")
ENDIF()

IF (${USE_CORE})
    SET(CORE_FLAG "-D_USE_CORE")
ELSE()
    SET(CORE_FLAG "")
ENDIF()

IF (${USE_SU2SZ})
    SET(SU2SZ_FLAG "-D_USE_SU2SZ")
ELSE()
    SET(SU2SZ_FLAG "")
ENDIF()

IF (${USE_SP_DMRG})
    SET(SP_DMRG_FLAG "-D_USE_SP_DMRG")
ELSE()
    SET(SP_DMRG_FLAG "")
ENDIF()

IF (${USE_IC})
    SET(IC_FLAG "-D_USE_IC")
ELSE()
    SET(IC_FLAG "")
ENDIF()

IF (${USE_KSYMM})
    SET(KSYMM_FLAG "-D_USE_KSYMM")
ELSE()
    SET(KSYMM_FLAG "")
ENDIF()

IF (${USE_SG})
    SET(SG_FLAG "-D_USE_SG")
ELSE()
    SET(SG_FLAG "")
ENDIF()

IF (${USE_SANY})
    SET(SANY_FLAG "-D_USE_SANY")
ELSE()
    SET(SANY_FLAG "")
ENDIF()

IF (${USE_COMPLEX})
    SET(COMPLEX_FLAG "-D_USE_COMPLEX")
ELSE()
    SET(COMPLEX_FLAG "")
ENDIF()

IF (${USE_SINGLE_PREC})
    SET(SINGLE_PREC_FLAG "-D_USE_SINGLE_PREC")
ELSE()
    SET(SINGLE_PREC_FLAG "")
ENDIF()

IF (${USE_SCI})
    IF (NOT ${USE_DMRG})
        MESSAGE(FATAL_ERROR "USE_DMRG must be ON for USE_SCI=ON.")
    ENDIF()
    SET(SCI_FLAG "-D_USE_SCI")
    SET(SCI_INCLUDE_DIR "")
    IF (${SCI_WRAPPER2})
        SET(SCI_FLAG ${SCI_FLAG} -D_SCI_WRAPPER2)
        FIND_PATH(SCI_INCLUDE_DIR NAMES pybind_sci.hpp HINTS $ENV{SCI})
        MESSAGE(STATUS "SCI_INCLUDE_DIR = ${SCI_INCLUDE_DIR}")
    ENDIF()
ELSE()
    SET(SCI_INCLUDE_DIR "")
    SET(SCI_FLAG "")
ENDIF()

MESSAGE(STATUS "BUILD_LIB = ${BUILD_LIB}")
MESSAGE(STATUS "BUILD_CLIB = ${BUILD_CLIB}")
MESSAGE(STATUS "BUILD_TEST = ${BUILD_TEST}")
MESSAGE(STATUS "BUILD_EXE = ${BUILD_EXE}")
MESSAGE(STATUS "REUSE_OBJS = ${REUSE_OBJS}")
MESSAGE(STATUS "USE_PCH = ${USE_PCH}")

IF (NOT(APPLE) AND NOT(WIN32))
    SET(NO_AS_NEEDED -Wl,--no-as-needed)
ELSEIF (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
    SET(XPREP -Xpreprocessor)
    INCLUDE_DIRECTORIES(/usr/local/include)
ENDIF()

SET(PTHREAD pthread)
CMAKE_POLICY(SET CMP0054 NEW) # quoted variable for STREQUAL
CMAKE_POLICY(SET CMP0074 NEW) # BLAS_ROOT

IF (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
    SET(OMP_FLAG -qopenmp)
ELSEIF (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    SET(OMP_FLAG -openmp)
ELSE()
    SET(OMP_FLAG -fopenmp)
ENDIF()

IF (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    SET(OMP_LIB_NAME "")
    SET(PTHREAD "")
    IF("${OMP_LIB}" STREQUAL "SEQ")
        SET(MKL_OMP_LIB_NAME mkl_sequential)
        SET(MKL_OMP_VALUE 0)
    ELSEIF ("${OMP_LIB}" STREQUAL "INTEL")
        SET(MKL_OMP_LIB_NAME mkl_intel_thread)
        SET(MKL_OMP_VALUE 2)
    ELSEIF ("${OMP_LIB}" STREQUAL "TBB")
        SET(MKL_OMP_LIB_NAME mkl_tbb_thread)
        SET(MKL_OMP_VALUE 3)
    ELSE()
        SET(OMP_LIB INTEL)
        SET(MKL_OMP_LIB_NAME mkl_intel_thread)
        UNSET(OMP_LIB_NAME)
        FIND_LIBRARY(OMP_LIB_NAME NAMES iomp5md PATHS $ENV{OMPROOT} $ENV{OMPROOT}/lib $ENV{OMPROOT}/lib/intel64_win)
        SET(MKL_OMP_VALUE 2)
    ENDIF()
ELSEIF (WIN32)
    SET(OMP_LIB_NAME "")
    SET(PTHREAD "")
    SET(OMP_LIB INTEL)
    SET(MKL_OMP_LIB_NAME mkl_intel_thread)
    UNSET(OMP_LIB_NAME)
    FIND_LIBRARY(OMP_LIB_NAME NAMES iomp5md PATHS $ENV{OMPROOT} $ENV{OMPROOT}/lib $ENV{OMPROOT}/lib/intel64_win)
    SET(MKL_OMP_VALUE 2)
ELSEIF ("${OMP_LIB}" STREQUAL "SEQ")
    FIND_LIBRARY(OMP_LIB_NAME NAMES gomp PATHS /usr/local/lib /usr/lib64)
    IF(NOT OMP_LIB_NAME)
        SET(OMP_LIB_NAME "")
        SET(PTHREAD "")
    ENDIF()
    SET(MKL_OMP_LIB_NAME mkl_sequential)
    SET(MKL_OMP_VALUE 0)
ELSEIF ("${OMP_LIB}" STREQUAL "INTEL")
    FIND_LIBRARY(OMP_LIB_NAME NAMES iomp5 PATHS /usr/local/lib /usr/lib64)
    IF (NOT OMP_LIB_NAME)
        EXECUTE_PROCESS(
            COMMAND ${CMAKE_CXX_COMPILER} -print-search-dirs
            COMMAND grep "^lib" COMMAND awk -F "=" "{print $2}" COMMAND tr ":" ";"
            OUTPUT_VARIABLE OMP_LIB_HINT OUTPUT_STRIP_TRAILING_WHITESPACE)
        FIND_LIBRARY(OMP_LIB_NAME NAMES iomp5 PATHS ${OMP_LIB_HINT})
    ENDIF()
    SET(MKL_OMP_LIB_NAME mkl_intel_thread)
    SET(MKL_OMP_VALUE 2)
ELSEIF ("${OMP_LIB}" STREQUAL "TBB")
    FIND_LIBRARY(OMP_LIB_NAME NAMES gomp PATHS /usr/local/lib /usr/lib64)
    IF(NOT OMP_LIB_NAME)
        SET(OMP_LIB_NAME "")
        SET(PTHREAD "")
    ENDIF()
    SET(MKL_OMP_LIB_NAME mkl_tbb_thread)
    SET(MKL_OMP_VALUE 3)
ELSEIF ((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") OR (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM"))
    EXECUTE_PROCESS(
        COMMAND ${CMAKE_CXX_COMPILER} -print-search-dirs
        COMMAND grep "^lib" COMMAND awk -F "=" "{print $2}" COMMAND tr ":" ";"
        OUTPUT_VARIABLE OMP_LIB_HINT OUTPUT_STRIP_TRAILING_WHITESPACE)
    FIND_LIBRARY(OMP_LIB_NAME NAMES iomp5 PATHS ${OMP_LIB_HINT} /usr/local/lib /usr/lib64 ${PYTHON_LIB_PATH} NO_DEFAULT_PATH)
    SET(MKL_OMP_LIB_NAME mkl_intel_thread)
    SET(MKL_OMP_VALUE 2)
ELSEIF (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
    IF("${OMP_LIB}" STREQUAL "OMP")
        SET(OMP_LIB_FIND_NAME omp)
    ELSE()
        SET(OMP_LIB_FIND_NAME iomp5)
    ENDIF()
    FIND_LIBRARY(OMP_LIB_NAME NAMES ${OMP_LIB_FIND_NAME} PATHS $ENV{OMPROOT} $ENV{OMPROOT}/lib NO_DEFAULT_PATH)
    IF (NOT OMP_LIB_NAME)
        FIND_LIBRARY(OMP_LIB_NAME NAMES ${OMP_LIB_FIND_NAME} PATHS /usr/local/lib /usr/lib64 ${PYTHON_LIB_PATH})
    ENDIF()
    IF (NOT OMP_LIB_NAME)
        EXECUTE_PROCESS(
            COMMAND ${CMAKE_CXX_COMPILER} -print-search-dirs
            COMMAND grep "^lib" COMMAND awk -F "=" "{print $2}" COMMAND tr ":" ";"
            OUTPUT_VARIABLE OMP_LIB_HINT OUTPUT_STRIP_TRAILING_WHITESPACE)
        FIND_LIBRARY(OMP_LIB_NAME NAMES ${OMP_LIB_FIND_NAME} PATHS ${OMP_LIB_HINT})
    ENDIF()
    SET(MKL_OMP_LIB_NAME mkl_intel_thread)
    SET(MKL_OMP_VALUE 2)
ELSE()
    SET(OMP_LIB GNU)
    FIND_LIBRARY(OMP_LIB_NAME NAMES gomp PATHS /usr/local/lib /usr/lib64 ${PYTHON_LIB_PATH})
    IF (NOT OMP_LIB_NAME)
        EXECUTE_PROCESS(
            COMMAND ${CMAKE_CXX_COMPILER} -print-search-dirs
            COMMAND grep "^lib" COMMAND awk -F "=" "{print $2}" COMMAND tr ":" ";"
            OUTPUT_VARIABLE OMP_LIB_HINT OUTPUT_STRIP_TRAILING_WHITESPACE)
        FIND_LIBRARY(OMP_LIB_NAME NAMES gomp PATHS ${OMP_LIB_HINT})
    ENDIF()
    SET(MKL_OMP_LIB_NAME mkl_gnu_thread)
    SET(MKL_OMP_VALUE 1)
ENDIF()

IF (${USE_BLIS})
    FIND_PATH(BLIS_INCLUDE_DIR NAMES blis/blis.h HINTS $ENV{MKLROOT}/include /usr/local/include
        $ENV{BLIS_PREFIX}/include ${PYTHON_INCLUDE_PATH})
    FIND_LIBRARY(BLIS_LIBS NAMES libblis.so PATHS $ENV{MKLROOT}/lib /usr/local/lib /usr/lib64
        $ENV{BLIS_PREFIX}/lib ${PYTHON_INCLUDE_PATH})
    SET(BLIS_FLAG "-D_HAS_BLIS")
ENDIF()

IF (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    SET(OPT_FLAG ${OMP_FLAG} -O2 -bigobj -MP -WX "-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING")
ELSEIF("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
    SET(OPT_FLAG -O0 -g ${XPREP} ${OMP_FLAG} -fstack-check -fno-omit-frame-pointer -fno-optimize-sibling-calls
        -Werror -Werror=return-type)
ELSE()
    SET(OPT_FLAG -O3 -funroll-loops ${XPREP} ${OMP_FLAG} -Werror -Werror=return-type)
ENDIF()

IF ((NOT APPLE) AND (NOT WIN32) AND (NOT (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")))
    SET(OPT_FLAG ${OPT_FLAG} -Wno-psabi)
ENDIF()

IF ((NOT APPLE) AND (NOT WIN32) AND (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM"))
    SET(OPT_FLAG ${OPT_FLAG} -Wno-unused-command-line-argument -Wno-tautological-constant-compare)
ENDIF()

IF (${ARCH_ARM64})
    SET(ARCH_FLAG -arch arm64)
    SET(ARCH_LINK_FLAGS "-arch arm64")
ELSE()
    SET(ARCH_FLAG "")
    SET(ARCH_LINK_FLAGS "")
ENDIF()

IF (${USE_MKL})
    SET(USE_MKL_ANY ON)
ELSEIF(${USE_MKL64})
    SET(USE_MKL_ANY ON)
ELSE()
    SET(USE_MKL_ANY OFF)
ENDIF()

IF (${TBB})
    FIND_PATH(TBB_INCLUDE_DIR NAMES tbb/tbb.h
        HINTS $ENV{MKLROOT}/include /usr/local/include $ENV{TBBROOT}/include ${PYTHON_INCLUDE_PATH})
    FIND_LIBRARY(TBB_LIB NAMES tbb
        PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib $ENV{TBBROOT}/lib ${PYTHON_LIB_PATH})
    FIND_LIBRARY(TBB_LIB_MAL NAMES tbbmalloc
        PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib $ENV{TBBROOT}/lib ${PYTHON_LIB_PATH})
    FIND_LIBRARY(TBB_LIBS_MALP NAMES tbbmalloc_proxy
        PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib $ENV{TBBROOT}/lib ${PYTHON_LIB_PATH})
    SET(TBB_LIBS ${TBB_LIB} ${TBB_LIB_MAL} ${TBB_LIBS_MALP})
    SET(TBB_FLAG "-D_HAS_TBB")
ENDIF()

IF (${USE_MKL_ANY})
    SET(CMAKE_FIND_LIBRARY_SUFFIXES_BKP ${CMAKE_FIND_LIBRARY_SUFFIXES})
    SET(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES_BKP};.so.1;.1.dylib;.so.2;.2.dylib;.so.3;.3.dylib;.so.4;.4.dylib")
    FIND_PATH(MKL_INCLUDE_DIR NAMES mkl.h HINTS $ENV{MKLROOT}/include /usr/local/include ${PYTHON_INCLUDE_PATH})
    IF (WIN32)
        SET(MKL_LIB_NAME_PRE_SUF "_dll")
    ELSE()
        SET(MKL_LIB_NAME_PRE_SUF "")
    ENDIF()
    IF (${USE_MKL})
        FIND_LIBRARY(MKL_LIB_LP NAMES mkl_intel_lp64${MKL_LIB_NAME_PRE_SUF}
            PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib ${PYTHON_LIB_PATH} NO_DEFAULT_PATH)
        SET(MKL_FLAG "-D_HAS_INTEL_MKL=${MKL_OMP_VALUE}")
    ELSE()
        FIND_LIBRARY(MKL_LIB_LP NAMES mkl_intel_ilp64${MKL_LIB_NAME_PRE_SUF}
            PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib ${PYTHON_LIB_PATH} NO_DEFAULT_PATH)
        SET(MKL_FLAG "-D_HAS_INTEL_MKL=${MKL_OMP_VALUE}" "-DMKL_ILP64")
    ENDIF()
    FIND_LIBRARY(MKL_LIB_CORE NAMES mkl_core${MKL_LIB_NAME_PRE_SUF}
        PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib ${PYTHON_LIB_PATH} NO_DEFAULT_PATH)
    FIND_LIBRARY(MKL_LIB_GT NAMES ${MKL_OMP_LIB_NAME}${MKL_LIB_NAME_PRE_SUF}
        PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib ${PYTHON_LIB_PATH} NO_DEFAULT_PATH)
    # AVX and AVX512 are required to avoid setting LD_PRELOAD for python
    FIND_LIBRARY(MKL_LIB_AVX NAMES mkl_avx2
        PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib ${PYTHON_LIB_PATH} NO_DEFAULT_PATH)
    FIND_LIBRARY(MKL_LIB_AVX512 NAMES mkl_avx512
        PATHS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64 /usr/local/lib ${PYTHON_LIB_PATH} NO_DEFAULT_PATH)
    IF (NOT MKL_LIB_AVX)
        SET(MKL_LIB_AVX "")
    ENDIF()
    IF (NOT MKL_LIB_AVX512)
        SET(MKL_LIB_AVX512 "")
    ENDIF()
    SET(MKL_LIBS ${NO_AS_NEEDED} ${PTHREADS} ${MKL_LIB_LP} ${MKL_LIB_CORE} ${MKL_LIB_GT}
        ${OMP_LIB_NAME} ${MKL_LIB_AVX} ${MKL_LIB_AVX512})
    SET(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BKP})
    MESSAGE(STATUS "MKL_INCLUDE_DIR = ${MKL_INCLUDE_DIR}")
    MESSAGE(STATUS "MKL_LIBS = ${MKL_LIBS}")
ELSE()
    IF (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
        SET(BLA_VENDOR Apple)
    ENDIF()

    IF (NOT ${USE_BLIS})
        FIND_PACKAGE(BLAS REQUIRED)
    ENDIF()

    FIND_PACKAGE(LAPACK REQUIRED)

    SET(MKL_INCLUDE_DIR "")
    SET(MKL_LIBS "")
    SET(MKL_FLAG "")
ENDIF()

IF(${F77UNDERSCORE})
    SET(MKL_FLAG ${MKL_FLAG} "-D_F77UNDERSCORE")
ENDIF()

IF (APPLE AND ${USE_SINGLE_PREC} AND (NOT ${USE_MKL_ANY}) AND ${APPLE_ACC_SINGLE_PREC})
    SET(MKL_FLAG ${MKL_FLAG} "-D_APPLE_ACC_SINGLE_PREC")
ENDIF()

IF (${MPI})
    FIND_PACKAGE(MPI)

    IF (NOT MPI_FOUND)
        MESSAGE(FATAL_ERROR "MPI not found. Make sure CMAKE_CXX_COMPILER, MPI_CXX_COMPILER and MPI_C_COMPILER are set.")
    ENDIF()

    MESSAGE(STATUS "MPI_COMPILE_FLAGS = ${MPI_COMPILE_FLAGS}")
    MESSAGE(STATUS "MPI_LINK_FLAGS = ${MPI_LINK_FLAGS}")
    MESSAGE(STATUS "MPI_INCLUDE_PATH = ${MPI_INCLUDE_PATH}")
    MESSAGE(STATUS "MPI_CXX_LIBRARIES = ${MPI_CXX_LIBRARIES}")
    SET(MPI_INCLUDE_DIR ${MPI_INCLUDE_PATH})
    SET(MPI_LIBS ${MPI_CXX_LIBRARIES})
    SET(MPI_FLAG "-D_HAS_MPI")
    SET(OPT_FLAG ${OPT_FLAG} ${MPI_COMPILE_FLAGS})
ELSE()
    SET(MPI_LINK_FLAGS "")
    SET(MPI_COMPILE_FLAGS "")
    SET(MPI_INCLUDE_DIR "")
    SET(MPI_LIBS "")
    SET(MPI_FLAG "")
ENDIF()

IF (NOT(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"))
    SET(OPT_FLAG ${OPT_FLAG} -Wno-error=attributes -Wno-attributes -Wno-deprecated-declarations)
ENDIF()

IF (USE_GLOBAL_VARIABLE)
    IF (NOT ("${EXP_TMPL}" STREQUAL "NONE"))
        SET(OPT_FLAG ${OPT_FLAG} "-D_USE_GLOBAL_VARIABLE")
    ELSE()
        MESSAGE(FATAL_ERROR "-DEXP_TMPL must not be NONE for USE_GLOBAL_VARIABLE.")
    ENDIF()
ENDIF()

MESSAGE(STATUS "SRCS = ${SRCS}")
MESSAGE(STATUS "PYBIND_SRCS = ${PYBIND_SRCS}")
MESSAGE(STATUS "OPT_FLAG = ${OPT_FLAG}")
MESSAGE(STATUS "ARCH_FLAG = ${ARCH_FLAG}")
MESSAGE(STATUS "BOND_FLAG = ${BOND_FLAG}")
MESSAGE(STATUS "MKL_FLAG = ${MKL_FLAG}")
MESSAGE(STATUS "CORE_FLAG = ${CORE_FLAG}")
MESSAGE(STATUS "SU2SZ_FLAG = ${SU2SZ_FLAG}")
MESSAGE(STATUS "SANY_FLAG = ${SANY_FLAG}")
MESSAGE(STATUS "DMRG_FLAG = ${DMRG_FLAG}")
MESSAGE(STATUS "BIG_SITE_FLAG = ${BIG_SITE_FLAG}")
MESSAGE(STATUS "SP_DMRG_FLAG = ${SP_DMRG_FLAG}")
MESSAGE(STATUS "IC_FLAG = ${IC_FLAG}")
MESSAGE(STATUS "KSYMM_FLAG = ${KSYMM_FLAG}")
MESSAGE(STATUS "SG_FLAG = ${SG_FLAG}")
MESSAGE(STATUS "COMPLEX_FLAG = ${COMPLEX_FLAG}")
MESSAGE(STATUS "SINGLE_PREC_FLAG = ${SINGLE_PREC_FLAG}")
MESSAGE(STATUS "SCI_FLAG = ${SCI_FLAG}")
MESSAGE(STATUS "TBB_FLAG = ${TBB_FLAG}")
MESSAGE(STATUS "MPI_FLAG = ${MPI_FLAG}")
MESSAGE(STATUS "OMP_LIB = ${OMP_LIB_NAME}")
MESSAGE(STATUS "MKL_OMP_LIB_NAME = ${MKL_OMP_LIB_NAME}")
MESSAGE(STATUS "TBB_LIBS = ${TBB_LIBS}")
MESSAGE(STATUS "BLIS_LIBS = ${BLIS_LIBS}")
MESSAGE(STATUS "BLIS_FLAG = ${BLIS_FLAG}")
MESSAGE(STATUS "USE_GLOBAL_VARIABLE = ${USE_GLOBAL_VARIABLE}")

SET(TARGETS "")
SET(CORE_SRCS ${SRCS})

IF (${REUSE_OBJS})
    ADD_LIBRARY(b2_core OBJECT ${SRCS})
    LIST(APPEND TARGETS b2_core)
    SET(CORE_SRCS $<TARGET_OBJECTS:b2_core>)
ENDIF()

IF (${BUILD_LIB})
    ADD_LIBRARY(b2_py_obj OBJECT src/pybind.cpp ${PYBIND_SRCS})
    ADD_LIBRARY(b2_py MODULE $<TARGET_OBJECTS:b2_py_obj> ${CORE_SRCS})
    SET_TARGET_PROPERTIES(b2_py PROPERTIES SUFFIX "${PYLIB_SUFFIX}" PREFIX "")
    LIST(APPEND TARGETS b2_py b2_py_obj)
    IF (APPLE)
        TARGET_LINK_LIBRARIES(b2_py PUBLIC -Wl,-undefined,dynamic_lookup)
    ENDIF()
    IF (NOT(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"))
        SET(VIS_OPT_FLAG -fvisibility=hidden)
        TARGET_COMPILE_OPTIONS(b2_py_obj BEFORE PRIVATE ${VIS_OPT_FLAG})
        TARGET_COMPILE_OPTIONS(b2_py BEFORE PRIVATE ${VIS_OPT_FLAG})
    ELSE()
        GET_FILENAME_COMPONENT(PYTHON_LIB_DIR ${PYTHON_LIBRARIES} DIRECTORY)
        FIND_LIBRARY(PYTHON_LIB_X NAMES python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR} HINTS "${PYTHON_LIB_DIR}")
        MESSAGE(STATUS "PYTHON_LIB_X = ${PYTHON_LIB_X}")
        TARGET_LINK_LIBRARIES(b2_py PUBLIC ${PYTHON_LIB_X})
    ENDIF()
ENDIF()

IF (${BUILD_TEST})
    ADD_EXECUTABLE(b2_testexe unit_test/debug_main.cpp)
    LIST(APPEND TARGETS b2_testexe)
ENDIF()

IF (${BUILD_CLIB})
    # CLIB target name must be block2 for other packages to find it.
    ADD_LIBRARY(${PROJECT_NAME} SHARED ${CORE_SRCS})
    LIST(APPEND TARGETS ${PROJECT_NAME})
    INCLUDE(GNUInstallDirs)
    MESSAGE(STATUS "CMAKE_INSTALL_LIBDIR = ${CMAKE_INSTALL_LIBDIR}")
    MESSAGE(STATUS "CMAKE_INSTALL_INCLUDEDIR = ${CMAKE_INSTALL_INCLUDEDIR}")
    MESSAGE(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")

    IF (NOT(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"))
        SET(VIS_OPT_FLAG "")
    ENDIF()

    INCLUDE(CMakePackageConfigHelpers)
    CONFIGURE_PACKAGE_CONFIG_FILE(CMake/${PROJECT_NAME}Config.cmake.in
        ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
        INSTALL_DESTINATION "share/cmake/${PROJECT_NAME}"
        PATH_VARS CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_LIBDIR)
    WRITE_BASIC_PACKAGE_VERSION_FILE(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
        VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion)
    INSTALL(TARGETS ${PROJECT_NAME} EXPORT "${PROJECT_NAME}Targets" LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
    INSTALL(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING
        PATTERN "src/*.hpp" PATTERN "src/*/*.hpp"
        PATTERN "src/instantiation/core*" EXCLUDE PATTERN "src/instantiation/dmrg*" EXCLUDE
        PATTERN "src/pybind" EXCLUDE)
    INSTALL(EXPORT "${PROJECT_NAME}Targets" NAMESPACE "${PROJECT_NAME}::" DESTINATION "share/cmake/${PROJECT_NAME}")
    INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
        ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
        DESTINATION "share/cmake/${PROJECT_NAME}")
ENDIF()

IF (${BUILD_EXE})
    IF (NOT ${USE_DMRG})
        MESSAGE(FATAL_ERROR "-DUSE_DMRG must be ON for compiling src/main.cpp.")
    ENDIF()
    ADD_LIBRARY(b2_exe_obj OBJECT src/main.cpp)
    ADD_EXECUTABLE(b2_exe $<TARGET_OBJECTS:b2_exe_obj> ${CORE_SRCS})
    LIST(APPEND TARGETS b2_exe b2_exe_obj)
ENDIF()

FOREACH (target ${TARGETS})

    TARGET_INCLUDE_DIRECTORIES(${target} PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
        $<INSTALL_INTERFACE:include> ${MKL_INCLUDE_DIR} ${SCI_INCLUDE_DIR})

    IF ((NOT APPLE) AND (NOT WIN32))
        TARGET_LINK_LIBRARIES(${target} PRIVATE rt)
    ENDIF()

    IF (("${target}" STREQUAL "b2_py") OR ("${target}" STREQUAL "b2_exe"))
        SET_TARGET_PROPERTIES(${target} PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
    ENDIF()

    IF (${USE_PCH})
        FILE(GLOB COREHDRS src/instantiation/*.hpp)
        TARGET_PRECOMPILE_HEADERS(${target} PRIVATE ${COREHDRS})
    ENDIF()

    SET_TARGET_PROPERTIES(${target} PROPERTIES POSITION_INDEPENDENT_CODE 1)
    TARGET_LINK_LIBRARIES(${target} PRIVATE ${OMP_LIB_NAME} ${PTHREAD})
    TARGET_LINK_LIBRARIES(${target} PRIVATE ${PTHREAD} ${LAPACK_LIBRARIES} ${BLAS_LIBRARIES} ${MKL_LIBS} ${MPI_LIBS} ${TBB_LIBS} ${BLIS_LIBS})
    SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "${ARCH_LINK_FLAGS} ${MPI_LINK_FLAGS}")

    TARGET_INCLUDE_DIRECTORIES(${target} PUBLIC ${PYTHON_INCLUDE_DIRS} ${PYBIND_INCLUDE_DIRS}
        ${MKL_INCLUDE_DIR} ${MPI_INCLUDE_DIR} ${TBB_INCLUDE_DIR} ${BLIS_INCLUDE_DIR})
    TARGET_COMPILE_OPTIONS(${target} BEFORE PRIVATE ${VIS_OPT_FLAG} ${OPT_FLAG} ${ARCH_FLAG})
    TARGET_COMPILE_OPTIONS(${target} BEFORE PUBLIC ${MKL_FLAG} ${MPI_FLAG}
        ${TMPL_FLAG} ${BOND_FLAG} ${SCI_FLAG} ${CORE_FLAG} ${DMRG_FLAG} ${BIG_SITE_FLAG}
        ${SP_DMRG_FLAG} ${IC_FLAG} ${KSYMM_FLAG} ${SG_FLAG} ${COMPLEX_FLAG} ${SINGLE_PREC_FLAG}
        ${TBB_FLAG} ${SU2SZ_FLAG} ${SANY_FLAG} ${BLIS_FLAG})

ENDFOREACH()

IF (${BUILD_TEST})
    ENABLE_TESTING()
    FIND_PACKAGE(GTest REQUIRED)
    INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS})

    IF (${SIMPLE_TEST})
        FILE(GLOB TSRCS unit_test/test_wick_*.cpp unit_test/test_npdm_*.cpp unit_test/test_dmrg_*.cpp)
    ELSE()
        FILE(GLOB TSRCS unit_test/test_*.cpp)
    ENDIF()
    MESSAGE(STATUS "TSRCS = ${TSRCS}")

    IF ((NOT APPLE) AND (NOT WIN32))
        SET(OPT_FLAG ${OPT_FLAG} -fcompare-debug-second)
    ENDIF()

    ADD_EXECUTABLE(${PROJECT_NAME}_tests ${TSRCS} ${CORE_SRCS})
    TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME}_tests PUBLIC src ${MKL_INCLUDE_DIR} ${MPI_INCLUDE_DIR} ${TBB_INCLUDE_DIR} ${BLIS_INCLUDE_DIR})
    TARGET_LINK_LIBRARIES(${PROJECT_NAME}_tests ${GTEST_BOTH_LIBRARIES} ${PTHREAD} ${MPI_LIBS} ${TBB_LIBS} ${BLIS_LIBS})
    TARGET_COMPILE_OPTIONS(${PROJECT_NAME}_tests BEFORE PUBLIC ${ARCH_FLAG} ${OPT_FLAG} ${MKL_FLAG} ${MPI_FLAG}
        ${TMPL_FLAG} ${BOND_FLAG} ${SCI_FLAG} ${CORE_FLAG} ${DMRG_FLAG} ${BIG_SITE_FLAG}
        ${SP_DMRG_FLAG} ${IC_FLAG} ${KSYMM_FLAG} ${SG_FLAG} ${COMPLEX_FLAG} ${SINGLE_PREC_FLAG} ${TBB_FLAG} ${BLIS_FLAG}
        ${SU2SZ_FLAG} ${SANY_FLAG})
    SET_TARGET_PROPERTIES(${PROJECT_NAME}_tests PROPERTIES LINK_FLAGS "${ARCH_LINK_FLAGS} ${MPI_LINK_FLAGS}")

    IF ((NOT APPLE) AND (NOT WIN32))
        TARGET_LINK_LIBRARIES(${PROJECT_NAME}_tests rt)
    ENDIF()
    TARGET_LINK_LIBRARIES(${PROJECT_NAME}_tests ${OMP_LIB_NAME} ${PTHREAD} ${LAPACK_LIBRARIES} ${BLAS_LIBRARIES} ${MKL_LIBS})

    ADD_CUSTOM_COMMAND(TARGET ${PROJECT_NAME}_tests POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
            ${CMAKE_SOURCE_DIR}/data ${CMAKE_CURRENT_BINARY_DIR}/data)

    ADD_TEST(NAME Test COMMAND ${PROJECT_NAME}_tests)
ENDIF()
