#------------------------------------------------------------------------
# -*- mode: cmake -*-
#------------------------------------------------------------------------
#
# LDASTools Frame Utility Library  - Frame Utility library
#
# Copyright (C) 2018 California Institute of Technology
#
# LDASTools Frame Utility Library  is free software; you may redistribute
# it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 (GPLv2)
#  of the License or at your discretion, any later version.
#
# LDASTools Frame Utility Library is distributed in the hope that it will
# be useful, but without any warranty or even the implied warranty of
# merchantability or fitness for a particular purpose. See the GNU
# General Public License (GPLv2) for more details.
#
# Neither the names of the California Institute of Technology (Caltech),
# The Massachusetts Institute of Technology (M.I.T), The Laser
# Interferometer Gravitational-Wave Observatory (LIGO), nor the names
# of its contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# You should have received a copy of the licensing terms for this
# software included in the file LICENSE located in the top-level
# directory of this package. If you did not, you can view a copy at
# http://dcc.ligo.org/M1500244/LICENSE
#
#------------------------------------------------------------------------

set( LDAS_TOOLS_AL_PACKAGE_NAME ldas-tools-al )
set( LDAS_TOOLS_AL_VERSION      2.10.0 )

set(
  PROJECT_DESCRIPTION
  "Abstraction library used by LDAS Tools"
  )
set(
  PROJECT_DESCRIPTION_LONG
  "This provides a collection of classes and fuctions"
  "allowing for system level abstraction"
  "as used by the LDAS Tools Suite."
  )

set( LDAS_TOOLS_CMAKE_VERSION   1.5.0 )

set( BOOST_MINIMUM_VERSION 1.67 )

cmake_minimum_required(VERSION 3.12...4.0)
#------------------------------------------------------------------------
#------------------------------------------------------------------------

if (NOT "${CMAKE_CXX_STANDARD}")
  set(CMAKE_CXX_STANDARD 20)
endif( )
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
if ( NOT CMAKE_OSX_ARCHITECTURES )
  set( CMAKE_OSX_ARCHITECTURES x86_64 )
endif( )

#------------------------------------------------------------------------
#
#------------------------------------------------------------------------

project( ${LDAS_TOOLS_AL_PACKAGE_NAME} )

#------------------------------------------------------------------------
# Configuration options
#------------------------------------------------------------------------

set( ENABLE_DOCUMENTATION_ONLY FALSE CACHE BOOL "Enable only building of documentation" )

#------------------------------------------------------------------------
# Locate the standard LDAS Tools cmake macro directory
#------------------------------------------------------------------------

include( GNUInstallDirs )

set(LDAS_TOOLS_CMAKE_MODULES_DIRS
  ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/ldas-tools/cmake/Modules
  ${CMAKE_INSTALL_FULL_DATADIR}/ldas-tools/cmake/Modules
  )

find_package(
  LDASToolsCMake
  CONFIG
  REQUIRED
  HINTS ${LDAS_TOOLS_CMAKE_MODULES_DIRS}
  PATHS ${LDAS_TOOLS_CMAKE_MODULES_DIRS}
  )

#========================================================================
# Start pulling in the LDAS Tools macros for easy setup
#========================================================================

find_package(AxLDASTools REQUIRED)

# Define BUILD_STATIC_LIBS option (shared across all LDAS Tools packages)
cx_static_libs_option()

cx_msg_debug_variable( CMAKE_INSTALL_DOCDIR )
cx_msg_debug_variable( CMAKE_INSTALL_FULL_DOCDIR )

cx_msg_debug_variable( BOOST_INCLUDEDIR )
cx_msg_debug_variable( BOOST_LIBRARYDIR )

cm_init(
  ${LDAS_TOOLS_AL_PACKAGE_NAME}
  "${LDAS_TOOLS_AL_VERSION}"
  ${LDAS_TOOLS_BUG_REPORT_URL}
  ${LDAS_TOOLS_AL_PACKAGE_NAME}
  ${LDAS_TOOLS_HOMEPAGE_URL}
  DESCRIPTION "${PROJECT_DESCRIPTION}"
  )

# Render COPYING, LICENSE.md, debian/copyright from suite-wide templates.
# See ldastools_cmake/Modules/cx_install_license.cmake (issue #267).
cx_install_license( )

