#/usr/bin/tclsh
# ^^^ help out editors which guess this file's content type.
#
# This is the main autosetup-compatible configure script for the
# SQLite project.
#
# This script should be kept compatible with JimTCL, a copy of which
# is included in this source tree as ./autosetup/jimsh0.c. The number
# of incompatibilities between canonical TCL and JimTCL is very low
# and alternative formulations of incompatible constructs have, so
# far, been easy to find.
#
# JimTCL: https://jim.tcl.tk
#
use cc cc-db cc-shared cc-lib proj pkg-config

# $DUMP_DEFINES_TXT is the file emitted by --dump-defines, intended
# only for build debugging and not part of the public build interface.
set DUMP_DEFINES_TXT ./config.defines.txt
# $DUMP_DEFINES_JSON is the autosetup counterpart of the historical
# "DEFS" var which was generated by the autotools in the pre-processed
# autotools builds (but not in the canonical tree). Generation of this
# file is disabled (via an empty file name) until/unless someone
# voices a specific interest in it. The original motivating use case
# is handled fine by sqlite_cfg.h.
set DUMP_DEFINES_JSON ""; #./config.defines.json

########################################################################
# Regarding flag compatibility with the historical autotool configure
# script:
#
# A very long story made short, autosetup's --flag handling has
# some behaviors which make it impossible to implement 100% identical
# flags compared to the historical autotools build. The differences
# are documented here:
#
# 1) --debug is used by autosetup itself, so we have to rename it to
# --with-debug. We cannot use --enable-debug because that is, for
# autosetup, and alias for --debug=1.
#
# 2) In autosetup, all flags starting with (--enable, --disable) are
# forced to be booleans and receive special handling in how they're
# resolved. Because of that we have to rename:
#
#   2.1) --enable-tempstore[=no] to --with-tempstore[=no].
#
########################################################################
# A gentle introduction to flags handling in autosetup
#
# Reference: https://msteveb.github.io/autosetup/developer/
#
# All configure flags must be described in an 'options' call, which
# must appear very early on in this script. The general syntax is:
#
#  FLAG => {Help text}
#
# Where FLAG can have any of the following formats:
#
#   boolopt            => "a boolean option which defaults to disabled"
#   boolopt2=1         => "a boolean option which defaults to enabled"
#   stringopt:         => "an option which takes an argument, e.g. --stringopt=value"
#   stringopt2:=value  => "an option where the argument is optional and defaults to 'value'"
#   optalias booltopt3 => "a boolean with a hidden alias. --optalias is not shown in --help"
#
# Autosetup does no small amount of specialized handling for flags,
# especially booleans. Each bool-type --FLAG implicitly gets
# --enable-FLAG and --disable-FLAG forms, and explicitly adding flags
# with those prefixes will force them to be boolean flags. e.g. we
# define a flag "readline", which will be interpreted in one of two
# ways, depending on how it's invoked and how its default is defined:
#
#   --enable-readline ==> boolean true
#   --disable-readline ==> boolean false
#
# Trying to pass --readline or --readline=1 or --readline=0 will
# result in an "unrecognized option" error, despite the the options
# call listing the flag as "readline".
#
# The behavior described above can lead lead to some confusion when
# writing help text. For example:
#
#   options { json=1 {Disable JSON functions} }
#
# The reason the help text says "disable" is because a boolean option
# defaulting to true is, in the --help text, rendered as:
#
#   --disable-json          Disable JSON functions
#
# Whereas a bool flag which defaults to false will instead render as:
#
#   --enable-FLAG
#
# Non-boolean flags, in contrast, use the names specifically given to
# them in the 'options' invocation. e.g. "with-tcl" is the --with-tcl
# flag. Autosetup may, however, choose to automatically alter the help
# text, as demonstrated here:
#
#   options {
#    readline=1           => {Disable readline support}
#    with-readline-lib:   => {Readline library}
#    with-readline-inc:   => {Readline include paths}
#   }
#
#   $ ./configure --help | grep readline
#   --disable-readline      disable readline support
#   --with-readline-lib     specify readline library
#   --with-readline-inc     specify readline include paths
#
# Note that it prefixed and lower-case the help message. Whether
# that's a feature or a bug can be debated.
#
# Fetching values for flags:
#
#   booleans: use one of:
#     - [opt-bool FLAG] is autosetup's built-in command for this, but we
#       have some convenience variants:
#     - [proj-opt-truthy FLAG]
#     - [proj-opt-if-truthy FLAG {THEN} {ELSE}]
#
#   Non-boolean (i.e. string) flags:
#     - [opt-val FLAG ?default?]
#
########################################################################
set flags {
  # <build-modes>
  with-debug:=1        => {Enable debug build flags}
  shared=1             => {Disable build of shared libary}
  static=1             => {Disable build of static library (mostly)}
  amalgamation=1       => {Disable the amalgamation and instead build all files separately.}
  # </build-modes>
  # <lib-feature>
  threadsafe=1         => {Disable mutexing}
  with-tempstore:=no   => {Use an in-ram database for temporary tables: never,no,yes,always}
  largefile=1          => {Disable large file support}
  load-extension=1     => {Disable loading of external extensions}
  math=1               => {Disable math functions}
  json=1               => {Disable JSON functions}
  memsys5              => {Enable MEMSYS5}
  memsys3              => {Enable MEMSYS3}
  fts3                 => {Enable the FTS3 extension}
  fts4                 => {Enable the FTS4 extension}
  fts5                 => {Enable the FTS5 extension}
  update-limit         => {Enable the UPDATE/DELETE LIMIT clause}
  geopoly              => {Enable the GEOPOLY extension}
  rtree                => {Enable the RTREE extension}
  session              => {Enable the SESSION extension}
  all                  => {Enable FTS4, FTS5, Geopoly, RTree, Sessions}
  # </lib-feature>
  # <tcl>
  # --with-tcl=DIR may be either a dir containing tclConfig.sh or a
  # dir one level up from that from which we can derive a dir
  # containing tclConfig.sh.
  with-tcl:DIR         => {Root of path containing tclConfig.sh}
  # If --with-tclsh=X given, it is used for (A) trying to find
  # tclConfig.sh and (B) all TCL-based code generation.  Warning: if
  # its containing dir has multiple tclsh versions, it may select the
  # wrong tclConfig.sh!
  with-tclsh:PATH      => {Full pathname of tclsh to use}
  # --disable-tcl only disables building of the SQLite TCL extension,
  # not the requirement for TCL.  This tree requires TCL for code
  # generation but can use the in-tree copy of autosetup/jimsh0.c for
  # that. The SQLite TCL extension and, by extension, the test code
  # require a canonical tclsh.
  tcl=1                => {Disable components which require TCL-dev}
  # <tcl>
  # <line-editing>
  readline=1           => {Disable readline support}
  # --with-readline-lib is a backwards-compatible alias for
  # --with-readline-ldflags
  with-readline-lib:
  with-readline-ldflags:=auto
                     => {Readline LDFLAGS, e.g. -lreadline -lncurses}
  # --with-readline-inc is a backwards-compatible alias for
  # --with-readline-cflags.
  with-readline-inc:
  with-readline-cflags:=auto
                       => {Readline CFLAGS, e.g. -I/path/to/includes}
  with-readline-header:PATH
                       => {Full path to readline.h, from which --with-readline-cflags will be derived}
  with-linenoise:DIR   => {Source directory for linenoise.c and linenoise.h}
  editline=0           => {BSD editline support}
  # </line-editing>
  # <icu>
  with-icu-ldflags:LDFLAGS
                        => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the ICU libraries}
  with-icu-config:=auto => {Enable SQLITE_ENABLE_ICU and fetch linker flags from the given icu-config binary}
  icu-collations=0      => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=... or --with-icu-config}
  # </icu>
  # <alternative-builds>
  with-wasi-sdk:=/opt/wasi-sdk
                       => {Top-most dir of the wasi-sdk for a WASI build}
  with-emsdk:DIR       => {Top-most dir of the Emscripten SDK installation}
  # </alternative-builds>
  # <developer>
  test-status          => {Enable status of tests}
  gcov=0               => {Enable coverage testing using gcov}
  linemacros           => {Enable #line macros in the amalgamation}
  dump-defines=0       => {Dump autosetup defines to $DUMP_DEFINES_TXT (for build debugging)}
  # </developer>

}
if {"" ne $DUMP_DEFINES_JSON} {
  lappend flags \
    defines-json-include-lowercase=0 \
    => {Include lower-case defines (primarily system paths) in $DUMP_DEFINES_JSON}
}

