#----------------------------------------------------------------------------
# Copyright © 2023-26 Sean Holden. All rights reserved.
#
# This file is part of Connect++.
#
# Connect++ is free software: you can redistribute it and/or modify it 
# under the terms of the GNU General Public License as published by the 
# Free Software Foundation, either version 3 of the License, or (at your 
# option) any later version.
#
# Connect++ is distributed in the hope that it will be useful, but WITHOUT 
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
# more details.
#
# You should have received a copy of the GNU General Public License along 
# with Connect++. If not, see <https://www.gnu.org/licenses/>. 
#----------------------------------------------------------------------------
#
# Primary CMakeLists.txt file for Connect++
#
# If you have Boost installed in a non-standard place and 
# cmake can't find it, use:
#
# cmake ../source -D BOOST_ROOT=/where/is/boost 
#
# If cmake can't find the SWI Prolog executable use:
#
# cmake ../source -D swipl_PATH=/where/is/swipl

# If this is ON, then do static linking.
# To enable, use: 
#
# cmake ../source -D STATIC_LINK=ON
option(STATIC_LINK "When ON, perform static linking." OFF)
if (STATIC_LINK)
    message(STATUS "Static linking selected.")
endif()

# If this is ON, search for SWI Prolog and build check_proof.
# To disable, use: 
#
# cmake ../source -D INCLUDE_PROLOG=OFF
option(INCLUDE_PROLOG "When ON, build the Prolog application 'check_proof'." ON)
if (INCLUDE_PROLOG)
    message(STATUS "Including Prolog proof checker.")
endif()

# If this is OFF, don't use link-time optimization. 
# To disable, use: 
#
# cmake ../source -D USE_IPO=OFF
option(USE_IPO "When ON, use link-time optimization." ON)
if (USE_IPO)
    message(STATUS "Using link-time optimization if available.")
endif()

# If this is ON, tell cmake to use Clang and the LLVM linker. 
# To enable use:
#
# cmake ../source -D USE_CLANG=ON
option(USE_CLANG "When ON, use Clang and the LLVM linker." OFF)
if (USE_CLANG)
    message(STATUS "Using Clang and the LLVM linker if available.")
    set(CMAKE_CXX_COMPILER /usr/bin/clang)
    set(CMAKE_C_COMPILER /usr/bin/clang)
    set(CMAKE_LINKER_TYPE LLD)
endif()

# Standard, basic information.
#
# Add C here because there is a single file in CaDiCaL that requires it.
cmake_minimum_required(VERSION 3.30)
project(connect++ VERSION 0.7.1 
                  DESCRIPTION "A First-Order Connection Prover"
                  HOMEPAGE_URL "https://www.cl.cam.ac.uk/~sbh11/connect++.html"
                  LANGUAGES C CXX)

# We need at least C++ 20 to use coroutines.
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# What are we actually using?
message(STATUS "C     : " ${CMAKE_C_COMPILER_ID} " version " ${CMAKE_C_COMPILER_VERSION})
message(STATUS "Linker: " ${CMAKE_C_COMPILER_LINKER_ID} " version " ${CMAKE_C_COMPILER_LINKER_VERSION})
message(STATUS "C++   : " ${CMAKE_CXX_COMPILER_ID} " version " ${CMAKE_CXX_COMPILER_VERSION})
message(STATUS "Linker: " ${CMAKE_CXX_COMPILER_LINKER_ID} " version " ${CMAKE_CXX_COMPILER_LINKER_VERSION})

# Do inter-procedural optimization if it's available and wasn't specifically disabled.
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION False)
include(CheckIPOSupported)
check_ipo_supported(RESULT supports_ipo)
if (supports_ipo AND USE_IPO)
    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION True)
    message(STATUS "Interprocedural optimization is available.")
endif()

# Sort out the header file for incorporating the version.
configure_file(connect++-version.hpp.in 
               connect++-version.hpp)

# We need to find the BOOST includes and libraries.
set(Boost_USE_RELEASE_LIBS ON)
set(Boost_USE_DEBUG_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_LIBS ON)
find_package(Boost CONFIG 
             1.66.0 
             REQUIRED 
             COMPONENTS program_options
)
if (Boost_FOUND)
    message(STATUS "Found the BOOST libraries. Woohoo!")
    message(STATUS "BOOST include from:   ")
    message(STATUS ${Boost_INCLUDE_DIRS})
    message(STATUS "BOOST libraries from: ")
    message(STATUS ${Boost_LIBRARY_DIRS})
    message(STATUS "Boost version:")
    message(STATUS ${Boost_VERSION_STRING})
endif()

# Build a custom version of the CaDiCaL SAT solver.
include(../cmake/cadical.cmake)

# Main executable.
add_executable(connect++ 
    connect++.cpp
    InferenceItem.cpp
    Lemmata.cpp
    Matrix.cpp
    Parameters.cpp
    ProverOutcome.cpp
    Schedule.cpp
    SimplePath.cpp
    StackItem.cpp
    StackProver.cpp
)
target_compile_options(connect++ PRIVATE -O3 -ffast-math)

# Add the subdirectories.
add_subdirectory(terms)
add_subdirectory(literal)
add_subdirectory(substitution)
add_subdirectory(utilities)
add_subdirectory(sat)
add_subdirectory(clauses)
add_subdirectory(fof)
add_subdirectory(tptp_parser)
add_subdirectory(proofs)

# Add the includes.
#
# Make sure CaDiCaL is at the end!
target_include_directories(connect++ PRIVATE 
    ${PROJECT_SOURCE_DIR}
    ${PROJECT_BINARY_DIR}
    ${Boost_INCLUDE_DIRS}
    ${PROJECT_SOURCE_DIR}/terms
    ${PROJECT_SOURCE_DIR}/literal
    ${PROJECT_SOURCE_DIR}/substitution
    ${PROJECT_SOURCE_DIR}/misc
    ${PROJECT_SOURCE_DIR}/utilities
    ${PROJECT_SOURCE_DIR}/sat
    ${PROJECT_SOURCE_DIR}/sat/cadical
    ${PROJECT_SOURCE_DIR}/clauses
    ${PROJECT_SOURCE_DIR}/fof
    ${PROJECT_SOURCE_DIR}/tptp_parser
    ${PROJECT_SOURCE_DIR}/proofs
    ${cadical_INCLUDE_DIRS}
)

# Add the link information.
target_link_libraries(connect++ PRIVATE 
    Boost::headers
    Boost::program_options
    cadical
)

# Optional static linking.
if(STATIC_LINK)
    message(STATUS "Compiler is: " ${CMAKE_CXX_COMPILER_ID})
    if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        target_link_options(connect++ PRIVATE
            -static 
            -static-libstdc++ 
            -static-libgcc
        )
        message(STATUS "Static linking for g++.")
    else()
        message(STATUS "No static linking - supported for g++ only.")
    endif()
endif()

# If needed, search for SWI Prolog and configure check_proof.
if (INCLUDE_PROLOG)
    message(STATUS "Searching for SWI Prolog...")
    find_program(swipl_PATH
                    NAMES swipl
                    PATHS   /usr/bin/ 
                            /opt/homebrew/bin/ 
                    REQUIRED
    )
    if (swipl_PATH)
        message(STATUS "Found swipl. Woohoo!")
        message(STATUS ${swipl_PATH})
        configure_file(prolog/check_proof.in
                       check_proof
                       FILE_PERMISSIONS OWNER_WRITE
                                        OWNER_READ
                                        OWNER_EXECUTE
                                        GROUP_READ
                                        WORLD_READ
        )
    endif()
endif()