set(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0075 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0079 NEW)

cmake_minimum_required(VERSION 3.5)
project(SWI-Prolog)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

# While GCC is good at optimization large   functions, MSVC is bad at it
# and using VMI functions more then   doubles the performance. For Clang
# the picture is less clear. The difference  is small, with a slight win
# on either depending on CPU and workload.

if(MSVC OR CMAKE_C_COMPILER_ID STREQUAL Clang)
  set(DEFAULT_VMI_FUNCTIONS ON)
else()
  set(DEFAULT_VMI_FUNCTIONS OFF)
endif()

option(MULTI_THREADED
       "Enable multiple Prolog threads"
       ON)
option(ENGINES
       "Enable multiple Prolog engines"
       OFF)
option(VMI_FUNCTIONS
       "Create a function for each VM instruction"
       ${DEFAULT_VMI_FUNCTIONS})
option(USE_SIGNALS
       "Enable signal handling"
       ON)
option(USE_GMP
       "Use GNU MP Bignum library (LGPL)"
       ON)
if(APPLE)
# tcmalloc breaks setlocale() on MacOS 12 (Monterey)
option(USE_TCMALLOC
       "Use Google tcmalloc instead of default malloc"
       OFF)
else()
option(USE_TCMALLOC
       "Use Google tcmalloc instead of default malloc"
       ON)
endif()
option(SWIPL_SHARED_LIB
       "Put kernel in a shared library"
       ON)
option(SWIPL_VERSIONED_DIR
       "Install into a versioned directory"
       OFF)
option(SWIPL_INSTALL_IN_LIB
       "Install library in ${CMAKE_INSTALL_PREFIX}/lib"
       OFF)
option(SWIPL_INSTALL_IN_SHARE
       "Install docs in ${CMAKE_INSTALL_PREFIX}/share/swipl"
       OFF)
if(WIN32)
option(SWIPL_INSTALL_AS_LINK
       "Install public binaries using a symlink"
       OFF)
else()
option(SWIPL_INSTALL_AS_LINK
       "Install public binaries using a symlink"
       ON)
endif()
option(SWIPL_M32
       "Build 32-bit version on 64-bit Linux using multilib and gcc -m32"
       OFF)
option(INSTALL_DOCUMENTATION
       "Install the HTML documentation files"
       ON)
option(BUILD_PDF_DOCUMENTATION
       "Build the PDF manuals from source"
       OFF)
option(MACOS_UNIVERSAL_BINARY
       "Build a universal binary for x86_64 and arm64"
       OFF)
option(BUILD_MACOS_BUNDLE
       "Install for a MacOS bundle (SWI-Prolog.app)"
       OFF)
option(BUILD_TESTING
       "Build test files and setup for ctest"
       ON)
option(SKIP_SSL_TESTS
       "Skip the SSL tests"
       OFF)
option(TEST_PROTOBUFS_PROTOC
       "Run protobuf tests that require protoc, etc."
       OFF)
option(BUILD_SWIPL_LD
       "Create the swipl-ld utility"
       ON)
option(INSTALL_TESTS
       "Install script and files needed to run tests of the final installation"
       OFF)
option(GCOV
       "Compile for coverage analysis using gcov (gcc)"
       OFF)
option(STATIC_EXTENSIONS
       "Add foreign extensions statically"
       OFF)
if(EMSCRIPTEN)
  set(DEFAULT_CCACHE OFF)
else()
  set(DEFAULT_CCACHE ON)
endif()
option(CCACHE
       "Use ccache when available"
       ${DEFAULT_CCACHE})
option(VALIDATE_API
       "Add runtime argument checks for PL_*() functions"
       ON)

set(JNIDIR ""
    CACHE STRING "Directory for linking Java JNI components")

if(NOT SWIPL_SHARED_LIB)
  set(CMAKE_ENABLE_EXPORTS ON)
endif()

set(CMAKE_C_STANDARD 11)

include(Utils)
include(BuildType)
include(Version)
include(PGO)
include(Locations)
include(Ports)
include(LocationsPostPorts)
include(InstallSource)
include(QLF)
include(PackageSelection)
include(Dependencies)
include(DocDepends)

if(GMP_FOUND)
  set(USE_LIBBF_DEFAULT OFF)
else()
  set(USE_LIBBF_DEFAULT ON)
endif()

option(USE_LIBBF
       "Use LibBF for bignums (MIT)"
       ${USE_LIBBF_DEFAULT})

# Verbosity
set(CMAKE_INSTALL_MESSAGE NEVER)

if(CCACHE)
  find_program(PROG_CCACHE ccache)
  if(PROG_CCACHE)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${PROG_CCACHE})
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${PROG_CCACHE})
  endif(PROG_CCACHE)
endif(CCACHE)