options [subst $flags]
unset flags

#
# Carry values from hidden --flag aliases over to their canonical flag
# forms.
#
proj-xfer-options-aliases {
  with-readline-inc => with-readline-cflags
  with-readline-lib => with-readline-ldflags
}
#
# "Re-export" the autoconf-conventional --XYZdir flags into something
# which is more easily overridable from a make invocation. See the docs
# for [proj-redirect-autoconf-dir-vars] for the explanation of why.
#
proj-redirect-autoconf-dir-vars

set srcdir $::autosetup(srcdir)
set top_srcdir [get-define abs_top_srcdir]
set PACKAGE_VERSION [readfile $srcdir/VERSION]
define PACKAGE_NAME "sqlite"
define PACKAGE_URL {https://sqlite.org}
define PACKAGE_VERSION $PACKAGE_VERSION
define PACKAGE_STRING "[get-define PACKAGE_NAME] $PACKAGE_VERSION"
define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
msg-result "srcdir = $srcdir"
msg-result "top_srcdir = $top_srcdir"
msg-result "Configuring SQLite version $PACKAGE_VERSION"

#
# SQLITE_AUTORECONFIG contains make target rules for re-running the
# configure script with the same arguments it was initially invoked
# with. This can be used to automatically reconfigure
#
define-append SQLITE_AUTORECONFIG cd '$::autosetup(builddir)' && '$top_srcdir/configure'
#{*}$::autosetup(argv) breaks with --flag='val with spaces', so...
foreach arg $::autosetup(argv) {
  define-append SQLITE_AUTORECONFIG '$arg'
}

# Are we cross-compiling?
set isCrossCompiling [proj-is-cross-compiling]
if {![file exists sqlite3.pc.in]} {
  msg-result "This appears to be an out-of-tree build."
}

cc-check-tools ld ar

define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
define OPT_SHELL {}         ; # CFLAGS for the sqlite3 CLI app
########################################################################
# Adds $args, if not empty, to OPT_FEATURE_FLAGS.
# If the first arg is -shell then it strips that arg
# and passes the remaining args th sqlite-add-shell-opt
# in addition to adding them to OPT_FEATURE_FLAGS.
proc sqlite-add-feature-flag {args} {
  set shell ""
  if {"-shell" eq [lindex $args 0]} {
    set args [lassign $args shell]
  }
  if {"" ne $args} {
    if {"" ne $shell} {
      sqlite-add-shell-opt {*}$args
    }
    define-append OPT_FEATURE_FLAGS {*}$args
  }
}
# Appends $args, if not empty, to OPT_SHELL.
proc sqlite-add-shell-opt {args} {
  if {"" ne $args} {
    define-append OPT_SHELL {*}$args
  }
}

# Pass msg-debug=1 to configure to enable obnoxiously loud output from
# msg-debug.
set msgDebugEnabled [proj-val-truthy [get-env msg-debug 0]]
proc msg-debug {msg} {
  if {$::msgDebugEnabled} {
    puts stderr [proj-bold "** DEBUG: $msg"]
  }
}

proj-file-extensions
if {".exe" eq [get-define TARGET_EXEEXT]} {
  define SQLITE_OS_UNIX 0
  define SQLITE_OS_WIN 1
  # todo? add -DSQLITE_OS_WIN=1 to CFLAGS or CFLAGS_sqlite3_os?
} else {
  define SQLITE_OS_UNIX 1
  define SQLITE_OS_WIN 0
  # todo? add -DSQLITE_OS_UNIX=1 to CFLAGS or CFLAGS_sqlite3_os
}

#########
# Programs needed
if {"" eq [proj-bin-define install]} {
  proj-warn "Cannot find install binary, so 'make install' will not work."
}

########################################################################
# We differentiate between two C compilers: the one used for binaries
# which are to run on the build system (in autosetup it's called
# CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
# compiling binaries for the target system (CC a.k.a. $(T.cc)).
# Normally they're the same, but they will differ when
# cross-compiling.
define CFLAGS [proj-get-env CFLAGS {-g -O2}]
define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]

