##------------------------------------------------------------------------
## 1:0:0 -- 2014.06.10
##    Library name change general -> ldastoolsal
## 1:1:0 -- 2014.09.19
##    Modifications resulting in the 2.0.3 release of ldas-tools
## 2:0:0 -- 2015.05.08
##    Added elements to class CommandLineOptions
##    Added parameters to MemChecker.Append( )
##    Added method MemChecker.Info( )
##    Added method ThreadPool.Active( )
##    Added mehtod mutex_lock::baton_type::bool( )
##    Added member to mutex_lock::baton_type
## 3:0:0 - 2015.07.06
##    Added SignalHandler class
## 4:0:0 - 2016.03.03
##    Modified Directory class
## 4:1:0 - 2016.09.09
##    Added leap second for 2017.01.01
##    Addressed valgrind issue by using new instead of strdup
## 4:2:0 - 2016.09.15
##    Added functions Timeout and Interval
## 4:3:0 - 2016.09.26
##    Added optional Thread debugging
## 4:4:0 - 2016.10.10
##    Corrections to how threads handle signals.
##    Optimized registration of signal handler.
## 4:5:0 - 2016.11.14
##    Correction to internal allocation of directory buffer
## 5:0:1 - 2017.10.25 (ldas-tools-al-2.5.7)
##    Added routines needed for diskcache
## 6:0:0 - 2018.05.11 ( ldas-tools-al-2.6.0 )
##    Removed hand rolled smart pointers in favor of boost smart pointers
## 7:0:0 - ????.??.?? ( ldas-tools-al-2.6.1 )
##    Removed LDASUnexpected class
## 7:1:0 - 2019.08.14 ( ldas-tools-al-2.6.3 )
##    Minor patching
## 7:2:0 - 2021.03.09 ( ldas-tools-al-2.6.5 )
## 8:0:1 - 2024.12.16 ( ldas-tools-al-2.7.0 )
##    - Corrections for valgrind memcheck
##    - Added new logging routines based on boost::logging
##------------------------------------------------------------------------
## form: <(c)urrent>:<(r)elease>:<(a)ge
##
## 1. Update the version information only immediately before a public
##    release of your software. More frequent updates are unnecessary,
##    and only guarantee that the current interface number gets larger
##    faster.
## 2. If the library source code has changed at all since the last
##    update, then increment revision (c:r:a becomes c:r+1:a).
## 3. If any interfaces [exported functions or data] have been added,
##    removed, or changed since the last update, increment current,
##    and set revision to 0.
## 4. If any interfaces have been added since the last public
##    release, then increment age.
## 5. If any interfaces have been removed since the last public
##    release, then set age to 0.
##------------------------------------------------------------------------

set( libldastoolsal_la_CURRENT 11 )
set( libldastoolsal_la_REVISION 0 )
set( libldastoolsal_la_AGE 0 )

#lib_LTLIBRARIES = libldastoolsal.la
#
#noinst_LTLIBRARIES = libldastoolspreload.la
#
#libldastoolspreload_la_SOURCES = \
#	Unlocked.cc
#

