# Copyright (C) 2015-2021 |Meso|Star> (contact@meso-star.com)
#
# This software is a computer program whose purpose is to generate files
# used to build the Star-SP library.
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.

cmake_minimum_required(VERSION 3.1)
project(star-sp C CXX)
enable_testing()

set(SSP_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
option(BUILD_R123_AES "Build the RNG based on AES-NI instructions, as provided by the Random123 library" ON)
option(NO_TEST "Disable the test" OFF)

################################################################################
# Check dependencies
################################################################################
get_filename_component(_current_source_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
set(Random123_DIR ${_current_source_dir}/)

find_package(Random123 REQUIRED)
find_package(RCMake 0.4 REQUIRED)
find_package(RSys 0.6 REQUIRED)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
include(rcmake_runtime)

if(MSVC)
  # CMake 3.11 is required to handle the naming rule of the boost 1.67 libs
  cmake_minimum_required(VERSION 3.11)

  # Currently, the C++11 random library on MSVC is bugged and consequently we
  # use the Boost library instead
  find_package(Boost 1.67 REQUIRED COMPONENTS random)
  add_definitions(-DUSE_BOOST_RANDOM)
  include_directories(${RSys_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${Random123_INCLUDE_DIR})
else()
  include_directories(${RSys_INCLUDE_DIR} ${Random123_INCLUDE_DIR})
endif()

if(BUILD_R123_AES)
  add_definitions(-DWITH_R123_AES)
endif()

rcmake_append_runtime_dirs(_runtime_dirs RSys ${Boost_LIBRARY_DIRS})

if(CMAKE_COMPILER_IS_GNUCXX)
  # Random123 warning that cannot be disabled by a GCC pragma
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-expansion-to-defined")
endif()

################################################################################
# Configure and define targets
################################################################################
set(VERSION_MAJOR 0)
set(VERSION_MINOR 12)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})

set(SSP_FILES_SRC
  ssp_ran.c
  ssp_ranst_discrete.c
  ssp_ranst_gaussian.c
  ssp_ranst_piecewise_linear.c
  ssp_rng.c
  ssp_rng_proxy.c)
set(SSP_FILES_INC
  ssp_rng_c.h)
set(SSP_FILES_INC_API
  ssp.h)
set(SSP_FILES_DOC
  COPYING.en
  COPYING.fr
  README.md)

# Prepend each file in the `SSP_FILES_<SRC|INC>' list by `SSP_SOURCE_DIR'
rcmake_prepend_path(SSP_FILES_SRC ${SSP_SOURCE_DIR})
rcmake_prepend_path(SSP_FILES_INC ${SSP_SOURCE_DIR})
rcmake_prepend_path(SSP_FILES_INC_API ${SSP_SOURCE_DIR})
rcmake_prepend_path(SSP_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
set_source_files_properties(${SSP_FILES_SRC} PROPERTIES LANGUAGE CXX)

if(CMAKE_COMPILER_IS_GNUCXX)
  # Random123 warning that cannot be disabled by a GCC pragma
  set_source_files_properties(${SSP_SOURCE_DIR}/ssp_rng.c PROPERTIES
    COMPILE_FLAGS "-Wno-expansion-to-defined")
endif()

add_library(star-sp SHARED ${SSP_FILES_SRC} ${SSP_FILES_INC} ${SSP_FILES_INC_API})
set_target_properties(star-sp PROPERTIES
  DEFINE_SYMBOL SSP_SHARED_BUILD
  LINKER_LANGUAGE CXX
  VERSION ${VERSION}
  SOVERSION ${VERSION_MAJOR})
target_link_libraries(star-sp RSys)

if(MSVC)
  target_link_libraries(star-sp ${Boost_LIBRARIES})
  # disable autolink
  set_target_properties(star-sp PROPERTIES COMPILE_FLAGS "/DBOOST_ALL_NO_LIB")
elseif(CMAKE_COMPILER_IS_GNUCXX)
  if(BUILD_R123_AES)
    set_target_properties(star-sp PROPERTIES COMPILE_FLAGS "-std=c++11 -maes")
  else()
    set_target_properties(star-sp PROPERTIES COMPILE_FLAGS "-std=c++11")
  endif()
endif()

rcmake_setup_devel(star-sp StarSP ${VERSION} star/ssp_version.h)

################################################################################
# Add tests
################################################################################
if(NOT NO_TEST)
  function(build_test _name)
    add_executable(${_name}
      ${SSP_SOURCE_DIR}/${_name}.c
      ${SSP_SOURCE_DIR}/${_name}.h
      ${SSP_SOURCE_DIR}/test_ssp_utils.h)

    target_link_libraries(${_name} star-sp RSys ${MATH_LIB})
    set(_libraries  ${ARGN})
    foreach(_lib ${_libraries})
      target_link_libraries(${_name} ${_lib})
    endforeach(_lib)
  endfunction()

  function(register_test _name)
    add_test(${_name} ${ARGN})
    rcmake_set_test_runtime_dirs(${_name} _runtime_dirs)
  endfunction()

  function(new_test _name)
    build_test(${_name} ${ARGN})
    register_test(${_name} ${_name})
  endfunction()


  if(CMAKE_COMPILER_IS_GNUCXX)
    set(MATH_LIB m)
  endif()

  build_test(test_ssp_rng)
  register_test(test_ssp_rng_kiss test_ssp_rng kiss)
  register_test(test_ssp_rng_mt19937_64 test_ssp_rng mt19937_64)
  register_test(test_ssp_rng_ranlux48 test_ssp_rng ranlux48)
  register_test(test_ssp_rng_random_device test_ssp_rng random_device)
  register_test(test_ssp_rng_threefry test_ssp_rng threefry)
  if(BUILD_R123_AES)
    register_test(test_ssp_rng_aes test_ssp_rng aes)
  endif()
  new_test(test_ssp_ran_circle ${MATH_LIB})
  new_test(test_ssp_ran_discrete)
  new_test(test_ssp_ran_gaussian)
  new_test(test_ssp_ran_hemisphere ${MATH_LIB})
  new_test(test_ssp_ran_hg ${MATH_LIB})
  new_test(test_ssp_ran_piecewise_linear)
  new_test(test_ssp_rng_proxy)
  new_test(test_ssp_ran_sphere ${MATH_LIB})
  new_test(test_ssp_ran_sphere_cap ${MATH_LIB})
  new_test(test_ssp_ran_spherical_zone ${MATH_LIB})
  new_test(test_ssp_ran_triangle ${MATH_LIB})
  new_test(test_ssp_ran_tetrahedron ${MATH_LIB})
  new_test(test_ssp_ran_uniform_disk)
  rcmake_copy_runtime_libraries(test_ssp_rng)
endif()

################################################################################
# Define output & install directories
################################################################################
install(TARGETS star-sp
  ARCHIVE DESTINATION bin
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin)
install(FILES ${SSP_FILES_INC_API} DESTINATION include/star)
install(FILES ${SSP_FILES_DOC} DESTINATION share/doc/star-sp)