if(NOT SWIPL_PKG_NAME)
  if(SWIPL_INSTALL_DIR STREQUAL "swi-prolog")
    set(SWIPL_PKG_NAME ${SWIPL_INSTALL_DIR})
  else()
    set(SWIPL_PKG_NAME "swipl")
  endif()
endif()

if(MSVC)
  add_compile_options(/W3)
else()
  add_compile_options(-Wall)
endif()

# on ARM, backtrace() requires -funwind-tables. See
# https://stackoverflow.com/questions/24700150/on-raspberry-pi-backtrace-returns-0-frames
# We must do this at the toplevel to ensure all packages use this as well.
if( (CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL Clang) AND
    CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
  include(CheckFunctionExists)
  check_function_exists(backtrace HAVE_BACKTRACE)
  if(HAVE_BACKTRACE)
    add_compile_options(-funwind-tables)
  endif()
endif()

if(SWIPL_M32)
  include(cross/linux_i386)
endif()

if(BUILD_TESTING)
  enable_testing()
endif()

# Configuration we need everywhere
if(MULTI_THREADED)
  if(NOT TARGET Threads::Threads)
    if(MSVC AND NOT ENV{CONDA_BUILD})
      find_package(PThreads4W)
    endif()
    if(TARGET PThreads4W::PThreads4W)
      add_library(Threads::Threads ALIAS PThreads4W::PThreads4W)
      set(CMAKE_USE_PTHREADS_INIT ON)
    else()
      if(WIN32 AND NOT MINGW)
	set(THREADS_USE_PTHREADS_WIN32 TRUE)
      else()
	set(THREADS_PREFER_PTHREAD_FLAG TRUE)
      endif()
      find_package(Threads)
    endif()
  endif()
endif()

include(TestLargeFiles)
OPJ_TEST_LARGE_FILES(HAVE_LARGE_FILES)

set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "Core_system")

# Add the core Prolog system
add_subdirectory(src)
install(FILES LICENSE README.md DESTINATION ${SWIPL_INSTALL_PREFIX})
install(FILES customize/edit customize/init.pl customize/README.md
	DESTINATION ${SWIPL_INSTALL_PREFIX}/customize)

if(INSTALL_DOCUMENTATION)
  include(Documentation)
  set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Documentation)

  add_custom_target(
      doc ALL
      COMMENT "Build the documentation")

  add_custom_target(
      doc.html
      COMMENT "Build HTML documentation")

  add_dependencies(doc doc.html)

  add_custom_command(
      OUTPUT ${MAN_INDEX}
      COMMAND ${PROG_SWIPL} -f none --no-packs --home=${SWIPL_BUILD_HOME}
			    -g "use_module(library(pldoc/man_index))"
	                    -g save_man_index -t halt
      DEPENDS swipl core doc.html
      VERBATIM)
  add_custom_target(
      man_index
      DEPENDS ${MAN_INDEX})
  add_dependencies(doc man_index)
  install(FILES ${MAN_INDEX} DESTINATION ${SWIPL_INSTALL_DOC})

  if(BUILD_PDF_DOCUMENTATION)
    add_custom_target(
	doc.pdf
	COMMENT "Build PDF documentation")
    add_dependencies(doc doc.pdf)
  endif()

  add_subdirectory(man)
  install(FILES packages/index.html
	  DESTINATION ${SWIPL_INSTALL_DOC}/packages)
endif(INSTALL_DOCUMENTATION)

# Install a prolog script to run tests on target device
# in which ctest is not available
if(INSTALL_TESTS)
  set(INSTALL_TESTS_DIR ${SWIPL_INSTALL_PREFIX}/test)
  set(PKGS_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/packages)
  set(INSTALL_TESTS_DB ${CMAKE_BINARY_DIR}/cmake_pkg_tests.db)
  #Move test db to installation
  install(FILES       ${INSTALL_TESTS_DB}
	  DESTINATION ${INSTALL_TESTS_DIR}
	  COMPONENT   Tests)
  file(REMOVE ${INSTALL_TESTS_DB})
endif(INSTALL_TESTS)

# Add the packages
if(STATIC_EXTENSIONS)
  set_property(GLOBAL PROPERTY static_extension_libs)
endif()
foreach(package ${SWIPL_PACKAGE_LIST})
  swipl_package_component(${package}
			  CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
  add_subdirectory(packages/${package})
endforeach(package)
if(STATIC_EXTENSIONS)
  get_property(extlibs GLOBAL PROPERTY static_extension_libs)
  include(StaticPackages)
  write_static_extensions(${CMAKE_BINARY_DIR}/src/static_packages.h ${extlibs})
endif()

# Check for environment variables that may cause the build to fail
include(CheckEnv)

# Packaging
include(Pack)