# Windows portability verification (#289): the source list is partitioned
# into two sets so the WIN32 build covers only the files that have been
# verified to compile cleanly under MinGW-w64. As each porting ticket
# lands, its file moves from libldastoolsal_la_SOURCES_POSIX_ONLY into
# the PORTABLE set in the same MR — that movement is the explicit
# "verified Windows-portable" graduation signal.
#
# Today's PORTABLE set is the regex layer alone (#93). The concurrency
# primitives ported as #290/#291/#292/#293 used std::mutex /
# std::condition_variable / std::shared_timed_mutex / std::thread, which
# the win32-threads MinGW-w64 toolchain (libstdc++ without
# _GLIBCXX_HAS_GTHREADS) does not provide — those types live in
# <mutex>/<thread>/<shared_mutex>/<condition_variable> only when a
# threading backend is wired up at the libstdc++ level. winpthreads is
# off the table per #288's "fail loudly on POSIX-only primitives" design,
# so the concurrency-primitive abstraction layer needs explicit Win32
# branches (CRITICAL_SECTION, CONDITION_VARIABLE, SRWLOCK, CreateThread)
# in MutexLockBaton.cc / ConditionalVariable.cc / ReadWriteLockBaton.cc /
# Thread.cc / TimerThread.cc. That's its own bundled ticket; until it
# lands, those files stay in the POSIX_ONLY set.
#
# Files not yet covered are tracked under Phase-3 of #289's roadmap
# (the rest of the inherently-POSIX surface, primarily the concurrency
# primitives — MutexLockBaton, ConditionalVariable, ReadWriteLock,
# Thread, TimerThread, TaskThread, ThreadPool, SystemCallTask, Task —
# pending the Win32-branch concurrency-primitive ticket).
#
# #298 (Fork.cc / Exec.cc): resolved as **POSIX-only by design**, not a
# pending port. fork()'s copy-on-write semantics have no Win32 analog,
# and the consumer chain — ldasgen StatFork → ldasgen StatPool →
# diskcache lstat path — is itself heavily POSIX-bound (daemonised
# lstat-pool model with shared pre-exec setup that doesn't translate to
# CreateProcess). Both .cc files stay in libldastoolsal_la_SOURCES_POSIX_ONLY;
# the .hh headers remain installed and parse under MinGW-w64
# (Fork.hh exposes pid_t which MinGW's <sys/types.h> defines as int on
# Win32 — harmless since no Win32 caller instantiates the class).
# Downstream consumers must guard their own usage with #ifndef _WIN32 or
# equivalent when their files start compiling on Win32 in later Phase
# tickets.
#
# #299 (SignalHandler.cc): resolved as **POSIX-only by design**, matching
# the #293 (Thread cancellation) decision to drop BY_SIGNAL on Windows.
# The implementation depends on sigaction / pthread_sigmask / sigwait
# and a dedicated signal-handling thread — fundamentally POSIX. A Win32
# SetConsoleCtrlHandler branch would only map SIGNAL_TERMINATE /
# SIGNAL_HANGUP cleanly and leave USR_1/USR_2 as dead enum values; the
# active consumer set (diskcache MetaCommandDaemon, ScanMountPointsDaemon,
# DumpCacheDaemon, MetaCommands) is itself a POSIX-only daemonised model.
# SignalHandler.cc stays in libldastoolsal_la_SOURCES_POSIX_ONLY; the .hh
# header parses under MinGW-w64 (signal_type is a plain enum — no POSIX
# types leak into the public ABI). Downstream consumers must guard their
# own usage, tracked under follow-up #308 alongside Fork/Exec.
#
# #300 (PSInfo.cc / UserInfoCache.cc): resolved as **POSIX-only by design**.
# PSInfo.cc reads Linux's /proc/<pid>/psinfo; UserInfoCache.cc uses
# getpwuid_r — both are inherently POSIX/Linux-specific (#284 already
# documents that macOS needs a different path). A Win32 branch using
# GetUserNameW + LookupAccountSid + GetProcessTimes + GetProcessMemoryInfo
# would be substantial work for code that's only used in diagnostic
# output. The active consumer set is the ldastoolsal test programs alone
# (tPSInfo.cc, ldas-ps-tail.cc) — no downstream package depends on these
# classes, so no follow-up consumer audit is needed.
# Both .cc files stay in libldastoolsal_la_SOURCES_POSIX_ONLY; the .hh
# headers stay installed. PSInfo.hh exposes pid_t which MinGW's
# <sys/types.h> defines as int on Win32 — harmless since no Win32 caller
# instantiates the class. UserInfoCache.hh exposes only INT_4U uid_type
# (no POSIX types leak). tPSInfo.cc's #ifdef skip arm picks up _WIN32
# under follow-up #284.
#
set( libldastoolsal_la_SOURCES_PORTABLE
	# #93: regex layer (boost::regex)
	regex.cc
	regexmatch.cc
	# Pure-C++ exception class, no platform deps; needed by regex.hh
	# transitively
	ldasexception.cc
	# Pure-C++ utility / data / exception TUs (no concurrency headers,
	# no POSIX system headers, no Boost.Log/Thread/etc. link deps).
	# Local MinGW build via ci/local-mingw-build.sh proves they compile;
	# CI windows_build_ldas_tools_al verifies the same on the
	# win32-threads MinGW toolchain.
	base64.cc
	Config.cc
	errorinfo.cc
	errors.cc
	Sed.cc
	streamexception.cc
	toss.cc
	util.cc
	# Pure-C++ command-line parsing + system-call base class +
	# refactored errno-to-string (no POSIX system headers in their
	# own implementations; only header-only Boost components —
	# shared_ptr / shared_array — and the regex layer which is
	# already portable). System.cc was refactored from POSIX
	# strerror_r (with its glibc-vs-XSI signature variance and
	# Windows incompatibility) to C++11 std::system_category()
	# .message(errno) in this MR — the std library handles the
	# platform dispatch under the hood.
	CommandLineOptions.cc
	System.cc
	SystemCall.cc
	# Phase-1 Ticket 5 / #294: filesystem family refactored from POSIX
	# lstat/stat/open/read/close (FileType.cc — in #289), mkdir (MkDir.cc
	# — this MR) and opendir/readdir/closedir (Directory.cc — this MR)
	# to std::filesystem + std::ifstream + std::filesystem::
	# directory_iterator. The PIMPL idiom in mutexlock.hh / Singleton.hh
	# keeps the std::mutex implementation detail confined to
	# MutexLockBaton.cc (POSIX_ONLY), so these files compile cleanly
	# even though they transitively include those headers.
	Directory.cc
	FileType.cc
	MkDir.cc
	# #296: gpstime.cc refactored from POSIX gettimeofday() to
	# std::chrono::system_clock::now() and from POSIX stat() to
	# std::filesystem::last_write_time. Drops <sys/time.h>, <time.h>,
	# <sys/types.h>, <sys/stat.h>, <unistd.h>.
	gpstime.cc
	# Pure-C++ consumers of the PIMPL'd concurrency primitives. These
	# files use MutexLock / ReadWriteLock / etc. only through their
	# opaque baton_type interface (boost::shared_ptr<impl>), with no
	# direct <mutex>/<thread>/<atomic> includes of their own. The
	# implementation files (mutexlock.cc, MutexLockBaton.cc, etc.)
	# stay in POSIX_ONLY because they actually need std::mutex et al.,
	# which the win32-threads MinGW libstdc++ doesn't define.
	AtExit.cc
	ErrorLog.cc
	IOLock.cc
	MemChecker.cc
	Pool.cc
	Singleton.cc
	TaskTimer.cc
	Timeout.cc
	# #297: SOLoader.cc ported from POSIX dlopen/dlsym/dlclose to a
	# #ifdef _WIN32 branch over LoadLibraryA/GetProcAddress/FreeLibrary.
	# The boost::dll alternative would have pulled in new link-time
	# Boost deps (boost_filesystem, boost_system) that #289 keeps off
	# the Windows build, so the thin Win32 branch was chosen instead
	# (same precedent as Thread.cc).
	SOLoader.cc
	# #295: fstream.cc mmap/munmap path moved behind a #ifdef _WIN32
	# branch using CreateFileMappingA/MapViewOfFile/UnmapViewOfFile;
	# page-size init switched to GetSystemInfo().dwAllocationGranularity
	# under Win32 (the alignment MapViewOfFile actually requires); the
	# int-fd _M_open() overload (no callers in the suite) short-circuits
	# on Win32 since MinGW msvcrt has no fcntl(F_GETFL). The historical
	# _get_osfflags() helper that walked __pioinfo[] internals was
	# removed as dead code. The boost::iostreams::mapped_file alternative
	# would have introduced a new link-time libboost_iostreams dep that
	# #289 keeps off the Windows build.
	fstream.cc
	# #309 (precursor): Task.cc previously had `#include "MutexLockBaton.cc"`
	# at line 36 that bypassed the PIMPL idiom and brought std::mutex into
	# the TU. Removed in this MR — Task.cc only uses MutexLock::baton_type
	# (a boost::shared_ptr<MutexLockBaton::impl> handle) through the
	# already-PIMPL'd mutexlock.hh, so the .cc include was redundant. CI
	# pipeline 856883 had originally flagged the bypass; this fix lets
	# Task.cc compile cleanly under MinGW-w64 win32-threads without
	# instantiating std::mutex.
	Task.cc
	# #309: MutexLockBaton.cc transitively included by mutexlock.cc gets a
	# #ifdef _WIN32 branch over CRITICAL_SECTION (InitializeCriticalSection
	# / EnterCriticalSection / TryEnterCriticalSection /
	# LeaveCriticalSection / DeleteCriticalSection). PIMPL keeps consumers
	# source-compatible; ref() now returns mutex_type* (the typedef
	# resolves to CRITICAL_SECTION on Win32, std::mutex on POSIX), and
	# ConditionalVariable.cc consumes the platform-flexible pointer
	# through its own #ifdef branch (SleepConditionVariableCS on Win32,
	# std::unique_lock + condition_variable::wait on POSIX).
	mutexlock.cc
	# #309: ConditionalVariable.cc paired with MutexLockBaton.cc above.
	# Win32 path uses CONDITION_VARIABLE + SleepConditionVariableCS /
	# WakeConditionVariable / WakeAllConditionVariable. POSIX path keeps
	# std::condition_variable + std::unique_lock<std::mutex>::adopt_lock.
	ConditionalVariable.cc
	# #309-thread: Thread.cc was already std::thread-based after #293
	# (std::thread + std::atomic<bool> stop flag, jthread-shape). All
	# POSIX-only surface — pthread_kill, sigaction-backed
	# SignalHandler::Register/ThreadCaptureSignal/ThreadIgnoreSignal,
	# the static Wakeup_ SignalHandler::Callback — is now hidden
	# behind #ifndef _WIN32 inside the TU. The four cancellation
	# modes that don't need signals (CANCEL_ASYNCHRONOUS,
	# CANCEL_DEFERRED, CANCEL_EXCEPTION, CANCEL_ABANDON) work
	# identically on POSIX and Win32 using std::thread +
	# std::atomic<bool>, both of which the win32-threads MinGW-w64
	# libstdc++ provides. CANCEL_BY_SIGNAL stays POSIX-only (Kill()
	# is a Win32 no-op; registration is #ifdef'd out).
	Thread.cc
	# #309-rwlock: ReadWriteLock.cc transitively includes
	# ReadWriteLockBaton.cc (POSIX: std::shared_timed_mutex; Win32:
	# SRWLOCK via InitializeSRWLock / Acquire*SRWLock* /
	# TryAcquire*SRWLock* / Release*SRWLock*). The timed-Lock overload
	# falls back to a TryAcquire + Sleep(1) spin loop on Win32 since
	# SRWLOCK has no timed-acquire API (no in-suite caller uses it).
	# Promotion to PORTABLE depended on Thread.cc landing first
	# (transitive Thread.icc include), satisfied above.
	ReadWriteLock.cc
	# #309-taskthread: TaskThread.cc's signal-mask block in action()
	# was already gated under !_WIN32 by #293. This MR also gates the
	# static Wakeup_ SignalHandler::Callback (whose vtable would
	# otherwise drag in SignalHandler.cc's ~Callback() — POSIX_ONLY).
	# Kill(m_cancel_signal) reaches Thread::Kill() which is a Win32
	# no-op since !301. CANCEL_BY_SIGNAL stays accepted as an enum
	# value on Win32 but registration and delivery are no-ops.
	TaskThread.cc
	# #309-taskthread: ThreadPool.cc has zero direct POSIX
	# dependencies (no signal, sigset, or pthread headers/calls in
	# its source). Once Thread.cc / TaskThread.cc are PORTABLE,
	# ThreadPool.cc moves with them free of any code change.
	ThreadPool.cc
	# #309-taskthread: SystemCallTask.cc is a thin wrapper over Task
	# / TaskThread with no direct POSIX dependencies. Moves to
	# PORTABLE alongside TaskThread.cc.
	SystemCallTask.cc
	# #309-timerthread: rewrote the waiter wake-up architecture from
	# nanosleep + pthread_kill(WAITER_SIGNAL) (which relied on the
	# POSIX "signal interrupts a system call" property — no Win32
	# equivalent) to std::condition_variable + wait_until / notify_one.
	# Works identically on POSIX and Win32 using std::mutex /
	# std::condition_variable (the latter is already PORTABLE after
	# the #309 mutex+cv MR's Win32 CONDITION_VARIABLE branch). One
	# signal-driven step remains POSIX-only and is #ifdef'd out on
	# Win32: when a timer fires, the waiter delivers the per-timer
	# signal to the requesting thread via pthread_kill — "deliver
	# signal X to thread Y" has no portable replacement, so on Win32
	# the timer accounting still works (queue, wake-up, fire-detection)
	# but the per-timer signal delivery is a no-op. Callers wanting a
	# portable "ring me back when my timer fires" mechanism should
	# move to a std::function-callback API in a follow-up.
	TimerThread.cc
)