set( PROJECT_CONFIG_PATH "${PROJECT_SOURCE_DIR}/config" )

#dnl =====================================================================
#dnl  Prepare a header file to store the glorious configuration info
#dnl =====================================================================

set( PROJECT_CONFIG_FILENAME
  "${CMAKE_CURRENT_BINARY_DIR}/ldastoolsal_config.h" )

ch_top(
  "#ifndef LDAS_TOOLS_AL_CONFIG_H"
  "#define LDAS_TOOLS_AL_CONFIG_H"
  " "
  )
ch_bottom(
  " "
  "#endif /* LDAS_TOOLS_AL_CONFIG_H */"
  )

#dnl =====================================================================
#dnl  Check for the operating system
#dnl =====================================================================
#
#AX_LDAS_OS
#AX_LDAS_CHECK_OS_VARIABLE_LIBRARY_LOAD_PATH
#
#dnl =====================================================================
#dnl  Check for compilers and language features
#dnl =====================================================================
#
#AX_LDAS_PROG_CC
#
cx_ldas_prog_cxx( )
#AX_CXX_COMPILE_STDCXX([11],[noext],[mandatory])
#AX_LDAS_CXX_CONSTEXPR
#AX_LDAS_CXX_EXCEPTIONS_RETHROW
#AX_LDAS_CXX_TEMPLATE_ALIASES
#AX_LDAS_CXX_TEMPLATE_ALIASES_VIA_USING
#AX_LDAS_CXX_TEMPLATE_AS_TEMPLATE_PARAMETER
#
#AX_LDAS_ARG_WITH_OPTIMIZATION
#
#dnl =====================================================================
#dnl  Checking if the OS is 64 bit
#dnl =====================================================================
#
#AX_LDAS_SYS_64BIT_OS
#

cx_scheme_sanitizer(
  ALLOW_WARNINGS
  ENABLE_ASAN
  ENABLE_USE_AFTER_SCOPE
  DISABLE_RECOVERY_ASAN
  SUPPRESSION_FILE_ASAN ${CMAKE_SOURCE_DIR}/asan_suppressions.txt
  ENABLE_LSAN
  DISABLE_RECOVERY_LSAN
  SUPPRESSION_FILE_LSAN ${CMAKE_SOURCE_DIR}/lsan_suppressions.txt
  ENABLE_MSAN
  DISABLE_RECOVERY_MSAN
  SUPPRESSION_FILE_MSAN ${CMAKE_SOURCE_DIR}/msan_suppressions.txt
  ENABLE_TSAN
  DISABLE_RECOVERY_TSAN
  SUPPRESSION_FILE_TSAN ${CMAKE_SOURCE_DIR}/tsan_suppressions.txt
  ENABLE_UBSAN
  DISABLE_RECOVERY_UBSAN
  SUPPRESSION_FILE_UBSAN ${CMAKE_SOURCE_DIR}/ubsan_suppressions.txt
)

# cx_check_compile_hardening() adds -fstack-clash-protection,
# -fcf-protection, -fstack-protector-strong, -fasynchronous-unwind-tables,
# and friends. The first interacts with MinGW-w64 gcc 12's SEH unwind
# code generation: stack-clash probes emitted inside SEH-instrumented
# functions trigger an internal compiler error at
# `seh_emit_stackalloc, at config/i386/winnt.cc:1055` (caught by #289
# pipeline 856805 building regex.cc, where std::vector<unsigned char>::
# operator[] lands in the wrong combination of SEH + stack-clash
# probing). Skip the hardening flags under WIN32 — Windows binaries
# produced from this configure aren't shipped yet; production
# hardening can be re-introduced as a separate task once the upstream
# MinGW gcc bug is resolved or a workaround flag combination is
# verified.
if(NOT WIN32)
  cx_check_compile_hardening( )
endif()
cx_cxx_warnings_as_errors( Debug )

