using autoconf

intf_libs = # Interface dependencies.
impl_libs = # Implementation dependencies.

# Public headers.
#
pub = [dir_path] ../include/

include $pub

pub_hdrs = $($pub/ pub_hdrs)

./: lib{cpptrace}
lib{cpptrace}: h{cpptrace-autoconf} $pub/{$pub_hdrs}

# Unwind back-ends.
#
unwind_with_unwind    = $config.libcpptrace.unwind_with_unwind
unwind_with_execinfo  = $config.libcpptrace.unwind_with_execinfo
unwind_with_winapi    = $config.libcpptrace.unwind_with_winapi
unwind_with_dbghelp   = $config.libcpptrace.unwind_with_dbghelp
unwind_with_libunwind = $config.libcpptrace.unwind_with_libunwind
unwind_with_nothing   = $config.libcpptrace.unwind_with_nothing

# Symbol resolution back-ends.
#
symbols_with_libdwarf     = $config.libcpptrace.symbols_with_libdwarf
symbols_with_dbghelp      = $config.libcpptrace.symbols_with_dbghelp
symbols_with_libbacktrace = $config.libcpptrace.symbols_with_libbacktrace
symbols_with_addr2line    = $config.libcpptrace.symbols_with_addr2line
symbols_with_libdl        = $config.libcpptrace.symbols_with_libdl
symbols_with_nothing      = $config.libcpptrace.symbols_with_nothing

if ($symbols_with_libdwarf)
{
  import impl_libs += libz%lib{z}
  import impl_libs += libzstd%lib{zstd}
}

# Demangling back-ends.
#
demangle_with_cxxabi  = $config.libcpptrace.demangle_with_cxxabi
demangle_with_winapi  = $config.libcpptrace.demangle_with_winapi
demangle_with_nothing = $config.libcpptrace.demangle_with_nothing

# Platform capability detection via autoconf checks and compiler predefs.
# Results are brought into buildfile scope and used as -D flags below, since
# cpptrace sources rely on them being passed as compile definitions rather than
# included from a config header.
#
h{cpptrace-autoconf}: in{cpptrace-autoconf}
{
  install = false
  autoconf.aliases = HAVE_DL_FIND_OBJECT@HAVE__DL_FIND_OBJECT
}

[rule_hint=c.predefs] \
buildfile{cpptrace-autoconf}: h{cpptrace-autoconf}
{
  c.predefs.poptions = false
  c.predefs.macros = HAVE_ATTRIBUTE_PACKED HAVE_MACH_MACH_VM_H \
                     HAVE_DL_FIND_OBJECT HAVE_DLADDR1
}

# Initialize to false for non-perform operations (e.g. configure).
#
HAS_ATTRIBUTE_PACKED        = [bool] false
CPPTRACE_HAS_MACH_VM        = [bool] false
CPPTRACE_HAS_DL_FIND_OBJECT = [bool] false
CPPTRACE_HAS_DLADDR1        = [bool] false

if ($build.meta_operation == 'perform')
{
  update buildfile{cpptrace-autoconf}
  source $path(buildfile{cpptrace-autoconf})

  HAS_ATTRIBUTE_PACKED        = ($HAVE_ATTRIBUTE_PACKED     == 1 ? true : false)
  CPPTRACE_HAS_MACH_VM        = ($HAVE_MACH_MACH_VM_H       == 1 ? true : false)
  CPPTRACE_HAS_DL_FIND_OBJECT = ($HAVE_DL_FIND_OBJECT       == 1 ? true : false)
  CPPTRACE_HAS_DLADDR1        = ($HAVE_DLADDR1              == 1 ? true : false)
}

