cmake_minimum_required(VERSION 3.1.3)
project(ColPack)

# Set the version number to the *next* release (not to the prevoius release).
set(COLPACK_VERSION 1.0.11)
set(COLPACK_ROOT_DIR "../..")   # modify as needed 
# CMake support was added by chrisdembia in 2017 to support building ColPack on
# Windows with Visual Studio and to supplement autotools. Various parts of the
# code base, such as the comments in the SampleDrivers files, still expect use
# of autotools.
# The layout of the installation generated by CMake is fairly similar to that
# created by autotools, except that
#    - we do not install a libtool library (libColPack.la),
#    - we install CMake config files (ColPackConfig.cmake) to support use of
#      ColPack by downstream projects, and
#    - the logic for determining the name of the lib directory is based on
#      CMake's GNUInstallDirs module.
# The Basic examples are always built and installed, and are used as tests
# via CTest. The non-Basic tests are built and installed if ENABLE_EXAMPLES is
# ON. The only example that we do not compile is SMB.
#
# When using Visual Studio, we cannot use OpenMP or build the ColPack executable,
# and we can only make use of the shared library if using CMake 3.4 or greater.
# Also, the examples are linked to the static library rather than to the shared
# library.

# User options.
# -------------
option(ENABLE_EXAMPLES
    "Build the examples in SampleDrivers/Matrix_Compression_and_Recovery." OFF)
    option(ENABLE_OPENMP "Enable OpenMP." ON)
set (CMAKE_CXX_STANDARD 11)

# Configuring variables, etc.
# ---------------------------
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    # MSVC and Xcode are mult-config generators that use
    # CMAKE_CONFIGURATION_TYPES; other generators (Makefiles) use
    # CMAKE_BUILD_TYPE.
    # By default, compile with optimizations and without debug symbols.
    set(CMAKE_BUILD_TYPE Release CACHE STRING
        "Choose the type of build, e.g., optimizaiton level, debug symbols."
        FORCE)
    # Show a list of options in the CMake-GUI or ccmake (curses interface).
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
        "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

set(ColPack_lib_to_use ColPack_shared)  # ColPack_lib_to_use is either ColPack_shared or ColPack_static

if(WIN32)
    # Since we do not use __declspec(dllexport) etc, the shared library
    # does not export symbols and cannot be used in general. Use the the static
    # library for the examples.
    set(ColPack_lib_to_use ColPack_static)
    if(${CMAKE_VERSION} VERSION_LESS 3.4)
        message(STATUS "Cannot use ColPack's shared library on Windows if using CMake older than 3.4 (because no symbols are exported).")
    else()
        # CMake can export symbols for us, allowing use of the shared library.
        set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
    endif()
endif()

if(ENABLE_OPENMP)
    find_package(OpenMP REQUIRED)
    if(MSVC)
        message(WARNING "ColPack requires a version of OpenMP greater than what Visual Studio provides.")
    endif()
endif()

# Define variables to use for organizing the installation.
include(GNUInstallDirs) 

if(WIN32)
    set(COLPACK_INSTALL_CMAKEDIR       ColPack_libs)
    set(COLPACK_INSTALL_EXAMPLESBINDIR ColPack_examples)
else()
    set(COLPACK_INSTALL_CMAKEDIR       ${CMAKE_INSTALL_LIBDIR}/ColPack_libs)
    # To follow the UNIX Filsystem Hierarchy Standard, we should install
    # examples somewhere else:
    set(COLPACK_INSTALL_EXAMPLESBINDIR ${CMAKE_INSTALL_LIBDIR}/ColPack_examples)
endif()