#dnl =====================================================================
#dnl  Check for key programs
#dnl =====================================================================
#
#AX_LDAS_PROG_LIBTOOL
#AX_LDAS_PROG_PKGBUILDER
#AX_LDAS_PROG_DOXYGEN
#AX_LDAS_PROG_VALGRIND
#AX_LDAS_PROG_ABI_COMPLIANCE_CHECKER
#AX_LDAS_PROG_ABI_DUMPER
#
#AC_CHECK_PROGS([EXPR],[expr])
#
#dnl =====================================================================
#dnl  Check for header files
#dnl =====================================================================

cm_header_stdc( )
cm_check_headers(mntent.h)
cm_check_headers(sys/kinfo_proc.h)
cm_check_headers(sys/mnttab.h)
cm_check_headers(sys/propppc.h)
cm_check_headers(sys/stat.h)
cm_check_headers(sys/sysctl.h)
cm_check_headers(sys/sysinfo.h)
cm_check_headers(sys/types.h)
cm_check_headers(dirent.h)
cm_check_headers(procfs.h)
cm_check_headers(stdlib.h)

# Use LDAS Tools Boost detection (handles conda header-only libraries)
cx_boost_base(${BOOST_MINIMUM_VERSION})

# Windows portability verification (#289): the link-time Boost components
# (Boost.Log / Boost.Thread / Boost.System / Boost.Filesystem /
# Boost.DateTime / Boost.ProgramOptions) are only consumed by source files
# that are themselves excluded from the WIN32 build below (Log.cc and the
# logging-infrastructure family, DebugLevelManager.cc, gpstime.cc, etc.).
# Skipping the component probes under WIN32 lets the configure succeed
# without MinGW-linkable boost binaries — which don't exist in any
# standard distribution, so requiring them would gate the whole
# Windows verification effort on building or sourcing them ourselves
# (see #289's tracking issue for the long-term plan).
#
# Boost.Regex (the #93 dependency) STAYS in the WIN32 build because the
# regex translation units are part of the verified-portable set and the
# Boost.Regex headers compile under MinGW even when libboost_regex isn't
# linkable.
cx_boost_regex()  # Direct dep (Regex/RegexMatch classes, #93); on POSIX
                  # also pulled in by log/log_setup.

if(NOT WIN32)
  cx_boost_log()
  cx_boost_log_setup()
  cx_boost_thread()
  cx_boost_system()
  cx_boost_filesystem()
  cx_boost_date_time()
  cx_boost_program_options()
endif()

# Verify all components found
if(WIN32)
  set(_required_components REGEX)
else()
  set(_required_components LOG LOG_SETUP REGEX THREAD SYSTEM FILESYSTEM DATE_TIME PROGRAM_OPTIONS)
endif()
foreach(_comp ${_required_components})
  if(NOT BOOST_${_comp}_FOUND)
    message(FATAL_ERROR "Required Boost component ${_comp} not found")
  endif()
endforeach()

# Build BOOST_CPPFLAGS for pkg-config
list(APPEND BOOST_CPPFLAGS "-I${BOOST_INCLUDE_DIR}")

# Build BOOST_LDFLAGS for pkg-config from component LDFLAGS
set(BOOST_LDFLAGS "")
foreach(_comp ${_required_components})
  if(BOOST_${_comp}_LDFLAGS)
    list(APPEND BOOST_LDFLAGS ${BOOST_${_comp}_LDFLAGS})
  endif()
endforeach()

# Convert lists to space-separated strings for pkg-config
string(REPLACE ";" " " BOOST_LDFLAGS "${BOOST_LDFLAGS}")
string(REPLACE ";" " " BOOST_CPPFLAGS "${BOOST_CPPFLAGS}")

cx_check_header_for_subst(unordered_map     HAVE_UNORDERED_MAP)
cx_check_header_for_subst(tr1/unordered_map HAVE_TR1_UNORDERED_MAP)
cx_check_header_for_subst(hash_map          HAVE_HASH_MAP)
cx_check_header_for_subst(ext/hash_map      HAVE_EXT_HASH_MAP)
cx_check_header_for_subst(map               HAVE_MAP)

# =======================================================================
#  Check for structures/sizes
# =======================================================================

cm_c_bigendian( )
if( WORDS_BIGENDIAN )
  set( LDAS_WORDS_BIGENDIAN 1)
else( )
  set( LDAS_WORDS_BIGENDIAN 0)