set( libldastoolsal_la_SOURCES_POSIX_ONLY
	DebugLevelManager.cc
	Exec.cc
	Log.cc
	LoggerManager.cc
	LoggerRegistry.cc
	PatternMatcher.cc
	PSInfo.cc
	SignalHandler.cc
	Fork.cc
  LoggerOptions.cc
  SimpleLogger.cc
	UserInfoCache.cc
)

set( libldastoolsal_la_SOURCES ${libldastoolsal_la_SOURCES_PORTABLE} )
if(NOT WIN32)
  list(APPEND libldastoolsal_la_SOURCES ${libldastoolsal_la_SOURCES_POSIX_ONLY})
endif()
#
#libldastoolsal_la_LDFLAGS = $(LDASTOOLSAL_LIBTOOL_VERSION_FLAG) $(LDFLAGS) $(BOOST_LDFLAGS)
#libldastoolsal_la_LIBADD = -ldl
#

set( HDR_DIR ldastoolsal )
set( ldastoolsalhhdir "${CMAKE_INSTALL_INCLUDEDIR}/${HDR_DIR}" )

set( ldastoolsalhh_HEADERS
 	AtExit.hh
 	BackgroundTaskCounter.hh
 	CommandLineOptions.hh
 	ConditionalVariable.hh
 	Config.hh
	DebugLevelManager.hh
 	Deprecated.hh
 	Directory.hh
 	Exec.hh
 	InfixIterator.hh
 	IOLock.hh
 	Log.hh
  Logger.hh
  LoggerManager.hh
  LoggerOptions.hh
  LoggerRegistry.hh
 	MemChecker.hh
 	MkDir.hh
 	PatternMatcher.hh
 	PtrHash.hh
 	PSInfo.hh
 	ReadWriteLock.hh
 	ReadWriteSingleton.hh
 	Sed.hh
  SimpleLogger.hh
  SimpleLogger.inl
 	SignalHandler.hh
 	Singleton.hh
 	SingletonMacro.hh
 	Timeout.hh
 	TimerThread.hh
 	base64.hh
 	bit_vector.hh
 	compiler.h
 	errors.hh
 	errorinfo.hh
 	ErrorLog.hh
 	FileType.hh
 	Fork.hh
 	formatexception.hh
 	fstream.hh
 	gpstime.hh
 	ldasexception.hh
 	mutexlock.hh
 	objectregistry.hh
 	objectregistry.icc
 	Pool.hh
 	port.hh
 	Profile.hh
 	regex.hh
 	regexmatch.hh
 	SOLoader.hh
 	streamexception.hh
 	System.hh
 	SystemCall.hh
 	SystemCallTask.hh
 	Task.hh
 	TaskTimer.hh
 	TaskThread.hh
 	Thread.hh
 	ThreadPool.hh
 	TriStatePool.hh
 	unittest.h
 	UnitTestTS.h
 	util.hh
 	unimplemented_error.hh
 	toss.hh
 	UserInfoCache.hh
)