########################################################################
# Handle --with-wasi-sdk=DIR
#
# This MUST be run early on because it may change the toolchain and
# disable a number of config options.
proc sqlite-check-wasi-sdk {} {
  set wasiSdkDir [opt-val with-wasi-sdk] ; # ??? [lindex [opt-val with-wasi-sdk] end]
  define HAVE_WASI_SDK 0
  if {$wasiSdkDir eq ""} {
    return 0
  } elseif {$::isCrossCompiling} {
    proj-fatal "Cannot combine --with-wasi-sdk with cross-compilation"
  }
  msg-result "Checking WASI SDK directory \[$wasiSdkDir]... "
  #puts "prefix = [prefix $wasiSdkDir/bin {clang ld}]"
  proj-affirm-files-exist -v {*}[prefix "$wasiSdkDir/bin/" {clang wasm-ld}]
  define HAVE_WASI_SDK 1
  define WASI_SDK_DIR $wasiSdkDir
  # Disable numerous options which we know either can't work or are
  # not useful in this build...
  msg-result "Using wasi-sdk clang. Disabling CLI shell and forcing:"
  foreach opt {
    editline
    gcov
    load-extension
    readline
    shared
    tcl
    threadsafe
  } {
    msg-result "  --disable-$opt"
    proj-opt-set $opt 0
  }
  # Remember that we now have a discrepancy beteween
  # $::isCrossCompiling and [proj-is-cross-compiling].
  set ::isCrossCompiling 1

  #
  # Changing --host and --target have no effect here except to
  # possibly cause confusion. Autosetup has finished processing them
  # by this point.
  #
  #  host_alias=wasm32-wasi
  #  target=wasm32-wasi
  #
  # Merely changing CC, LD, and AR to the wasi-sdk's is enough to get
  # sqlite3.o building in WASM format.
  #
  define CC "${wasiSdkDir}/bin/clang"
  define LD "${wasiSdkDir}/bin/wasm-ld"
  define AR "${wasiSdkDir}/bin/ar"
  #define STRIP "${wasiSdkDir}/bin/strip"
  return 1
}; # sqlite-check-wasi-sdk
sqlite-check-wasi-sdk

#
# Enable large file support (if special flags are necessary)
define HAVE_LFS 0
if {[opt-bool largefile]} {
  cc-check-lfs
}

#
# Check for needed/wanted data types
cc-with {-includes stdint.h} \
  {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
     uint8_t uint16_t uint32_t uint64_t uintptr_t}

#
# Check for needed/wanted functions
cc-check-functions gmtime_r isnan localtime_r localtime_s \
  malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64

proj-check-function-in-lib fdatasync rt
define LDFLAGS_FDATASYNC [get-define lib_fdatasync]
undefine lib_fdatasync

#
# Check for needed/wanted headers
cc-check-includes \
  sys/types.h sys/stat.h dlfcn.h unistd.h \
  stdlib.h malloc.h memory.h \
  string.h strings.h \
  inttypes.h

if {[cc-check-includes zlib.h] && [proj-check-function-in-lib deflate z]} {
  # TODO? port over the more sophisticated zlib search from the fossil auto.def
  define HAVE_ZLIB 1
  define LDFLAGS_ZLIB -lz
  sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
} else {
  define HAVE_ZLIB 0
  define LDFLAGS_ZLIB ""
}

proj-check-rpath; # Determine proper rpath-handling flags.

proj-define-if-opt-truthy shared ENABLE_SHARED "Build shared library?"

if {![proj-define-if-opt-truthy static ENABLE_STATIC \
        "Build static library?"]} {
  proj-warn "Static lib build may be implicitly re-activated by other components, e.g. some test apps."
}

proj-define-if-opt-truthy amalgamation USE_AMALGAMATION "Use amalgamation for builds?"

proj-define-if-opt-truthy gcov USE_GCOV "Use gcov?"

proj-define-if-opt-truthy test-status TSTRNNR_OPTS \
  "test-runner flags:" {--status} {}

proj-define-if-opt-truthy linemacros AMALGAMATION_LINE_MACROS \
  "Use #line macros in the amalgamation:"

msg-checking "SQLITE_DEBUG build? "
proj-if-opt-truthy with-debug {
  define SQLITE_DEBUG 1
  define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall}
  msg-result yes
} {
  define TARGET_DEBUG {-DNDEBUG}
  msg-result no
}