# Lists of the source files.
# -------------------------
file(GLOB HEADERS
    ${COLPACK_ROOT_DIR}/inc/ColPackHeaders.h
    ${COLPACK_ROOT_DIR}/inc/Definitions.h
    ${COLPACK_ROOT_DIR}/src/Utilities/*.h
    ${COLPACK_ROOT_DIR}/src/BipartiteGraphBicoloring/*.h
    ${COLPACK_ROOT_DIR}/src/BipartiteGraphPartialColoring/*.h
    ${COLPACK_ROOT_DIR}/src/GeneralGraphColoring/*.h
    ${COLPACK_ROOT_DIR}/src/Recovery/*.h
    ${COLPACK_ROOT_DIR}/src/SMPGC/*.h)
    #${COLPACK_ROOT_DIR}/src/PartialD2SMPGC/*.h)
file(GLOB SOURCES
    ${COLPACK_ROOT_DIR}/src/Utilities/*.cpp
    ${COLPACK_ROOT_DIR}/src/BipartiteGraphBicoloring/*.cpp
    ${COLPACK_ROOT_DIR}/src/BipartiteGraphPartialColoring/*.cpp
    ${COLPACK_ROOT_DIR}/src/GeneralGraphColoring/*.cpp
    ${COLPACK_ROOT_DIR}/src/Recovery/*.h
    ${COLPACK_ROOT_DIR}/src/SMPGC/*.cpp)
    #${COLPACK_ROOT_DIR}/src/PartialD2SMPGC/*.cpp)


# Use these include directories when building the ColPack library.
set(COLPACK_SOURCE_INCLUDE_DIRS
    "${COLPACK_ROOT_DIR}/inc"
    "${COLPACK_ROOT_DIR}/src/Utilities"
    "${COLPACK_ROOT_DIR}/src/BipartiteGraphPartialColoring"
    "${COLPACK_ROOT_DIR}/src/BipartiteGraphBicoloring"
    "${COLPACK_ROOT_DIR}/src/GeneralGraphColoring"
    "${COLPACK_ROOT_DIR}/src/SMPGC"
    "${COLPACK_ROOT_DIR}/src/Recovery")



# Static library.
# ---------------
add_library(ColPack_static STATIC ${HEADERS} ${SOURCES})
if(NOT WIN32)
    # On Windows, the static and shared libraries can't have the same
    # name (because both have .lib files that will conflict).
    set_target_properties(ColPack_static PROPERTIES OUTPUT_NAME ColPack)
endif()

target_include_directories(ColPack_static PRIVATE
    ${COLPACK_SOURCE_INCLUDE_DIRS})
# For clients of the ColPack target within this project (e.g. examples).
# (Must use quotes because the variable is a list of paths.)
#target_include_directories(ColPack_static INTERFACE
#    "$<BUILD_INTERFACE:${COLPACK_SOURCE_INCLUDE_DIRS}>")
# For clients of an installation of ColPack.
target_include_directories(ColPack_static INTERFACE
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)

if(ENABLE_OPENMP)
    set_target_properties(ColPack_static PROPERTIES COMPILE_FLAGS
        ${OpenMP_CXX_FLAGS})
endif()

# "EXPORT" helps with creating a ColPackConfig.cmake file to place in the
# installation, to help downstream projects use ColPack.
install(TARGETS ColPack_static EXPORT ColPackTargets
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/archive
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/library
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/runtime)


# Shared library.
# ---------------
add_library(ColPack_shared SHARED ${HEADERS} ${SOURCES})
set_target_properties(ColPack_shared PROPERTIES
    OUTPUT_NAME ColPack
    SOVERSION 0)

# Use these include directories when building the ColPack library.
target_include_directories(ColPack_shared PRIVATE
    ${COLPACK_SOURCE_INCLUDE_DIRS})
# For clients of the ColPack target within this project (e.g. examples).
#target_include_directories(ColPack_shared INTERFACE
#    "$<BUILD_INTERFACE:${COLPACK_SOURCE_INCLUDE_DIRS}>")
# For clients of an installation of ColPack.
target_include_directories(ColPack_shared INTERFACE
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)

if(ENABLE_OPENMP)
    set_target_properties(ColPack_shared PROPERTIES COMPILE_FLAGS
        ${OpenMP_CXX_FLAGS})
    target_link_libraries(ColPack_shared PRIVATE ${OpenMP_CXX_FLAGS})
endif()

install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ColPack_headers)

install(TARGETS ColPack_shared EXPORT ColPackTargets
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/shared_archive
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/shared_library
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/shared_runtime)



# -------------------
# The ColPack executable depends on getopt.h, which is POSIX
# and not readily available when using Visual Studio.
# -------------------
# xin cheng: on Oct 2018. It seems getopt.h havn't been used. So the following check getopt
#            could be removed. For safety, still pop up a message.
find_path(HAS_GETOPT getopt.h)
if(NOT HAS_GETOPT)
    message(STATUS "Cannot find getopt.h; ColPack may or may not build.")
endif()

# ColPack executable.
add_executable(ColPack "${COLPACK_ROOT_DIR}/Examples/ColPackAll/Main.cpp")
target_link_libraries(ColPack ${ColPack_lib_to_use})
target_include_directories(ColPack PRIVATE ${COLPACK_SOURCE_INCLUDE_DIRS})

# To facilitate running the ColPack executable from the build directory.
file(COPY "${COLPACK_ROOT_DIR}/Graphs" DESTINATION "${CMAKE_BINARY_DIR}")

# Examples.
# ---------
# enable_testing()
# The behavior here is different from autotools, because ENABLE_EXAMPLES
# also affects the Basic examples.
# First, gather up all the example files.
# To replicate the behavior of autotools, we build and install the Basic
# examples regardless of the setting for ENABLE_EXAMPLES.
# First, gather up all the example files.
file(GLOB SAMPLE_DRIVERS_BASIC RELATIVE "${COLPACK_ROOT_DIR}/Examples/SampleDrivers"
    ${COLPACK_ROOT_DIR}/Examples/SampleDrivers/Basic/*.cpp)
set(EXAMPLES ${SAMPLE_DRIVERS_BASIC})
if(ENABLE_EXAMPLES)
    file(GLOB SAMPLE_DRIVERS_BASIC RELATIVE "${CMAKE_SOURCE_DIR}/SampleDrivers"
        SampleDrivers/Basic/*.cpp)
    set(EXAMPLES ${SAMPLE_DRIVERS_BASIC})
    file(GLOB SAMPLE_DRIVERS_MATRIX_COMPRESSION_AND_RECOVERY
        RELATIVE "${COLPACK_ROOT_DIR}/Examples/SampleDrivers"
        ${COLPACK_ROOT_DIR}/Examples/SampleDrivers/Matrix_Compression_and_Recovery/ADIC/*.cpp
        ${COLPACK_ROOT_DIR}/Examples/SampleDrivers/Matrix_Compression_and_Recovery/ADOL-C/*.cpp
        ${COLPACK_ROOT_DIR}/Examples/SampleDrivers/Matrix_Compression_and_Recovery/CSR_input/*.cpp
        # Leaving out SMB because that depends on ADOL-C.
        )
    list(APPEND EXAMPLES ${SAMPLE_DRIVERS_MATRIX_COMPRESSION_AND_RECOVERY})
endif()

# Now create targets for each example.
foreach(example_cpp ${EXAMPLES})
    # Get the file name without extension ("_WE"), and store it in `example`.
    get_filename_component(example ${example_cpp} NAME_WE)
    # Get a directory relative to the SampleDrivers directory.
    get_filename_component(example_rel_dir ${example_cpp} DIRECTORY
        BASE_DIR SampleDrivers)
    add_executable(${example} Examples/SampleDrivers/${example_cpp})
    target_link_libraries(${example} ${ColPack_lib_to_use})
#<<<<<<< master
#    # Autools installs the examples in CSR_input into a dir. named CSR.
#=======
    # Autotools installs the examples in CSR_input into a dir. named CSR.
#>>>>>>> master
    string(REPLACE "CSR_input" "CSR" example_rel_dir ${example_rel_dir})
    install(TARGETS ${example} DESTINATION
        ${COLPACK_INSTALL_EXAMPLESBINDIR}/${example_rel_dir})
    # Allow running the basic examples as tests.
    if(${example_rel_dir} STREQUAL Basic)
        add_test(${example} ${example})
    endif()
endforeach()

# Install and support for downstream projects.
# --------------------------------------------
# Consider installing Graphs:
# install(DIRECTORY Graphs DESTINATION ${CMAKE_INSTALL_SHAREDIR})

# Create files that define the ColPack targets to import into other projects.
# https://cmake.org/cmake/help/v3.1/manual/cmake-packages.7.html
install(EXPORT ColPackTargets DESTINATION ${COLPACK_INSTALL_CMAKEDIR})

# CMake Config file., and version file, which CMake will look for when
# downstream projects use find_package(ColPack).
include(CMakePackageConfigHelpers)
# The ConfigVersion file determines if an installed copy of ColPack is
# compatible with a user's requested version for ColPack.
write_basic_package_version_file(
    "${CMAKE_BINARY_DIR}/ColPackConfigVersion.cmake"
    VERSION ${COLPACK_VERSION}
    COMPATIBILITY AnyNewerVersion)
configure_package_config_file(ColPackConfig.cmake.in
    "${CMAKE_BINARY_DIR}/ColPackConfigToInstall.cmake"
    INSTALL_DESTINATION ${COLPACK_INSTALL_CMAKEDIR}
    PATH_VARS CMAKE_INSTALL_PREFIX)
install(FILES "${CMAKE_BINARY_DIR}/ColPackConfigToInstall.cmake"
    DESTINATION ${COLPACK_INSTALL_CMAKEDIR}
    RENAME ColPackConfig.cmake)
install(FILES "${CMAKE_BINARY_DIR}/ColPackConfigVersion.cmake"
    DESTINATION ${COLPACK_INSTALL_CMAKEDIR})