set( nodist_ldastoolsalhh_HEADERS
	ldas_types.h
	reverse.hh
	types.hh
	unordered_map.hh
  )

# Set default values for byte swap function detection (used in reverse.hh.in)
# These would be set by feature detection in a complete implementation
if(NOT DEFINED HAVE__OSSWAPINT16)
  set(HAVE__OSSWAPINT16 0)
endif()
if(NOT DEFINED HAVE__OSSWAPINT32)
  set(HAVE__OSSWAPINT32 0)
endif()
if(NOT DEFINED HAVE__OSSWAPINT64)
  set(HAVE__OSSWAPINT64 0)
endif()

foreach( filename ${nodist_ldastoolsalhh_HEADERS} )
  configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/${filename}.in
    ${CMAKE_CURRENT_BINARY_DIR}/${filename}
    @ONLY
    )
endforeach( )

cx_link_headers( ${HDR_DIR} ${ldastoolsalhh_HEADERS} )
cx_link_headers( BUILT_HEADERS ${HDR_DIR} ${nodist_ldastoolsalhh_HEADERS} )

# Link stdc++fs only on Linux (not needed on macOS/BSD)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  set(STDCXXFS_LIBS "-lstdc++fs")
  set(STDCXXFS_LIB stdc++fs)
else()
  set(STDCXXFS_LIBS "")
  set(STDCXXFS_LIB "")