########################################################################
# TCL...
#
# sqlite-check-tcl performs most of the --with-tcl and --with-tclsh
# handling. Some related bits and pieces are performed before and
# after that function is called.
#
# Important [define]'d vars:
#
#  - HAVE_TCL indicates whether we have a tclsh suitable for building
#    the TCL SQLite extension and, by extension, the testing
#    infrastructure. This must only be 1 for environments where
#    tclConfig.sh can be found.
#
#  - TCLSH_CMD is the path to the canonical tclsh or "". It never
#    refers to jimtcl.
#
#  - TCL_CONFIG_SH is the path to tclConfig.sh or "".
#
#  - TCLLIBDIR is the dir to which libtclsqlite3 gets installed.
#
#  - TCLLIB_RPATH = the -rpath flag specific to libtclsqlite3, which
#    will usually differ from the rpath used by the rest of the lib.
#
#  - BTCLSH = the path to the tcl interpreter used for in-tree code
#    generation.  It may be jimtcl or the canonical tclsh but may not
#    be empty - this tree requires TCL to generated numerous
#    components.
#
proc sqlite-check-tcl {} {
  define TCLSH_CMD false ; # Significant is that it exits with non-0
  define HAVE_TCL 0      ; # Will be enabled via --tcl or a successful search
  define TCLLIBDIR ""    ; # Installation dir for TCL extension lib
  define TCLLIB_RPATH "" ; # rpath for TCL extension lib
  define TCL_CONFIG_SH ""; # full path to tclConfig.sh
  if {![opt-bool tcl]} {
    msg-result "TCL disabled via --disable-tcl. Will not be able to run tests."
    return
  }
  # TODO: document the steps this is taking.
  global top_srcdir
  msg-result "Checking for a suitable tcl... "
  proj-assert {proj-opt-truthy tcl}
  set use_tcl 1
  set with_tclsh [opt-val with-tclsh]
  set with_tcl [opt-val with-tcl]
  msg-debug "sqlite-check-tcl: use_tcl ${use_tcl}"
  msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
  msg-debug "sqlite-check-tcl: with_tcl=$with_tcl"
  if {"" eq $with_tclsh && "" eq $with_tcl} {
    # If neither --with-tclsh nor --with-tcl are provided, try to find
    # a workable tclsh.
    set with_tclsh [proj-first-bin-of tclsh9.0 tclsh8.6 tclsh]
    msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
  }

  if {"" ne $with_tclsh} {
    # --with-tclsh was provided. Validate it and use it to trump any
    # value passed via --with-tcl=DIR.
    if {![file isfile $with_tclsh]} {
      proj-fatal "TCL shell $with_tclsh is not a file"
    } elseif {![file-isexec $with_tclsh]} {
      proj-fatal "TCL shell $with_tclsh is not executable"
    } else {
      define TCLSH_CMD $with_tclsh
      #msg-result "Using tclsh: $with_tclsh"
    }
    if {[catch {exec $with_tclsh $top_srcdir/tool/find_tclconfig.tcl} result] == 0} {
      set with_tcl $result
    }
    if {"" ne $with_tcl && [file isdir $with_tcl]} {
      msg-result "$with_tclsh recommends the tclConfig.sh from $with_tcl"
    } else {
      proj-warn "$with_tclsh is unable to recommand a tclConfig.sh"
      set use_tcl 0
    }
  }

  set cfg ""
  set tclSubdirs {tcl9.0 tcl8.6 lib}
  while {1} {
    if {$use_tcl} {
      if {"" ne $with_tcl} {
        # Ensure that we can find tclConfig.sh under ${with_tcl}/...
        if {[file readable "${with_tcl}/tclConfig.sh"]} {
          set cfg "${with_tcl}/tclConfig.sh"
        } else {
          foreach i $tclSubdirs {
            if {[file readable "${with_tcl}/$i/tclConfig.sh"]} {
              set cfg "${with_tcl}/$i/tclConfig.sh"
              break
            }
          }
        }
        if {"" eq $cfg} {
          proj-fatal "No tclConfig.sh found under ${with_tcl}"
        }
      } else {
        # If we have not yet found a tclConfig.sh file, look in
        # $libdir which is set automatically by autosetup or by the
        # --prefix command-line option.  See
        # https://sqlite.org/forum/forumpost/e04e693439a22457
        set libdir [get-define libdir]
        if {[file readable "${libdir}/tclConfig.sh"]} {
          set cfg "${libdir}/tclConfig.sh"
        } else {
          foreach i $tclSubdirs {
            if {[file readable "${libdir}/$i/tclConfig.sh"]} {
              set cfg "${libdir}/$i/tclConfig.sh"
              break
            }
          }
        }
        if {![file readable $cfg]} {
          proj-indented-notice {
            WARNING: Cannot find a usable tclConfig.sh file.  Use
            --with-tcl=DIR to specify a directory where tclConfig.sh
            can be found.  SQLite does not use TCL internally, but TCL
            is required for testing.
          }
          break
        }
      }
      msg-result "Using tclConfig.sh: $cfg"
    } else {
      proj-warn "Unable to run tests because no tclConfig.sh file could be located"
    }
    break
  }
  define TCL_CONFIG_SH $cfg
  # Export a subset of tclConfig.sh to the current TCL-space.  If the
  # config is not available, this emits empty-string entries for the
  # various options we're interested in.
  eval [exec "${top_srcdir}/tool/tclConfigShToTcl.sh" "$cfg"]

  if {"" eq $with_tclsh && $cfg ne ""} {
    proj-assert {expr {"" ne [get-define TCL_EXEC_PREFIX]}}
    set with_tclsh [get-define TCL_EXEC_PREFIX]/bin/tclsh[get-define TCL_VERSION]
    if {![file-isexec $with_tclsh]} {
      set with_tclsh2 [get-define TCL_EXEC_PREFIX]/bin/tclsh
      if {![file-isexec $with_tclsh2]} {
        proj-warn "Cannot find a usable tclsh (tried: $with_tclsh $with_tclsh2)"
      } else {
        set with_tclsh $with_tclsh2
      }
    }
  }
  define TCLSH_CMD $with_tclsh
  if {$use_tcl} {
    # Set up the TCLLIBDIR and TCLLIB_RPATH
    #
    # 2024-10-28: calculation of TCLLIBDIR is now done via the shell
    # in the main.mk (search it for T.tcllibdir) so that
    # static/hand-written makefiles which import main.mk do not have
    # to define that before importing main.mk. Even so, we export
    # TCLLIBDIR from here for the benefit of those who want to provide
    # it at configure-time and have it "stick", without having to
    # provide it on each make invocation or set it in their
    # environment.
    set tcllibdir [get-env TCLLIBDIR ""]
    if {"" eq $tcllibdir} {
      # Attempt to extract TCLLIBDIR from TCL's $auto_path
      if {[catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} {
        foreach i $result {
          if {[file isdir $i]} {
            set tcllibdir $i/sqlite3
            break
          }
        }
      } else {
        proj-warn "Cannot determine TCLLIBDIR"
      }
    }
    set tclrpath ""
    if {"" ne $tcllibdir} {
      set rp [get-define SH_LINKRPATH]
      set tclrpath [string map [list "%s" $tcllibdir] $rp]
      # Reminder: tclConfig.sh has TCL_LD_SEARCH_FLAGS to set the
      # rpath but (A) it includes an unexpand var ref to
      # ${LIB_RUNTIME_DIR}, which must be set in the makefile and (B)
      # that flag is inherently compiler-dependent so it's not as
      # portable as tclConfig.sh assumes. We'll instead use the rpath
      # flag which autosetup determines for the current compiler.
    }
    define TCLLIBDIR $tcllibdir
    define TCLLIB_RPATH $tclrpath
    #msg-debug "TCLLIB_RPATH = [get-define TCLLIB_RPATH]"
  }; # find TCLLIBDIR

  if {[file exists $with_tclsh]} {
    msg-result "Using tclsh: $with_tclsh"
    define HAVE_TCL 1
  } else {
    proj-warn "Cannot find a usable tclsh, so cannot run tests."
  }
  show-notices
}; # sqlite-check-tcl

sqlite-check-tcl

########################################################################
# sqlite-determine-codegen-tcl checks which TCL to use as a code
# generator.  By default, prefer jimsh simply because we have it
# in-tree (it's part of autosetup) unless --with-tclsh=X is used, in
# which case prefix X.
#
# Returns the human-readable name of the TCL it selects. Fails fatally
# if it cannot detect a TCL appropriate for code generation.
#
# Defines:
#
#   - BTCLSH = the TCL shell used for code generation. It may set this
#     to an unexpanded makefile var name.
#
#   - CFLAGS_JIMSH = any flags needed for buildng a BTCLSH-compatible
#     jimsh. The defaults may be pass on to configure as
#     CFLAGS_JIMSH=...
proc sqlite-determine-codegen-tcl {} {
  msg-result "Checking for TCL to use for code generation... "
  define CFLAGS_JIMSH [proj-get-env CFLAGS_JIMSH {-O1}]
  set cgtcl [opt-val with-tclsh jimsh]
  set flagsToRestore {CC CFLAGS CPPFLAGS LDFLAGS LINKFLAGS LIBS CROSS}
  define-push $flagsToRestore {
    # We have to swap CC to CC_FOR_BUILD for purposes of the various
    # [cc-...] tests below. Recall that --with-wasi-sdk may have
    # swapped out CC with one which is not appropriate for this block.
    # Per consulation with autosetup's creator, doing this properly
    # requires us to [define-push] the whole $flagsToRestore list
    # (plus a few others which are not relevant in this tree).
    foreach flag $flagsToRestore {define $flag ""}
    define CC [get-define CC_FOR_BUILD]
    if {"jimsh" ne $cgtcl} {
      # When --with-tclsh=X is used, use that for all TCL purposes,
      # including in-tree code generation, per developer request.
      define BTCLSH "\$(TCLSH_CMD)"
    } else {
      # These headers are technically optional for JimTCL but necessary if
      # we want to use it for code generation:
      set sysh [cc-check-includes dirent.h sys/time.h]
      if {$sysh && [cc-check-functions realpath]} {
        define-append CFLAGS_JIMSH -DHAVE_REALPATH
        define BTCLSH "\$(JIMSH)"
      } elseif {$sysh && [cc-check-functions _fullpath]} {
        # _fullpath() is a Windows API
        define-append CFLAGS_JIMSH -DHAVE__FULLPATH
        define BTCLSH "\$(JIMSH)"
      } elseif {[file exists [get-define TCLSH_CMD]]} {
        set cgtcl [get-define TCLSH_CMD]
        define BTCLSH "\$(TCLSH_CMD)"
      } else {
        # One last-ditch effort to find TCLSH_CMD: use info from
        # tclConfig.sh to try to find a tclsh
        if {"" eq [get-define TCLSH_CMD]} {
          set tpre [get-define TCL_EXEC_PREFIX]
          if {"" ne $tpre} {
            set tv [get-define TCL_VERSION]
            if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
              define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
            } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
              define TCLSH_CMD "${tpre}/bin/tclsh"
            }
          }
        }
        set cgtcl [get-define TCLSH_CMD]
        if {![file exists $cgtcl]} {
          proj-fatal "Cannot find a tclsh to use for code generation."
        }
        define BTCLSH "\$(TCLSH_CMD)"
      }
    }
  }; # CC swap-out
  return $cgtcl
}; # sqlite-determine-codegen-tcl
msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
# /TCL
########################################################################