endif( )
cx_check_sizes( )
cm_define(
  VARIABLE LDAS_WORDS_BIGENDIAN
  VALUE ${LDAS_WORDS_BIGENDIAN}
  DESCRIPTION "Set to 1 if system is bigendian" )
# /proc/<pid>/psinfo and /proc/<pid>/stat are Linux/Solaris-specific. Skip
# the structure probes under WIN32; PSInfo.cc (which consumes them) is
# already excluded from the WIN32 source set.
if(NOT WIN32)
  cx_struct_procfs_psinfo( )
  cx_struct_procfs_stat( )
endif()

#dnl =====================================================================
#dnl  Check for individual libraries
#dnl =====================================================================

# Windows portability verification (#289): all of these probes are
# inherently POSIX (pthread, libsocket/libnsl, librt, libumem, libz).
# They probe for libraries that are either Linux-distribution-specific
# (umem, the rt detection that supplies clock_gettime on older glibc) or
# Win32-irrelevant (POSIX threading library detection — the concurrency
# primitive abstraction layer files that need them are excluded from the
# WIN32 build). Skip the whole block under WIN32.
if(NOT WIN32)
  set( THREADS_PREFER_PTHREAD ON )
  find_package( Threads REQUIRED )

  cx_thread( )
  cx_lib_socket_nsl( )
  cm_check_lib(rt clock_gettime)
  # cm_check_lib(pthread pthread_cancel)
  cx_check_lib_umem( )
  cx_check_lib_z( )
endif()
#
#dnl =====================================================================
#dnl  Check for individual functions
#dnl =====================================================================
#
include(CheckSymbolExists)

# All of these probe POSIX functions / POSIX types. Under WIN32 they would
# all come up undefined, which is fine for the verified-portable source
# set (regex layer) — none of those TUs reference these HAVE_* macros.
# Skip the probes to keep the configure output focused on what matters.
if(NOT WIN32)
  cm_check_funcs(clock_gettime)
  cm_func_strerror_r( )
  cm_check_funcs(fpathconf)
  cm_check_funcs(dirfd)
  cm_check_funcs(fdopendir)
  check_symbol_exists(
    dirfd
    "sys/types.h;dirent.h"
    HAVE_DIRFD_MACRO
    )
  cm_define(
    VARIABLE HAVE_DIRFD_MACRO
    VALUE ${HAVE_DIRFD_MACRO}
    DESCRIPTION "Defined if dirfd() is a macro in dirent.h" )
  cx_check_func_swap_all( )
  cx_check_pthread_read_write_lock( )
endif()

#dnl =====================================================================
#dnl  Check for supported classes
#dnl =====================================================================
#
#AX_LDAS_CXX_TEMPLATE_MOVE
#AX_LDAS_CXX_UNIQUE_PTR
#
#dnl =====================================================================
#dnl 
#dnl =====================================================================
#
#AC_DEFINE([LIBEXECDIR],["@libexecdir@"],[Directory for installing executables that other other programs run])
#AX_LDAS_DEF_VARIABLE([PACKAGE_VERSION_NUMERIC],
#			  ["`echo ${PACKAGE_VERSION} |  ${SED} -e 's/[[~]][(]alpha|beta[)].*$//'`"])
#
#========================================================================
# Traverse the tree
#========================================================================

add_subdirectory(src)
# Tests + docs are gated on POSIX while the Windows verification only
# covers the portable source set (#289). The test/ tree pulls in the
# Boost.Test consumer + many POSIX-only TUs; doc/ pulls in doxygen
# which doesn't run under cross-compile. Both subdirectories return to
# the WIN32 build once the corresponding files become portable.
if(NOT WIN32)
  add_subdirectory(test)
  add_subdirectory(doc)
endif()

#========================================================================
# Commit configuration information to the file
#========================================================================

cm_config_headers( ${PROJECT_CONFIG_FILENAME} )

#=======================================================================
# Prepare the distribution
#========================================================================

