set(SPLA_SOURCE_FILES
        block_generation/block_cyclic_generator.cpp
        util/blas_interface.cpp
        timing/rt_graph.cpp
        timing/timing.cpp
        pgemm_ssb/pgemm_ssb_host.cpp
        pgemm_ssb/ring_ssb_host.cpp
        pgemm_ssb/add_kernel.cpp
        pgemm_sbs/pgemm_sbs_host.cpp
        pgemm_sbs/ring_sbs_host.cpp
        gemm/gemm_host.cpp
        spla/matrix_distribution.cpp
        spla/matrix_distribution_internal.cpp
        spla/pgemm_ssb.cpp
        spla/pgemm_ssbtr.cpp
        spla/pgemm_sbs.cpp
        spla/context.cpp
        spla/gemm.cpp
        )

if(SPLA_CUDA OR SPLA_ROCM)
        list(APPEND SPLA_SOURCE_FILES
                                pgemm_ssb/ring_ssb_gpu.cpp
                                pgemm_ssb/pgemm_ssb_gpu.cpp
                                pgemm_sbs/pgemm_sbs_gpu.cpp
                pgemm_sbs/ring_sbs_gpu.cpp
                                gemm/gemm_gpu.cpp
                                gpu_util/multiply_gpu.cpp
                )
endif()

# Creates spla library with given name. All common target modifications should be done here.
macro(spla_create_library _TARGET_NAME)
        add_library(${_TARGET_NAME} ${SPLA_LIBRARY_TYPE}
                ${SPLA_SOURCE_FILES}
                )

        set_property(TARGET ${_TARGET_NAME} PROPERTY VERSION ${SPLA_VERSION})
        set_property(TARGET ${_TARGET_NAME} PROPERTY SOVERSION ${SPLA_SO_VERSION})


        # Don't export any symbols of external static libaries. Only works on linux.
        if(UNIX AND NOT APPLE)
                if(${CMAKE_VERSION} VERSION_LESS "3.13.5") 
                        target_link_libraries(${_TARGET_NAME} PRIVATE "-Wl,--exclude-libs,ALL")
                else()
                        target_link_options(${_TARGET_NAME} PRIVATE "-Wl,--exclude-libs,ALL")
                endif()
        endif()


        target_compile_options(${_TARGET_NAME} PRIVATE ${SPLA_DEFINITIONS} ${SPLA_EXTERNAL_COMPILE_OPTIONS})
        target_include_directories(${_TARGET_NAME} PRIVATE ${SPLA_EXTERNAL_INCLUDE_DIRS} ${SPLA_INCLUDE_DIRS})


        target_link_libraries(${_TARGET_NAME} PRIVATE ${SPLA_EXTERNAL_LIBS})
        # SPLA inteface needs MPI to be compiled. Avoid requiring CXX language for installed cmake config files, so only make public for build.
        target_link_libraries(${_TARGET_NAME} PUBLIC $<BUILD_INTERFACE:MPI::MPI_CXX>)

        target_include_directories(${_TARGET_NAME} INTERFACE ${SPLA_INTERFACE_INCLUDE_DIRS})
        target_include_directories(${_TARGET_NAME} INTERFACE $<INSTALL_INTERFACE:include>) # for install(EXPORT ...)
        target_include_directories(${_TARGET_NAME} INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>  $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>) # for export(...)
        if(${SPLA_FORTRAN}) # Add include directory for fortran module
                target_include_directories(${_TARGET_NAME} INTERFACE $<INSTALL_INTERFACE:include/spla>)
                target_include_directories(${_TARGET_NAME} INTERFACE $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/src>)
        endif()

endmacro()

spla_create_library(spla)
set_target_properties(spla PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE CXX_VISIBILITY_PRESET hidden)

if(SPLA_BUILD_TESTS)
        # create library with default visibility if tests are build, to allow linking to internal symbols
        spla_create_library(spla_test)
        set_target_properties(spla_test PROPERTIES VISIBILITY_INLINES_HIDDEN FALSE CXX_VISIBILITY_PRESET default)
        target_compile_options(spla_test PUBLIC -DSPLA_STATIC_DEFINE)
        # enable internal timings
        target_compile_options(spla_test PUBLIC -DSPLA_TIMING)
