##------------------------------------------------------------------------
## 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 12 )
set( libldastoolsal_la_REVISION 0 )
set( libldastoolsal_la_AGE 1 )

#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
	# #392/#389: GNU-standard --version / -V helper. Pure boost::program_options,
	# no POSIX dependencies.
	ProgramVersion.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
 	# #392/#389: GNU-standard --version / -V helper.
 	ProgramVersion.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()