# Private headers and sources as well as dependencies.
#
lib{cpptrace}: cpptrace/hxx{**} cpptrace/{cxx mxx}{** -unwind/** -symbols/symbols_with_* -demangle/demangle_with_*} \
               $impl_libs $intf_libs

lib{cpptrace}: cpptrace/unwind/cxx{unwind_with_unwind}:         include = $unwind_with_unwind
lib{cpptrace}: cpptrace/unwind/cxx{unwind_with_execinfo}:       include = $unwind_with_execinfo
lib{cpptrace}: cpptrace/unwind/cxx{unwind_with_winapi}:         include = $unwind_with_winapi
lib{cpptrace}: cpptrace/unwind/cxx{unwind_with_dbghelp}:        include = $unwind_with_dbghelp
lib{cpptrace}: cpptrace/unwind/cxx{unwind_with_libunwind}:      include = $unwind_with_libunwind
lib{cpptrace}: cpptrace/unwind/cxx{unwind_with_nothing}:        include = $unwind_with_nothing

lib{cpptrace}: cpptrace/symbols/cxx{symbols_with_libdwarf}:     include = $symbols_with_libdwarf
lib{cpptrace}: cpptrace/symbols/cxx{symbols_with_dbghelp}:      include = $symbols_with_dbghelp
lib{cpptrace}: cpptrace/symbols/cxx{symbols_with_libbacktrace}: include = $symbols_with_libbacktrace
lib{cpptrace}: cpptrace/symbols/cxx{symbols_with_addr2line}:    include = $symbols_with_addr2line
lib{cpptrace}: cpptrace/symbols/cxx{symbols_with_dl}:           include = $symbols_with_libdl
lib{cpptrace}: cpptrace/symbols/cxx{symbols_with_nothing}:      include = $symbols_with_nothing

lib{cpptrace}: cpptrace/demangle/cxx{demangle_with_cxxabi}:     include = $demangle_with_cxxabi
lib{cpptrace}: cpptrace/demangle/cxx{demangle_with_winapi}:     include = $demangle_with_winapi
lib{cpptrace}: cpptrace/demangle/cxx{demangle_with_nothing}:    include = $demangle_with_nothing

# Build options.
#
out_pfx_inc = [dir_path] $out_root/include/
src_pfx_inc = [dir_path] $src_root/include/
out_pfx_src = [dir_path] $out_root/src/cpptrace
src_pfx_src = [dir_path] $src_root/src/cpptrace

cxx.poptions =+ "-I$out_pfx_src" "-I$src_pfx_src" \
                "-I$out_pfx_inc" "-I$src_pfx_inc" "-I$src_base" \
                ($config.libcpptrace.build_testing ? -DCPPTRACE_BUILD_TESTING:)

# Platform capability flags (mirrors upstream cmake/Autoconfig.cmake checks).
#
cxx.poptions += \
  ($HAS_ATTRIBUTE_PACKED ? -DHAS_ATTRIBUTE_PACKED :) \
  ($CPPTRACE_HAS_MACH_VM ? -DCPPTRACE_HAS_MACH_VM :) \
  ($CPPTRACE_HAS_DL_FIND_OBJECT ? -DCPPTRACE_HAS_DL_FIND_OBJECT :) \
  ($CPPTRACE_HAS_DLADDR1 ? -DCPPTRACE_HAS_DLADDR1 :) \
  (!($cxx.target.class == 'windows' && $cxx.target.system != 'mingw32') ? -DCPPTRACE_HAS_CXX_EXCEPTION_TYPE :)

if ($cxx.target.system != 'win32-msvc')
  objs{**}: cxx.coptions += -Wno-missing-field-initializers \
                            -fvisibility=hidden \
                            -fvisibility-inlines-hidden \
                            -fPIC

obja{**}: cxx.poptions += -DCPPTRACE_STATIC_DEFINE
objs{**}: cxx.poptions += -Dcpptrace_lib_EXPORTS

# Unwind back-ends.
#
obj{**}: cxx.poptions += \
  ($unwind_with_unwind    ? -DCPPTRACE_UNWIND_WITH_UNWIND    :) \
  ($unwind_with_execinfo  ? -DCPPTRACE_UNWIND_WITH_EXECINFO  :) \
  ($unwind_with_winapi    ? -DCPPTRACE_UNWIND_WITH_WINAPI    :) \
  ($unwind_with_dbghelp   ? -DCPPTRACE_UNWIND_WITH_DBGHELP   :) \
  ($unwind_with_libunwind ? -DCPPTRACE_UNWIND_WITH_LIBUNWIND -DUNW_LOCAL_ONLY :) \
  ($unwind_with_nothing   ? -DCPPTRACE_UNWIND_WITH_NOTHING   :)

# Symbol resolution back-ends.
#
obj{**}: cxx.poptions += \
  ($symbols_with_libdwarf     ? -DCPPTRACE_GET_SYMBOLS_WITH_LIBDWARF     :) \
  ($symbols_with_dbghelp      ? -DCPPTRACE_GET_SYMBOLS_WITH_DBGHELP      :) \
  ($symbols_with_libbacktrace ? -DCPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE :) \
  ($symbols_with_addr2line    ? -DCPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE -DCPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH :) \
  ($symbols_with_libdl        ? -DCPPTRACE_GET_SYMBOLS_WITH_LIBDL        :) \
  ($symbols_with_nothing      ? -DCPPTRACE_GET_SYMBOLS_WITH_NOTHING      :)

# Demangling back-ends.
#
obj{**}: cxx.poptions += \
  ($demangle_with_cxxabi  ? -DCPPTRACE_DEMANGLE_WITH_CXXABI  :) \
  ($demangle_with_winapi  ? -DCPPTRACE_DEMANGLE_WITH_WINAPI  :) \
  ($demangle_with_nothing ? -DCPPTRACE_DEMANGLE_WITH_NOTHING :)

# System libraries (implementation only, not exported).
#
sys_libs =

if ($unwind_with_dbghelp || $symbols_with_dbghelp || $demangle_with_winapi)
{
  if ($cxx.target.system == 'mingw32')
    sys_libs += -ldbghelp
  else
    sys_libs += dbghelp.lib
}

# dladdr in object.cpp is always used on Linux. MinGW only for libdl-family back-ends.
#
if ($cxx.target.class == 'linux')
  sys_libs += -ldl

if ($cxx.target.system == 'mingw32' && \
    ($symbols_with_libdwarf || $symbols_with_libdl || $symbols_with_libbacktrace))
  sys_libs += -ldl

if ($symbols_with_libdwarf)
  sys_libs += -ldwarf

if ($symbols_with_libbacktrace)
  sys_libs += -lbacktrace

if ($unwind_with_libunwind)
  sys_libs += -lunwind

if ($unwind_with_execinfo && $cxx.target.class == 'bsd')
  sys_libs += -lexecinfo

cxx.libs += $sys_libs

# Export options.
#
lib{cpptrace}:
{
  cxx.export.poptions = "-I$out_pfx_inc" "-I$src_pfx_inc" \
                        ($config.libcpptrace.build_testing ? -DCPPTRACE_BUILD_TESTING "-I$src_pfx_src" :)
  cxx.export.libs = $intf_libs
}

liba{cpptrace}: cxx.export.poptions += -DCPPTRACE_STATIC_DEFINE

# For pre-releases use the complete version to make sure they cannot
# be used in place of another pre-release or the final version. See
# the version module for details on the version.* variable values.
#
if $version.pre_release
  lib{cpptrace}: bin.lib.version = "-$version.project_id"
else
  lib{cpptrace}: bin.lib.version = "-$version.major.$version.minor"

# Don't install private headers (except for testing).
#
cpptrace/{hxx ixx txx}{*}:
{
  install = ($config.libcpptrace.build_testing ? include/cpptrace/internal/ : false)
  install.subdirs = true
}

# Make sure private headers installed into cpptrace/internal/ can
# also be included without the directory prefixes (for tests).
#
lib{cpptrace}: cxx.pkgconfig.include = include/ \
               ($config.libcpptrace.build_testing ? include/cpptrace/internal/ :)

# Install module interfaces.
#
mxx{*}:
{
  install         = include/cpptrace/
  install.subdirs = false
}