########################################################################
# Thread safety?
msg-checking "Support threadsafe operation? "
proj-if-opt-truthy threadsafe {
  msg-result yes
  sqlite-add-feature-flag -DSQLITE_THREADSAFE=1
  if {![proj-check-function-in-lib pthread_create pthread]
      || ![proj-check-function-in-lib pthread_mutexattr_init pthread]} {
    user-error "Missing required pthread bits"
  }
  define LDFLAGS_PTHREAD [get-define lib_pthread_create]
  undefine lib_pthread_create
} {
  msg-result no
  sqlite-add-feature-flag -DSQLITE_THREADSAFE=0
  define LDFLAGS_PTHREAD ""
}

########################################################################
# Do we want temporary databases in memory?
#
if {1} {
  set ts [opt-val with-tempstore no]
  set tsn 1
  msg-checking "Use an in-ram database for temporary tables? "
  switch -- $ts {
    never  { set tsn 0 }
    no     { set tsn 1 }
    yes    { set tsn 2 }
    always { set tsn 3 }
    default {
      user-error "Invalid with-tempstore value \[$ts]. Use one of: never, no, yes, always"
    }
  }
  msg-result $ts
  define TEMP_STORE $tsn
  unset ts tsn
}

########################################################################
# sqlite-check-line-editing jumps through proverbial hoops to try to
# find a working line-editing library, setting:
#
#   - HAVE_READLINE to 0 or 1
#   - HAVE_LINENOISE to 0, 1, or 2
#   - HAVE_EDITLINE to 0 or 1
#
# Only one of ^^^ those will be set to 1.
#
#   - LDFLAGS_READLINE = linker flags or empty string
#
#   - CFLAGS_READLINE = compilation flags for clients or empty string.
#
# Note that LDFLAGS_READLINE and CFLAGS_READLINE may refer to
# linenoise or editline, not necessarily libreadline.  In some cases
# it will set HAVE_READLINE=1 when it's really using editline, for
# reasons described in this function's comments.
#
# Returns a string describing which line-editing approach to use, or
# "none" if no option is available.
#
# Order of checks:
#
#  1) --with-linenoise trumps all others
#
#  2) --editline trumps --readline
#
#  3) --disable-readline trumps --readline
#
#  4) Default to automatic search for optional readline
#
#  5) Try to find readline resp. editline. If it's not found AND the
#     corresponding --FEATURE flag was explicitly given, fail fatally,
#     else fail silently.
proc sqlite-check-line-editing {} {
  msg-result "Checking for line-editing capability..."
  define HAVE_READLINE 0
  define HAVE_LINENOISE 0
  define HAVE_EDITLINE 0
  define LDFLAGS_READLINE ""
  define CFLAGS_READLINE ""
  set failIfNotFound 0 ; # Set to 1 for explicit --FEATURE requests
  set libsForReadline {readline edit} ; # -l<LIB> names to check for readline().
                                        # The libedit check changes this.
  set editLibName "readline" ; # "readline" or "editline"
  set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
  set dirLn [opt-val with-linenoise]
  if {"" ne $dirLn} {
    # Use linenoise from a copy of its sources (not a library)...
    if {![file isdir $dirLn]} {
      proj-fatal "--with-linenoise value is not a directory"
    }
    set lnH $dirLn/linenoise.h
    if {![file exists $lnH] } {
      proj-fatal "Cannot find linenoise.h in $dirLn"
    }
    set lnC ""
    set lnCOpts {linenoise-ship.c linenoise.c}
    foreach f $lnCOpts {
      if {[file exists $dirLn/$f]} {
        set lnC $dirLn/$f
        break;
      }
    }
    if {"" eq $lnC} {
      proj-fatal "Cannot find any of $lnCOpts in $dirLn"
    }
    set flavor ""
    set lnVal [proj-which-linenoise $lnH]
    switch -- $lnVal {
      1 { set flavor "antirez" }
      2 { set flavor "msteveb" }
      default {
        proj-fatal "Cannot determine the flavor of linenoise from $lnH"
      }
    }
    define CFLAGS_READLINE "-I$dirLn $lnC"
    define HAVE_LINENOISE $lnVal
    sqlite-add-shell-opt -DHAVE_LINENOISE=$lnVal
    return "linenoise ($flavor)"
  } elseif {[opt-bool editline]} {
    # libedit mimics libreadline and on some systems does not have its
    # own header installed (instead, that of libreadline is used).
    #
    # shell.c historically expects HAVE_EDITLINE to be set for
    # libedit, but it then expects to see <editline/readline.h>, which
    # some system's don't actually have, despite having libedit.  If
    # we end up finding <editline/readline.h> below, we will use
    # -DHAVE_EDITLINE=1, else we will use -DHAVE_READLINE=1. In either
    # case, we will link against libedit.
    set failIfNotFound 1
    set libsForReadline {edit}
    set editLibName editline
  } elseif {![opt-bool readline]} {
    msg-result "Readline support explicitly disabled with --disable-readline"
    return "none"
  } elseif {[proj-opt-was-provided readline]} {
    # If an explicit --[enable-]readline was used, fail if it's not
    # found, else treat the feature as optional.
    set failIfNotFound 1
  }

  # Transform with-readline-header=X to with-readline-cflags=-I...
  set v [opt-val with-readline-header]
  proj-opt-set with-readline-header ""
  if {"" ne $v} {
    if {"auto" eq $v} {
      proj-opt-set with-readline-cflags auto
    } else {
      set v [file dirname $v]
      if {[string match */readline $v]} {
        # Special case: if the path includes .../readline/readline.h, set
        # the -I to one dir up from that because our sources include
        # <readline/readline.h> or <editline/readline.h>.  Reminder: if
        # auto.def is being run by jimsh0 then [file normalize] will not
        # work!
        set v [file dirname $v]
      }
      proj-opt-set with-readline-cflags "-I$v"
    }
  }

  # Look for readline.h
  set rlInc [opt-val with-readline-cflags auto]
  if {"auto" eq $rlInc} {
    set rlInc ""
    if {$::isCrossCompiling} {
      # ^^^ this check is derived from the legacy configure script.
      proj-warn "Skipping check for readline.h because we're cross-compiling."
    } else {
      set dirs "[get-define prefix] /usr /usr/local /usr/local/readline /usr/contrib /mingw"
      set subdirs "include/$editLibName"
      if {"editline" eq $editLibName} {
        lappend subdirs include/readline
        # ^^^ editline, on some systems, does not have its own header,
        # and uses libreadline's header.
      }
      lappend subdirs include
      # ^^^ The dirs and subdirs lists are, except for the inclusion
      # of $prefix and editline, from the legacy configure script
      set rlInc [proj-search-for-header-dir readline.h \
                 -dirs $dirs -subdirs $subdirs]
      if {"" ne $rlInc} {
        if {[string match */readline $rlInc]} {
          set rlInc [file dirname $rlInc]; # shell #include's <readline/readline.h>
        } elseif {[string match */editline $rlInc]} {
          set editLibDef HAVE_EDITLINE
          set rlInc [file dirname $rlInc]; # shell #include's <editline/readline.h>
        }
        set rlInc "-I${rlInc}"
      }
    }
  } elseif {"" ne $rlInc && ![string match *-I* $rlInc]} {
    proj-fatal "Argument to --with-readline-cflags is intended to be CFLAGS and contain -I..."
  }

  # If readline.h was found/specified, look for lib(readline|edit)...
  #
  # This is not quite straightforward because both libreadline and
  # libedit typically require some other library which (according to
  # legacy autotools-generated tests) provides tgetent(3). On some
  # systems that's built into libreadline/edit, on some (most?) its in
  # lib[n]curses, and on some it's in libtermcap.
  set rlLib ""
  if {"" ne $rlInc} {
    set rlLib [opt-val with-readline-ldflags]
    if {"" eq $rlLib || "auto" eq $rlLib} {
      set rlLib ""
      set libTerm ""
      if {[proj-check-function-in-lib tgetent "$editLibName ncurses curses termcap"]} {
        # ^^^ that libs list comes from the legacy configure script ^^^
        set libTerm [get-define lib_tgetent]
        undefine lib_tgetent
      }
      if {$editLibName eq $libTerm} {
        set rlLib $libTerm
      } elseif {[proj-check-function-in-lib readline $libsForReadline $libTerm]} {
        set rlLib [get-define lib_readline]
        lappend rlLib $libTerm
        undefine lib_readline
      }
    }
  }

  # If we found a library, configure the build to use it...
  if {"" ne $rlLib} {
    if {"editline" eq $editLibName && "HAVE_READLINE" eq $editLibDef} {
      proj-indented-notice {
        NOTE: the local libedit but uses <readline/readline.h> so we
        will compile with -DHAVE_READLINE=1 but will link with
        libedit.
      }
    }
    set rlLib [join $rlLib]
    set rlInc [join $rlInc]
    define LDFLAGS_READLINE $rlLib
    define CFLAGS_READLINE $rlInc
    proj-assert {expr {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}}
    proj-assert {expr {$editLibName in {readline editline}}}
    sqlite-add-shell-opt -D${editLibDef}=1
    msg-result "Using $editLibName flags: $rlInc $rlLib"
    # Check whether rl_completion_matches() has a signature we can use
    # and disable that sub-feature if it doesn't.
    if {![cctest \
            -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 -source {
             #include <stdio.h>
             #ifdef HAVE_EDITLINE
             #include <editline/readline.h>
             #else
             #include <readline/readline.h>
             #endif
             static char * rcg(const char *z, int i){(void)z; (void)i; return 0;}
             int main(void) {
               char ** x = rl_completion_matches("one", rcg);
               (void)x;
               return 0;
             }
           }]} {
      user-notice "WARNING: readline-style completion disabled due to rl_completion_matches() signature mismatch"
      show-notices
      sqlite-add-shell-opt -DSQLITE_OMIT_READLINE_COMPLETION
    }
    return $editLibName
  }

  if {$failIfNotFound} {
    proj-fatal "Explicit --$editLibName failed to find a matching library."
  }

  return "none"
}; # sqlite-check-line-editing
msg-result "Line-editing support for the sqlite3 shell: [sqlite-check-line-editing]"