endif()

# generate export header to control symbol visibility
include(GenerateExportHeader)
generate_export_header(spla)
configure_file("${CMAKE_CURRENT_BINARY_DIR}/spla_export.h"
        "${PROJECT_BINARY_DIR}/spla/spla_export.h"
        COPYONLY
)

# build fortran module
if(SPLA_FORTRAN)
        add_library(spla_fortran OBJECT ${PROJECT_SOURCE_DIR}/include/spla/spla.f90)
endif()


# set packge config names
get_target_property(_LIB_TYPE spla TYPE)
if(_LIB_TYPE STREQUAL "STATIC_LIBRARY")
        set(SPLA_VERSION_FILE "SPLAStaticConfigVersion.cmake")
        set(SPLA_CONFIG_FILE "SPLAStaticConfig.cmake")
        set(SPLA_TARGETS_FILE "SPLAStaticTargets.cmake")
else()
        set(SPLA_VERSION_FILE "SPLASharedConfigVersion.cmake")
        set(SPLA_CONFIG_FILE "SPLASharedConfig.cmake")
        set(SPLA_TARGETS_FILE "SPLASharedTargets.cmake")
endif()


# generate cmake package
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
        "${PROJECT_BINARY_DIR}/${SPLA_VERSION_FILE}"
        VERSION ${Upstream_VERSION}
        COMPATIBILITY AnyNewerVersion
)
export(TARGETS spla NAMESPACE SPLA:: FILE ${PROJECT_BINARY_DIR}/${SPLA_TARGETS_FILE})
configure_file(${PROJECT_SOURCE_DIR}/cmake/${SPLA_CONFIG_FILE}
        "${PROJECT_BINARY_DIR}/${SPLA_CONFIG_FILE}"
        @ONLY
)
configure_file(${PROJECT_SOURCE_DIR}/cmake/SPLAConfig.cmake
        "${PROJECT_BINARY_DIR}/SPLAConfig.cmake"
        COPYONLY
)
configure_file(${PROJECT_SOURCE_DIR}/cmake/SPLAConfigVersion.cmake
        "${PROJECT_BINARY_DIR}/SPLAConfigVersion.cmake"
        COPYONLY
)
configure_file(${PROJECT_SOURCE_DIR}/cmake/SPLATargets.cmake
        "${PROJECT_BINARY_DIR}/SPLATargets.cmake"
        COPYONLY
)
configure_file(${PROJECT_SOURCE_DIR}/cmake/SPLA.pc.in
        "${PROJECT_BINARY_DIR}/SPLA.pc"
        @ONLY
)

# installation commands
if(SPLA_INSTALL)
        install(TARGETS spla DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT SPLATargets)
        install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/spla DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "*.f90")
        install(FILES ${PROJECT_BINARY_DIR}/spla/config.h "${PROJECT_BINARY_DIR}/spla/spla_export.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/spla)
        install(EXPORT SPLATargets NAMESPACE SPLA:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/SPLA FILE ${SPLA_TARGETS_FILE})
        install(
          FILES
                "${PROJECT_BINARY_DIR}/SPLAConfig.cmake"
                "${PROJECT_BINARY_DIR}/SPLATargets.cmake"
                "${PROJECT_BINARY_DIR}/SPLAConfigVersion.cmake"
                "${PROJECT_BINARY_DIR}/${SPLA_CONFIG_FILE}"
                "${PROJECT_BINARY_DIR}/${SPLA_VERSION_FILE}"
          DESTINATION
            ${CMAKE_INSTALL_LIBDIR}/cmake/SPLA
        )

        install(FILES ${PROJECT_BINARY_DIR}/SPLA.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

        install(DIRECTORY "${PROJECT_SOURCE_DIR}/cmake/modules"
                DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/SPLA"
        FILES_MATCHING PATTERN "*.cmake")

        if(SPLA_FORTRAN)
                install(FILES ${PROJECT_BINARY_DIR}/src/spla.mod DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/spla)
        endif()
endif()