# Issue #307: distribution-template relocation. Per-sub-package opt-in
# to debian/{control,rules}.in and rpm/<pkg>.spec.in locations instead
# of the historical config/ melting-pot. The cx_packaging_{deb,rpm}
# functions in igwn-cmake-macros already support per-project overrides
# via PROJECT_DEBIAN_*_INPUT_FILENAME and RPM_SPEC_FILE_TEMPLATE; this
# block just points them at the relocated templates. When igwn-cmake-macros'
# defaults are updated to prefer debian/ / rpm/ over config/ (separate
# external-repo ticket per #307's risk-#3 note), these set() calls
# become no-ops and can be removed.
set( PROJECT_DEBIAN_CONTROL_INPUT_FILENAME
  "${CMAKE_CURRENT_SOURCE_DIR}/debian/control.in" )
set( PROJECT_DEBIAN_RULES_INPUT_FILENAME
  "${CMAKE_CURRENT_SOURCE_DIR}/debian/rules.in" )

# CPack assembles real distributable packages (rpm/deb/macports). Under
# WIN32 we're only doing the portability compile-check; skip the
# package-assembly hook (#289).
if(NOT WIN32)
  cx_cpack(
    MACPORTS_CATEGORY science
    MAINTAINER "Edward Maros <ed.maros@ligo.org>"
    RPM_SPEC_FILE_TEMPLATE
      "${CMAKE_CURRENT_SOURCE_DIR}/rpm/${PROJECT_NAME}.spec.in"
    )
endif()

#========================================================================
# Report configuration information
#  CMAKE_MAKE_PROGRAM:FILEPATH
#========================================================================
get_target_property( my_cxx_flags ldastoolsal LINK_OPTIONS )
cm_msg_notice( "=========================================================")
cm_msg_notice( "  Project ${PROJECT_NAME} has now ben successfully configured:")
cm_msg_notice( " " )
cm_msg_notice( "  configuration information:" )
cm_msg_notice( "      CMAKE_C_FLAGS                  ${CMAKE_C_FLAGS}" )
cm_msg_notice( "      CMAKE_CXX_FLAGS                ${EXTRA_PKGCONFIG_CFLAGS}")
cm_msg_notice( "  installation directories:" )
cm_msg_notice( "      CMAKE_INSTALL_BINDIR           ${CMAKE_INSTALL_BINDIR}" )
cm_msg_notice( "      CMAKE_INSTALL_DATADIR          ${CMAKE_INSTALL_DATADIR}" )
cm_msg_notice( "      CMAKE_INSTALL_PREFIX           ${CMAKE_INSTALL_PREFIX}" )
cm_msg_notice( "      CMAKE_INSTALL_DOCDIR           ${CMAKE_INSTALL_DOCDIR}" )
cm_msg_notice( "      CMAKE_INSTALL_FULL_DOCDIR      ${CMAKE_INSTALL_FULL_DOCDIR}" )
cm_msg_notice( " " )
cm_msg_notice( "  Boost Libraries:" )
cm_msg_notice( "      BOOST_LIBRARY_DIR              ${BOOST_LIBRARY_DIR}" )
cm_msg_notice( "      BOOST_TARGETS                  ${BOOST_TARGETS}" )
cm_msg_notice( " " )
cm_msg_notice( "  Sanitizers:" )
cm_msg_notice( "      Active:                         ${CX_SCHEME_SANITIZERS_ACTIVE}")
cm_msg_notice( " " )
cm_msg_notice( "  Now run 'cmake --build .' to build ${PROJECT_NAME}")
cm_msg_notice( "  and run 'cpack' to package ${PROJECT_NAME}")
cm_msg_notice( "=========================================================")
#dnl =====================================================================
#dnl  Generate local output
#dnl =====================================================================
#
#AC_OUTPUT(
#	ldas-tools-al.spec
#	config/Makefile
#	config/autotools/Makefile
#	config/autotools/m4/Makefile
#	config/autotools/make/Makefile
#	config/scripts/Makefile
#	config/swig/Makefile
#	config/data/Makefile
#) dnl AC_OUTPUT
#
#AC_OUTPUT(
#	Makefile
#	ldastoolsal.pc
#	ldastoolsal-uninstalled.pc
#	src/Makefile
#	src/types.hh
#	src/ldas_types.h
#	src/reverse.hh
#	src/unordered_map.hh
#	test/Makefile
#	doc/Makefile
#	debian/Makefile
#) dnl AC_OUTPUT - general
#