proj-if-opt-truthy load-extension {
  if {[proj-check-function-in-lib dlopen dl]} {
    define LDFLAGS_DLOPEN [get-define lib_dlopen]
    undefine lib_dlopen
  } else {
    user-error "dlopen() not found. Use --disable-load-extension to bypass this check."
  }
} {
  define LDFLAGS_DLOPEN ""
  sqlite-add-feature-flag {-DSQLITE_OMIT_LOAD_EXTENSION=1}
  msg-result "Disabling loadable extensions."
}

proj-if-opt-truthy math {
  if {![proj-check-function-in-lib ceil m]} {
    user-error "Cannot find libm functions. Use --disable-math to bypass this."
  }
  define LDFLAGS_MATH [get-define lib_ceil]
  undefine lib_ceil
  sqlite-add-feature-flag {-DSQLITE_ENABLE_MATH_FUNCTIONS}
  msg-result "Enabling math SQL functions [get-define LDFLAGS_MATH]"
} {
  define LDFLAGS_MATH ""
  msg-result "Disabling math SQL functions"
}

########################################################################
# ICU - International Components for Unicode
#
# Handles these flags:
#
#  --with-icu-ldflags=LDFLAGS
#  --with-icu-config[=/path/to/icu-config]
#  --enable-icu-collations
#
# If both icu-ldflags and icu-config are provided, they are
# cumulative.  If neither are provided, icu-collations is not honored
# and a warning is emitted if it is provided.
#
# Design note: though we can automatically enable ICU if the
# icu-config binary is found, we specifically do not. ICU is always an
# opt-in feature.
proc sqlite-check-icu {} {
  define LDFLAGS_ICU [join [opt-val with-icu-ldflags ""]]
  # Flags sets seen in the wild for ICU:
  # - -licui18n -licuuc -licudata
  # - -licui18n -licuuc
  # - /usr/local/bin/icu-config --ldflags
  if {[proj-opt-was-provided with-icu-config]} {
    set bin [opt-val with-icu-config]
    if {"auto" eq $bin} {
      set bin [proj-first-bin-of \
                 [get-define prefix]/bin/icu-config \
                 /usr/local/bin/icu-config \
                 /usr/bin/icu-config]
      if {"" eq $bin} {
        proj-fatal "--with-icu-config=auto cannot find icu-config binary"
      }
    }
    if {[file-isexec $bin]} {
      set x [exec $bin --ldflags]
      if {"" eq $x} {
        proj-fatal "$bin --ldflags returned no data"
      }
      define-append LDFLAGS_ICU $x
    } else {
      proj-fatal "--with-icu-config=$bin does not refer to an executable"
    }
  }
  set flags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
  if {"" ne $flags} {
    sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU
    msg-result "Enabling ICU support with libs: $flags"
    if {[opt-bool icu-collations]} {
      msg-result "Enabling ICU collations."
      sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU_COLLATIONS
      # Recall that shell.c builds with sqlite3.c
    }
  } elseif {[opt-bool icu-collations]} {
    proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
  } else {
    msg-result "ICU support is disabled."
  }
}; # sqlite-check-icu
sqlite-check-icu