endif()

# Build static library only if BUILD_STATIC_LIBS is ON
cx_static_libs_arg(_static_arg)

# Windows portability verification (#289): collect the cx_target_library
# arguments that differ between WIN32 (CONVENIENCE — OBJECT library
# only, no SHARED link, no install, no ABI check) and POSIX (the full
# SHARED + STATIC + install + ABI check pipeline) into a single
# variable, then expand it at the call site. Same pattern as
# _CX_TARGET_LIB_CONVENIENCE but extended to cover the entire set of
# arguments that only apply to one of the two paths.
#
# Why CONVENIENCE on WIN32: the verified-portable source set uses
# Boost.Regex, which is NOT header-only
# (cx_boost_component.cmake's _always_header_only list excludes it).
# A real SHARED link would fail with undefined references to
# boost::regex_*. The .o files themselves compile cleanly under
# MinGW — and "the .o files compile" is what this Windows
# portability check is asking. Sidesteps the boost-binary-sourcing
# question entirely (its own follow-up issue).
if(WIN32)
  set(_CX_TARGET_LIB_PLATFORM_ARGS
    CONVENIENCE
    )
else()
  set( libldastoolsal_la_LIBADD
    PUBLIC
      ${BOOST_TARGETS}
      ${STDCXXFS_LIB}
      Threads::Threads
    PRIVATE
      ${CMAKE_DL_LIBS}
    )
  set(_CX_TARGET_LIB_PLATFORM_ARGS
    ${_static_arg}
    LIBRARIES ${libldastoolsal_la_LIBADD}
    ABI_MESSAGE "LDAS Tools Abstraction Library"
    ABI_HEADER_DIR ${HDR_DIR}
    ABI_LOCAL_INCLUDE_DIR ${CMAKE_BINARY_DIR}/include/${HDR_DIR}
    ABI_HEADERS ${ldastoolsalhh_HEADERS}
    )