########################################################################
# Emscripten SDK for building the web-based wasm components.
#
proc sqlite-check-emsdk {} {
  set emccsh $::srcdir/tool/emcc.sh
  if {![get-define HAVE_WASI_SDK] && [proj-check-emsdk]} {
    define EMCC_WRAPPER $emccsh
    proj-make-from-dot-in $emccsh
    catch {exec chmod u+x $emccsh}
  } else {
    define EMCC_WRAPPER ""
    file delete -force $emccsh
  }
}
sqlite-check-emsdk

########################################################################
# Check for log(3) in libm and die with an error if it is not
# found. $featureName should be the feature name which requires that
# function (it's used only in error messages). defines LDFLAGS_MATH to
# the required linker flags (which may be empty even if the math APIs
# are found, depending on the OS).
proc affirm-have-math {featureName} {
  if {![msg-quiet proj-check-function-in-lib log m]} {
    user-error "Missing math APIs for $featureName"
  }
  define LDFLAGS_MATH [get-define lib_log ""]
  undefine lib_log
}

########################################################################
# Handle various SQLITE_ENABLE_... feature flags.
msg-result "Feature flags..."
foreach {boolFlag featureFlag ifSetEvalThis} {
  all         {} {
    proj-opt-set fts4
    proj-opt-set fts5
    proj-opt-set geopoly
    proj-opt-set rtree
    proj-opt-set session
  }
  fts4         -DSQLITE_ENABLE_FTS4    {affirm-have-math fts4}
  fts5         -DSQLITE_ENABLE_FTS5    {affirm-have-math fts5}
  geopoly      -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
  rtree        -DSQLITE_ENABLE_RTREE   {}
  session      {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
  update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
  memsys5      -DSQLITE_ENABLE_MEMSYS5 {}
  memsys3      {} {
    if {[opt-bool memsys5]} {
      proj-warn "not enabling memsys3 because memsys5 is enabled."
      expr 0
    } else {
      sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
    }
  }
} {
  proj-if-opt-truthy $boolFlag {
    sqlite-add-feature-flag $featureFlag
    if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
      msg-result "  + $boolFlag"
    }
  } {
    if {"all" ne $boolFlag} {
      msg-result "  - $boolFlag"
    }
  }
}

########################################################################
# Invert the above loop's logic for some explicit SQLITE_OMIT_...
# cases. If config option $boolFlag is set, [sqlite-add-feature-flag
# $featureFlag], where $featureFlag is intended to be
# -DSQLITE_OMIT_...
foreach {boolFlag featureFlag} {
  json        -DSQLITE_OMIT_JSON
} {
  if {[proj-opt-truthy $boolFlag]} {
    msg-result "  + $boolFlag"
  } else {
    sqlite-add-feature-flag $featureFlag
    msg-result "  - $boolFlag"
  }
}

#########################################################################
# Show the final feature flag sets:
set oFF [get-define OPT_FEATURE_FLAGS]
if {"" ne $oFF} {
  define OPT_FEATURE_FLAGS [lsort -unique $oFF]
  msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
}
set oFF [get-define OPT_SHELL]
if {"" ne $oFF} {
  define OPT_SHELL [lsort -unique $oFF]
  msg-result "Shell options: [get-define OPT_SHELL]"
}
unset oFF

########################################################################
# Maybe extend JimTCL a bit. As of this writing (2024-09-27) it only
# needs (-DHAVE_REALPATH or -DHAVE__FULLPATH) and -DHAVE_DIRENT_H to
# be compatible with our code generators. It can, however, be slightly
# extended via easy-to-detect features, should we need them.
if {0 && "" ne [get-define CFLAGS_JIMSH]} {
  foreach jimFunc {opendir fsync isascii} {
    if {[cc-check-functions $jimFunc]} {
      define-append CFLAGS_JIMSH -DHAVE_[string toupper $jimFunc]
    }
  }
  #These are hard-coded into jimsh0.c, so we must not -D them:
  #foreach jimDef {HAVE_UNISTD_H HAVE_DIRENT_H} {
  #  if {[is-defined $jimDef]} {
  #    define-append CFLAGS_JIMSH -D$jimDef
  #  }
  #}
  define-append CFLAGS_JIMSH -DHAVE_LONG_LONG; # SQLite relies on long long, so we know it's available
}; # JimTCL

########################################################################
# Generate the output files.
#
# Potential TODO (unclear): in sqlite3.pc.in, do we need to include
# any CFLAGS_READLINE, CFLAGS_ZLIB, etc in its "Cflags:" section?
proj-make-from-dot-in -touch Makefile sqlite3.pc
if {0} {
  # Requires a hand-written sqlite_cfg.h.in...
  proj-make-from-dot-in sqlite_cfg.h
  # vs...
} else {
  # Requires no input template...
  make-config-header sqlite_cfg.h \
    -bare {SIZEOF_* HAVE_DECL_*} \
    -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
      TARGET_* USE_GCOV TCL_*} \
    -auto {HAVE_* PACKAGE_*} \
    -none *
  proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
}
#TODO proj-make-from-dot-in ext/wasm/GNUmakefile

if {"" ne $DUMP_DEFINES_JSON} {
  ########################################################################
  # Dump config-defines.json...
  # Demonstrate (mis?)handling of spaces in JSON-export array values:
  # define-append OPT_FOO.list {"-DFOO=bar baz" -DBAR="baz barre"}
  define OPT_FEATURE_FLAGS.list [get-define OPT_FEATURE_FLAGS]
  define OPT_SHELL.list [get-define OPT_SHELL]
  set dumpDefsOpt {
    -bare {SIZEOF_* HAVE_DECL_*}
    -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG TARGET_* USE_GCOV TCL_*}
    -array {*.list}
    -auto {OPT_* PACKAGE_* HAVE_*}
  }
  if {[opt-bool defines-json-include-lowercase]} {
    lappend dumpDefsOpt -none {lib_*} ; # remnants from proj-check-function-in-lib and friends
    lappend dumpDefsOpt -auto {[a-z]*}
  }
  lappend dumpDefsOpt -none *
  proj-dump-defs-json $DUMP_DEFINES_JSON {*}$dumpDefsOpt
  undefine OPT_FEATURE_FLAGS.list
  undefine OPT_SHELL.list
}

########################################################################
# Some build-dev/debug-only output
proj-if-opt-truthy dump-defines {
  msg-result "--dump-defines is creating $::DUMP_DEFINES_TXT"
  make-config-header $::DUMP_DEFINES_TXT \
    -bare {SQLITE_OS* SQLITE_DEBUG USE_*} \
    -str {BIN_* CC LD AR LDFLAG* OPT_*} \
    -auto {*}
  # achtung: ^^^^ whichever SQLITE_OS_foo flag which is set to 0 will
  # get _undefined_ here unless it's part of the -bare set.
  if {0} {
    foreach x [all-defines] {
      puts "\t$x"
    }
  }
}