endif()
cx_target_library(
  ${_CX_TARGET_LIB_PLATFORM_ARGS}
  TARGET ldastoolsal
  CURRENT ${libldastoolsal_la_CURRENT}
  REVISION ${libldastoolsal_la_REVISION}
  AGE ${libldastoolsal_la_AGE}
  SOURCES ${libldastoolsal_la_SOURCES}
  DEFINES
  HAVE_CONFIG_H=1
  INCLUDE_DIRECTORIES BEFORE PRIVATE
  ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_BINARY_DIR}/include
  ${CMAKE_BINARY_DIR}
  ${BOOST_INCLUDE_DIR}
  )

foreach(filename ${nodist_ldastoolsalhh_HEADERS})
  list(APPEND nodist_full_ldastoolsalhh_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/${filename}" )
endforeach( )

# Header install + pkg-config rules describe a real distributable install
# layout. Under WIN32 we're only doing the portability compile-check
# (#289), so the install machinery is gated until a real Windows runtime
# build is in scope.
if(NOT WIN32)
  install(
    FILES ${ldastoolsalhh_HEADERS} ${nodist_full_ldastoolsalhh_HEADERS}
    DESTINATION ${ldastoolsalhhdir}
    )

  cx_target_pkgconfig( ldastoolsal )
endif()
