diff --git a/.fossil-settings/binary-glob b/.fossil-settings/binary-glob new file mode 100755 index 0000000000..3997beadf8 --- /dev/null +++ b/.fossil-settings/binary-glob @@ -0,0 +1 @@ +*.db \ No newline at end of file diff --git a/Makefile.in b/Makefile.in index 3bb66f13ff..57728b0498 100644 --- a/Makefile.in +++ b/Makefile.in @@ -122,10 +122,13 @@ LDFLAGS.rt = @LDFLAGS_RT@ CFLAGS.icu = @CFLAGS_ICU@ LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@ # soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded -LDFLAGS.libsqlite3.os-specific = @LDFLAGS_MAC_CVERSION@ @LDFLAGS_OUT_IMPLIB@ +LDFLAGS.libsqlite3.os-specific = \ + @LDFLAGS_MAC_CVERSION@ @LDFLAGS_MAC_INSTALL_NAME@ @LDFLAGS_OUT_IMPLIB@ # os-specific: see # - https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7 # - https://sqlite.org/forum/forumpost/0c7fc097b2 +# - https://sqlite.org/forum/forumpost/5651662b8875ec0a + libsqlite3.DLL.basename = @SQLITE_DLL_BASENAME@ # DLL.basename: see https://sqlite.org/forum/forumpost/828fdfe904 libsqlite3.out.implib = @SQLITE_OUT_IMPLIB@ @@ -138,16 +141,10 @@ libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@ # -fsanitize flags for the fuzzcheck-asap app CFLAGS.fuzzcheck-asan.fsanitize = @CFLAGS_ASAN_FSANITIZE@ -T.cc.sqlite = $(T.cc) @TARGET_DEBUG@ - # -# Define -D_HAVE_SQLITE_CONFIG_H so that the code knows it -# can include the generated sqlite_cfg.h. +# Intended to either be empty or be set to -g -DSQLITE_DEBUG=1. # -# main.mk will fill out T.cc.sqlite with additional flags common to -# all builds. -# -T.cc.sqlite += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite +T.cc.TARGET_DEBUG = @TARGET_DEBUG@ # # $(JIMSH) and $(CFLAGS.jimsh) are documented in main.mk. $(JIMSH) @@ -246,8 +243,8 @@ TSTRNNR_OPTS = @TSTRNNR_OPTS@ CFLAGS.gcov1 = -DSQLITE_COVERAGE_TEST=1 -fprofile-arcs -ftest-coverage LDFLAGS.gcov1 = -lgcov USE_GCOV = @USE_GCOV@ -T.compile.extras = $(CFLAGS.gcov$(USE_GCOV)) -T.link.extras = $(LDFLAGS.gcov$(USE_GCOV)) +T.compile.gcov = $(CFLAGS.gcov$(USE_GCOV)) +T.link.gcov = $(LDFLAGS.gcov$(USE_GCOV)) # # Vars with the AS_ prefix are specifically related to AutoSetup. @@ -265,6 +262,8 @@ USE_AMALGAMATION ?= @USE_AMALGAMATION@ LINK_TOOLS_DYNAMICALLY ?= @LINK_TOOLS_DYNAMICALLY@ AMALGAMATION_GEN_FLAGS ?= --linemacros=@AMALGAMATION_LINE_MACROS@ EXTRA_SRC ?= @AMALGAMATION_EXTRA_SRC@ +STATIC_TCLSQLITE3 = @STATIC_TCLSQLITE3@ +STATIC_CLI_SHELL = @STATIC_CLI_SHELL@ # # CFLAGS for sqlite3$(T.exe) diff --git a/Makefile.msc b/Makefile.msc index 80e294003d..af9f2b9c7a 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -2594,6 +2594,11 @@ testfixture.exe: $(TESTFIXTURE_SRC) $(TESTFIXTURE_DEP) $(SQLITE3H) $(LIBRESOBJS) $(TESTFIXTURE_SRC) \ /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS) +# A small helper for manually running individual tests +tf.bat: testfixture.exe Makefile.msc + echo @set PATH=$(LIBTCLPATH);%PATH% > $@ + echo .\testfixture.exe %* >> $@ + extensiontest: testfixture.exe testloadext.dll @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) @@ -2845,7 +2850,9 @@ clean: del /Q lsm.dll lsmtest.exe 2>NUL del /Q atrc.exe changesetfuzz.exe dbtotxt.exe index_usage.exe 2>NUL del /Q testloadext.dll 2>NUL - del /Q testfixture.exe test.db 2>NUL + del /Q testfixture.exe test.db tf.bat 2>NUL + del /Q /S testdir 2>/NUL + -rmdir /Q /S testdir 2>NUL del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL del /Q changeset.exe 2>NUL del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL diff --git a/README.md b/README.md index d6d41da3b9..0be1fb9f43 100644 --- a/README.md +++ b/README.md @@ -57,18 +57,18 @@ If you do not want to use Fossil, you can download tarballs or ZIP archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows: * Latest trunk check-in as - [Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz), - [ZIP-archive](https://www.sqlite.org/src/zip/sqlite.zip), or - [SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar). + [Tarball](https://sqlite.org/src/tarball/sqlite.tar.gz), + [ZIP-archive](https://sqlite.org/src/zip/sqlite.zip), or + [SQLite-archive](https://sqlite.org/src/sqlar/sqlite.sqlar). * Latest release as - [Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=release), - [ZIP-archive](https://www.sqlite.org/src/zip/sqlite.zip?r=release), or - [SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar?r=release). + [Tarball](https://sqlite.org/src/tarball/sqlite.tar.gz?r=release), + [ZIP-archive](https://sqlite.org/src/zip/sqlite.zip?r=release), or + [SQLite-archive](https://sqlite.org/src/sqlar/sqlite.sqlar?r=release). * For other check-ins, substitute an appropriate branch name or tag or hash prefix in place of "release" in the URLs of the previous - bullet. Or browse the [timeline](https://www.sqlite.org/src/timeline) + bullet. Or browse the [timeline](https://sqlite.org/src/timeline) to locate the check-in desired, click on its information page link, then click on the "Tarball" or "ZIP Archive" links on the information page. @@ -308,14 +308,14 @@ individual source file exceeds 32K lines in length. ## How It All Fits Together SQLite is modular in design. -See the [architectural description](https://www.sqlite.org/arch.html) +See the [architectural description](https://sqlite.org/arch.html) for details. Other documents that are useful in helping to understand how SQLite works include the -[file format](https://www.sqlite.org/fileformat2.html) description, -the [virtual machine](https://www.sqlite.org/opcode.html) that runs +[file format](https://sqlite.org/fileformat2.html) description, +the [virtual machine](https://sqlite.org/opcode.html) that runs prepared statements, the description of -[how transactions work](https://www.sqlite.org/atomiccommit.html), and -the [overview of the query planner](https://www.sqlite.org/optoverview.html). +[how transactions work](https://sqlite.org/atomiccommit.html), and +the [overview of the query planner](https://sqlite.org/optoverview.html). Decades of effort have gone into optimizing SQLite, both for small size and high performance. And optimizations tend to result in diff --git a/auto.def b/auto.def index a1191cdd1e..43c597551b 100644 --- a/auto.def +++ b/auto.def @@ -26,6 +26,7 @@ sqlite-configure canonical { # [proj-get-env] and we want this to supercede that. sqlite-munge-cflags; # straighten out -DSQLITE_ENABLE/OMIT flags } + sqlite-handle-debug ;# must come after --dev flag check sqlite-check-common-bins ;# must come before [sqlite-handle-wasi-sdk] sqlite-handle-wasi-sdk ;# must run relatively early, as it changes the environment sqlite-check-common-system-deps @@ -53,4 +54,11 @@ sqlite-configure canonical { sqlite-handle-tcl sqlite-handle-emsdk -} + proj-if-opt-truthy static-shells { + proj-opt-set static-tclsqlite3 1 + proj-opt-set static-cli-shell 1 + } + proj-define-for-opt static-tclsqlite3 STATIC_TCLSQLITE3 "Statically link tclsqlite3?" + proj-define-for-opt static-cli-shell STATIC_CLI_SHELL "Statically link CLI shell?" + +}; # sqlite-configure diff --git a/autoconf/Makefile.in b/autoconf/Makefile.in index 009398617c..aaa23b7def 100644 --- a/autoconf/Makefile.in +++ b/autoconf/Makefile.in @@ -125,10 +125,8 @@ OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@ # soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded -LDFLAGS.libsqlite3.os-specific = @LDFLAGS_MAC_CVERSION@ @LDFLAGS_OUT_IMPLIB@ -# os-specific: see -# - https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7 -# - https://sqlite.org/forum/forumpost/0c7fc097b2 +LDFLAGS.libsqlite3.os-specific = \ + @LDFLAGS_MAC_CVERSION@ @LDFLAGS_MAC_INSTALL_NAME@ @LDFLAGS_OUT_IMPLIB@ LDFLAGS.libsqlite3 = \ $(LDFLAGS.rpath) $(LDFLAGS.pthread) \ @@ -193,6 +191,8 @@ install-dll-unix-generic: install-dll-out-implib install-dll-msys: install-dll-out-implib $(install-dir.bin) $(INSTALL) $(libsqlite3.DLL) "$(install-dir.bin)" # ----------------------------------------------^^^ yes, bin +# Each of {msys,mingw,cygwin} uses a different name for the DLL, but +# that is already accounted for via $(libsqlite3.DLL). install-dll-mingw: install-dll-msys install-dll-cygwin: install-dll-msys @@ -227,9 +227,22 @@ sqlite3-shell-link-flags.1 = $(TOP)/sqlite3.c $(LDFLAGS.libsqlite3) sqlite3-shell-link-flags.0 = -L. -lsqlite3 $(LDFLAGS.zlib) sqlite3-shell-deps.1 = $(TOP)/sqlite3.c sqlite3-shell-deps.0 = $(libsqlite3.DLL) +# +# STATIC_CLI_SHELL = 1 to statically link sqlite3$(T.exe), else +# 0. Requires static versions of all requisite libraries. Primarily +# intended for use with static-friendly environments like Alpine +# Linux. +# +STATIC_CLI_SHELL = @STATIC_CLI_SHELL@ +# +# sqlite3-shell-static.flags.N = N is $(STATIC_CLI_SHELL) +# +sqlite3-shell-static.flags.1 = -static +sqlite3-shell-static.flags.0 = sqlite3$(T.exe): $(TOP)/shell.c $(sqlite3-shell-deps.$(ENABLE_STATIC_SHELL)) $(CC) -o $@ \ $(TOP)/shell.c $(sqlite3-shell-link-flags.$(ENABLE_STATIC_SHELL)) \ + $(sqlite3-shell-static.flags.$(STATIC_CLI_SHELL)) \ -I. $(OPT_FEATURE_FLAGS) $(SHELL_OPT) \ $(CFLAGS) $(CFLAGS.readline) $(CFLAGS.icu) \ $(LDFLAGS) $(LDFLAGS.readline) @@ -280,7 +293,6 @@ dist: rm -fr $(dist_name) mkdir -p $(dist_name) cp -rp $(DIST_FILES) $(dist_name)/. - rm -f $(dist_name)/tea/configure.ac.in tar czf $(dist_tarball) $(dist_name) rm -fr $(dist_name) ls -l $(dist_tarball) diff --git a/autoconf/README.txt b/autoconf/README.txt index 1192a80fb1..ca0ed20fd4 100644 --- a/autoconf/README.txt +++ b/autoconf/README.txt @@ -90,7 +90,7 @@ Other preprocessor defines Additionally, preprocessor defines may be specified by using the OPTS macro on the NMAKE command line. However, not all possible preprocessor defines may be specified in this manner as some require the amalgamation to be built -with them enabled (see http://www.sqlite.org/compile.html). For example, the +with them enabled (see http://sqlite.org/compile.html). For example, the following will work: "OPTS=-DSQLITE_ENABLE_STAT4=1 -DSQLITE_OMIT_JSON=1" diff --git a/autoconf/auto.def b/autoconf/auto.def index 85fa7d93ed..c61d81e506 100644 --- a/autoconf/auto.def +++ b/autoconf/auto.def @@ -5,11 +5,16 @@ # "autoconf" bundle of the SQLite project. use sqlite-config sqlite-configure autoconf { + sqlite-handle-debug sqlite-check-common-bins ;# must come before [sqlite-handle-wasi-sdk] sqlite-handle-wasi-sdk ;# must run relatively early, as it changes the environment sqlite-check-common-system-deps proj-define-for-opt static-shell ENABLE_STATIC_SHELL \ "Link library statically into the CLI shell?" + proj-define-for-opt static-cli-shell STATIC_CLI_SHELL "Statically link CLI shell?" + if {![opt-bool static-shell] && [opt-bool static-cli-shell]} { + proj-fatal "--disable-static-shell and --static-cli-shell are mutualy exclusive" + } if {![opt-bool shared] && ![opt-bool static-shell]} { proj-opt-set shared 1 proj-indented-notice { diff --git a/autoconf/tea/Makefile.in b/autoconf/tea/Makefile.in index cc98ab1825..911717bc43 100644 --- a/autoconf/tea/Makefile.in +++ b/autoconf/tea/Makefile.in @@ -1,463 +1,429 @@ -# Makefile.in -- +all: # -# This file is a Makefile for Sample TEA Extension. If it has the name -# "Makefile.in" then it is a template for a Makefile; to generate the -# actual Makefile, run "./configure", which is a configuration script -# generated by the "autoconf" program (constructs like "@foo@" will get -# replaced in the actual Makefile. +# This makefile is part of the teaish framework, a tool for building +# Tcl extensions, conceptually related to TEA/tclconfig but using the +# Autosetup configuration system instead of the GNU Autotools. # -# Copyright (c) 1999 Scriptics Corporation. -# Copyright (c) 2002-2005 ActiveState Corporation. +# A copy of this makefile gets processed for each extension separately +# and populated with info about how to build, test, and install the +# extension. # -# See the file "license.terms" for information on usage and redistribution -# of this file, and for a DISCLAIMER OF ALL WARRANTIES. - -#======================================================================== -# Add additional lines to handle any additional AC_SUBST cases that -# have been added in a customized configure script. -#======================================================================== - -#SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ - -#======================================================================== -# Nothing of the variables below this line should need to be changed. -# Please check the TARGETS section below to make sure the make targets -# are correct. -#======================================================================== - -#======================================================================== -# The names of the source files is defined in the configure script. -# The object files are used for linking into the final library. -# This will be used when a dist target is added to the Makefile. -# It is not important to specify the directory, as long as it is the -# $(srcdir) or in the generic, win or unix subdirectory. -#======================================================================== - -PKG_SOURCES = @PKG_SOURCES@ -PKG_OBJECTS = @PKG_OBJECTS@ - -PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ -PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ - -#======================================================================== -# PKG_TCL_SOURCES identifies Tcl runtime files that are associated with -# this package that need to be installed, if any. -#======================================================================== - -PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ - -#======================================================================== -# This is a list of public header files to be installed, if any. -#======================================================================== - -PKG_HEADERS = @PKG_HEADERS@ - -#======================================================================== -# "PKG_LIB_FILE" refers to the library (dynamic or static as per -# configuration options) composed of the named objects. -#======================================================================== - -PKG_LIB_FILE = @PKG_LIB_FILE@ -PKG_LIB_FILE8 = @PKG_LIB_FILE8@ -PKG_LIB_FILE9 = @PKG_LIB_FILE9@ -PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ - -lib_BINARIES = $(PKG_LIB_FILE) -BINARIES = $(lib_BINARIES) - -SHELL = @SHELL@ - -srcdir = @srcdir@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ - -bindir = @bindir@ -libdir = @libdir@ -includedir = @includedir@ -datarootdir = @datarootdir@ -runstatedir = @runstatedir@ -datadir = @datadir@ -mandir = @mandir@ - -DESTDIR = - -PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) -pkgdatadir = $(datadir)/$(PKG_DIR) -pkglibdir = $(libdir)/$(PKG_DIR) -pkgincludedir = $(includedir)/$(PKG_DIR) - -top_builddir = @abs_top_builddir@ - -INSTALL_OPTIONS = -INSTALL = @INSTALL@ $(INSTALL_OPTIONS) -INSTALL_DATA_DIR = @INSTALL_DATA_DIR@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_LIBRARY = @INSTALL_LIBRARY@ - -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -CC = @CC@ -CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ -CFLAGS_WARNING = @CFLAGS_WARNING@ -EXEEXT = @EXEEXT@ -LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ -MAKE_LIB = @MAKE_LIB@ -MAKE_STUB_LIB = @MAKE_STUB_LIB@ -OBJEXT = @OBJEXT@ -RANLIB = @RANLIB@ -RANLIB_STUB = @RANLIB_STUB@ -SHLIB_CFLAGS = @SHLIB_CFLAGS@ -SHLIB_LD = @SHLIB_LD@ -SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ -STLIB_LD = @STLIB_LD@ -#TCL_DEFS = @TCL_DEFS@ -TCL_BIN_DIR = @TCL_BIN_DIR@ -TCL_SRC_DIR = @TCL_SRC_DIR@ -#TK_BIN_DIR = @TK_BIN_DIR@ -#TK_SRC_DIR = @TK_SRC_DIR@ - -# Not used, but retained for reference of what libs Tcl required -#TCL_LIBS = @TCL_LIBS@ - -#======================================================================== -# TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our -# package without installing. The other environment variables allow us -# to test against an uninstalled Tcl. Add special env vars that you -# require for testing here (like TCLX_LIBRARY). -#======================================================================== - -EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) -#EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) -TCLLIBPATH = $(top_builddir) -TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` -PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ - PATH="$(EXTRA_PATH):$(PATH)" \ - TCLLIBPATH="$(TCLLIBPATH)" - -TCLSH_PROG = @TCLSH_PROG@ -TCLSH = $(TCLSH_ENV) $(PKG_ENV) $(TCLSH_PROG) - -#WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` -#WISH_PROG = @WISH_PROG@ -#WISH = $(TCLSH_ENV) $(WISH_ENV) $(PKG_ENV) $(WISH_PROG) - -SHARED_BUILD = @SHARED_BUILD@ - -INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ -I. -I$(srcdir)/.. -#INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ - -PKG_CFLAGS = @PKG_CFLAGS@ - -# TCL_DEFS is not strictly need here, but if you remove it, then you -# must make sure that configure.ac checks for the necessary components -# that your library may use. TCL_DEFS can actually be a problem if -# you do not compile with a similar machine setup as the Tcl core was -# compiled with. -#DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) -DEFS = @DEFS@ $(PKG_CFLAGS) - -# Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile -CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl -CLEANFILES = @CLEANFILES@ - -CPPFLAGS = @CPPFLAGS@ -LIBS = @PKG_LIBS@ @LIBS@ -AR = @AR@ -CFLAGS = @CFLAGS@ -LDFLAGS = @LDFLAGS@ -LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ -COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \ - $(CFLAGS_DEFAULT) $(CFLAGS_WARNING) $(SHLIB_CFLAGS) $(CFLAGS) - -GDB = gdb -VALGRIND = valgrind -VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \ - --leak-check=yes --show-reachable=yes -v - -.SUFFIXES: .c .$(OBJEXT) - -#======================================================================== -# Start of user-definable TARGETS section -#======================================================================== - -#======================================================================== -# TEA TARGETS. Please note that the "libraries:" target refers to platform -# independent files, and the "binaries:" target includes executable programs and -# platform-dependent libraries. Modify these targets so that they install -# the various pieces of your package. The make and install rules -# for the BINARIES that you specified above have already been done. -#======================================================================== - -all: binaries libraries doc - -#======================================================================== -# The binaries target builds executable programs, Windows .dll's, unix -# shared/static libraries, and any other platform-dependent files. -# The list of targets to build for "binaries:" is specified at the top -# of the Makefile, in the "BINARIES" variable. -#======================================================================== - -binaries: $(BINARIES) - -libraries: - -#======================================================================== -# Your doc target should differentiate from doc builds (by the developer) -# and doc installs (see install-doc), which just install the docs on the -# end user machine when building from source. -#======================================================================== - -doc: - @echo "If you have documentation to create, place the commands to" - @echo "build the docs in the 'doc:' target. For example:" - @echo " xml2nroff sample.xml > sample.n" - @echo " xml2html sample.xml > sample.html" - -install: all install-binaries install-libraries install-doc - -install-binaries: binaries install-lib-binaries install-bin-binaries - -#======================================================================== -# This rule installs platform-independent files, such as header files. -# The list=...; for p in $$list handles the empty list case x-platform. -#======================================================================== - -install-libraries: libraries - @$(INSTALL_DATA_DIR) "$(DESTDIR)$(includedir)" - @echo "Installing header files in $(DESTDIR)$(includedir)" - @list='$(PKG_HEADERS)'; for i in $$list; do \ - echo "Installing $(srcdir)/$$i" ; \ - $(INSTALL_DATA) $(srcdir)/$$i "$(DESTDIR)$(includedir)" ; \ - done; - -#======================================================================== -# Install documentation. Unix manpages should go in the $(mandir) -# directory. -#======================================================================== - -install-doc: doc - @$(INSTALL_DATA_DIR) "$(DESTDIR)$(mandir)/mann" - @echo "Installing documentation in $(DESTDIR)$(mandir)" - @list='$(srcdir)/doc/*.n'; for i in $$list; do \ - echo "Installing $$i"; \ - $(INSTALL_DATA) $$i "$(DESTDIR)$(mandir)/mann" ; \ - done - -test: binaries libraries - @echo "SQLite TEA distribution does not include tests" - -shell: binaries libraries - @$(TCLSH) $(SCRIPT) - -gdb: - $(TCLSH_ENV) $(PKG_ENV) $(GDB) $(TCLSH_PROG) $(SCRIPT) - -gdb-test: binaries libraries - $(TCLSH_ENV) $(PKG_ENV) $(GDB) \ - --args $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` \ - $(TESTFLAGS) -singleproc 1 \ - -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \ - [list load `@CYGPATH@ $(PKG_LIB_FILE)` [string totitle $(PACKAGE_NAME)]]" - -valgrind: binaries libraries - $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) \ - `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) - -valgrindshell: binaries libraries - $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT) - -depend: - -#======================================================================== -# $(PKG_LIB_FILE) should be listed as part of the BINARIES variable -# mentioned above. That will ensure that this target is built when you -# run "make binaries". +# Maintenance reminder: this file needs to stay portable with POSIX +# Make, not just GNU Make. Yes, that's unfortunate because it makes +# some things impossible (like skipping over swathes of rules when +# 'make distclean' is invoked). # -# The $(PKG_OBJECTS) objects are created and linked into the final -# library. In most cases these object files will correspond to the -# source files above. -#======================================================================== -$(PKG_LIB_FILE): $(PKG_OBJECTS) - -rm -f $(PKG_LIB_FILE) - ${MAKE_LIB} - $(RANLIB) $(PKG_LIB_FILE) +CC = @CC@ +INSTALL = @BIN_INSTALL@ +INSTALL.noexec = $(INSTALL) -m 0644 -$(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) - -rm -f $(PKG_STUB_LIB_FILE) - ${MAKE_STUB_LIB} - $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) - -#======================================================================== -# We need to enumerate the list of .c to .o lines here. # -# In the following lines, $(srcdir) refers to the toplevel directory -# containing your extension. If your sources are in a subdirectory, -# you will have to modify the paths to reflect this: +# Var name prefixes: # -# sample.$(OBJEXT): $(srcdir)/generic/sample.c -# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ +# teaish. => teaish core +# tx. => teaish extension # -# Setting the VPATH variable to a list of paths will cause the makefile -# to look into these paths when resolving .c to .obj dependencies. -# As necessary, add $(srcdir):$(srcdir)/compat:.... -#======================================================================== - -VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macosx - -.c.@OBJEXT@: - $(COMPILE) -c `@CYGPATH@ $<` -o $@ - - -#======================================================================== -# Distribution creation -# You may need to tweak this target to make it work correctly. -#======================================================================== - -#COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar -COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) -DIST_ROOT = /tmp/dist -DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) - -DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644 -DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755 - -dist-clean: - rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* - -dist: dist-clean $(srcdir)/manifest.uuid - $(INSTALL_DATA_DIR) $(DIST_DIR) - - # TEA files - $(DIST_INSTALL_DATA) $(srcdir)/Makefile.in \ - $(srcdir)/aclocal.m4 $(srcdir)/configure.ac \ - $(DIST_DIR)/ - $(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/ - - $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig - $(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \ - $(srcdir)/manifest.uuid \ - $(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \ - $(DIST_DIR)/tclconfig/ - - # Extension files - $(DIST_INSTALL_DATA) \ - $(srcdir)/ChangeLog \ - $(srcdir)/README.sha \ - $(srcdir)/license.terms \ - $(srcdir)/README \ - $(srcdir)/pkgIndex.tcl.in \ - $(DIST_DIR)/ - - list='demos doc generic library macosx tests unix win'; \ - for p in $$list; do \ - if test -d $(srcdir)/$$p ; then \ - $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \ - $(DIST_INSTALL_DATA) $(srcdir)/$$p/* $(DIST_DIR)/$$p/; \ - fi; \ - done - - (cd $(DIST_ROOT); $(COMPRESS);) - -#======================================================================== -# End of user-definable section -#======================================================================== - -#======================================================================== -# Don't modify the file to clean here. Instead, set the "CLEANFILES" -# variable in configure.ac -#======================================================================== - -clean: - -test -z "$(BINARIES)" || rm -f $(BINARIES) - -rm -f *.$(OBJEXT) core *.core - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean: clean - -rm -f *.tab.c - -rm -f $(CONFIG_CLEAN_FILES) - -rm -f config.cache config.log config.status - -#======================================================================== -# Install binary object libraries. On Windows this includes both .dll and -# .lib files. Because the .lib files are not explicitly listed anywhere, -# we need to deduce their existence from the .dll file of the same name. -# Library files go into the lib directory. -# In addition, this will generate the pkgIndex.tcl -# file in the install location (assuming it can find a usable tclsh shell) +# Vars with a "tx." or "teaish." prefix are all "public" for purposes +# of the extension makefile, but the extension must not any "teaish." +# vars and must only modify "tx." vars where that allowance is +# specifically noted. # -# You should not have to modify this target. -#======================================================================== +# Vars with a "teaish__" prefix are "private" and must not be used by +# the extension makefile. They may change semantics or be removed in +# any given teaish build. +# +tx.name = @TEAISH_NAME@ +tx.pkgName = @TEAISH_PKGNAME@ +tx.version = @TEAISH_VERSION@ +tx.libdir = @TEAISH_LIBDIR_NAME@ +tx.loadPrefix = @TEAISH_LOAD_PREFIX@ +tx.tcl = @TEAISH_TCL@ +tx.makefile = @TEAISH_MAKEFILE@ +tx.makefile.in = @TEAISH_MAKEFILE_IN@ +tx.dll8.basename = @TEAISH_DLL8_BASENAME@ +tx.dll9.basename = @TEAISH_DLL9_BASENAME@ +tx.dll8 = @TEAISH_DLL8@ +tx.dll9 = @TEAISH_DLL9@ +tx.dll = $(tx.dll$(TCL_MAJOR_VERSION)) +tx.dir = @TEAISH_DIR@ -install-lib-binaries: binaries - @$(INSTALL_DATA_DIR) "$(DESTDIR)$(pkglibdir)" - @list='$(lib_BINARIES)'; for p in $$list; do \ - if test -f $$p; then \ - echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ - $(INSTALL_LIBRARY) $$p "$(DESTDIR)$(pkglibdir)/$$p"; \ - ext=`echo $$p|sed -e "s/.*\.//"`; \ - if test "x$$ext" = "xdll"; then \ - lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ - if test -f $$lib; then \ - echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ - $(INSTALL_DATA) $$lib "$(DESTDIR)$(pkglibdir)/$$lib"; \ - fi; \ - fi; \ - fi; \ - done - @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ - if test -f $(srcdir)/$$p; then \ - destp=`basename $$p`; \ - echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ - $(INSTALL_DATA) $(srcdir)/$$p "$(DESTDIR)$(pkglibdir)/$$destp"; \ - fi; \ - done - @if test "x$(SHARED_BUILD)" = "x1"; then \ - echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ - $(INSTALL_DATA) pkgIndex.tcl "$(DESTDIR)$(pkglibdir)"; \ +teaish.dir = @abs_top_srcdir@ +#teaish.dir.autosetup = @TEAISH_AUTOSETUP_DIR@ +teaish.makefile = Makefile +teaish.makefile.in = $(teaish.dir)/Makefile.in +teaish__auto.def = $(teaish.dir)/auto.def + +# +# Autotools-conventional vars. We don't actually use these in this +# makefile but some may be referenced by vars imported via +# tclConfig.sh. They are part of the public API and may be reliably +# depended on from teaish.make.in. +# +bindir = @bindir@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +includedir = @includedir@ +infodir = @infodir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ + + +# +# Vars derived (mostly) from tclConfig.sh. These may be reliably +# used from the extension makefile. +# +TCLSH = @TCLSH_CMD@ +TCL_CONFIG_SH = @TCL_CONFIG_SH@ +TCL_INCLUDE_SPEC = @TCL_INCLUDE_SPEC@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_EXEC_PREFIX = @TCL_EXEC_PREFIX@ +TCL_VERSION = @TCL_VERSION@ +TCL_MAJOR_VERSION = @TCL_MAJOR_VERSION@ +TCL_MINOR_VERSION = @TCL_MINOR_VERSION@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@ +TCL_LIBS = @TCL_LIBS@ +TCLLIBDIR = @TCLLIBDIR@ + +# +# CFLAGS.configure = CFLAGS as known at configure-time. +# +# This ordering is deliberate: flags populated via tcl's +# [teaish-cflags-add] should preceed CFLAGS and CPPFLAGS (which +# typically come from the ./configure command-line invocation). +# +CFLAGS.configure = @SH_CFLAGS@ @TEAISH_CFLAGS@ @CFLAGS@ @CPPFLAGS@ $(TCL_INCLUDE_SPEC) +#CFLAGS.configure += -DUSE_TCL_STUBS=1 + +# +# LDFLAGS.configure = LDFLAGS as known at configure-time. +# +# This ordering is deliberate: flags populated via tcl's +# [teaish-ldflags-add] should preceed LDFLAGS (which typically +# comes from the ./configure command-line invocation). +# +LDFLAGS.configure = @SH_LDFLAGS@ @TEAISH_LDFLAGS@ @LDFLAGS@ $(TCL_STUB_LIB_SPEC) + +# +# The following tx.XYZ vars may be populated/modified by teaish.tcl +# and/or teaish.make. +# + +# +# tx.src is the list of source or object files to include in the +# (single) compiler invocation. This will initially contain any +# sources passed to [teaish-src-add], but may also be appended to +# by teaish.make. +# +tx.src =@TEAISH_SRC@ + +# +# tx.CFLAGS is typically set by teaish.make, whereas TEAISH_CFLAGS +# gets set up via the configure script. +# +tx.CFLAGS = + +# +# tx.LDFLAGS is typically set by teaish.make, whereas TEAISH_LDFLAGS +# gets set up via the configure script. +# +tx.LDFLAGS = + +# +# The list of 'dist' files may be appended to from teaish.make.in. +# It can also be set up from teaish.tcl using [teaish-dist-add] +# and/or [teaish-src-add -dist ...]. +# +tx.dist.files = @TEAISH_DIST_FILES@ + +# +# May get amended with generated file names. They are cleaned up by +# the 'clean' rules. Client code which wants to clean up extra stuff +# should do so by adding their cleanup target (e.g. clean-extension) +# as a dependency to the 'clean' target, like so: +# +# clean: distclean-extension +# distclean: distclean-extension +# +teaish__cleanExtra = + +# List of deps which may trigger an auto-reconfigure. +# +teaish__autogen.deps = \ + $(tx.makefile.in) $(teaish.makefile.in) \ + $(tx.tcl) \ + @TEAISH_PKGINDEX_TCL_IN@ \ + @TEAISH_MODULE_TEST_TCL@ \ + @AUTODEPS@ + +# +# Problem: when more than one target can invoke TEAISH_AUTORECONFIG, +# we can get parallel reconfigures running. Thus, targets which +# may require reconfigure should depend on... +# +config.log: $(teaish__autogen.deps) + @TEAISH_AUTORECONFIG@ +# ^^^ We would love to skip this when running [dist]clean, but there's +# no POSIX Make-portable way to do that. GNU Make can. +.PHONY: reconfigure +reconfigure: + @TEAISH_AUTORECONFIG@ + +$(teaish.makefile): $(teaish__auto.def) $(teaish.makefile.in) \ + @AUTODEPS@ + +@TEAISH_TESTER_TCL_IN@: +@TEAISH_TESTER_TCL@: @TEAISH_TESTER_TCL_IN@ +config.log: @TEAISH_TESTER_TCL@ + +# +# The rest of this makefile exists solely to support this brief +# target: the extension shared lib. +# +$(tx.dll): $(tx.src) config.log + $(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS) \ + $(tx.src) $(LDFLAGS.configure) $(LDFLAGS) $(tx.LDFLAGS) + +all: $(tx.dll) + +tclsh: $(teaish.makefile) config.log + @{ echo "#!/bin/sh"; echo 'exec $(TCLSH) "$$@"'; } > $@ + @chmod +x $@ + @echo "Created $@" + +# +# If the extension includes teaish.test.tcl then provide a "test" +# target which which runs that script, passing it (1) the full path to +# extension's DLL (which also provides the script with a way to get +# the test directory) and (2) a script of test utility code intended for +# sourcing by the client. +# +# If the extension has no test script, add a small one which +# simply loads the DLL and success if it can. +# +# +tx.tester.args = $(tx.dll) $(tx.loadPrefix) @TEAISH_MODULE_TEST_TCL@ +.PHONY: test-pre test-core test test-post test-extension +test-extension: # this name is reserved for use by teaish.make +test-prepre: $(tx.dll) @TEAISH_TESTER_TCL@ +test-pre: test-prepre +test-core: test-pre + $(TCLSH) @TEAISH_TESTER_TCL@ $(tx.tester.args) +test-post: test-core +test: test-post + +# +# Cleanup rules... +# +#.PHONY: clean-pre clean-core clean-post clean-extension +clean-extension: # this name is reserved for use by teaish.make +clean-pre: +clean-core: clean-pre + rm -f $(tx.dll8) $(tx.dll9) tclsh $(teaish__cleanExtra) +clean-post: clean-core +clean: clean-post + +.PHONY: distclean-pre distclean-core distclean-post clean-extension +distclean-extension: # this name is reserved for use by teaish.make +distclean-pre: clean +distclean-core: distclean-pre + rm -f Makefile + rm -f config.log config.defines.txt +@if TEAISH_MAKEFILE_IN +@if TEAISH_MAKEFILE + rm -f @TEAISH_MAKEFILE@ +@endif +@endif +@if TEAISH_TESTER_TCL_IN + rm -f @TEAISH_TESTER_TCL@ +@endif +@if TEAISH_PKGINDEX_TCL_IN + rm -f @TEAISH_PKGINDEX_TCL@ +@endif +@if TEAISH_PKGINIT_TCL_IN + rm -f @TEAISH_PKGINIT_TCL@ +@endif +@if TEAISH_TEST_TCL_IN + rm -f @TEAISH_TEST_TCL@ +@endif +distclean-post: distclean-core +distclean: distclean-post + +# +# Installation rules... +# +.PHONY: install-pre install-core install-post install-test install-prepre install-extension +install-extension: # this name is reserved for use by teaish.make +install-prepre: $(tx.dll) +install-pre: install-prepre +install-core: install-pre + @if [ ! -d "$(DESTDIR)$(TCLLIBDIR)" ]; then \ + set -x; $(INSTALL) -d "$(DESTDIR)$(TCLLIBDIR)"; \ fi +# ^^^^ on some platforms, install -d fails if the target already exists. + $(INSTALL) $(tx.dll) "$(DESTDIR)$(TCLLIBDIR)" + $(INSTALL.noexec) pkgIndex.tcl "$(DESTDIR)$(TCLLIBDIR)" +@if TEAISH_PKGINIT_TCL + $(INSTALL.noexec) @TEAISH_PKGINIT_TCL@ "$(DESTDIR)$(TCLLIBDIR)" +@endif +install-test: install-core + @echo 'package require $(tx.pkgName) $(tx.version)' > $@.tcl + @echo "Post-install test of [package require $(tx.pkgName) $(tx.version)]..." + @if $(TCLSH) $@.tcl ; then \ + echo "test passed"; \ + rm -f $@.tcl; \ + else \ + echo "TEST FAILED"; \ + rm -f $@.tcl; \ + exit 1; \ + fi +install-post: install-test +install: install-post -#======================================================================== -# Install binary executables (e.g. .exe files and dependent .dll files) -# This is for files that must go in the bin directory (located next to -# wish and tclsh), like dependent .dll files on Windows. # -# You should not have to modify this target, except to define bin_BINARIES -# above if necessary. -#======================================================================== +# Uninstall rules... +# +.PHONY: uninstall uninstall-pre uninstall-core uninstall-post uninstall-extension +uninstall-extension: # this name is reserved for use by teaish.make +uninstall-pre: +uninstall-core: uninstall-pre + rm -fr "$(DESTDIR)$(TCLLIBDIR)" +uninstall-post: uninstall-core + @echo "Uninstalled Tcl extension $(tx.name) $(tx.version)" +uninstall: uninstall-post -install-bin-binaries: binaries - @$(INSTALL_DATA_DIR) "$(DESTDIR)$(bindir)" - @list='$(bin_BINARIES)'; for p in $$list; do \ - if test -f $$p; then \ - echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ - $(INSTALL_PROGRAM) $$p "$(DESTDIR)$(bindir)/$$p"; \ - fi; \ - done +Makefile: config.log $(teaish.makefile.in) +@if TEAISH_MAKEFILE_IN +config.log: @TEAISH_MAKEFILE_IN@ +@endif -.SUFFIXES: .c .$(OBJEXT) +# +# Package archive generation ("dist") rules... +# +@if TEAISH_ENABLE_DIST +@if BIN_ZIP +# Temp dir for dist.zip. Must be different than dist.tgz or else +# parallel builds may hose the dist. +teaish__dist.tmp.zip = teaish__dist_zip +# +# Make a distribution zip file... +# +dist.zip.dir = $(tx.name)-$(tx.version) +dist.zip = $(dist.zip.dir).zip +.PHONY: dist.zip dist.zip-core dist.zip-post +#dist.zip-pre: +# We apparently can't add a pre-hook here, even if dist.zip-pre is +# .PHONY, else "make dist" rebuilds the archive each time it's run. +$(dist.zip): $(tx.dist.files) + @rm -fr $(teaish__dist.tmp.zip) + @mkdir -p $(teaish__dist.tmp.zip)/$(dist.zip.dir) + @tar cf $(teaish__dist.tmp.zip)/tmp.tar $(tx.dist.files) + @tar xf $(teaish__dist.tmp.zip)/tmp.tar -C $(teaish__dist.tmp.zip)/$(dist.zip.dir) + @rm -f $(dist.zip.dir)/tmp.tar $(dist.zip) + @cd $(teaish__dist.tmp.zip) && zip -q -r ../$(dist.zip) $(dist.zip.dir) + @rm -fr $(teaish__dist.tmp.zip) + @ls -la $(dist.zip) +dist.zip-core: $(dist.zip) +dist.zip-post: dist.zip-core +dist.zip: dist.zip-post +dist: dist.zip +undist-zip: + rm -f $(dist.zip) +undist: undist-zip +@endif #BIN_ZIP -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - cd $(top_builddir) \ - && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status +@if BIN_TAR +# +# Make a distribution tarball... +# +teaish__dist.tmp.tgz = teaish__dist_tgz +dist.tgz.dir = $(tx.name)-$(tx.version) +dist.tgz = $(dist.tgz.dir).tar.gz +.PHONY: dist.tgz dist.tgz-core dist.tgz-post +# dist.tgz-pre: +# see notes in dist.zip +$(dist.tgz): $(tx.dist.files) + @rm -fr $(teaish__dist.tmp.tgz) + @mkdir -p $(teaish__dist.tmp.tgz)/$(dist.tgz.dir) + @tar cf $(teaish__dist.tmp.tgz)/tmp.tar $(tx.dist.files) + @tar xf $(teaish__dist.tmp.tgz)/tmp.tar -C $(teaish__dist.tmp.tgz)/$(dist.tgz.dir) + @rm -f $(dist.tgz.dir)/tmp.tar $(dist.tgz) + @cd $(teaish__dist.tmp.tgz) && tar czf ../$(dist.tgz) $(dist.tgz.dir) + @rm -fr $(teaish__dist.tmp.tgz) + @ls -la $(dist.tgz) +dist.tgz-core: $(dist.tgz) +dist.tgz-post: dist.tgz-core +dist.tgz: dist.tgz-post +dist: dist.tgz +undist-tgz: + rm -f $(dist.tgz) +undist: undist-tgz +@endif #BIN_TAR +@else +undist: +dist: +@if TEAISH_OUT_OF_EXT_TREE + @echo "'dist' can only be used from an extension's home dir" 1>&2; \ + echo "In this case: @TEAISH_DIR@" 1>&2; exit 1 +@endif +@endif #TEAISH_ENABLE_DIST -uninstall-binaries: - list='$(lib_BINARIES)'; for p in $$list; do \ - rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \ - done - list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ - p=`basename $$p`; \ - rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \ - done - list='$(bin_BINARIES)'; for p in $$list; do \ - rm -f "$(DESTDIR)$(bindir)/$$p"; \ - done +# +# TEAISH_MAKEFILE[_IN] defines any extension-specific state this file +# needs. +# +# It must set the following vars if they're not already accounted for +# via teaish.tcl. +# +# - tx.src = list of the extension's source files, being sure to +# prefix each with $(tx.dir) (if it's in the same dir as the +# extension) so that out-of-tree builds can find them. Optionally, +# [define] TEAISH_SRC or pass them to [teaish-src-add]. +# +# It may optionally set the following vars: +# +# - tx.CFLAGS = CFLAGS/CPPFLAGS. Optionally, [define] TEAISH_CFLAGS +# or pass them to [teaish-cflags-add]. +# +# - tx.LDFLAGS = LDFLAGS. Optionally, [define] TEAISH_LDFLAGS or +# pass them to [teaish-ldflags-add]. +# +# It may optionally hook into various targets as documented in +# /doc/extensions.md in the canonical teaish source tree. +# +# Interestingly, we don't have to pre-filter teaish.makefile.in - +# we can just import it into here. That skips its teaish-specific +# validation though. Hmm. +# +#@if TEAISH_MAKEFILE_IN +## TEAISH_MAKEFILE_IN ==> +#Makefile: @TEAISH_MAKEFILE_IN@ +#@include @TEAISH_MAKEFILE_IN@ +#@endif +#@if !TEAISH_MAKEFILE_IN +@if TEAISH_MAKEFILE +# TEAISH_MAKEFILE ==> +Makefile: @TEAISH_MAKEFILE@ +@include @TEAISH_MAKEFILE@ +@endif #TEAISH_MAKEFILE +#@endif #!TEAISH_MAKEFILE_IN -.PHONY: all binaries clean depend distclean doc install libraries test -.PHONY: gdb gdb-test valgrind valgrindshell - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: +# +# TEAISH_MAKEFILE_CODE may contain literal makefile code, which +# gets pasted verbatim here. Either [define TEAISH_MAKEFILE_CODE +# ...] or use [teaish-make-add] to incrementally build up this +# content. +# +@if TEAISH_MAKEFILE_CODE +# TEAISH_MAKEFILE_CODE ==> +Makefile: @TEAISH_TCL@ +@TEAISH_MAKEFILE_CODE@ +@endif #TEAISH_MAKEFILE_CODE diff --git a/autoconf/tea/README.txt b/autoconf/tea/README.txt index 05044173f5..28f23a88dd 100644 --- a/autoconf/tea/README.txt +++ b/autoconf/tea/README.txt @@ -1,9 +1,30 @@ -This is the SQLite extension for Tcl using the Tcl Extension -Architecture (TEA). +This is the SQLite extension for Tcl using something akin to +the Tcl Extension Architecture (TEA). To build it: ------------------------ A BETTER WAY --------------------------- + ./configure ...flags... -A better way to build the TCL extension for SQLite is to use the +e.g.: + + ./configure --with-tcl=/path/to/tcl/install/root + +or: + + ./configure --with-tclsh=/path/to/tcl/install/root + +Run ./configure --help for the full list of flags. + +The configuration process will fail if tclConfig.sh cannot be found. + +The makefile will only honor CFLAGS and CPPFLAGS passed to the +configure script, not those directly passed to the makefile. + +Then: + + make test install + +----------------------- THE PREFERRED WAY --------------------------- + +The preferred way to build the TCL extension for SQLite is to use the canonical source code tarball. For Unix: ./configure --with-tclsh=$(TCLSH) diff --git a/autoconf/tea/aclocal.m4 b/autoconf/tea/aclocal.m4 deleted file mode 100644 index 0b057391d2..0000000000 --- a/autoconf/tea/aclocal.m4 +++ /dev/null @@ -1,9 +0,0 @@ -# -# Include the TEA standard macro set -# - -builtin(include,tclconfig/tcl.m4) - -# -# Add here whatever m4 macros you want to define for your package -# diff --git a/autoconf/tea/auto.def b/autoconf/tea/auto.def new file mode 100644 index 0000000000..861257cce3 --- /dev/null +++ b/autoconf/tea/auto.def @@ -0,0 +1,7 @@ +#/do/not/tclsh +# ^^^ help out editors which guess this file's content type. +# +# Main configure script entry point for the "TEA-via-autosetup" +# framework. +use teaish/core +teaish-configure-core diff --git a/autoconf/tea/autosetup/README.txt b/autoconf/tea/autosetup/README.txt new file mode 100644 index 0000000000..e11519b042 --- /dev/null +++ b/autoconf/tea/autosetup/README.txt @@ -0,0 +1,4 @@ +The *.tcl files in this directory are part of the SQLite's "autoconf" +bundle which are specific to the TEA(-ish) build. During the tarball +generation process, they are copied into /autoconf/autosetup/teaish +(which itself is created as part of that process). diff --git a/autoconf/tea/autosetup/core.tcl b/autoconf/tea/autosetup/core.tcl new file mode 100644 index 0000000000..4c9aee4d66 --- /dev/null +++ b/autoconf/tea/autosetup/core.tcl @@ -0,0 +1,1590 @@ +######################################################################## +# 2025 April 5 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# * May you do good and not evil. +# * May you find forgiveness for yourself and forgive others. +# * May you share freely, never taking more than you give. +# +######################################################################## +# ----- @module teaish.tcl ----- +# @section TEA-ish ((TCL Extension Architecture)-ish) +# +# Functions in this file with a prefix of teaish__ are +# private/internal APIs. Those with a prefix of teaish- are +# public APIs. +# +# Teaish has a hard dependency on proj.tcl, and any public API members +# of that module are considered legal for use by teaish extensions. +# +# Project home page: https://fossil.wanderinghorse.net/r/teaish + +use proj + +define TEAISH_CORE_VERSION 0.1-beta + +# +# API-internal settings and shared state. +array set teaish__Config [proj-strip-hash-comments { + # set to 1 to enable some internal debugging output + debug-enabled 0 + # + # 0 = don't yet have extension's pkgindex + # 0x01 = teaish__find_extension found TEAISH_DIR/pkgIndex.tcl + # 0x02 = teaish__find_extension found srcdir/pkgIndex.tcl.in + # 0x04 = teaish__find_extension found TEAISH_DIR/pkgIndex.tcl (static file) + # 0x10 = teaish-pragma was called: behave as if 0x04 + # + # This might no longer be needed. + pkgindex-policy 0 + + # + # If 1+ then teaish__verbose will emit messages. + # + verbose 0 + + # + # Mapping of pkginfo -flags to their TEAISH_xxx define (if any). + # + pkginfo-f2d { + -name TEAISH_NAME + -pkgName TEAISH_PKGNAME + -libDir TEAISH_LIBDIR_NAME + -loadPrefix TEAISH_LOAD_PREFIX + -version TEAISH_VERSION + -vsatisfies TEAISH_VSATISFIES_TCL + -options {} + } + + # + # Queues for use with teaish-checks-queue and teaish-checks-run. + # + queued-checks-pre {} + queued-checks-post {} + +}] +set teaish__Config(core-dir) $::autosetup(libdir)/teaish + +# +# Runs {*}$args if $lvl is <= the current verbosity level, else it has +# no side effects. +# +proc teaish__verbose {lvl args} { + if {$lvl <= $::teaish__Config(verbose)} { + {*}$args + } +} + +# +# @teaish-argv-has flags... +# +# Returns true if any arg in $::argv matches any of the given globs, +# else returns false. +# +proc teaish-argv-has {args} { + foreach glob $args { + foreach arg $::argv { + if {[string match $glob $arg]} { + return 1 + } + } + } + return 0 +} + +if {[teaish-argv-has --teaish-verbose --t-v]} { + # Check this early so that we can use verbose-only messages in the + # pre-options-parsing steps. + set ::teaish__Config(verbose) 1 + #teaish__verbose 1 msg-result "--teaish-verbose activated" +} + +msg-quiet use system ; # Outputs "Host System" and "Build System" lines +if {"--help" ni $::argv} { + teaish__verbose 1 msg-result "TEA(ish) Version = [get-define TEAISH_CORE_VERSION]" + teaish__verbose 1 msg-result "Source dir = $::autosetup(srcdir)" + teaish__verbose 1 msg-result "Build dir = $::autosetup(builddir)" +} + +# +# @teaish-configure-core +# +# Main entry point for the TEA-ish configure process. auto.def's primary +# (ideally only) job should be to call this. +# +proc teaish-configure-core {} { + proj-tweak-default-env-dirs + + set gotExt 0; # True if an extension config is found + if {![teaish-argv-has --teaish-create-extension=* --t-c-e=*]} { + # Don't look for an extension if we're in --t-c-e mode + set gotExt [teaish__find_extension] + } + + # + # Set up the core --flags. This needs to come before teaish.tcl is + # sourced so that that file can use teaish-pkginfo-set to append + # options. + # + options-add [proj-strip-hash-comments { + with-tcl:DIR + => {Directory containing tclConfig.sh or a directory one level up from + that, from which we can derive a directory containing tclConfig.sh. + Defaults to the $TCL_HOME environment variable.} + + with-tclsh:PATH + => {Full pathname of tclsh to use. It is used for trying to find + tclConfig.sh. Warning: if its containing dir has multiple tclsh + versions, it may select the wrong tclConfig.sh! + Defaults to the $TCLSH environment variable.} + + # TEA has --with-tclinclude but it appears to only be useful for + # building an extension against an uninstalled copy of TCL's own + # source tree. Either we get that info from tclConfig.sh or we + # give up. + # + # with-tclinclude:DIR + # => {Specify the directory which contains the tcl.h. This should not + # normally be required, as that information comes from tclConfig.sh.} + + # We _generally_ want to reduce the possibility of flag collisions with + # extensions, and thus use a teaish-... prefix on most flags. However, + # --teaish-extension-dir is frequently needed, so... + # + # As of this spontaneous moment, we'll formalize using using + # --t-X-Y to abbreviate teaish flags when doing so is + # unambiguous... + ted: t-e-d: + teaish-extension-dir:DIR + => {Looks for an extension in the given directory instead of the current dir.} + + t-c-e: + teaish-create-extension:TARGET_DIRECTORY + => {Writes stub files for creating an extension. Will refuse to overwrite + existing files without --force.} + + t-f + teaish-force + => {Has a context-dependent meaning (autosetup defines --force for its own use)} + + t-d-d + teaish-dump-defines => {Dump all configure-defined vars to config.defines.txt} + + t-v + teaish-verbose=0 + => {Enable more (often extraneous) messages from the teaish core.} + + t-d + teaish-debug => {Enable teaish-specific debug output} + }]; # main options. + + if {$gotExt} { + set ttcl [get-define TEAISH_TCL] + proj-assert {[file exists $ttcl]} "Expecting to have found teaish.tcl by now" + uplevel 1 [list source $ttcl] + proj-assert {"" ne [teaish-pkginfo-get -name]} + unset ttcl + # Set up some default values if the extension did not set them. + # This must happen _after_ it's sourced. + foreach {pflag key type val} { + - TEAISH_CFLAGS -v "" + - TEAISH_DIST_FILES -v "" + - TEAISH_LDFLAGS -v "" + - TEAISH_MAKEFILE -v "" + - TEAISH_MAKEFILE_CODE -v "" + - TEAISH_MAKEFILE_IN -v "" + - TEAISH_PKGINDEX_TCL -v "" + - TEAISH_PKGINDEX_TCL_IN -v "" + - TEAISH_PKGINIT_TCL -v "" + - TEAISH_PKGINIT_TCL_IN -v "" + - TEAISH_SRC -v "" + - TEAISH_TEST_TCL -v "" + - TEAISH_TEST_TCL_IN -v "" + + -version TEAISH_VERSION -v 0.0.0 + -pkgName TEAISH_PKGNAME -e {teaish-pkginfo-get -name} + -libDir TEAISH_LIBDIR_NAME -e {join [list \ + [teaish-pkginfo-get -pkgName] \ + [teaish-pkginfo-get -version]]} + -loadPrefix TEAISH_LOAD_PREFIX -e {string totitle [get-define TEAISH_PKGNAME ""]} + -vsatisfies TEAISH_VSATISFIES_TCL -v 8.5- + } { + set isDefOnly [expr {"-" eq $pflag}] + if {!$isDefOnly && [info exists ::teaish__Config($pflag)]} { + continue; + } + set got [get-define $key ""] + if {$isDefOnly && "" ne $got} { + continue + } + switch -exact -- $type { + -v {} + -e { set val [eval $val] } + default { proj-error "Invalid type flag: $type" } + } + #puts "***** defining default $pflag $key {$val} isDefOnly=$isDefOnly got=$got" + define $key $val + if {!$isDefOnly} { + set ::teaish__Config($pflag) $val + } + } + unset key type val + }; # sourcing extension's teaish.tcl + + if {[llength [info proc teaish-options]] > 0} { + # Add options defined by teaish-options, which is assumed to be + # imported via TEAISH_TCL. + set o [teaish-options] + if {"" ne $o} { + options-add $o + } + } + #set opts [proj-options-combine] + #lappend opts teaish-debug => {x}; #testing dupe entry handling + if {[catch {options {}} msg xopts]} { + # Workaround for + # where [options] behaves oddly on _some_ TCL builds when it's + # called from deeper than the global scope. + dict incr xopts -level + return {*}$xopts $msg + } + + proj-xfer-options-aliases { + t-c-e => teaish-create-extension + t-d => teaish-debug + t-d-d => teaish-dump-defines + ted => teaish-extension-dir + t-e-d => teaish-extension-dir + t-f => teaish-force + t-v => teaish-verbose + } + + set ::teaish__Config(verbose) [opt-bool teaish-verbose] + set ::teaish__Config(debug-enabled) [opt-bool teaish-debug] + + if {[proj-opt-was-provided teaish-create-extension]} { + teaish__create_extension [opt-val teaish-create-extension] + return + } + proj-assert {1==$gotExt} "Else we cannot have gotten this far" + + teaish__configure-phase1 +} + + +# +# Internal config-time debugging output routine. It is not legal to +# call this from the global scope. +# +proc teaish-debug {msg} { + if {$::teaish__Config(debug-enabled)} { + puts stderr [proj-bold "** DEBUG: \[[proj-current-scope 1]\]: $msg"] + } +} + +# +# Runs "phase 1" of the configuration, immediately after processing +# --flags. This is what will import the client-defined teaish.tcl. +# +proc teaish__configure-phase1 {} { + msg-result \ + [join [list "Configuring build of Tcl extension" \ + [proj-bold [teaish-pkginfo-get -name] \ + [teaish-pkginfo-get -version]] "..."]] + + uplevel 1 { + use cc cc-db cc-shared cc-lib; # pkg-config + } + teaish__check_tcl + apply {{} { + # + # If --prefix or --exec-prefix are _not_ provided, use their + # TCL_... counterpart from tclConfig.sh. Caveat: by the time we can + # reach this point, autosetup's system.tcl will have already done + # some non-trivial amount of work with these to create various + # derived values from them, so we temporarily end up with a mishmash + # of autotools-compatibility var values. That will be straightened + # out in the final stage of the configure script via + # [proj-remap-autoconf-dir-vars]. + # + foreach {flag uflag tclVar} { + prefix prefix TCL_PREFIX + exec-prefix exec_prefix TCL_EXEC_PREFIX + } { + if {![proj-opt-was-provided $flag]} { + if {"exec-prefix" eq $flag} { + # If --exec-prefix was not used, ensure that --exec-prefix + # derives from the --prefix we may have just redefined. + set v {${prefix}} + } else { + set v [get-define $tclVar "???"] + teaish__verbose 1 msg-result "Using \$$tclVar for --$flag=$v" + } + proj-assert {"???" ne $v} "Expecting teaish__check_tcl to have defined $tclVar" + #puts "*** $flag $uflag $tclVar = $v" + proj-opt-set $flag $v + define $uflag $v + + # ^^^ As of here, all autotools-compatibility vars which derive + # from --$flag, e.g. --libdir, still derive from the default + # --$flag value which was active when system.tcl was + # included. So long as those flags are not explicitly passed to + # the configure script, those will be straightened out via + # [proj-remap-autoconf-dir-vars]. + } + } + }}; # --[exec-]prefix defaults + teaish__check_common_bins + + # + # Set up library file names + # + proj-file-extensions + apply {{} { + set name [teaish-pkginfo-get -name]; # _not_ -pkgName + set pkgver [teaish-pkginfo-get -version] + set libname "lib" + if {[string match *-cygwin [get-define host]]} { + set libname cyg + } + define TEAISH_DLL8_BASENAME $libname$name$pkgver + define TEAISH_DLL9_BASENAME ${libname}tcl9$name$pkgver + set ext [get-define TARGET_DLLEXT] + define TEAISH_DLL8 [get-define TEAISH_DLL8_BASENAME]$ext + define TEAISH_DLL9 [get-define TEAISH_DLL9_BASENAME]$ext + }} + + teaish-checks-run -pre + if {[llength [info proc teaish-configure]] > 0} { + # teaish-configure is assumed to be imported via + # TEAISH_TCL + teaish-configure + } + teaish-checks-run -post + + if {0} { + # Reminder: we cannot do a TEAISH_VSATISFIES_TCL check like the following + # from here because _this_ tcl instance is very possibly not the one + # which will be hosting the extension. + if {$::autosetup(istcl)} { + # ^^^ this is a canonical Tcl, not JimTcl + set vsat [get-define TEAISH_VSATISFIES_TCL ""] + if {$vsat ne "" + && ![package vsatisfies [package provide Tcl] $vsat]} { + error [join [list "Tcl package vsatisfies failed for" \ + [teaish-pkginfo-get -name] \ + [teaish-pkginfo-get -version] \ + ": expecting vsatisfies to match ($vsat)"]] + } + unset vsat + } + } + + + if {[proj-looks-like-windows]} { + # Without this, linking of an extension will not work on Cygwin or + # Msys2. + msg-result "Using USE_TCL_STUBS for Unix(ish)-on-Windows environment" + teaish-cflags-add -DUSE_TCL_STUBS=1 + } + + #define AS_LIBDIR $::autosetup(libdir) + define TEAISH_MODULE_TEST_TCL $::teaish__Config(core-dir)/tester.tcl + + apply {{} { + # + # Ensure we have a pkgIndex.tcl and don't have a stale generated one + # when rebuilding for different --with-tcl=... values. + # + if {!$::teaish__Config(pkgindex-policy)} { + proj-error "Cannot determine which pkgIndex.tcl to use" + } + set tpi [proj-coalesce \ + [get-define TEAISH_PKGINDEX_TCL_IN] \ + [get-define TEAISH_PKGINDEX_TCL]] + proj-assert {$tpi ne ""} \ + "TEAISH_PKGINDEX_TCL should have been set up by now" + teaish__verbose 1 msg-result "Using pkgIndex from $tpi" + }}; # $::teaish__Config(pkgindex-policy) + + set dEx $::teaish__Config(teaish-dir) + set dSrc $::autosetup(srcdir) + + proj-dot-ins-append $dSrc/Makefile.in + proj-dot-ins-append $dSrc/teaish.tester.tcl.in + + define TEAISH_ENABLE_DIST [expr {![get-define TEAISH_OUT_OF_EXT_TREE]}] + define TEAISH_AUTOSETUP_DIR $::teaish__Config(core-dir) + proj-setup-autoreconfig TEAISH_AUTORECONFIG + foreach f { + TEAISH_CFLAGS + TEAISH_LDFLAGS + TEAISH_SRC + TEAISH_DIST_FILES + } { + define $f [join [get-define $f]] + } + proj-remap-autoconf-dir-vars + define TEAISH__DEFINES_MAP \ + [teaish__dump_defs_to_list]; # injected into teaish.tester.tcl + proj-dot-ins-process -validate; # do not [define] after this point + proj-if-opt-truthy teaish-dump-defines { + make-config-header config.defines.txt \ + -none {TEAISH__* TEAISH_MAKEFILE_CODE} \ + -str { + BIN_* CC LD AR INSTALL LDFLAG* CFLAGS* *_LDFLAGS *_CFLAGS + } \ + -bare {HAVE_*} \ + -auto {*} + } + + # + # If these are set up before call [options], it triggers an + # "option already defined" error. + # + #proj-opt-set teaish.tcl [get-define ] + #proj-opt-set teaish.make.in [get-define ] + + # + # $::autosetup(builddir)/.configured is a workaround to prevent + # concurrent executions of TEAISH_AUTORECONFIG. MUST come last in + # the configure process. + # + #proj-file-write $::autosetup(builddir)/.configured "" +} + +# +# Run checks for required binaries. +# +proc teaish__check_common_bins {} { + if {"" eq [proj-bin-define install]} { + proj-warn "Cannot find install binary, so 'make install' will not work." + define BIN_INSTALL false + } + if {"" eq [proj-bin-define zip]} { + proj-warn "Cannot find zip, so 'make dist.zip' will not work." + } + if {"" eq [proj-bin-define tar]} { + proj-warn "Cannot find tar, so 'make dist.tgz' will not work." + } +} + +# +# TCL... +# +# teaish__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: +# +# - TCLSH_CMD is the path to the canonical tclsh or "". +# +# - TCL_CONFIG_SH is the path to tclConfig.sh or "". +# +# - TCLLIBDIR is the dir to which the extension library gets +# - installed. +# +proc teaish__check_tcl {} { + define TCLSH_CMD false ; # Significant is that it exits with non-0 + define TCLLIBDIR "" ; # Installation dir for TCL extension lib + define TCL_CONFIG_SH ""; # full path to tclConfig.sh + + # Clear out all vars which would harvest from tclConfig.sh so that + # the late-config validation of @VARS@ works even if --disable-tcl + # is used. + proj-tclConfig-sh-to-autosetup "" + + # TODO: better document the steps this is taking. + set srcdir $::autosetup(srcdir) + msg-result "Checking for a suitable tcl... " + set use_tcl 1 + set with_tclsh [opt-val with-tclsh [proj-get-env TCLSH]] + set with_tcl [opt-val with-tcl [proj-get-env TCL_HOME]] + if {0} { + # This misinteracts with the $TCL_PREFIX default: it will use the + # autosetup-defined --prefix default + if {"prefix" eq $with_tcl} { + set with_tcl [get-define prefix] + } + } + teaish-debug "use_tcl ${use_tcl}" + teaish-debug "with_tclsh=${with_tclsh}" + teaish-debug "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.1 tclsh9.0 tclsh8.6 tclsh] + teaish-debug "with_tclsh=${with_tclsh}" + } + + set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases + if {"" ne $with_tclsh} { + # --with-tclsh was provided or found above. Validate it and use it + # to trump any value passed via --with-tcl=DIR. + if {![file-isexec $with_tclsh]} { + proj-error "TCL shell $with_tclsh is not executable" + } else { + define TCLSH_CMD $with_tclsh + #msg-result "Using tclsh: $with_tclsh" + } + if {$doConfigLookup && + [catch {exec $with_tclsh $::autosetup(libdir)/find_tclconfig.tcl} result] == 0} { + set with_tcl $result + } + if {"" ne $with_tcl && [file isdirectory $with_tcl]} { + teaish__verbose 1 msg-result "$with_tclsh recommends the tclConfig.sh from $with_tcl" + } else { + proj-warn "$with_tclsh is unable to recommend a tclConfig.sh" + set use_tcl 0 + } + } + set cfg "" + set tclSubdirs {tcl9.1 tcl9.0 tcl8.6 lib} + while {$use_tcl} { + if {"" ne $with_tcl} { + # Ensure that we can find tclConfig.sh under ${with_tcl}/... + if {$doConfigLookup} { + 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-error "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 via 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]} { + break + } + } + teaish__verbose 1 msg-result "Using tclConfig.sh = $cfg" + break + } + define TCL_CONFIG_SH $cfg + # Export a subset of tclConfig.sh to the current TCL-space. If $cfg + # is an empty string, this emits empty-string entries for the + # various options we're interested in. + proj-tclConfig-sh-to-autosetup $cfg + + if {"" eq $with_tclsh && $cfg ne ""} { + # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh + # based on info from tclConfig.sh. + set tclExecPrefix [get-define TCL_EXEC_PREFIX] + proj-assert {"" ne $tclExecPrefix} + set tryThese [list \ + $tclExecPrefix/bin/tclsh[get-define TCL_VERSION] \ + $tclExecPrefix/bin/tclsh ] + foreach trySh $tryThese { + if {[file-isexec $trySh]} { + set with_tclsh $trySh + break + } + } + if {![file-isexec $with_tclsh]} { + proj-warn "Cannot find a usable tclsh (tried: $tryThese)" + } + } + define TCLSH_CMD $with_tclsh + if {$use_tcl} { + # Set up the TCLLIBDIR + set tcllibdir [get-env TCLLIBDIR ""] + set extDirName [get-define TEAISH_LIBDIR_NAME] + if {"" eq $tcllibdir} { + # Attempt to extract TCLLIBDIR from TCL's $auto_path + if {"" ne $with_tclsh && + [catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} { + foreach i $result { + if {[file isdirectory $i]} { + set tcllibdir $i/$extDirName + break + } + } + } else { + proj-error "Cannot determine TCLLIBDIR." + } + } + define TCLLIBDIR $tcllibdir + }; # find TCLLIBDIR + + if {[file-isexec $with_tclsh]} { + teaish__verbose 1 msg-result "Using tclsh = $with_tclsh" + if {$cfg ne ""} { + define HAVE_TCL 1 + } else { + proj-warn "Found tclsh but no tclConfig.sh." + } + } + show-notices + # If TCL is not found: if it was explicitly requested then fail + # fatally, else just emit a warning. If we can find the APIs needed + # to generate a working JimTCL then that will suffice for build-time + # TCL purposes (see: proc sqlite-determine-codegen-tcl). + if {![file-isexec $with_tclsh]} { + proj-error "Did not find tclsh" + } elseif {"" eq $cfg} { + proj-indented-notice -error { + Cannot find a usable tclConfig.sh file. Use + --with-tcl=DIR to specify a directory where tclConfig.sh can be + found, or --with-tclsh=/path/to/tclsh to allow the tclsh binary + to locate its tclConfig.sh. + } + } + msg-result "Using Tcl [get-define TCL_VERSION]." +}; # teaish__check_tcl + +# +# Searches $::argv and/or the build dir and/or the source dir for +# teaish.tcl and friends. Fails if it cannot find teaish.tcl or if +# there are other irreconcilable problems. If it returns 0 then it did +# not find an extension but the --help flag was seen, in which case +# that's not an error. +# +# This does not _load_ the extension, it simply locates the files +# which make up an extension. +# +# This sets up lots of defines, e.g. TEAISH_DIR. +# +proc teaish__find_extension {} { + + teaish__verbose 1 msg-result "Looking for teaish extension..." + # Helper for the foreach loop below. + set lambdaMT {{mustHave fid dir} { + if {[file isdirectory $dir]} { + set f [file join $dir $fid] + if {[file readable $f]} { + return [file-normalize $f] + } elseif {$mustHave} { + proj-error "Missing required $dir/$fid" + } + } elseif {$mustHave} { + proj-error "--teaish-extension-dir=$dir does not reference a directory" + } + return "" + }} + # + # We have to handle some flags manually because the extension must + # be loaded before [options] is run (so that the extension can + # inject its own options). + # + #set extM ""; # teaish.make.in + set dirBld $::autosetup(builddir); # dir we're configuring under + set dirSrc $::autosetup(srcdir); # where teaish's configure script lives + set extT ""; # teaish.tcl + set largv {}; # rewritten $::argv + set gotHelpArg 0; # got the --help + foreach arg $::argv { + #puts "*** arg=$arg" + switch -glob -- $arg { + --ted=* - + --t-e-d=* - + --teaish-extension-dir=* { + # Ensure that $extD refers to a directory and contains a + # teaish.tcl. + regexp -- {--[^=]+=(.+)} $arg - extD + set extD [file-normalize $extD] + if {![file isdirectory $extD]} { + proj-error "--teaish-extension-dir value is not a directory: $extD" + } + set extT [apply $lambdaMT 1 teaish.tcl $extD] + define TEAISH_DIR $extD + set ::teaish__Config(teaish-dir) $extD + } + --help { + incr gotHelpArg + } + default { + lappend largv $arg + } + } + } + set ::argv $largv + + set dirExt [proj-coalesce \ + [get-define TEAISH_DIR ""] \ + $dirBld]; # dir with the extension + # + # teaish.tcl is a TCL script which implements various + # interfaces described by this framework. + # + # We use the first one we find in the builddir or srcdir. + # + if {"" eq $extT} { + set flist [list $dirExt/teaish.tcl] + if {$dirExt ne $dirSrc} { + lappend flist $dirSrc/teaish.tcl + } + if {![proj-first-file-found $flist extT]} { + if {$gotHelpArg} { + # Tell teaish-configure-core that the lack of extension is not + # an error when --help is used. + return 0; + } + proj-indented-notice -error " +Did not find any of: $flist + +If you are attempting an out-of-tree build, use + --teaish-extension-dir=/path/to/extension" + } + } + if {![file readable $extT]} { + proj-error "extension tcl file is not readable: $extT" + } + define TEAISH_TCL $extT + + if {"" eq $dirExt} { + # If this wasn't set via --teaish-extension-dir then derive it from + # $extT. + #puts "extT=$extT dirExt=$dirExt" + set dirExt [file dirname $extT] + } + define TEAISH_DIR $dirExt + set ::teaish__Config(teaish-dir) $dirExt + set ::teaish__Config(blddir-is-extdir) \ + [define TEAISH_ENABLE_DIST [expr {$dirBld eq $dirExt}]] + set addDist {{file} { + teaish-dist-add [file tail $file] + }} + apply $addDist $extT + + teaish__verbose 1 msg-result "Extension dir = [get-define TEAISH_DIR]" + teaish__verbose 1 msg-result "Extension config = $extT" + + teaish-pkginfo-set -name [file tail [file dirname $extT]] + + # + # teaish.make[.in] provides some of the info for the main makefile, + # like which source(s) to build and their build flags. + # + # We use the first one of teaish.make.in or teaish.make we find in + # $dirExt. + # + if {[proj-first-file-found \ + [list $dirExt/teaish.make.in $dirExt/teaish.make] \ + extM]} { + if {[string match *.in $extM]} { + define TEAISH_MAKEFILE_IN $extM + define TEAISH_MAKEFILE [file rootname [file tail $extM]] + proj-dot-ins-append $extM [get-define TEAISH_MAKEFILE] + } else { + define TEAISH_MAKEFILE_IN "" + define TEAISH_MAKEFILE $extM + } + apply $addDist $extM + teaish__verbose 1 msg-result "Extension makefile = $extM" + } else { + define TEAISH_MAKEFILE_IN "" + define TEAISH_MAKEFILE "" + } + + # Look for teaish.pkginit.tcl[.in] + if {[proj-first-file-found \ + [list $dirExt/teaish.pkginit.tcl.in $dirExt/teaish.pkginit.tcl] \ + extI]} { + if {[string match *.in $extI]} { + proj-dot-ins-append $extI + define TEAISH_PKGINIT_TCL_IN $extI + define TEAISH_PKGINIT_TCL [file tail [file rootname $extI]] + } else { + define TEAISH_PKGINIT_TCL_IN "" + define TEAISH_PKGINIT_TCL $extI + } + apply $addDist $extI + teaish__verbose 1 msg-result "Extension post-load init = $extI" + define TEAISH_PKGINIT_TCL_TAIL \ + [file tail [get-define TEAISH_PKGINIT_TCL]]; # for use in pkgIndex.tcl.in + } + + # Look for pkgIndex.tcl[.in]... + set piPolicy 0 + if {[proj-first-file-found $dirExt/pkgIndex.tcl.in extPI]} { + # Generate ./pkgIndex.tcl from it. + define TEAISH_PKGINDEX_TCL_IN $extPI + define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]] + proj-dot-ins-append $extPI + file delete -force -- [get-define TEAISH_PKGINDEX_TCL] + apply $addDist $extPI + set piPolicy 0x01 + } elseif {$dirExt ne $dirSrc + && [proj-first-file-found $dirSrc/pkgIndex.tcl.in extPI]} { + # Generate ./pkgIndex.tcl from it. + define TEAISH_PKGINDEX_TCL_IN $extPI + define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]] + proj-dot-ins-append $extPI + file delete -force -- [get-define TEAISH_PKGINDEX_TCL] + set piPolicy 0x02 + } elseif {[proj-first-file-found $dirExt/pkgIndex.tcl extPI]} { + # Assume it's a static file and use it. + define TEAISH_PKGINDEX_TCL_IN "" + define TEAISH_PKGINDEX_TCL $extPI + apply $addDist $extPI + set piPolicy 0x04 + } + + set ::teaish__Config(pkgindex-policy) $piPolicy + + # Look for teaish.test.tcl[.in] + proj-assert {"" ne $dirExt} + set flist [list $dirExt/teaish.test.tcl.in $dirExt/teaish.test.tcl] + if {[proj-first-file-found $flist ttt]} { + if {[string match *.in $ttt]} { + # Generate teaish.test.tcl from $ttt + set xt [file rootname [file tail $ttt]] + file delete -force -- $xt; # ensure no stale copy is used + define TEAISH_TEST_TCL $xt + define TEAISH_TEST_TCL_IN $ttt + proj-dot-ins-append $ttt $xt + } else { + define TEAISH_TEST_TCL $ttt + define TEAISH_TEST_TCL_IN "" + } + apply $addDist $ttt + } else { + define TEAISH_TEST_TCL "" + define TEAISH_TEST_TCL_IN "" + } + + # Look for teaish.tester.tcl[.in] + set flist [list $dirExt/teaish.tester.tcl.in $dirSrc/teaish.tester.tcl.in] + if {[proj-first-file-found $flist ttt]} { + # Generate teaish.test.tcl from $ttt + set xt [file rootname [file tail $ttt]] + file delete -force -- $xt; # ensure no stale copy is used + define TEAISH_TESTER_TCL $xt + define TEAISH_TESTER_TCL_IN $ttt + proj-dot-ins-append $ttt $xt + if {[lindex $flist 0] eq $ttt} { + apply $addDist $ttt + } + } else { + set ttt [file join $dirSrc teaish.tester.tcl.in] + set xt [file rootname [file tail $ttt]] + proj-dot-ins-append $ttt $xt + define TEAISH_TESTER_TCL $xt + define TEAISH_TESTER_TCL_IN $ttt + } + unset flist xt ttt + + # TEAISH_OUT_OF_EXT_TREE = 1 if we're building from a dir other + # than the extension's home dir. + set dteaish [file-normalize [get-define TEAISH_DIR]] + define TEAISH_OUT_OF_EXT_TREE \ + [expr {[file-normalize $::autosetup(builddir)] ne $dteaish}] + + return 1 +}; # teaish__find_extension + +# +# @teaish-cflags-add ?-p|prepend? ?-define? cflags... +# +# Equivalent to [proj-define-amend TEAISH_CFLAGS {*}$args]. +# +proc teaish-cflags-add {args} { + proj-define-amend TEAISH_CFLAGS {*}$args +} + +# +# @teaish-define-to-cflag defineName... +# +# Uses [proj-define-to-cflag] to expand a list of [define] keys, each +# one a separate argument, to CFLAGS-style -D... form then appends +# that to the current TEAISH_CFLAGS. +# +proc teaish-define-to-cflag {args} { + teaish-cflags-add [proj-define-to-cflag {*}$args] +} + +# +# @teaish-ldflags-add ?-p|-prepend? ?-define? ldflags... +# +# Equivalent to [proj-define-amend TEAISH_LDFLAGS {*}$args]. +# +# Typically, -lXYZ flags need to be in "reverse" order, with each -lY +# resolving symbols for -lX's to its left. This order is largely +# historical, and not relevant on all environments, but it is +# technically correct and still relevant on some environments. +# +# See: teaish-ldflags-prepend +# +proc teaish-ldflags-add {args} { + proj-define-amend TEAISH_LDFLAGS {*}$args +} + +# +# @teaish-ldflags-prepend args... +# +# Functionally equivalent to [teaish-ldflags-add -p {*}$args] +# +proc teaish-ldflags-prepend {args} { + teaish-ldflags-add -p {*}$args +} + +# +# @teaish-src-add ?-dist? ?-dir? src-files... +# +# Appends all non-empty $args to TEAISH_SRC. +# +# If passed -dist then it also passes each filename, as-is, to +# [teaish-dist-add]. +# +# If passed -dir then each src-file has the TEAISH_DIR prepended to +# it for before they're added to TEAISH_SRC. As often as not, that +# will be the desired behavior so that out-of-tree builds can find the +# sources, but there are cases where it's not desired (e.g. when using +# a source file from outside of the extension's dir). +# +proc teaish-src-add {args} { + set i 0 + proj-parse-simple-flags args flags { + -dist 0 {return 1} + -dir 0 {return 1} + } + if {$flags(-dist)} { + teaish-dist-add {*}$args + } + if {$flags(-dir)} { + set xargs {} + set d [get-define TEAISH_DIR] + foreach arg $args { + if {"" ne $arg} { + lappend xargs [file join $d $arg] + } + } + set args $xargs + } + proj-define-append TEAISH_SRC {*}$args +} + +# +# @teaish-dist-add files-or-dirs... +# +# Equivalent to [proj-define-apend TEAISH_DIST_FILES ...]. +# +# This is a no-op when the current build is not in the extension's +# directory, as dist support is disabled in out-of-tree builds. +# +# It is not legal to call this until TEAISH_DIR has been reliably set +# (via teaish__find_extension). +# +proc teaish-dist-add {args} { + if {$::teaish__Config(blddir-is-extdir)} { + proj-define-amend TEAISH_DIST_FILES {*}$args + } +} + +# teaish-install-add files... +# Equivalent to [proj-define-apend TEAISH_INSTALL_FILES ...]. +#proc teaish-install-add {args} { +# proj-define-amend TEAISH_INSTALL_FILES {*}$args +#} + +# +# @teash-append-make args... +# +# Appends makefile code to the TEAISH_MAKEFILE_CODE define. Each +# arg may be any of: +# +# -tab: emit a literal tab +# -nl: emit a literal newline +# -nltab: short for -nl -tab +# -eol: emit a backslash-escaped end-of-line +# -eoltab: short for -eol -tab +# +# Anything else is appended verbatim. This function adds no additional +# spacing between each argument nor between subsequent invocations. +# +proc teaish-make-add {args} { + set out [get-define TEAISH_MAKEFILE_CODE ""] + foreach a $args { + switch -exact -- $a { + -eol { set a " \\\n" } + -eoltab { set a " \\\n\t" } + -tab { set a "\t" } + -nl { set a "\n" } + -nltab { set a "\n\t" } + } + append out $a + } + define TEAISH_MAKEFILE_CODE $out +} + +# +# @teaish-make-config-header filename +# +# Invokes autosetup's [make-config-header] and passes it $filename and +# a relatively generic list of options for controlling which defined +# symbols get exported. Clients which need more control over the +# exports can copy/paste/customize this. +# +# The exported file is then passed to [proj-touch] because, in +# practice, that's sometimes necessary to avoid build dependency +# issues. +# +proc teaish-make-config-header {filename} { + make-config-header $filename \ + -bare {} \ + -none {HAVE_CFLAG_* LDFLAGS_* SH_*} \ + -auto {SIZEOF_* HAVE_* TEAISH_* TCL_*} \ + -none * + proj-touch $filename; # help avoid frequent unnecessary auto-reconfig +} + +# +# @teaish-feature-cache-set ?$key? value +# +# Sets a feature-check cache entry with the given key. +# See proj-cache-set for the key's semantics. +# +proc teaish-feature-cache-set {{key 0} val} { + proj-cache-set $key 1 $val +} + +# +# @teaish-feature-cache-check ?$key? tgtVarName +# +# Checks for a feature-check cache entry with the given key. +# See proj-cache-set for the key's semantics. +# +# If the feature-check cache has a matching entry then this function +# assigns its value to tgtVar and returns 1, else it assigns tgtVar to +# "" and returns 0. +# +# See proj-cache-check for $key's semantics. +# +proc teaish-feature-cache-check {{key 0} tgtVar} { + upvar $tgtVar tgt + proj-cache-check $key 1 tgt +} + +# +# @teaish-check-cached@ ?-nostatus? msg script +# +# A proxy for feature-test impls which handles caching of a feature +# flag check on per-function basis, using the calling scope's name as +# the cache key. +# +# It emits [msg-checking $msg]. If $msg is empty then it defaults to +# the name of the caller's scope. At the end, it will [msg-result "ok"] +# [msg-result "no"] unless -nostatus is used, in which case the caller +# is responsible for emitting at least a newline when it's done. +# +# This function checks for a cache hit before running $script and +# caching the result. If no hit is found then $script is run in the +# calling scope and its result value is stored in the cache. This +# routine will intercept a 'return' from $script. +# +# Flags: +# +# -nostatus = do not emit "ok" or "no" at the end. This presumes +# that the caller will emit at least one newline before turning. +# +proc teaish-check-cached {args} { + proj-parse-simple-flags args flags { + -nostatus 0 {expr 1} + } + lassign $args msg script + if {"" eq $msg} { + set msg [proj-current-scope 1] + } + msg-checking "${msg} ... " + if {[teaish-feature-cache-check 1 check]} { + msg-checking "(cached) " + if {$check} {msg-result "ok"} else {msg-result "no"} + return $check + } else { + set code [catch {uplevel 1 $script} rc xopt] + #puts "***** cached-check got code=$code rc=$rc" + if {$code in {0 2}} { + teaish-feature-cache-set 1 $rc + if {!$flags(-nostatus)} { + if {$rc} { + msg-result "ok" + } else { + msg-result "no" + } + } + } else { + #puts "**** code=$code rc=$rc xopt=$xopt" + teaish-feature-cache-set 1 0 + } + #puts "**** code=$code rc=$rc" + return {*}$xopt $rc + } +} + +# +# Internal helper for teaish__defs_format_: returns a JSON-ish quoted +# form of the given string-type values. +# +# If $asList is true then the return value is in {$value} form. If +# $asList is false it only performs the most basic of escaping and +# the input must not contain any control characters. +# +proc teaish__quote_str {asList value} { + if {$asList} { + return [join [list "\{" $value "\}"] ""] + } + return \"[string map [list \\ \\\\ \" \\\"] $value]\" +} + +# +# Internal helper for teaish__dump_defs_to_list. Expects to be passed +# a name and the variadic $args which are passed to +# teaish__dump_defs_to_list.. If it finds a pattern match for the +# given $name in the various $args, it returns the type flag for that +# $name, e.g. "-str" or "-bare", else returns an empty string. +# +proc teaish__defs_type {name spec} { + foreach {type patterns} $spec { + foreach pattern $patterns { + if {[string match $pattern $name]} { + return $type + } + } + } + return "" +} + +# +# An internal impl detail. Requires a data type specifier, as used by +# make-config-header, and a value. Returns the formatted value or the +# value $::teaish__Config(defs-skip) if the caller should skip +# emitting that value. +# +# In addition to -str, -auto, etc., as defined by make-config-header, +# it supports: +# +# -list {...} will cause non-integer values to be quoted in {...} +# instead of quotes. +# +# -autolist {...} works like -auto {...} except that it falls back to +# -list {...} type instead of -str {...} style for non-integers. +# +# -array {...} emits the output in something which, for conservative +# inputs, will be a valid JSON array. It can only handle relatively +# simple values with no control characters in them. +# +set teaish__Config(defs-skip) "-teaish__defs_format sentinel" +proc teaish__defs_format {type value} { + switch -exact -- $type { + -bare { + # Just output the value unchanged + } + -none { + set value $::teaish__Config(defs-skip) + } + -str { + set value [teaish__quote_str 0 $value] + } + -auto { + # Automatically determine the type + if {![string is integer -strict $value]} { + set value [teaish__quote_str 0 $value] + } + } + -autolist { + if {![string is integer -strict $value]} { + set value [teaish__quote_str 1 $value] + } + } + -list { + set value [teaish__quote_str 1 $value] + } + -array { + set ar {} + foreach v $value { + set v [teaish__defs_format -auto $v] + if {$::teaish__Config(defs-skip) ne $v} { + lappend ar $v + } + } + set value "\[ [join $ar {, }] \]" + } + "" { + set value $::teaish__Config(defs-skip) + } + default { + proj-error \ + "Unknown [project-current-scope] -type ($type) called from" \ + [proj-current-scope 1] + } + } + return $value +} + +# +# Returns Tcl code in the form of code which evaluates to a list of +# configure-time DEFINEs in the form {key val key2 val...}. It may +# misbehave for values which are not numeric or simple strings. +# +proc teaish__dump_defs_to_list {args} { + set lines {} + lappend lines "\{" + set skipper $::teaish__Config(defs-skip) + lappend args \ + -none { + TEAISH__* + TEAISH_MAKEFILE_CODE + AM_* AS_* + } \ + -auto { + SIZEOF_* HAVE_* + } \ + -autolist * + foreach n [lsort [dict keys [all-defines]]] { + set type [teaish__defs_type $n $args] + set value [teaish__defs_format $type [get-define $n]] + if {$skipper ne $value} { + lappend lines "$n $value" + } + } + lappend lines "\}" + return [join $lines "\n"] +} + +# +# @teaish-pragma ...flags +# +# Offers a way to tweak how teaish's core behaves in some cases, in +# particular those which require changing how the core looks for an +# extension and its files. +# +# Accepts the following flags. Those marked with [L] are safe to use +# during initial loading of tclish.tcl (recall that most teaish APIs +# cannot be used until [teaish-configure] is called). +# +# --have-own-pkgIndex.tcl [L]: Tells teaish that ./pkgIndex.tcl is +# not a generated file, so it will not try to overwrite or delete +# it. +# +# Emits a warning message for unknown arguments. +# +proc teaish-pragma {args} { + foreach arg $args { + switch -exact -- $arg { + + --have-own-pkgIndex.tcl { + set flist [list \ + [file join $::teaish__Config(teaish-dir) pkgIndex.tcl.in] \ + [file join $::teaish__Config(teaish-dir) pkgIndex.tcl]] + if {[proj-first-file-found $flist tpi]} { + if {[string match *.in $tpi]} { + define TEAISH_PKGINDEX_TCL_IN $tpi + teaish-dist-add [file tail $tpi] + define TEAISH_PKGINDEX_TCL [file rootname [file tail $pi]] + } else { + define TEAISH_PKGINDEX_TCL_IN "" + define TEAISH_PKGINDEX_TCL $tpi + teaish-dist-add [file tail $tpi] + } + } else { + proj-error "teaish-pragma $arg found no package-local pkgIndex.tcl\[.in]" + } + set ::teaish__Config(pkgindex-policy) 0x10 + } + + default { + proj-warn "Unknown [proj-current-scope] flag: $arg" + } + } + +# --disable-dist [L]: disables the "dist" parts of the filtered +# Makefile. May be used during initial loading of teaish.tcl. +# +# --disable-dist { +# define TEAISH_ENABLE_DIST 0 +# } + } +} + +# +# @teaish-pkginfo-set ...flags +# +# The preferred way to set up the initial package state. Used like: +# +# teaish-pkginfo-set -name foo -version 0.1.2 +# +# Where each flag corresponds to one piece of extension package info. +# +# -name TEAISH_NAME +# -pkgName TEAISH_PKGNAME +# -libDir TEAISH_LIBDIR_NAME +# -loadPrefix TEAISH_LOAD_PREFIX +# -version TEAISH_VERSION +# -vsatisfies TEAISH_VSATISFIES_TCL +# -options {...} optional [options-add] value +# +proc teaish-pkginfo-set {args} { + set sentinel "" + set f2d $::teaish__Config(pkginfo-f2d) + set flagDefs [list] + foreach {f d} $f2d { + lappend flagDefs $f => $sentinel + } + proj-parse-simple-flags args flags $flagDefs + if {[llength $args]} { + proj-error -up "Too many (or unknown) arguments to [proj-current-scope]: $args" + } + foreach {f d} $f2d { + if {$sentinel ne [set v $flags($f)]} { + switch -exact -- $f { + -options { + options-add $v + } + default { + define $d $v + } + } + set ::teaish__Config($f) $v + } + } +} + +# +# @teaish-pkginfo-get ?arg? +# +# If passed no arguments, it returns the extension config info in the +# same form accepted by teaish-pkginfo-set. +# +# If passed one -flagname arg then it returns the value of that config +# option. +# +# Else it treats arg as the name of caller-scoped variable to +# which this function assigns an array containing the configuration +# state of this extension, in the same structure accepted by +# teaish-pkginfo-set. In this case it returns an empty string. +# +proc teaish-pkginfo-get {args} { + set cases {} + set argc [llength $args] + set rv {} + switch -exact $argc { + 0 { + # Return a list of (-flag value) pairs + lappend cases default {{ + if {[info exists ::teaish__Config($flag)]} { + lappend rv $flag $::teaish__Config($flag) + } else { + lappend rv $flag [get-define $defName] + } + }} + } + + 1 { + set arg $args + if {[string match -* $arg]} { + # Return the corresponding -flag's value + lappend cases $arg {{ + if {[info exists ::teaish__Config($flag)]} { + return $::teaish__Config($flag) + } else { + return [get-define $defName] + } + }} + } else { + # Populate target with an array of (-flag value). + upvar $arg tgt + array set tgt {} + lappend cases default {{ + if {[info exists ::teaish__Config($flag)]} { + set tgt($flag) $::teaish__Config($flag) + } else { + set tgt($flag) [get-define $defName] + } + }} + } + } + + default { + proj-error "invalid arg count from [proj-current-scope 1]" + } + } + + foreach {flag defName} $::teaish__Config(pkginfo-f2d) { + switch -exact -- $flag [join $cases] + } + if {0 == $argc} { return $rv } +} + +#proc teaish-pget {flag} { +# teaish-pkginfo-get $flag +#} + +# +# @teaish-enable-dist ?yes? +# +# Explicitly enables or disables the "dist" rules in the default +# Makefile.in. This is equivalent to defining TEAISH_ENABLE_DIST +# to $yes (which must be 0 or 1). +# +# By default, dist creation is enabled. +# +proc teaish-enable-dist {{yes 1}} { + define TEAISH_ENABLE_DIST $yes +} + +# +# @teaish-checks-queue -pre|-post args... +# +# Queues one or more arbitrary "feature test" functions to be run when +# teaish-checks-run is called. $flag must be one of -pre or -post to +# specify whether the tests should be run before or after +# teaish-configure is run. Each additional arg is the name of a +# feature-test proc. +# +proc teaish-checks-queue {flag args} { + if {$flag ni {-pre -post}} { + proj-error "illegal flag: $flag" + } + lappend ::teaish__Config(queued-checks${flag}) {*}$args +} + +# +# @teaish-checks-run -pre|-post +# +# Runs all feature checks queued using teaish-checks-queue +# then cleares the queue. +# +proc teaish-checks-run {flag} { + if {$flag ni {-pre -post}} { + proj-error "illegal flag: $flag" + } + #puts "*** running $flag: $::teaish__Config(queued-checks${flag})" + set foo 0 + foreach f $::teaish__Config(queued-checks${flag}) { + if {![teaish-feature-cache-check $f foo]} { + set v [$f] + teaish-feature-cache-set $f $v + } + } + set ::teaish__Config(queued-checks${flag}) {} +} + +# +# Handles --teaish-create-extension=TARGET-DIR +# +proc teaish__create_extension {dir} { + set force [opt-bool teaish-force] + if {"" eq $dir} { + proj-error "--teaish-create-extension=X requires a directory name." + } + file mkdir $dir + set cwd [pwd] + #set dir [file-normalize [file join $cwd $dir]] + msg-result "Created dir $dir" + cd $dir + if {!$force} { + # Ensure that we don't blindly overwrite anything + foreach f { + teaish.c + teaish.tcl + teaish.make.in + teaish.test.tcl + } { + if {[file exists $f]} { + error "Cowardly refusing to overwrite $dir/$f. Use --teaish-force to overwrite." + } + } + } + + set name [file tail $dir] + set pkgName $name + set version 0.0.1 + set loadPrefix [string totitle $pkgName] + set content "teaish-pkginfo-set \ + -name ${name} \ + -pkgName ${pkgName} \ + -version ${version} \ + -loadPrefix $loadPrefix \ + -libDir ${name}${version} + -vsatisfies 8.5- \ + -options { foo=1 => {Disable foo} } + +#proc teaish-options {} { + # Return a list and/or use \[options-add\] to add new + # configure flags. This is called before teaish's + # bootstrapping is finished, so only teaish-* + # APIs which are explicitly noted as being safe + # early on may be used here. Any autosetup-related + # APIs may be used here. + # + # Return an empty string if there are no options to add + # or if they are added using \[options-add\]. +#} + +proc teaish-configure {} { + set d \[get-define TEAISH_DIR\] + teaish-src-add \$d/teaish.c + teaish-dist-add teaish.c + + # TODO: your code goes here.. +} +" + proj-file-write teaish.tcl $content + msg-result "Created teaish.tcl" + + set content "# Teaish test script. +# When this tcl script is invoked via 'make test' it will have loaded +# the package, run any teaish.pkginit.tcl code, and loaded +# autosetup/teaish/tester.tcl. +" + proj-file-write teaish.test.tcl $content + msg-result "Created teaish.test.tcl" + + set content [subst -nocommands -nobackslashes { +#include +static int +${loadPrefix}_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]){ + Tcl_SetObjResult(interp, Tcl_NewStringObj("this is the ${name} extension", -1)); + return TCL_OK; +} + +extern int DLLEXPORT ${loadPrefix}_Init(Tcl_Interp *interp){ + if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { + return TCL_ERROR; + } + if (Tcl_PkgProvide(interp, "${name}", "${version}") == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_CreateObjCommand(interp, "${name}", ${loadPrefix}_Cmd, NULL, NULL); + return TCL_OK; +} +}] + proj-file-write teaish.c $content + msg-result "Created teaish.c" + + set content "# teaish makefile for the ${name} extension +# tx.src = \$(tx.dir)/teaish.c +# tx.LDFLAGS = +# tx.CFLAGS = +" + proj-file-write teaish.make.in $content + msg-result "Created teaish.make.in" + + msg-result "Created new extension $name in \[$dir]" + + cd $cwd +} diff --git a/autoconf/tea/autosetup/feature-tests.tcl b/autoconf/tea/autosetup/feature-tests.tcl new file mode 100644 index 0000000000..9d77092c82 --- /dev/null +++ b/autoconf/tea/autosetup/feature-tests.tcl @@ -0,0 +1,214 @@ +######################################################################## +# 2025 April 7 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# * May you do good and not evil. +# * May you find forgiveness for yourself and forgive others. +# * May you share freely, never taking more than you give. +# +######################################################################## +# ----- @module feature-tests.tcl ----- +# @section TEA-ish collection of feature tests. +# +# Functions in this file with a prefix of teaish__ are +# private/internal APIs. Those with a prefix of teaish- are +# public APIs. + + +# @teaish-check-libz +# +# Checks for zlib.h and the function deflate in libz. If found, +# prepends -lz to the extension's ldflags and returns 1, else returns +# 0. It also defines LDFLAGS_LIBZ to the libs flag. +# +proc teaish-check-libz {} { + teaish-check-cached "Checking for libz" { + set rc 0 + if {[msg-quiet cc-check-includes zlib.h] && [msg-quiet proj-check-function-in-lib deflate z]} { + teaish-ldflags-prepend [define LDFLAGS_LIBZ [get-define lib_deflate]] + undefine lib_deflate + incr rc + } + expr $rc + } +} + +# @teaish-check-librt ?funclist? +# +# Checks whether -lrt is needed for any of the given functions. If +# so, appends -lrt via [teaish-ldflags-prepend] and returns 1, else +# returns 0. It also defines LDFLAGS_LIBRT to the libs flag or an +# empty string. +# +# Some systems (ex: SunOS) require -lrt in order to use nanosleep. +# +proc teaish-check-librt {{funclist {fdatasync nanosleep}}} { + teaish-check-cached -nostatus "Checking whether ($funclist) need librt" { + define LDFLAGS_LIBRT "" + foreach func $funclist { + if {[msg-quiet proj-check-function-in-lib $func rt]} { + set ldrt [get-define lib_${func}] + undefine lib_${func} + if {"" ne $ldrt} { + teaish-ldflags-prepend -r [define LDFLAGS_LIBRT $ldrt] + msg-result $ldrt + return 1 + } else { + msg-result "no lib needed" + return 1 + } + } + } + msg-result "not found" + return 0 + } +} + +# @teaish-check-stdint +# +# A thin proxy for [cc-with] which checks for and the +# various fixed-size int types it declares. It defines HAVE_STDINT_T +# to 0 or 1 and (if it's 1) defines HAVE_XYZ_T for each XYZ int type +# to 0 or 1, depending on whether its available. +proc teaish-check-stdint {} { + teaish-check-cached "Checking for stdint.h" { + msg-quiet 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} + } +} + +# @teaish-is-mingw +# +# Returns 1 if building for mingw, else 0. +proc teaish-is-mingw {} { + return [expr { + [string match *mingw* [get-define host]] && + ![file exists /dev/null] + }] +} + +# @teaish-check-libdl +# +# Checks for whether dlopen() can be found and whether it requires +# -ldl for linking. If found, returns 1, defines LDFLAGS_DLOPEN to the +# linker flags (if any), and passes those flags to +# teaish-ldflags-prepend. It unconditionally defines HAVE_DLOPEN to 0 +# or 1 (the its return result value). +proc teaish-check-dlopen {} { + teaish-check-cached -nostatus "Checking for dlopen()" { + set rc 0 + set lfl "" + if {[cc-with {-includes dlfcn.h} { + cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} { + msg-result "-ldl not needed" + incr rc + } elseif {[cc-check-includes dlfcn.h]} { + incr rc + if {[cc-check-function-in-lib dlopen dl]} { + set lfl [get-define lib_dlopen] + undefine lib_dlopen + msg-result " dlopen() needs $lfl" + } else { + msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in." + } + } else { + msg-result "not found" + } + teaish-ldflags-prepend [define LDFLAGS_DLOPEN $lfl] + define HAVE_DLOPEN $rc + } +} + +# +# @teaish-check-libmath +# +# Handles the --enable-math flag. Returns 1 if found, else 0. +# If found, it prepends -lm (if needed) to the linker flags. +proc teaish-check-libmath {} { + teaish-check-cached "Checking for libc math library" { + set lfl "" + set rc 0 + if {[msg-quiet proj-check-function-in-lib ceil m]} { + incr rc + set lfl [get-define lib_ceil] + undefine lib_ceil + teaish-ldflags-prepend $lfl + msg-checking "$lfl " + } + define LDFLAGS_LIBMATH $lfl + expr $rc + } +} + +# @teaish-import-features ?-flags? feature-names... +# +# For each $name in feature-names... it invokes: +# +# use teaish/feature/$name +# +# to load TEAISH_AUTOSETUP_DIR/feature/$name.tcl +# +# By default, if a proc named teaish-check-${name}-options is defined +# after sourcing a file, it is called and its result is passed to +# proj-append-options. This can be suppressed with the -no-options +# flag. +# +# Flags: +# +# -no-options: disables the automatic running of +# teaish-check-NAME-options, +# +# -run: if the function teaish-check-NAME exists after importing +# then it is called. This flag must not be used when calling this +# function from teaish-options. This trumps both -pre and -post. +# +# -pre: if the function teaish-check-NAME exists after importing +# then it is passed to [teaish-checks-queue -pre]. +# +# -post: works like -pre but instead uses[teaish-checks-queue -post]. +proc teaish-import-features {args} { + set pk "" + set doOpt 1 + proj-parse-simple-flags args flags { + -no-options 0 {set doOpt 0} + -run 0 {expr 1} + -pre 0 {set pk -pre} + -post 0 {set pk -post} + } + # + # TODO: never import the same module more than once. The "use" + # command is smart enough to not do that but we would need to + # remember whether or not any teaish-check-${arg}* procs have been + # called before, and skip them. + # + if {$flags(-run) && "" ne $pk} { + proj-error "Cannot use both -run and $pk" \ + " (called from [proj-current-scope 1])" + } + + foreach arg $args { + uplevel "use teaish/feature/$arg" + if {$doOpt} { + set n "teaish-check-${arg}-options" + if {[llength [info proc $n]] > 0} { + if {"" ne [set x [$n]]} { + options-add $x + } + } + } + if {$flags(-run)} { + set n "teaish-check-${arg}" + if {[llength [info proc $n]] > 0} { + uplevel 1 $n + } + } elseif {"" ne $pk} { + set n "teaish-check-${arg}" + if {[llength [info proc $n]] > 0} { + teaish-checks-queue {*}$pk $n + } + } + } +} diff --git a/autoconf/tea/autosetup/tester.tcl b/autoconf/tea/autosetup/tester.tcl new file mode 100644 index 0000000000..199f64dafb --- /dev/null +++ b/autoconf/tea/autosetup/tester.tcl @@ -0,0 +1,188 @@ +######################################################################## +# 2025 April 5 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# * May you do good and not evil. +# * May you find forgiveness for yourself and forgive others. +# * May you share freely, never taking more than you give. +# +######################################################################## +# +# Helper routines for running automated tests on teaish extensions +# +######################################################################## +# ----- @module teaish-tester.tcl ----- +# +# @section TEA-ish Testing APIs. +# +# Though these are part of the autosup dir hierarchy, they are not +# intended to be run from autosetup code. Rather, they're for +# use with/via teaish.tester.tcl. + +# +# @test-current-scope ?lvl? +# +# Returns the name of the _calling_ proc from ($lvl + 1) levels up the +# call stack (where the caller's level will be 1 up from _this_ +# call). If $lvl would resolve to global scope "global scope" is +# returned and if it would be negative then a string indicating such +# is returned (as opposed to throwing an error). +proc test-current-scope {{lvl 0}} { + #uplevel [expr {$lvl + 1}] {lindex [info level 0] 0} + set ilvl [info level] + set offset [expr {$ilvl - $lvl - 1}] + if { $offset < 0} { + return "invalid scope ($offset)" + } elseif { $offset == 0} { + return "global scope" + } else { + return [lindex [info level $offset] 0] + } +} + +# @test-msg +# +# Emits all arugments to stdout. +proc test-msg {args} { + puts "$args" +} + +# @test-warn +# +# Emits all arugments to stderr. +# +proc test-warn {args} { + puts stderr "WARNING: $args" +} + +# +# @test-error msg +# +# Triggers a test-failed error with a string describing the calling +# scope and the provided message. +# +proc test-fail {args} { + #puts stderr "ERROR: \[[test-current-scope 1]]: $msg" + #exit 1 + error "FAIL: \[[test-current-scope 1]]: $args" +} + +# +# Internal impl for assert-likes. Should not be called directly by +# client code. +# +proc test__assert {lvl script {msg ""}} { + set src "expr \{ $script \}" + # puts "XXXX evalling $src"; + if {![uplevel $lvl $src]} { + if {"" eq $msg} { + set msg $script + } + set caller1 [test-current-scope $lvl] + incr lvl + set caller2 [test-current-scope $lvl] + error "Assertion failed in: \[$caller2 -> $caller1]]: $msg" + } +} + +# +# @assert script ?message? +# +# Kind of like a C assert: if uplevel (eval) of [expr {$script}] is +# false, a fatal error is triggered. The error message, by default, +# includes the body of the failed assertion, but if $msg is set then +# that is used instead. +# +proc assert {script {msg ""}} { + test__assert 1 $script $msg +} + +# +# @test-assert testId script ?msg? +# +# Works like [assert] but emits $testId to stdout first. +# +proc test-assert {testId script {msg ""}} { + puts "test $testId" + test__assert 2 $script $msg +} + +# +# @test-expect testId script result +# +# Runs $script in the calling scope and compares its result to +# $result. If they differ, it triggers an [assert]. +# +proc test-expect {testId script result} { + puts "test $testId" + set x [uplevel 1 $script] + test__assert 1 {$x eq $result} "\nEXPECTED: <<$result>>\nGOT: <<$x>>" +} + +# +# @test-catch cmd ?...args? +# +# Runs [cmd ...args], repressing any exception except to possibly log +# the failure. Returns 1 if it caught anything, 0 if it didn't. +# +proc test-catch {cmd args} { + if {[catch { + $cmd {*}$args + } rc xopts]} { + puts "[test-current-scope] ignoring failure of: $cmd [lindex $args 0]: $rc" + return 1 + } + return 0 +} + +if {![array exists ::teaish__BuildFlags]} { + array set ::teaish__BuildFlags {} +} + +# +# @teaish-build-flag2 flag tgtVar ?dflt? +# +# Caveat #1: only valid when called in the context of teaish's default +# "make test" recipe, e.g. from teaish.test.tcl. It is not valid from +# a teaish.tcl configure script because (A) the state it relies on +# doesn't fully exist at that point and (B) that level of the API has +# more direct access to the build state. This function requires that +# an external script have populated its internal state, which is +# normally handled via teaish.tester.tcl.in. +# +# If the current build has the configure-time flag named $flag set +# then tgtVar is assigned its value and 1 is returned, else tgtVal is +# assigned $dflt and 0 is returned. +# +# Caveat #2: defines in the style of HAVE_FEATURENAME with a value of +# 0 are, by long-standing configure script conventions, treated as +# _undefined_ here. +# +proc teaish-build-flag2 {flag tgtVar {dflt ""}} { + upvar $tgtVar tgt + if {[info exists ::teaish__BuildFlags($flag)]} { + set tgt $::teaish__BuildFlags($flag) + return 1; + } elseif {0==[array size ::teaish__BuildFlags]} { + test-warn \ + "\[[test-current-scope]] was called from " \ + "[test-current-scope 1] without the build flags imported." + } + set tgt $dflt + return 0 +} + +# +# @teaish-build-flag flag ?dflt? +# +# Convenience form of teaish-build-flag2 which returns the +# configure-time-defined value of $flag or "" if it's not defined (or +# if it's an empty string). +# +proc teaish-build-flag {flag {dflt ""}} { + set tgt "" + teaish-build-flag2 $flag tgt $dflt + return $tgt +} diff --git a/autoconf/tea/configure b/autoconf/tea/configure new file mode 100755 index 0000000000..47378126f5 --- /dev/null +++ b/autoconf/tea/configure @@ -0,0 +1,7 @@ +#!/bin/sh +dir0="`dirname "$0"`" +dirA="$dir0/../autosetup" +# This is the case ^^^^^^^^^^^^ in the SQLite "autoconf" bundle. +WRAPPER="$0"; export WRAPPER; exec "`"$dirA/autosetup-find-tclsh"`" \ + "$dirA/autosetup" --teaish-extension-dir="$dir0" \ + "$@" diff --git a/autoconf/tea/configure.ac.in b/autoconf/tea/configure.ac.in deleted file mode 100644 index 95688b7c99..0000000000 --- a/autoconf/tea/configure.ac.in +++ /dev/null @@ -1,227 +0,0 @@ -#!/bin/bash -norc -dnl This file is an input file used by the GNU "autoconf" program to -dnl generate the file "configure", which is run during Tcl installation -dnl to configure the system for the local environment. - -#----------------------------------------------------------------------- -# Sample configure.ac for Tcl Extensions. The only places you should -# need to modify this file are marked by the string __CHANGE__ -#----------------------------------------------------------------------- - -#----------------------------------------------------------------------- -# __CHANGE__ -# Set your package name and version numbers here. -# -# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION -# set as provided. These will also be added as -D defs in your Makefile -# so you can encode the package version directly into the source files. -# This will also define a special symbol for Windows (BUILD_ -# so that we create the export library with the dll. -#----------------------------------------------------------------------- - -AC_INIT([sqlite],[@VERSION@]) - -#-------------------------------------------------------------------- -# Call TEA_INIT as the first TEA_ macro to set up initial vars. -# This will define a ${TEA_PLATFORM} variable == "unix" or "windows" -# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. -#-------------------------------------------------------------------- - -TEA_INIT() - -AC_CONFIG_AUX_DIR(tclconfig) - -#-------------------------------------------------------------------- -# Load the tclConfig.sh file -#-------------------------------------------------------------------- - -TEA_PATH_TCLCONFIG -TEA_LOAD_TCLCONFIG - -#-------------------------------------------------------------------- -# Load the tkConfig.sh file if necessary (Tk extension) -#-------------------------------------------------------------------- - -#TEA_PATH_TKCONFIG -#TEA_LOAD_TKCONFIG - -#----------------------------------------------------------------------- -# Handle the --prefix=... option by defaulting to what Tcl gave. -# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. -#----------------------------------------------------------------------- - -TEA_PREFIX - -#----------------------------------------------------------------------- -# Standard compiler checks. -# This sets up CC by using the CC env var, or looks for gcc otherwise. -# This also calls AC_PROG_CC and a few others to create the basic setup -# necessary to compile executables. -#----------------------------------------------------------------------- - -TEA_SETUP_COMPILER - -#----------------------------------------------------------------------- -# __CHANGE__ -# Specify the C source files to compile in TEA_ADD_SOURCES, -# public headers that need to be installed in TEA_ADD_HEADERS, -# stub library C source files to compile in TEA_ADD_STUB_SOURCES, -# and runtime Tcl library files in TEA_ADD_TCL_SOURCES. -# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS -# and PKG_TCL_SOURCES. -#----------------------------------------------------------------------- - -TEA_ADD_SOURCES([tclsqlite3.c]) -TEA_ADD_HEADERS([]) -TEA_ADD_INCLUDES([]) -TEA_ADD_LIBS([]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS4=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS5=1]) -TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_GEOPOLY=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_MATH_FUNCTIONS=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DESERIALIZE=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBPAGE_VTAB=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_BYTECODE_VTAB=1]) -TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBSTAT_VTAB=1]) -TEA_ADD_STUB_SOURCES([]) -TEA_ADD_TCL_SOURCES([]) - -#-------------------------------------------------------------------- -# The --with-system-sqlite causes the TCL bindings to SQLite to use -# the system shared library for SQLite rather than statically linking -# against its own private copy. This is dangerous and leads to -# undesirable dependences and is not recommended. -# Patchs from rmax. -#-------------------------------------------------------------------- -AC_ARG_WITH([system-sqlite], - [AS_HELP_STRING([--with-system-sqlite], - [use a system-supplied libsqlite3 instead of the bundled one])], - [], [with_system_sqlite=no]) -if test x$with_system_sqlite != xno; then - AC_CHECK_HEADER([sqlite3.h], - [AC_CHECK_LIB([sqlite3],[sqlite3_initialize], - [AC_DEFINE(USE_SYSTEM_SQLITE) - LIBS="$LIBS -lsqlite3"])]) -fi - -#-------------------------------------------------------------------- -# __CHANGE__ -# -# You can add more files to clean if your extension creates any extra -# files by extending CLEANFILES. -# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure -# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. -# -# A few miscellaneous platform-specific items: -# TEA_ADD_* any platform specific compiler/build info here. -#-------------------------------------------------------------------- - -#CLEANFILES="$CLEANFILES pkgIndex.tcl" -if test "${TEA_PLATFORM}" = "windows" ; then - # Ensure no empty if clauses - : - #TEA_ADD_SOURCES([win/winFile.c]) - #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) -else - # Ensure no empty else clauses - : - #TEA_ADD_SOURCES([unix/unixFile.c]) - #TEA_ADD_LIBS([-lsuperfly]) -fi - -#-------------------------------------------------------------------- -# __CHANGE__ -# Choose which headers you need. Extension authors should try very -# hard to only rely on the Tcl public header files. Internal headers -# contain private data structures and are subject to change without -# notice. -# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG -#-------------------------------------------------------------------- - -TEA_PUBLIC_TCL_HEADERS -#TEA_PRIVATE_TCL_HEADERS - -#TEA_PUBLIC_TK_HEADERS -#TEA_PRIVATE_TK_HEADERS -#TEA_PATH_X - -#-------------------------------------------------------------------- -# Check whether --enable-threads or --disable-threads was given. -# This auto-enables if Tcl was compiled threaded. -#-------------------------------------------------------------------- - -TEA_ENABLE_THREADS -if test "${TCL_THREADS}" = "1" ; then - AC_DEFINE(SQLITE_THREADSAFE, 1, [Trigger sqlite threadsafe build]) - # Not automatically added by Tcl because its assumed Tcl links to them, - # but it may not if it isn't really a threaded build. - TEA_ADD_LIBS([$THREADS_LIBS]) -else - AC_DEFINE(SQLITE_THREADSAFE, 0, [Trigger sqlite non-threadsafe build]) -fi - -#-------------------------------------------------------------------- -# The statement below defines a collection of symbols related to -# building as a shared library instead of a static library. -#-------------------------------------------------------------------- - -TEA_ENABLE_SHARED - -#-------------------------------------------------------------------- -# This macro figures out what flags to use with the compiler/linker -# when building shared/static debug/optimized objects. This information -# can be taken from the tclConfig.sh file, but this figures it all out. -#-------------------------------------------------------------------- - -TEA_CONFIG_CFLAGS - -#-------------------------------------------------------------------- -# Set the default compiler switches based on the --enable-symbols option. -#-------------------------------------------------------------------- - -TEA_ENABLE_SYMBOLS - -#-------------------------------------------------------------------- -# This macro generates a line to use when building a library. It -# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, -# and TEA_LOAD_TCLCONFIG macros above. -#-------------------------------------------------------------------- - -TEA_MAKE_LIB - -#-------------------------------------------------------------------- -# Determine the name of the tclsh and/or wish executables in the -# Tcl and Tk build directories or the location they were installed -# into. These paths are used to support running test cases only, -# the Makefile should not be making use of these paths to generate -# a pkgIndex.tcl file or anything else at extension build time. -#-------------------------------------------------------------------- - -TEA_PROG_TCLSH -#TEA_PROG_WISH - -#-------------------------------------------------------------------- -# Setup a *Config.sh.in configuration file. -#-------------------------------------------------------------------- - -#TEA_EXPORT_CONFIG([sample]) -#AC_SUBST(SAMPLE_VAR) - -#-------------------------------------------------------------------- -# Specify files to substitute AC variables in. You may alternatively -# have a special pkgIndex.tcl.in or other files which require -# substituting the AC variables in. Include these here. -#-------------------------------------------------------------------- - -AC_CONFIG_FILES([Makefile pkgIndex.tcl]) -#AC_CONFIG_FILES([sampleConfig.sh]) - -#-------------------------------------------------------------------- -# Finally, substitute all of the various values into the files -# specified with AC_CONFIG_FILES. -#-------------------------------------------------------------------- - -AC_OUTPUT diff --git a/autoconf/tea/doc/sqlite3.n b/autoconf/tea/doc/sqlite3.n index 13913e5583..3514046342 100644 --- a/autoconf/tea/doc/sqlite3.n +++ b/autoconf/tea/doc/sqlite3.n @@ -11,5 +11,5 @@ SQLite3 is a self-contains, zero-configuration, transactional SQL database engine. This extension provides an easy to use interface for accessing SQLite database files from Tcl. .PP -For full documentation see \fIhttp://www.sqlite.org/\fR and -in particular \fIhttp://www.sqlite.org/tclsqlite.html\fR. +For full documentation see \fIhttps://sqlite.org/\fR and +in particular \fIhttps://sqlite.org/tclsqlite.html\fR. diff --git a/autoconf/tea/pkgIndex.tcl.in b/autoconf/tea/pkgIndex.tcl.in index 666812dee7..6ed6bb68db 100644 --- a/autoconf/tea/pkgIndex.tcl.in +++ b/autoconf/tea/pkgIndex.tcl.in @@ -1,10 +1,38 @@ # -*- tcl -*- -# Tcl package index file, version 1.1 +# Tcl package index file # -if {[package vsatisfies [package provide Tcl] 9.0-]} { - package ifneeded sqlite3 @PACKAGE_VERSION@ \ - [list load [file join $dir @PKG_LIB_FILE9@] Sqlite3] -} else { - package ifneeded sqlite3 @PACKAGE_VERSION@ \ - [list load [file join $dir @PKG_LIB_FILE8@] Sqlite3] +# Unless this file is named pkgIndex.tcl.in, you are probably looking +# at an automatically generated/filtered copy and should probably not +# edit it. +# +# Adapted from https://core.tcl-lang.org/tcltls +@if TEAISH_VSATISFIES_TCL +if {![package vsatisfies [package provide Tcl] @TEAISH_VSATISFIES_TCL@]} { + error "Package @TEAISH_PKGNAME@ @TEAISH_VERSION@ requires Tcl @TEAISH_VSATISFIES_TCL@" +} +@endif +if {[package vsatisfies [package provide Tcl] 9.0-]} { + package ifneeded {@TEAISH_PKGNAME@} {@TEAISH_VERSION@} [list apply {{dir} { + load [file join $dir {@TEAISH_DLL9@}] @TEAISH_LOAD_PREFIX@ +@if TEAISH_PKGINIT_TCL_TAIL + set initScript [file join $dir {@TEAISH_PKGINIT_TCL_TAIL@}] + if {[file exists $initScript]} { + source -encoding utf-8 $initScript + } +@endif + }} $dir] +} else { + package ifneeded {@TEAISH_PKGNAME@} {@TEAISH_VERSION@} [list apply {{dir} { + if {[string tolower [file extension {@TEAISH_DLL8@}]] in [list .dll .dylib .so]} { + load [file join $dir {@TEAISH_DLL8@}] @TEAISH_LOAD_PREFIX@ + } else { + load {} @TEAISH_LOAD_PREFIX@ + } +@if TEAISH_PKGINIT_TCL_TAIL + set initScript [file join $dir {@TEAISH_PKGINIT_TCL_TAIL@}] + if {[file exists $initScript]} { + source -encoding utf-8 $initScript + } +@endif + }} $dir] } diff --git a/autoconf/tea/tclconfig/install-sh b/autoconf/tea/tclconfig/install-sh deleted file mode 100644 index ec298b5374..0000000000 --- a/autoconf/tea/tclconfig/install-sh +++ /dev/null @@ -1,541 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2020-11-14.01; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# 'make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -tab=' ' -nl=' -' -IFS=" $tab$nl" - -# Set DOITPROG to "echo" to test this script. - -doit=${DOITPROG-} -doit_exec=${doit:-exec} - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -# Create dirs (including intermediate dirs) using mode 755. -# This is like GNU 'install' as of coreutils 8.32 (2020). -mkdir_umask=22 - -backupsuffix= -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -is_target_a_directory=possibly - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -p pass -p to $cpprog. - -s $stripprog installed files. - -S SUFFIX attempt to back up existing files, with suffix SUFFIX. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG - -By default, rm is invoked with -f; when overridden with RMPROG, -it's up to you to specify -f if you want it. - -If -S is not specified, no backups are attempted. - -Email bug reports to bug-automake@gnu.org. -Automake home page: https://www.gnu.org/software/automake/ -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -p) cpprog="$cpprog -p";; - - -s) stripcmd=$stripprog;; - - -S) backupsuffix="$2" - shift;; - - -t) - is_target_a_directory=always - dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; - - -T) is_target_a_directory=never;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -# We allow the use of options -d and -T together, by making -d -# take the precedence; this is for compatibility with GNU install. - -if test -n "$dir_arg"; then - if test -n "$dst_arg"; then - echo "$0: target directory not allowed when installing a directory." >&2 - exit 1 - fi -fi - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call 'install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - if test $# -gt 1 || test "$is_target_a_directory" = always; then - if test ! -d "$dst_arg"; then - echo "$0: $dst_arg: Is not a directory." >&2 - exit 1 - fi - fi -fi - -if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names problematic for 'test' and other utilities. - case $src in - -* | [=\(\)!]) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - # Don't chown directories that already exist. - if test $dstdir_status = 0; then - chowncmd="" - fi - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - dst=$dst_arg - - # If destination is a directory, append the input filename. - if test -d "$dst"; then - if test "$is_target_a_directory" = never; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dstbase=`basename "$src"` - case $dst in - */) dst=$dst$dstbase;; - *) dst=$dst/$dstbase;; - esac - dstdir_status=0 - else - dstdir=`dirname "$dst"` - test -d "$dstdir" - dstdir_status=$? - fi - fi - - case $dstdir in - */) dstdirslash=$dstdir;; - *) dstdirslash=$dstdir/;; - esac - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - # The $RANDOM variable is not portable (e.g., dash). Use it - # here however when possible just to lower collision chance. - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - - trap ' - ret=$? - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null - exit $ret - ' 0 - - # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writeable /tmp, make sure that the '$tmpdir' - # directory is successfully created first before we actually test - # 'mkdir -p'. - if (umask $mkdir_umask && - $mkdirprog $mkdir_mode "$tmpdir" && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null - fi - trap '' 0;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; - esac - - oIFS=$IFS - IFS=/ - set -f - set fnord $dstdir - shift - set +f - IFS=$oIFS - - prefixes= - - for d - do - test X"$d" = X && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=${dstdirslash}_inst.$$_ - rmtmp=${dstdirslash}_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && - { test -z "$stripcmd" || { - # Create $dsttmp read-write so that cp doesn't create it read-only, - # which would cause strip to fail. - if test -z "$doit"; then - : >"$dsttmp" # No need to fork-exec 'touch'. - else - $doit touch "$dsttmp" - fi - } - } && - $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - set +f && - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # If $backupsuffix is set, and the file being installed - # already exists, attempt a backup. Don't worry if it fails, - # e.g., if mv doesn't support -f. - if test -n "$backupsuffix" && test -f "$dst"; then - $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null - fi - - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC0" -# time-stamp-end: "; # UTC" -# End: diff --git a/autoconf/tea/tclconfig/tcl.m4 b/autoconf/tea/tclconfig/tcl.m4 deleted file mode 100644 index 237d50a7bd..0000000000 --- a/autoconf/tea/tclconfig/tcl.m4 +++ /dev/null @@ -1,4119 +0,0 @@ -# tcl.m4 -- -# -# This file provides a set of autoconf macros to help TEA-enable -# a Tcl extension. -# -# Copyright (c) 1999-2000 Ajuba Solutions. -# Copyright (c) 2002-2005 ActiveState Corporation. -# -# See the file "license.terms" for information on usage and redistribution -# of this file, and for a DISCLAIMER OF ALL WARRANTIES. - -AC_PREREQ([2.69]) - -# Possible values for key variables defined: -# -# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') -# TEA_PLATFORM - windows unix -# TEA_TK_EXTENSION - True if this is a Tk extension -# - -#------------------------------------------------------------------------ -# TEA_PATH_TCLCONFIG -- -# -# Locate the tclConfig.sh file and perform a sanity check on -# the Tcl compile flags -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --with-tcl=... -# -# Defines the following vars: -# TCL_BIN_DIR Full path to the directory containing -# the tclConfig.sh file -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PATH_TCLCONFIG], [ - dnl TEA specific: Make sure we are initialized - AC_REQUIRE([TEA_INIT]) - # - # Ok, lets find the tcl configuration - # First, look for one uninstalled. - # the alternative search directory is invoked by --with-tcl - # - - if test x"${no_tcl}" = x ; then - # we reset no_tcl in case something fails here - no_tcl=true - AC_ARG_WITH(tcl, - AS_HELP_STRING([--with-tcl], - [directory containing tcl configuration (tclConfig.sh)]), - [with_tclconfig="${withval}"]) - AC_ARG_WITH(tcl8, - AS_HELP_STRING([--with-tcl8], - [Compile for Tcl8 in Tcl9 environment]), - [with_tcl8="${withval}"]) - AC_MSG_CHECKING([for Tcl configuration]) - AC_CACHE_VAL(ac_cv_c_tclconfig,[ - - # First check to see if --with-tcl was specified. - if test x"${with_tclconfig}" != x ; then - case "${with_tclconfig}" in - */tclConfig.sh ) - if test -f "${with_tclconfig}"; then - AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) - with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" - fi ;; - esac - if test -f "${with_tclconfig}/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" - else - AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) - fi - fi - - # then check for a private Tcl installation - if test x"${ac_cv_c_tclconfig}" = x ; then - for i in \ - ../tcl \ - `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../tcl \ - `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../../tcl \ - `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test "${TEA_PLATFORM}" = "windows" \ - -a -f "$i/win/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd $i/win; pwd)`" - break - fi - if test -f "$i/unix/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" - break - fi - done - fi - - # on Darwin, check in Framework installation locations - if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then - for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ - `ls -d /Library/Frameworks 2>/dev/null` \ - `ls -d /Network/Library/Frameworks 2>/dev/null` \ - `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ - `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ - `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ - ; do - if test -f "$i/Tcl.framework/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" - break - fi - done - fi - - # TEA specific: on Windows, check in common installation locations - if test "${TEA_PLATFORM}" = "windows" \ - -a x"${ac_cv_c_tclconfig}" = x ; then - for i in `ls -d C:/Tcl/lib 2>/dev/null` \ - `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ - ; do - if test -f "$i/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd $i; pwd)`" - break - fi - done - fi - - # check in a few common install locations - if test x"${ac_cv_c_tclconfig}" = x ; then - for i in `ls -d ${libdir} 2>/dev/null` \ - `ls -d ${exec_prefix}/lib 2>/dev/null` \ - `ls -d ${prefix}/lib 2>/dev/null` \ - `ls -d /usr/local/lib 2>/dev/null` \ - `ls -d /usr/contrib/lib 2>/dev/null` \ - `ls -d /usr/pkg/lib 2>/dev/null` \ - `ls -d /usr/lib 2>/dev/null` \ - `ls -d /usr/lib64 2>/dev/null` \ - `ls -d /usr/lib/tcl9.0 2>/dev/null` \ - `ls -d /usr/lib/tcl8.7 2>/dev/null` \ - `ls -d /usr/lib/tcl8.6 2>/dev/null` \ - `ls -d /usr/lib/tcl8.5 2>/dev/null` \ - `ls -d /usr/local/lib/tcl9.0 2>/dev/null` \ - `ls -d /usr/local/lib/tcl8.7 2>/dev/null` \ - `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ - `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tcl9.0 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tcl8.7 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \ - ; do - if test -f "$i/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd $i; pwd)`" - break - fi - done - fi - - # check in a few other private locations - if test x"${ac_cv_c_tclconfig}" = x ; then - for i in \ - ${srcdir}/../tcl \ - `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test "${TEA_PLATFORM}" = "windows" \ - -a -f "$i/win/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd $i/win; pwd)`" - break - fi - if test -f "$i/unix/tclConfig.sh" ; then - ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" - break - fi - done - fi - ]) - - if test x"${ac_cv_c_tclconfig}" = x ; then - TCL_BIN_DIR="# no Tcl configs found" - AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) - else - no_tcl= - TCL_BIN_DIR="${ac_cv_c_tclconfig}" - AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_PATH_TKCONFIG -- -# -# Locate the tkConfig.sh file -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --with-tk=... -# -# Defines the following vars: -# TK_BIN_DIR Full path to the directory containing -# the tkConfig.sh file -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PATH_TKCONFIG], [ - # - # Ok, lets find the tk configuration - # First, look for one uninstalled. - # the alternative search directory is invoked by --with-tk - # - - if test x"${no_tk}" = x ; then - # we reset no_tk in case something fails here - no_tk=true - AC_ARG_WITH(tk, - AS_HELP_STRING([--with-tk], - [directory containing tk configuration (tkConfig.sh)]), - [with_tkconfig="${withval}"]) - AC_MSG_CHECKING([for Tk configuration]) - AC_CACHE_VAL(ac_cv_c_tkconfig,[ - - # First check to see if --with-tkconfig was specified. - if test x"${with_tkconfig}" != x ; then - case "${with_tkconfig}" in - */tkConfig.sh ) - if test -f "${with_tkconfig}"; then - AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) - with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" - fi ;; - esac - if test -f "${with_tkconfig}/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" - else - AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) - fi - fi - - # then check for a private Tk library - if test x"${ac_cv_c_tkconfig}" = x ; then - for i in \ - ../tk \ - `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../tk \ - `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../../tk \ - `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test "${TEA_PLATFORM}" = "windows" \ - -a -f "$i/win/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd $i/win; pwd)`" - break - fi - if test -f "$i/unix/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" - break - fi - done - fi - - # on Darwin, check in Framework installation locations - if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then - for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ - `ls -d /Library/Frameworks 2>/dev/null` \ - `ls -d /Network/Library/Frameworks 2>/dev/null` \ - ; do - if test -f "$i/Tk.framework/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" - break - fi - done - fi - - # check in a few common install locations - if test x"${ac_cv_c_tkconfig}" = x ; then - for i in `ls -d ${libdir} 2>/dev/null` \ - `ls -d ${exec_prefix}/lib 2>/dev/null` \ - `ls -d ${prefix}/lib 2>/dev/null` \ - `ls -d /usr/local/lib 2>/dev/null` \ - `ls -d /usr/contrib/lib 2>/dev/null` \ - `ls -d /usr/pkg/lib 2>/dev/null` \ - `ls -d /usr/lib/tk9.0 2>/dev/null` \ - `ls -d /usr/lib/tk8.7 2>/dev/null` \ - `ls -d /usr/lib/tk8.6 2>/dev/null` \ - `ls -d /usr/lib/tk8.5 2>/dev/null` \ - `ls -d /usr/lib 2>/dev/null` \ - `ls -d /usr/lib64 2>/dev/null` \ - `ls -d /usr/local/lib/tk9.0 2>/dev/null` \ - `ls -d /usr/local/lib/tk8.7 2>/dev/null` \ - `ls -d /usr/local/lib/tk8.6 2>/dev/null` \ - `ls -d /usr/local/lib/tk8.5 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tk9.0 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tk8.7 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \ - `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \ - ; do - if test -f "$i/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd $i; pwd)`" - break - fi - done - fi - - # TEA specific: on Windows, check in common installation locations - if test "${TEA_PLATFORM}" = "windows" \ - -a x"${ac_cv_c_tkconfig}" = x ; then - for i in `ls -d C:/Tcl/lib 2>/dev/null` \ - `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ - ; do - if test -f "$i/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd $i; pwd)`" - break - fi - done - fi - - # check in a few other private locations - if test x"${ac_cv_c_tkconfig}" = x ; then - for i in \ - ${srcdir}/../tk \ - `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test "${TEA_PLATFORM}" = "windows" \ - -a -f "$i/win/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd $i/win; pwd)`" - break - fi - if test -f "$i/unix/tkConfig.sh" ; then - ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" - break - fi - done - fi - ]) - - if test x"${ac_cv_c_tkconfig}" = x ; then - TK_BIN_DIR="# no Tk configs found" - AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) - else - no_tk= - TK_BIN_DIR="${ac_cv_c_tkconfig}" - AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_LOAD_TCLCONFIG -- -# -# Load the tclConfig.sh file -# -# Arguments: -# -# Requires the following vars to be set: -# TCL_BIN_DIR -# -# Results: -# -# Substitutes the following vars: -# TCL_BIN_DIR -# TCL_SRC_DIR -# TCL_LIB_FILE -# TCL_ZIP_FILE -# TCL_ZIPFS_SUPPORT -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_LOAD_TCLCONFIG], [ - AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) - - if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then - AC_MSG_RESULT([loading]) - . "${TCL_BIN_DIR}/tclConfig.sh" - else - AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) - fi - - # If the TCL_BIN_DIR is the build directory (not the install directory), - # then set the common variable name to the value of the build variables. - # For example, the variable TCL_LIB_SPEC will be set to the value - # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC - # instead of TCL_BUILD_LIB_SPEC since it will work with both an - # installed and uninstalled version of Tcl. - if test -f "${TCL_BIN_DIR}/Makefile" ; then - TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" - TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" - TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" - elif test "`uname -s`" = "Darwin"; then - # If Tcl was built as a framework, attempt to use the libraries - # from the framework at the given location so that linking works - # against Tcl.framework installed in an arbitrary location. - case ${TCL_DEFS} in - *TCL_FRAMEWORK*) - if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then - for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ - "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do - if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then - TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" - break - fi - done - fi - if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then - TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" - TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" - fi - ;; - esac - fi - - AC_SUBST(TCL_VERSION) - AC_SUBST(TCL_PATCH_LEVEL) - AC_SUBST(TCL_BIN_DIR) - AC_SUBST(TCL_SRC_DIR) - - AC_SUBST(TCL_LIB_FILE) - AC_SUBST(TCL_LIB_FLAG) - AC_SUBST(TCL_LIB_SPEC) - - AC_SUBST(TCL_STUB_LIB_FILE) - AC_SUBST(TCL_STUB_LIB_FLAG) - AC_SUBST(TCL_STUB_LIB_SPEC) - - AC_MSG_CHECKING([platform]) - hold_cc=$CC; CC="$TCL_CC" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ - #ifdef _WIN32 - #error win32 - #endif - ]])],[ - # first test we've already retrieved platform (cross-compile), fallback to unix otherwise: - TEA_PLATFORM="${TEA_PLATFORM-unix}" - CYGPATH=echo - ],[ - TEA_PLATFORM="windows" - AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) - ]) - CC=$hold_cc - AC_MSG_RESULT($TEA_PLATFORM) - - # The BUILD_$pkg is to define the correct extern storage class - # handling when making this package - AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], - [Building extension source?]) - # Do this here as we have fully defined TEA_PLATFORM now - if test "${TEA_PLATFORM}" = "windows" ; then - EXEEXT=".exe" - CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" - fi - - # TEA specific: - AC_SUBST(CLEANFILES) - AC_SUBST(TCL_LIBS) - AC_SUBST(TCL_DEFS) - AC_SUBST(TCL_EXTRA_CFLAGS) - AC_SUBST(TCL_LD_FLAGS) - AC_SUBST(TCL_SHLIB_LD_LIBS) -]) - -#------------------------------------------------------------------------ -# TEA_LOAD_TKCONFIG -- -# -# Load the tkConfig.sh file -# -# Arguments: -# -# Requires the following vars to be set: -# TK_BIN_DIR -# -# Results: -# -# Sets the following vars that should be in tkConfig.sh: -# TK_BIN_DIR -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_LOAD_TKCONFIG], [ - AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) - - if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then - AC_MSG_RESULT([loading]) - . "${TK_BIN_DIR}/tkConfig.sh" - else - AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) - fi - - # If the TK_BIN_DIR is the build directory (not the install directory), - # then set the common variable name to the value of the build variables. - # For example, the variable TK_LIB_SPEC will be set to the value - # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC - # instead of TK_BUILD_LIB_SPEC since it will work with both an - # installed and uninstalled version of Tcl. - if test -f "${TK_BIN_DIR}/Makefile" ; then - TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" - TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" - TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" - elif test "`uname -s`" = "Darwin"; then - # If Tk was built as a framework, attempt to use the libraries - # from the framework at the given location so that linking works - # against Tk.framework installed in an arbitrary location. - case ${TK_DEFS} in - *TK_FRAMEWORK*) - if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then - for i in "`cd "${TK_BIN_DIR}"; pwd`" \ - "`cd "${TK_BIN_DIR}"/../..; pwd`"; do - if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then - TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" - break - fi - done - fi - if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then - TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" - TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" - fi - ;; - esac - fi - - # TEA specific: Ensure windowingsystem is defined - if test "${TEA_PLATFORM}" = "unix" ; then - case ${TK_DEFS} in - *MAC_OSX_TK*) - AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) - TEA_WINDOWINGSYSTEM="aqua" - ;; - *) - TEA_WINDOWINGSYSTEM="x11" - ;; - esac - elif test "${TEA_PLATFORM}" = "windows" ; then - TEA_WINDOWINGSYSTEM="win32" - fi - - AC_SUBST(TK_VERSION) - AC_SUBST(TK_BIN_DIR) - AC_SUBST(TK_SRC_DIR) - - AC_SUBST(TK_LIB_FILE) - AC_SUBST(TK_LIB_FLAG) - AC_SUBST(TK_LIB_SPEC) - - AC_SUBST(TK_STUB_LIB_FILE) - AC_SUBST(TK_STUB_LIB_FLAG) - AC_SUBST(TK_STUB_LIB_SPEC) - - # TEA specific: - AC_SUBST(TK_LIBS) - AC_SUBST(TK_XINCLUDES) -]) - -#------------------------------------------------------------------------ -# TEA_PROG_TCLSH -# Determine the fully qualified path name of the tclsh executable -# in the Tcl build directory or the tclsh installed in a bin -# directory. This macro will correctly determine the name -# of the tclsh executable even if tclsh has not yet been -# built in the build directory. The tclsh found is always -# associated with a tclConfig.sh file. This tclsh should be used -# only for running extension test cases. It should never be -# or generation of files (like pkgIndex.tcl) at build time. -# -# Arguments: -# none -# -# Results: -# Substitutes the following vars: -# TCLSH_PROG -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PROG_TCLSH], [ - AC_MSG_CHECKING([for tclsh]) - if test -f "${TCL_BIN_DIR}/Makefile" ; then - # tclConfig.sh is in Tcl build directory - if test "${TEA_PLATFORM}" = "windows"; then - if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" - elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" - elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" - elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" - fi - else - TCLSH_PROG="${TCL_BIN_DIR}/tclsh" - fi - else - # tclConfig.sh is in install location - if test "${TEA_PLATFORM}" = "windows"; then - TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" - else - TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" - fi - list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ - `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ - `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" - for i in $list ; do - if test -f "$i/${TCLSH_PROG}" ; then - REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" - break - fi - done - TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" - fi - AC_MSG_RESULT([${TCLSH_PROG}]) - AC_SUBST(TCLSH_PROG) -]) - -#------------------------------------------------------------------------ -# TEA_PROG_WISH -# Determine the fully qualified path name of the wish executable -# in the Tk build directory or the wish installed in a bin -# directory. This macro will correctly determine the name -# of the wish executable even if wish has not yet been -# built in the build directory. The wish found is always -# associated with a tkConfig.sh file. This wish should be used -# only for running extension test cases. It should never be -# or generation of files (like pkgIndex.tcl) at build time. -# -# Arguments: -# none -# -# Results: -# Substitutes the following vars: -# WISH_PROG -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PROG_WISH], [ - AC_MSG_CHECKING([for wish]) - if test -f "${TK_BIN_DIR}/Makefile" ; then - # tkConfig.sh is in Tk build directory - if test "${TEA_PLATFORM}" = "windows"; then - if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then - WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" - elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then - WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}" - elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then - WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" - elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then - WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" - fi - else - WISH_PROG="${TK_BIN_DIR}/wish" - fi - else - # tkConfig.sh is in install location - if test "${TEA_PLATFORM}" = "windows"; then - WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" - else - WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" - fi - list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ - `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ - `ls -d ${TK_PREFIX}/bin 2>/dev/null`" - for i in $list ; do - if test -f "$i/${WISH_PROG}" ; then - REAL_TK_BIN_DIR="`cd "$i"; pwd`/" - break - fi - done - WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" - fi - AC_MSG_RESULT([${WISH_PROG}]) - AC_SUBST(WISH_PROG) -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_SHARED -- -# -# Allows the building of shared libraries -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --enable-shared=yes|no -# --enable-stubs=yes|no -# -# Defines the following vars: -# STATIC_BUILD Used for building import/export libraries -# on Windows. -# -# Sets the following vars: -# SHARED_BUILD Value of 1 or 0 -# STUBS_BUILD Value if 1 or 0 -# USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs -# USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs -# USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs -# AND TEA_WINDOWING_SYSTEM != "" -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ENABLE_SHARED], [ - AC_MSG_CHECKING([how to build libraries]) - AC_ARG_ENABLE(shared, - AS_HELP_STRING([--enable-shared], - [build and link with shared libraries (default: on)]), - [shared_ok=$enableval], [shared_ok=yes]) - - if test "${enable_shared+set}" = set; then - enableval="$enable_shared" - shared_ok=$enableval - else - shared_ok=yes - fi - - AC_ARG_ENABLE(stubs, - AS_HELP_STRING([--enable-stubs], - [build and link with stub libraries. Always true for shared builds (default: on)]), - [stubs_ok=$enableval], [stubs_ok=yes]) - - if test "${enable_stubs+set}" = set; then - enableval="$enable_stubs" - stubs_ok=$enableval - else - stubs_ok=yes - fi - - # Stubs are always enabled for shared builds - if test "$shared_ok" = "yes" ; then - AC_MSG_RESULT([shared]) - SHARED_BUILD=1 - STUBS_BUILD=1 - else - AC_MSG_RESULT([static]) - SHARED_BUILD=0 - AC_DEFINE(STATIC_BUILD, 1, [This a static build]) - if test "$stubs_ok" = "yes" ; then - STUBS_BUILD=1 - else - STUBS_BUILD=0 - fi - fi - if test "${STUBS_BUILD}" = "1" ; then - AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) - AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) - if test "${TEA_WINDOWINGSYSTEM}" != ""; then - AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) - fi - fi - - AC_SUBST(SHARED_BUILD) - AC_SUBST(STUBS_BUILD) -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_THREADS -- -# -# Specify if thread support should be enabled. If "yes" is specified -# as an arg (optional), threads are enabled by default, "no" means -# threads are disabled. "yes" is the default. -# -# TCL_THREADS is checked so that if you are compiling an extension -# against a threaded core, your extension must be compiled threaded -# as well. -# -# Note that it is legal to have a thread enabled extension run in a -# threaded or non-threaded Tcl core, but a non-threaded extension may -# only run in a non-threaded Tcl core. -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --enable-threads -# -# Sets the following vars: -# THREADS_LIBS Thread library(s) -# -# Defines the following vars: -# TCL_THREADS -# _REENTRANT -# _THREAD_SAFE -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_ENABLE_THREADS], [ - AC_ARG_ENABLE(threads, - AS_HELP_STRING([--enable-threads], - [build with threads (default: on)]), - [tcl_ok=$enableval], [tcl_ok=yes]) - - if test "${enable_threads+set}" = set; then - enableval="$enable_threads" - tcl_ok=$enableval - else - tcl_ok=yes - fi - - if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then - TCL_THREADS=1 - - if test "${TEA_PLATFORM}" != "windows" ; then - # We are always OK on Windows, so check what this platform wants: - - # USE_THREAD_ALLOC tells us to try the special thread-based - # allocator that significantly reduces lock contention - AC_DEFINE(USE_THREAD_ALLOC, 1, - [Do we want to use the threaded memory allocator?]) - AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) - if test "`uname -s`" = "SunOS" ; then - AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, - [Do we really want to follow the standard? Yes we do!]) - fi - AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) - AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) - if test "$tcl_ok" = "no"; then - # Check a little harder for __pthread_mutex_init in the same - # library, as some systems hide it there until pthread.h is - # defined. We could alternatively do an AC_TRY_COMPILE with - # pthread.h, but that will work with libpthread really doesn't - # exist, like AIX 4.2. [Bug: 4359] - AC_CHECK_LIB(pthread, __pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - fi - - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -lpthread" - else - AC_CHECK_LIB(pthreads, pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -lpthreads" - else - AC_CHECK_LIB(c, pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = "no"; then - AC_CHECK_LIB(c_r, pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -pthread" - else - TCL_THREADS=0 - AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) - fi - fi - fi - fi - fi - else - TCL_THREADS=0 - fi - # Do checking message here to not mess up interleaved configure output - AC_MSG_CHECKING([for building with threads]) - if test "${TCL_THREADS}" = 1; then - AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) - AC_MSG_RESULT([yes (default)]) - else - AC_MSG_RESULT([no]) - fi - # TCL_THREADS sanity checking. See if our request for building with - # threads is the same as the way Tcl was built. If not, warn the user. - case ${TCL_DEFS} in - *THREADS=1*) - if test "${TCL_THREADS}" = "0"; then - AC_MSG_WARN([ - Building ${PACKAGE_NAME} without threads enabled, but building against Tcl - that IS thread-enabled. It is recommended to use --enable-threads.]) - fi - ;; - esac - AC_SUBST(TCL_THREADS) -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_SYMBOLS -- -# -# Specify if debugging symbols should be used. -# Memory (TCL_MEM_DEBUG) debugging can also be enabled. -# -# Arguments: -# none -# -# TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives -# the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. -# Requires the following vars to be set in the Makefile: -# CFLAGS_DEFAULT -# LDFLAGS_DEFAULT -# -# Results: -# -# Adds the following arguments to configure: -# --enable-symbols -# -# Defines the following vars: -# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true -# Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false -# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true -# Sets to $(LDFLAGS_OPTIMIZE) if false -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_ENABLE_SYMBOLS], [ - dnl TEA specific: Make sure we are initialized - AC_REQUIRE([TEA_CONFIG_CFLAGS]) - AC_MSG_CHECKING([for build with symbols]) - AC_ARG_ENABLE(symbols, - AS_HELP_STRING([--enable-symbols], - [build with debugging symbols (default: off)]), - [tcl_ok=$enableval], [tcl_ok=no]) - if test "$tcl_ok" = "no"; then - CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" - LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" - AC_MSG_RESULT([no]) - AC_DEFINE(TCL_CFG_OPTIMIZED, 1, [Is this an optimized build?]) - else - CFLAGS_DEFAULT="${CFLAGS_DEBUG}" - LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" - if test "$tcl_ok" = "yes"; then - AC_MSG_RESULT([yes (standard debugging)]) - fi - fi - AC_SUBST(CFLAGS_DEFAULT) - AC_SUBST(LDFLAGS_DEFAULT) - - if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then - AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) - fi - - if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then - if test "$tcl_ok" = "all"; then - AC_MSG_RESULT([enabled symbols mem debugging]) - else - AC_MSG_RESULT([enabled $tcl_ok debugging]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_LANGINFO -- -# -# Allows use of modern nl_langinfo check for better l10n. -# This is only relevant for Unix. -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --enable-langinfo=yes|no (default is yes) -# -# Defines the following vars: -# HAVE_LANGINFO Triggers use of nl_langinfo if defined. -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_ENABLE_LANGINFO], [ - AC_ARG_ENABLE(langinfo, - AS_HELP_STRING([--enable-langinfo], - [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), - [langinfo_ok=$enableval], [langinfo_ok=yes]) - - HAVE_LANGINFO=0 - if test "$langinfo_ok" = "yes"; then - AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) - fi - AC_MSG_CHECKING([whether to use nl_langinfo]) - if test "$langinfo_ok" = "yes"; then - AC_CACHE_VAL(tcl_cv_langinfo_h, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[nl_langinfo(CODESET);]])], - [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) - AC_MSG_RESULT([$tcl_cv_langinfo_h]) - if test $tcl_cv_langinfo_h = yes; then - AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) - fi - else - AC_MSG_RESULT([$langinfo_ok]) - fi -]) - -#-------------------------------------------------------------------- -# TEA_CONFIG_SYSTEM -# -# Determine what the system is (some things cannot be easily checked -# on a feature-driven basis, alas). This can usually be done via the -# "uname" command. -# -# Arguments: -# none -# -# Results: -# Defines the following var: -# -# system - System/platform/version identification code. -# -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_CONFIG_SYSTEM], [ - AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ - # TEA specific: - if test "${TEA_PLATFORM}" = "windows" ; then - tcl_cv_sys_version=windows - else - tcl_cv_sys_version=`uname -s`-`uname -r` - if test "$?" -ne 0 ; then - AC_MSG_WARN([can't find uname command]) - tcl_cv_sys_version=unknown - else - if test "`uname -s`" = "AIX" ; then - tcl_cv_sys_version=AIX-`uname -v`.`uname -r` - fi - if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then - tcl_cv_sys_version=NetBSD-Debian - fi - fi - fi - ]) - system=$tcl_cv_sys_version -]) - -#-------------------------------------------------------------------- -# TEA_CONFIG_CFLAGS -# -# Try to determine the proper flags to pass to the compiler -# for building shared libraries and other such nonsense. -# -# Arguments: -# none -# -# Results: -# -# Defines and substitutes the following vars: -# -# DL_OBJS, DL_LIBS - removed for TEA, only needed by core. -# LDFLAGS - Flags to pass to the compiler when linking object -# files into an executable application binary such -# as tclsh. -# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", -# that tell the run-time dynamic linker where to look -# for shared libraries such as libtcl.so. Depends on -# the variable LIB_RUNTIME_DIR in the Makefile. Could -# be the same as CC_SEARCH_FLAGS if ${CC} is used to link. -# CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", -# that tell the run-time dynamic linker where to look -# for shared libraries such as libtcl.so. Depends on -# the variable LIB_RUNTIME_DIR in the Makefile. -# SHLIB_CFLAGS - Flags to pass to cc when compiling the components -# of a shared library (may request position-independent -# code, among other things). -# SHLIB_LD - Base command to use for combining object files -# into a shared library. -# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when -# creating shared libraries. This symbol typically -# goes at the end of the "ld" commands that build -# shared libraries. The value of the symbol defaults to -# "${LIBS}" if all of the dependent libraries should -# be specified when creating a shared library. If -# dependent libraries should not be specified (as on -# SunOS 4.x, where they cause the link to fail, or in -# general if Tcl and Tk aren't themselves shared -# libraries), then this symbol has an empty string -# as its value. -# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable -# extensions. An empty string means we don't know how -# to use shared libraries on this platform. -# LIB_SUFFIX - Specifies everything that comes after the "libfoo" -# in a static or shared library name, using the $PACKAGE_VERSION variable -# to put the version in the right place. This is used -# by platforms that need non-standard library names. -# Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs -# to have a version after the .so, and ${PACKAGE_VERSION}.a -# on AIX, since a shared library needs to have -# a .a extension whereas shared objects for loadable -# extensions have a .so extension. Defaults to -# ${PACKAGE_VERSION}${SHLIB_SUFFIX}. -# CFLAGS_DEBUG - -# Flags used when running the compiler in debug mode -# CFLAGS_OPTIMIZE - -# Flags used when running the compiler in optimize mode -# CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_CONFIG_CFLAGS], [ - dnl TEA specific: Make sure we are initialized - AC_REQUIRE([TEA_INIT]) - - # Step 0.a: Enable 64 bit support? - - AC_MSG_CHECKING([if 64bit support is requested]) - AC_ARG_ENABLE(64bit, - AS_HELP_STRING([--enable-64bit], - [enable 64bit support (default: off)]), - [do64bit=$enableval], [do64bit=no]) - AC_MSG_RESULT([$do64bit]) - - # Step 0.b: Enable Solaris 64 bit VIS support? - - AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) - AC_ARG_ENABLE(64bit-vis, - AS_HELP_STRING([--enable-64bit-vis], - [enable 64bit Sparc VIS support (default: off)]), - [do64bitVIS=$enableval], [do64bitVIS=no]) - AC_MSG_RESULT([$do64bitVIS]) - # Force 64bit on with VIS - AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) - - # Step 0.c: Check if visibility support is available. Do this here so - # that platform specific alternatives can be used below if this fails. - - AC_CACHE_CHECK([if compiler supports visibility "hidden"], - tcl_cv_cc_visibility_hidden, [ - hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - extern __attribute__((__visibility__("hidden"))) void f(void); - void f(void) {}]], [[f();]])],[tcl_cv_cc_visibility_hidden=yes], - [tcl_cv_cc_visibility_hidden=no]) - CFLAGS=$hold_cflags]) - AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ - AC_DEFINE(MODULE_SCOPE, - [extern __attribute__((__visibility__("hidden")))], - [Compiler support for module scope symbols]) - AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) - ]) - - # Step 0.d: Disable -rpath support? - - AC_MSG_CHECKING([if rpath support is requested]) - AC_ARG_ENABLE(rpath, - AS_HELP_STRING([--disable-rpath], - [disable rpath support (default: on)]), - [doRpath=$enableval], [doRpath=yes]) - AC_MSG_RESULT([$doRpath]) - - # Set the variable "system" to hold the name and version number - # for the system. - - TEA_CONFIG_SYSTEM - - # Require ranlib early so we can override it in special cases below. - - AC_REQUIRE([AC_PROG_RANLIB]) - - # Set configuration options based on system name and version. - # This is similar to Tcl's unix/tcl.m4 except that we've added a - # "windows" case and removed some core-only vars. - - do64bit_ok=no - # default to '{$LIBS}' and set to "" on per-platform necessary basis - SHLIB_LD_LIBS='${LIBS}' - # When ld needs options to work in 64-bit mode, put them in - # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] - # is disabled by the user. [Bug 1016796] - LDFLAGS_ARCH="" - UNSHARED_LIB_SUFFIX="" - # TEA specific: use PACKAGE_VERSION instead of VERSION - TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' - ECHO_VERSION='`echo ${PACKAGE_VERSION}`' - TCL_LIB_VERSIONS_OK=ok - CFLAGS_DEBUG=-g - AS_IF([test "$GCC" = yes], [ - CFLAGS_OPTIMIZE=-O2 - CFLAGS_WARNING="-Wall" - ], [ - CFLAGS_OPTIMIZE=-O - CFLAGS_WARNING="" - ]) - AC_CHECK_TOOL(AR, ar) - STLIB_LD='${AR} cr' - LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" - AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) - case $system in - # TEA specific: - windows) - MACHINE="X86" - if test "$do64bit" != "no" ; then - case "$do64bit" in - amd64|x64|yes) - MACHINE="AMD64" ; # default to AMD64 64-bit build - ;; - arm64|aarch64) - MACHINE="ARM64" - ;; - ia64) - MACHINE="IA64" - ;; - esac - fi - - if test "$GCC" != "yes" ; then - if test "${SHARED_BUILD}" = "0" ; then - runtime=-MT - else - runtime=-MD - fi - case "x`echo \${VisualStudioVersion}`" in - x1[[4-9]]*) - lflags="${lflags} -nodefaultlib:libucrt.lib" - TEA_ADD_LIBS([ucrt.lib]) - ;; - *) - ;; - esac - - if test "$do64bit" != "no" ; then - CC="cl.exe" - RC="rc.exe" - lflags="${lflags} -nologo -MACHINE:${MACHINE} " - LINKBIN="link.exe" - CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" - CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" - # Avoid 'unresolved external symbol __security_cookie' - # errors, c.f. http://support.microsoft.com/?id=894573 - TEA_ADD_LIBS([bufferoverflowU.lib]) - else - RC="rc" - lflags="${lflags} -nologo" - LINKBIN="link" - CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" - CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" - fi - fi - - if test "$GCC" = "yes"; then - # mingw gcc mode - AC_CHECK_TOOL(RC, windres) - CFLAGS_DEBUG="-g" - CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" - SHLIB_LD='${CC} -shared' - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" - LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" - - AC_CACHE_CHECK(for cross-compile version of gcc, - ac_cv_cross, - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - #ifdef _WIN32 - #error cross-compiler - #endif - ]], [[]])], - [ac_cv_cross=yes], - [ac_cv_cross=no]) - ) - if test "$ac_cv_cross" = "yes"; then - case "$do64bit" in - amd64|x64|yes) - CC="x86_64-w64-mingw32-${CC}" - LD="x86_64-w64-mingw32-ld" - AR="x86_64-w64-mingw32-ar" - RANLIB="x86_64-w64-mingw32-ranlib" - RC="x86_64-w64-mingw32-windres" - ;; - arm64|aarch64) - CC="aarch64-w64-mingw32-clang" - LD="aarch64-w64-mingw32-ld" - AR="aarch64-w64-mingw32-ar" - RANLIB="aarch64-w64-mingw32-ranlib" - RC="aarch64-w64-mingw32-windres" - ;; - *) - CC="i686-w64-mingw32-${CC}" - LD="i686-w64-mingw32-ld" - AR="i686-w64-mingw32-ar" - RANLIB="i686-w64-mingw32-ranlib" - RC="i686-w64-mingw32-windres" - ;; - esac - fi - - else - SHLIB_LD="${LINKBIN} -dll ${lflags}" - # link -lib only works when -lib is the first arg - STLIB_LD="${LINKBIN} -lib ${lflags}" - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' - PATHTYPE=-w - # For information on what debugtype is most useful, see: - # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp - # and also - # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx - # This essentially turns it all on. - LDFLAGS_DEBUG="-debug -debugtype:cv" - LDFLAGS_OPTIMIZE="-release" - LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" - LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" - fi - - SHLIB_SUFFIX=".dll" - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' - - TCL_LIB_VERSIONS_OK=nodots - ;; - AIX-*) - AS_IF([test "$GCC" != "yes"], [ - # AIX requires the _r compiler when gcc isn't being used - case "${CC}" in - *_r|*_r\ *) - # ok ... - ;; - *) - # Make sure only first arg gets _r - CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` - ;; - esac - AC_MSG_RESULT([Using $CC for compiling with threads]) - ]) - LIBS="$LIBS -lc" - SHLIB_CFLAGS="" - SHLIB_SUFFIX=".so" - - LD_LIBRARY_PATH_VAR="LIBPATH" - - # Check to enable 64-bit flags for compiler/linker - AS_IF([test "$do64bit" = yes], [ - AS_IF([test "$GCC" = yes], [ - AC_MSG_WARN([64bit mode not supported with GCC on $system]) - ], [ - do64bit_ok=yes - CFLAGS="$CFLAGS -q64" - LDFLAGS_ARCH="-q64" - RANLIB="${RANLIB} -X64" - AR="${AR} -X64" - SHLIB_LD_FLAGS="-b64" - ]) - ]) - - AS_IF([test "`uname -m`" = ia64], [ - # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC - SHLIB_LD="/usr/ccs/bin/ld -G -z text" - AS_IF([test "$GCC" = yes], [ - CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' - ], [ - CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"' - ]) - LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' - ], [ - AS_IF([test "$GCC" = yes], [ - SHLIB_LD='${CC} -shared -Wl,-bexpall' - ], [ - SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" - LDFLAGS="$LDFLAGS -brtl" - ]) - SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" - CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - ]) - ;; - BeOS*) - SHLIB_CFLAGS="-fPIC" - SHLIB_LD='${CC} -nostart' - SHLIB_SUFFIX=".so" - - #----------------------------------------------------------- - # Check for inet_ntoa in -lbind, for BeOS (which also needs - # -lsocket, even if the network functions are in -lnet which - # is always linked to, for compatibility. - #----------------------------------------------------------- - AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) - ;; - BSD/OS-2.1*|BSD/OS-3*) - SHLIB_CFLAGS="" - SHLIB_LD="shlicc -r" - SHLIB_SUFFIX=".so" - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - ;; - BSD/OS-4.*) - SHLIB_CFLAGS="-export-dynamic -fPIC" - SHLIB_LD='${CC} -shared' - SHLIB_SUFFIX=".so" - LDFLAGS="$LDFLAGS -export-dynamic" - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - ;; - CYGWIN_*) - SHLIB_CFLAGS="" - SHLIB_LD='${CC} -shared' - SHLIB_SUFFIX=".dll" - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" - EXEEXT=".exe" - do64bit_ok=yes - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - ;; - dgux*) - SHLIB_CFLAGS="-K PIC" - SHLIB_LD='${CC} -G' - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - ;; - Haiku*) - LDFLAGS="$LDFLAGS -Wl,--export-dynamic" - SHLIB_CFLAGS="-fPIC" - SHLIB_SUFFIX=".so" - SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' - AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) - ;; - HP-UX-*.11.*) - # Use updated header definitions where possible - AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) - # TEA specific: Needed by Tcl, but not most extensions - #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) - #LIBS="$LIBS -lxnet" # Use the XOPEN network library - - AS_IF([test "`uname -m`" = ia64], [ - SHLIB_SUFFIX=".so" - ], [ - SHLIB_SUFFIX=".sl" - ]) - AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) - AS_IF([test "$tcl_ok" = yes], [ - SHLIB_CFLAGS="+z" - SHLIB_LD="ld -b" - LDFLAGS="$LDFLAGS -Wl,-E" - CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."' - LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."' - LD_LIBRARY_PATH_VAR="SHLIB_PATH" - ]) - AS_IF([test "$GCC" = yes], [ - SHLIB_LD='${CC} -shared' - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - ], [ - CFLAGS="$CFLAGS -z" - ]) - - # Check to enable 64-bit flags for compiler/linker - AS_IF([test "$do64bit" = "yes"], [ - AS_IF([test "$GCC" = yes], [ - case `${CC} -dumpmachine` in - hppa64*) - # 64-bit gcc in use. Fix flags for GNU ld. - do64bit_ok=yes - SHLIB_LD='${CC} -shared' - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - ;; - *) - AC_MSG_WARN([64bit mode not supported with GCC on $system]) - ;; - esac - ], [ - do64bit_ok=yes - CFLAGS="$CFLAGS +DD64" - LDFLAGS_ARCH="+DD64" - ]) - ]) ;; - HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) - SHLIB_SUFFIX=".sl" - AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) - AS_IF([test "$tcl_ok" = yes], [ - SHLIB_CFLAGS="+z" - SHLIB_LD="ld -b" - SHLIB_LD_LIBS="" - LDFLAGS="$LDFLAGS -Wl,-E" - CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."' - LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."' - LD_LIBRARY_PATH_VAR="SHLIB_PATH" - ]) ;; - IRIX-5.*) - SHLIB_CFLAGS="" - SHLIB_LD="ld -shared -rdata_shared" - SHLIB_SUFFIX=".so" - AC_LIBOBJ(mkstemp) - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) - ;; - IRIX-6.*) - SHLIB_CFLAGS="" - SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_SUFFIX=".so" - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) - AS_IF([test "$GCC" = yes], [ - CFLAGS="$CFLAGS -mabi=n32" - LDFLAGS="$LDFLAGS -mabi=n32" - ], [ - case $system in - IRIX-6.3) - # Use to build 6.2 compatible binaries on 6.3. - CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" - ;; - *) - CFLAGS="$CFLAGS -n32" - ;; - esac - LDFLAGS="$LDFLAGS -n32" - ]) - ;; - IRIX64-6.*) - SHLIB_CFLAGS="" - SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_SUFFIX=".so" - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) - - # Check to enable 64-bit flags for compiler/linker - - AS_IF([test "$do64bit" = yes], [ - AS_IF([test "$GCC" = yes], [ - AC_MSG_WARN([64bit mode not supported by gcc]) - ], [ - do64bit_ok=yes - SHLIB_LD="ld -64 -shared -rdata_shared" - CFLAGS="$CFLAGS -64" - LDFLAGS_ARCH="-64" - ]) - ]) - ;; - Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*) - SHLIB_CFLAGS="-fPIC" - SHLIB_SUFFIX=".so" - - # TEA specific: - CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" - - # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS - SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' - LDFLAGS="$LDFLAGS -Wl,--export-dynamic" - - case $system in - DragonFly-*|FreeBSD-*) - AS_IF([test "${TCL_THREADS}" = "1"], [ - # The -pthread needs to go in the LDFLAGS, not LIBS - LIBS=`echo $LIBS | sed s/-pthread//` - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) - ;; - esac - - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) - AS_IF([test $do64bit = yes], [ - AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ - hold_cflags=$CFLAGS - CFLAGS="$CFLAGS -m64" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], - [tcl_cv_cc_m64=yes],[tcl_cv_cc_m64=no]) - CFLAGS=$hold_cflags]) - AS_IF([test $tcl_cv_cc_m64 = yes], [ - CFLAGS="$CFLAGS -m64" - do64bit_ok=yes - ]) - ]) - - # The combo of gcc + glibc has a bug related to inlining of - # functions like strtod(). The -fno-builtin flag should address - # this problem but it does not work. The -fno-inline flag is kind - # of overkill but it works. Disable inlining only when one of the - # files in compat/*.c is being linked in. - - AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) - ;; - Lynx*) - SHLIB_CFLAGS="-fPIC" - SHLIB_SUFFIX=".so" - CFLAGS_OPTIMIZE=-02 - SHLIB_LD='${CC} -shared' - LD_FLAGS="-Wl,--export-dynamic" - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) - ;; - OpenBSD-*) - arch=`arch -s` - case "$arch" in - alpha|sparc64) - SHLIB_CFLAGS="-fPIC" - ;; - *) - SHLIB_CFLAGS="-fpic" - ;; - esac - SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' - SHLIB_SUFFIX=".so" - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' - LDFLAGS="$LDFLAGS -Wl,-export-dynamic" - CFLAGS_OPTIMIZE="-O2" - # On OpenBSD: Compile with -pthread - # Don't link with -lpthread - LIBS=`echo $LIBS | sed s/-lpthread//` - CFLAGS="$CFLAGS -pthread" - # OpenBSD doesn't do version numbers with dots. - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - TCL_LIB_VERSIONS_OK=nodots - ;; - NetBSD-*) - # NetBSD has ELF and can use 'cc -shared' to build shared libs - SHLIB_CFLAGS="-fPIC" - SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' - SHLIB_SUFFIX=".so" - LDFLAGS="$LDFLAGS -export-dynamic" - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - # The -pthread needs to go in the CFLAGS, not LIBS - LIBS=`echo $LIBS | sed s/-pthread//` - CFLAGS="$CFLAGS -pthread" - LDFLAGS="$LDFLAGS -pthread" - ;; - Darwin-*) - CFLAGS_OPTIMIZE="-Os" - SHLIB_CFLAGS="-fno-common" - # To avoid discrepancies between what headers configure sees during - # preprocessing tests and compiling tests, move any -isysroot and - # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: - CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ - awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ - if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" - CFLAGS="`echo " ${CFLAGS}" | \ - awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ - if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" - AS_IF([test $do64bit = yes], [ - case `arch` in - ppc) - AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], - tcl_cv_cc_arch_ppc64, [ - hold_cflags=$CFLAGS - CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], - [tcl_cv_cc_arch_ppc64=yes],[tcl_cv_cc_arch_ppc64=no]) - CFLAGS=$hold_cflags]) - AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ - CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" - do64bit_ok=yes - ]);; - i386) - AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], - tcl_cv_cc_arch_x86_64, [ - hold_cflags=$CFLAGS - CFLAGS="$CFLAGS -arch x86_64" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], - [tcl_cv_cc_arch_x86_64=yes],[tcl_cv_cc_arch_x86_64=no]) - CFLAGS=$hold_cflags]) - AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ - CFLAGS="$CFLAGS -arch x86_64" - do64bit_ok=yes - ]);; - *) - AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; - esac - ], [ - # Check for combined 32-bit and 64-bit fat build - AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ - && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ - fat_32_64=yes]) - ]) - # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS - SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' - AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ - hold_ldflags=$LDFLAGS - LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], - [tcl_cv_ld_single_module=yes],[tcl_cv_ld_single_module=no]) - LDFLAGS=$hold_ldflags]) - AS_IF([test $tcl_cv_ld_single_module = yes], [ - SHLIB_LD="${SHLIB_LD} -Wl,-single_module" - ]) - # TEA specific: link shlib with current and compatibility version flags - vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` - SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" - SHLIB_SUFFIX=".dylib" - LDFLAGS="$LDFLAGS -headerpad_max_install_names" - AC_CACHE_CHECK([if ld accepts -search_paths_first flag], - tcl_cv_ld_search_paths_first, [ - hold_ldflags=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-search_paths_first" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], - [tcl_cv_ld_search_paths_first=yes],[tcl_cv_ld_search_paths_first=no]) - LDFLAGS=$hold_ldflags]) - AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ - LDFLAGS="$LDFLAGS -Wl,-search_paths_first" - ]) - AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ - AC_DEFINE(MODULE_SCOPE, [__private_extern__], - [Compiler support for module scope symbols]) - tcl_cv_cc_visibility_hidden=yes - ]) - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" - # TEA specific: for combined 32 & 64 bit fat builds of Tk - # extensions, verify that 64-bit build is possible. - AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ - AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ - AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ - for v in CFLAGS CPPFLAGS LDFLAGS; do - eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' - done - CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" - LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[XrmInitialize();]])], - [tcl_cv_lib_x11_64=yes],[tcl_cv_lib_x11_64=no]) - for v in CFLAGS CPPFLAGS LDFLAGS; do - eval $v'="$hold_'$v'"' - done]) - ]) - AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ - AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ - for v in CFLAGS CPPFLAGS LDFLAGS; do - eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' - done - CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" - LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[Tk_InitStubs(NULL, "", 0);]])], - [tcl_cv_lib_tk_64=yes],[tcl_cv_lib_tk_64=no]) - for v in CFLAGS CPPFLAGS LDFLAGS; do - eval $v'="$hold_'$v'"' - done]) - ]) - # remove 64-bit arch flags from CFLAGS et al. if configuration - # does not support 64-bit. - AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ - AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) - for v in CFLAGS CPPFLAGS LDFLAGS; do - eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' - done]) - ]) - ;; - OS/390-*) - CFLAGS_OPTIMIZE="" # Optimizer is buggy - AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h - [Should OS/390 do the right thing with sockets?]) - ;; - OSF1-V*) - # Digital OSF/1 - SHLIB_CFLAGS="" - AS_IF([test "$SHARED_BUILD" = 1], [ - SHLIB_LD='ld -shared -expect_unresolved "*"' - ], [ - SHLIB_LD='ld -non_shared -expect_unresolved "*"' - ]) - SHLIB_SUFFIX=".so" - AS_IF([test $doRpath = yes], [ - CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) - AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ - CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) - # see pthread_intro(3) for pthread support on osf1, k.furukawa - CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" - CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" - LIBS=`echo $LIBS | sed s/-lpthreads//` - AS_IF([test "$GCC" = yes], [ - LIBS="$LIBS -lpthread -lmach -lexc" - ], [ - CFLAGS="$CFLAGS -pthread" - LDFLAGS="$LDFLAGS -pthread" - ]) - ;; - QNX-6*) - # QNX RTP - # This may work for all QNX, but it was only reported for v6. - SHLIB_CFLAGS="-fPIC" - SHLIB_LD="ld -Bshareable -x" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - ;; - SCO_SV-3.2*) - AS_IF([test "$GCC" = yes], [ - SHLIB_CFLAGS="-fPIC -melf" - LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" - ], [ - SHLIB_CFLAGS="-Kpic -belf" - LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" - ]) - SHLIB_LD="ld -G" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - ;; - SunOS-5.[[0-6]]) - # Careful to not let 5.10+ fall into this case - - # Note: If _REENTRANT isn't defined, then Solaris - # won't define thread-safe library routines. - - AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) - AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, - [Do we really want to follow the standard? Yes we do!]) - - SHLIB_CFLAGS="-KPIC" - SHLIB_SUFFIX=".so" - AS_IF([test "$GCC" = yes], [ - SHLIB_LD='${CC} -shared' - CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - ], [ - SHLIB_LD="/usr/ccs/bin/ld -G -z text" - CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - ]) - ;; - SunOS-5*) - # Note: If _REENTRANT isn't defined, then Solaris - # won't define thread-safe library routines. - - AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) - AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, - [Do we really want to follow the standard? Yes we do!]) - - SHLIB_CFLAGS="-KPIC" - - # Check to enable 64-bit flags for compiler/linker - AS_IF([test "$do64bit" = yes], [ - arch=`isainfo` - AS_IF([test "$arch" = "sparcv9 sparc"], [ - AS_IF([test "$GCC" = yes], [ - AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ - AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) - ], [ - do64bit_ok=yes - CFLAGS="$CFLAGS -m64 -mcpu=v9" - LDFLAGS="$LDFLAGS -m64 -mcpu=v9" - SHLIB_CFLAGS="-fPIC" - ]) - ], [ - do64bit_ok=yes - AS_IF([test "$do64bitVIS" = yes], [ - CFLAGS="$CFLAGS -xarch=v9a" - LDFLAGS_ARCH="-xarch=v9a" - ], [ - CFLAGS="$CFLAGS -xarch=v9" - LDFLAGS_ARCH="-xarch=v9" - ]) - # Solaris 64 uses this as well - #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" - ]) - ], [AS_IF([test "$arch" = "amd64 i386"], [ - AS_IF([test "$GCC" = yes], [ - case $system in - SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) - do64bit_ok=yes - CFLAGS="$CFLAGS -m64" - LDFLAGS="$LDFLAGS -m64";; - *) - AC_MSG_WARN([64bit mode not supported with GCC on $system]);; - esac - ], [ - do64bit_ok=yes - case $system in - SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) - CFLAGS="$CFLAGS -m64" - LDFLAGS="$LDFLAGS -m64";; - *) - CFLAGS="$CFLAGS -xarch=amd64" - LDFLAGS="$LDFLAGS -xarch=amd64";; - esac - ]) - ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) - ]) - - SHLIB_SUFFIX=".so" - AS_IF([test "$GCC" = yes], [ - SHLIB_LD='${CC} -shared' - CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - AS_IF([test "$do64bit_ok" = yes], [ - AS_IF([test "$arch" = "sparcv9 sparc"], [ - # We need to specify -static-libgcc or we need to - # add the path to the sparv9 libgcc. - # JH: static-libgcc is necessary for core Tcl, but may - # not be necessary for extensions. - SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" - # for finding sparcv9 libgcc, get the regular libgcc - # path, remove so name and append 'sparcv9' - #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." - #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" - ], [AS_IF([test "$arch" = "amd64 i386"], [ - # JH: static-libgcc is necessary for core Tcl, but may - # not be necessary for extensions. - SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" - ])]) - ]) - ], [ - case $system in - SunOS-5.[[1-9]][[0-9]]*) - # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS - SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; - *) - SHLIB_LD='/usr/ccs/bin/ld -G -z text';; - esac - CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' - LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' - ]) - ;; - UNIX_SV* | UnixWare-5*) - SHLIB_CFLAGS="-KPIC" - SHLIB_LD='${CC} -G' - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers - # that don't grok the -Bexport option. Test that it does. - AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ - hold_ldflags=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-Bexport" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], - [tcl_cv_ld_Bexport=yes],[tcl_cv_ld_Bexport=no]) - LDFLAGS=$hold_ldflags]) - AS_IF([test $tcl_cv_ld_Bexport = yes], [ - LDFLAGS="$LDFLAGS -Wl,-Bexport" - ]) - CC_SEARCH_FLAGS="" - LD_SEARCH_FLAGS="" - ;; - esac - - AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ - AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) - ]) - -dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so -dnl # until the end of configure, as configure's compile and link tests use -dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's -dnl # preprocessing tests use only CPPFLAGS. - AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) - - # Add in the arch flags late to ensure it wasn't removed. - # Not necessary in TEA, but this is aligned with core - LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" - - # If we're running gcc, then change the C flags for compiling shared - # libraries to the right flags for gcc, instead of those for the - # standard manufacturer compiler. - - AS_IF([test "$GCC" = yes], [ - case $system in - AIX-*) ;; - BSD/OS*) ;; - CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;; - IRIX*) ;; - NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; - Darwin-*) ;; - SCO_SV-3.2*) ;; - windows) ;; - *) SHLIB_CFLAGS="-fPIC" ;; - esac]) - - AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ - AC_DEFINE(MODULE_SCOPE, [extern], - [No Compiler support for module scope symbols]) - ]) - - AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ - # TEA specific: use PACKAGE_VERSION instead of VERSION - SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) - AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ - # TEA specific: use PACKAGE_VERSION instead of VERSION - UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) - - if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then - AC_CACHE_CHECK(for SEH support in compiler, - tcl_cv_seh, - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#define WIN32_LEAN_AND_MEAN -#include -#undef WIN32_LEAN_AND_MEAN - - int main(int argc, char** argv) { - int a, b = 0; - __try { - a = 666 / b; - } - __except (EXCEPTION_EXECUTE_HANDLER) { - return 0; - } - return 1; - } - ]])], - [tcl_cv_seh=yes], - [tcl_cv_seh=no], - [tcl_cv_seh=no]) - ) - if test "$tcl_cv_seh" = "no" ; then - AC_DEFINE(HAVE_NO_SEH, 1, - [Defined when mingw does not support SEH]) - fi - - # - # Check to see if the excpt.h include file provided contains the - # definition for EXCEPTION_DISPOSITION; if not, which is the case - # with Cygwin's version as of 2002-04-10, define it to be int, - # sufficient for getting the current code to work. - # - AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, - tcl_cv_eh_disposition, - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -# define WIN32_LEAN_AND_MEAN -# include -# undef WIN32_LEAN_AND_MEAN - ]], [[ - EXCEPTION_DISPOSITION x; - ]])], - [tcl_cv_eh_disposition=yes], - [tcl_cv_eh_disposition=no]) - ) - if test "$tcl_cv_eh_disposition" = "no" ; then - AC_DEFINE(EXCEPTION_DISPOSITION, int, - [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) - fi - - # Check to see if winnt.h defines CHAR, SHORT, and LONG - # even if VOID has already been #defined. The win32api - # used by mingw and cygwin is known to do this. - - AC_CACHE_CHECK(for winnt.h that ignores VOID define, - tcl_cv_winnt_ignore_void, - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -#define VOID void -#define WIN32_LEAN_AND_MEAN -#include -#undef WIN32_LEAN_AND_MEAN - ]], [[ - CHAR c; - SHORT s; - LONG l; - ]])], - [tcl_cv_winnt_ignore_void=yes], - [tcl_cv_winnt_ignore_void=no]) - ) - if test "$tcl_cv_winnt_ignore_void" = "yes" ; then - AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, - [Defined when cygwin/mingw ignores VOID define in winnt.h]) - fi - fi - - # See if the compiler supports casting to a union type. - # This is used to stop gcc from printing a compiler - # warning when initializing a union member. - - AC_CACHE_CHECK(for cast to union support, - tcl_cv_cast_to_union, - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ - union foo { int i; double d; }; - union foo f = (union foo) (int) 0; - ]])], - [tcl_cv_cast_to_union=yes], - [tcl_cv_cast_to_union=no]) - ) - if test "$tcl_cv_cast_to_union" = "yes"; then - AC_DEFINE(HAVE_CAST_TO_UNION, 1, - [Defined when compiler supports casting to union type.]) - fi - - AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have ?])],) - - AC_SUBST(CFLAGS_DEBUG) - AC_SUBST(CFLAGS_OPTIMIZE) - AC_SUBST(CFLAGS_WARNING) - AC_SUBST(LDFLAGS_DEBUG) - AC_SUBST(LDFLAGS_OPTIMIZE) - - AC_SUBST(STLIB_LD) - AC_SUBST(SHLIB_LD) - - AC_SUBST(SHLIB_LD_LIBS) - AC_SUBST(SHLIB_CFLAGS) - - AC_SUBST(LD_LIBRARY_PATH_VAR) - - # These must be called after we do the basic CFLAGS checks and - # verify any possible 64-bit or similar switches are necessary - TEA_TCL_EARLY_FLAGS - TEA_TCL_64BIT_FLAGS -]) - -#-------------------------------------------------------------------- -# TEA_SERIAL_PORT -# -# Determine which interface to use to talk to the serial port. -# Note that #include lines must begin in leftmost column for -# some compilers to recognize them as preprocessor directives, -# and some build environments have stdin not pointing at a -# pseudo-terminal (usually /dev/null instead.) -# -# Arguments: -# none -# -# Results: -# -# Defines only one of the following vars: -# HAVE_SYS_MODEM_H -# USE_TERMIOS -# USE_TERMIO -# USE_SGTTY -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_SERIAL_PORT], [ - AC_CHECK_HEADERS(sys/modem.h) - AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include - -int main() { - struct termios t; - if (tcgetattr(0, &t) == 0) { - cfsetospeed(&t, 0); - t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; -}]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) - if test $tcl_cv_api_serial = no ; then - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include - -int main() { - struct termio t; - if (ioctl(0, TCGETA, &t) == 0) { - t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; -}]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) - fi - if test $tcl_cv_api_serial = no ; then - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include - -int main() { - struct sgttyb t; - if (ioctl(0, TIOCGETP, &t) == 0) { - t.sg_ospeed = 0; - t.sg_flags |= ODDP | EVENP | RAW; - return 0; - } - return 1; -}]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) - fi - if test $tcl_cv_api_serial = no ; then - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include -#include - -int main() { - struct termios t; - if (tcgetattr(0, &t) == 0 - || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { - cfsetospeed(&t, 0); - t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; -}]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) - fi - if test $tcl_cv_api_serial = no; then - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include -#include - -int main() { - struct termio t; - if (ioctl(0, TCGETA, &t) == 0 - || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { - t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; - }]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) - fi - if test $tcl_cv_api_serial = no; then - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include -#include - -int main() { - struct sgttyb t; - if (ioctl(0, TIOCGETP, &t) == 0 - || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { - t.sg_ospeed = 0; - t.sg_flags |= ODDP | EVENP | RAW; - return 0; - } - return 1; -}]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=none],[tcl_cv_api_serial=none]) - fi]) - case $tcl_cv_api_serial in - termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; - termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; - sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; - esac -]) - -#-------------------------------------------------------------------- -# TEA_PATH_X -# -# Locate the X11 header files and the X11 library archive. Try -# the ac_path_x macro first, but if it doesn't find the X stuff -# (e.g. because there's no xmkmf program) then check through -# a list of possible directories. Under some conditions the -# autoconf macro will return an include directory that contains -# no include files, so double-check its result just to be safe. -# -# This should be called after TEA_CONFIG_CFLAGS as setting the -# LIBS line can confuse some configure macro magic. -# -# Arguments: -# none -# -# Results: -# -# Sets the following vars: -# XINCLUDES -# XLIBSW -# PKG_LIBS (appends to) -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_PATH_X], [ - if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then - TEA_PATH_UNIX_X - fi -]) - -AC_DEFUN([TEA_PATH_UNIX_X], [ - AC_PATH_X - not_really_there="" - if test "$no_x" = ""; then - if test "$x_includes" = ""; then - AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[],[not_really_there="yes"]) - else - if test ! -r $x_includes/X11/Xlib.h; then - not_really_there="yes" - fi - fi - fi - if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then - AC_MSG_CHECKING([for X11 header files]) - found_xincludes="no" - AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[found_xincludes="yes"],[found_xincludes="no"]) - if test "$found_xincludes" = "no"; then - dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" - for i in $dirs ; do - if test -r $i/X11/Xlib.h; then - AC_MSG_RESULT([$i]) - XINCLUDES=" -I$i" - found_xincludes="yes" - break - fi - done - fi - else - if test "$x_includes" != ""; then - XINCLUDES="-I$x_includes" - found_xincludes="yes" - fi - fi - if test "$found_xincludes" = "no"; then - AC_MSG_RESULT([couldn't find any!]) - fi - - if test "$no_x" = yes; then - AC_MSG_CHECKING([for X11 libraries]) - XLIBSW=nope - dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" - for i in $dirs ; do - if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then - AC_MSG_RESULT([$i]) - XLIBSW="-L$i -lX11" - x_libraries="$i" - break - fi - done - else - if test "$x_libraries" = ""; then - XLIBSW=-lX11 - else - XLIBSW="-L$x_libraries -lX11" - fi - fi - if test "$XLIBSW" = nope ; then - AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) - fi - if test "$XLIBSW" = nope ; then - AC_MSG_RESULT([could not find any! Using -lX11.]) - XLIBSW=-lX11 - fi - # TEA specific: - if test x"${XLIBSW}" != x ; then - PKG_LIBS="${PKG_LIBS} ${XLIBSW}" - fi -]) - -#-------------------------------------------------------------------- -# TEA_BLOCKING_STYLE -# -# The statements below check for systems where POSIX-style -# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. -# On these systems (mostly older ones), use the old BSD-style -# FIONBIO approach instead. -# -# Arguments: -# none -# -# Results: -# -# Defines some of the following vars: -# HAVE_SYS_IOCTL_H -# HAVE_SYS_FILIO_H -# USE_FIONBIO -# O_NONBLOCK -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_BLOCKING_STYLE], [ - AC_CHECK_HEADERS(sys/ioctl.h) - AC_CHECK_HEADERS(sys/filio.h) - TEA_CONFIG_SYSTEM - AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) - case $system in - OSF*) - AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) - AC_MSG_RESULT([FIONBIO]) - ;; - *) - AC_MSG_RESULT([O_NONBLOCK]) - ;; - esac -]) - -#-------------------------------------------------------------------- -# TEA_TIME_HANDLER -# -# Checks how the system deals with time.h, what time structures -# are used on the system, and what fields the structures have. -# -# Arguments: -# none -# -# Results: -# -# Defines some of the following vars: -# USE_DELTA_FOR_TZ -# HAVE_TM_GMTOFF -# HAVE_TM_TZADJ -# HAVE_TIMEZONE_VAR -# -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_TIME_HANDLER], [ - AC_CHECK_HEADERS(sys/time.h) - AC_HEADER_TIME - AC_STRUCT_TIMEZONE - - AC_CHECK_FUNCS(gmtime_r localtime_r mktime) - - AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)tm.tm_tzadj;]])], - [tcl_cv_member_tm_tzadj=yes], - [tcl_cv_member_tm_tzadj=no])]) - if test $tcl_cv_member_tm_tzadj = yes ; then - AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) - fi - - AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)tm.tm_gmtoff;]])], - [tcl_cv_member_tm_gmtoff=yes], - [tcl_cv_member_tm_gmtoff=no])]) - if test $tcl_cv_member_tm_gmtoff = yes ; then - AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) - fi - - # - # Its important to include time.h in this check, as some systems - # (like convex) have timezone functions, etc. - # - AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], - [[extern long timezone; - timezone += 1; - exit (0);]])], - [tcl_cv_timezone_long=yes], [tcl_cv_timezone_long=no])]) - if test $tcl_cv_timezone_long = yes ; then - AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) - else - # - # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. - # - AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], - [[extern time_t timezone; - timezone += 1; - exit (0);]])], - [tcl_cv_timezone_time=yes], [tcl_cv_timezone_time=no])]) - if test $tcl_cv_timezone_time = yes ; then - AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) - fi - fi -]) - -#-------------------------------------------------------------------- -# TEA_BUGGY_STRTOD -# -# Under Solaris 2.4, strtod returns the wrong value for the -# terminating character under some conditions. Check for this -# and if the problem exists use a substitute procedure -# "fixstrtod" (provided by Tcl) that corrects the error. -# Also, on Compaq's Tru64 Unix 5.0, -# strtod(" ") returns 0.0 instead of a failure to convert. -# -# Arguments: -# none -# -# Results: -# -# Might defines some of the following vars: -# strtod (=fixstrtod) -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_BUGGY_STRTOD], [ - AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) - if test "$tcl_strtod" = 1; then - AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ - AC_RUN_IFELSE([AC_LANG_SOURCE([[ - #include - extern double strtod(); - int main() { - char *infString="Inf", *nanString="NaN", *spaceString=" "; - char *term; - double value; - value = strtod(infString, &term); - if ((term != infString) && (term[-1] == 0)) { - exit(1); - } - value = strtod(nanString, &term); - if ((term != nanString) && (term[-1] == 0)) { - exit(1); - } - value = strtod(spaceString, &term); - if (term == (spaceString+1)) { - exit(1); - } - exit(0); - }]])], [tcl_cv_strtod_buggy=ok], [tcl_cv_strtod_buggy=buggy], - [tcl_cv_strtod_buggy=buggy])]) - if test "$tcl_cv_strtod_buggy" = buggy; then - AC_LIBOBJ([fixstrtod]) - USE_COMPAT=1 - AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) - fi - fi -]) - -#-------------------------------------------------------------------- -# TEA_TCL_LINK_LIBS -# -# Search for the libraries needed to link the Tcl shell. -# Things like the math library (-lm), socket stuff (-lsocket vs. -# -lnsl), zlib (-lz) and libtommath (-ltommath) are dealt with here. -# -# Arguments: -# None. -# -# Results: -# -# Might append to the following vars: -# LIBS -# MATH_LIBS -# -# Might define the following vars: -# HAVE_NET_ERRNO_H -# -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_TCL_LINK_LIBS], [ - #-------------------------------------------------------------------- - # On a few very rare systems, all of the libm.a stuff is - # already in libc.a. Set compiler flags accordingly. - #-------------------------------------------------------------------- - - AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") - - #-------------------------------------------------------------------- - # Interactive UNIX requires -linet instead of -lsocket, plus it - # needs net/errno.h to define the socket-related error codes. - #-------------------------------------------------------------------- - - AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) - AC_CHECK_HEADER(net/errno.h, [ - AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) - - #-------------------------------------------------------------------- - # Check for the existence of the -lsocket and -lnsl libraries. - # The order here is important, so that they end up in the right - # order in the command line generated by make. Here are some - # special considerations: - # 1. Use "connect" and "accept" to check for -lsocket, and - # "gethostbyname" to check for -lnsl. - # 2. Use each function name only once: can't redo a check because - # autoconf caches the results of the last check and won't redo it. - # 3. Use -lnsl and -lsocket only if they supply procedures that - # aren't already present in the normal libraries. This is because - # IRIX 5.2 has libraries, but they aren't needed and they're - # bogus: they goof up name resolution if used. - # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. - # To get around this problem, check for both libraries together - # if -lsocket doesn't work by itself. - #-------------------------------------------------------------------- - - tcl_checkBoth=0 - AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) - if test "$tcl_checkSocket" = 1; then - AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, - LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) - fi - if test "$tcl_checkBoth" = 1; then - tk_oldLibs=$LIBS - LIBS="$LIBS -lsocket -lnsl" - AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) - fi - AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, - [LIBS="$LIBS -lnsl"])]) - AC_CHECK_FUNC(mp_log_u32, , [AC_CHECK_LIB(tommath, mp_log_u32, - [LIBS="$LIBS -ltommath"])]) - AC_CHECK_FUNC(deflateSetHeader, , [AC_CHECK_LIB(z, deflateSetHeader, - [LIBS="$LIBS -lz"])]) -]) - -#-------------------------------------------------------------------- -# TEA_TCL_EARLY_FLAGS -# -# Check for what flags are needed to be passed so the correct OS -# features are available. -# -# Arguments: -# None -# -# Results: -# -# Might define the following vars: -# _ISOC99_SOURCE -# _FILE_OFFSET_BITS -# -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_TCL_EARLY_FLAG],[ - AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]], [[$3]])], - [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ ]m4_default([$4],[1])[ -]$2]], [[$3]])], - [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, - [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no)])) - if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then - AC_DEFINE($1, m4_default([$4],[1]), [Add the ]$1[ flag when building]) - tcl_flags="$tcl_flags $1" - fi -]) - -AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ - AC_MSG_CHECKING([for required early compiler flags]) - tcl_flags="" - TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], - [char *p = (char *)strtoll; char *q = (char *)strtoull;]) - if test "${TCL_MAJOR_VERSION}" -ne 8 ; then - TEA_TCL_EARLY_FLAG(_FILE_OFFSET_BITS,[#include ], - [switch (0) { case 0: case (sizeof(off_t)==sizeof(long long)): ; }],64) - fi - if test "x${tcl_flags}" = "x" ; then - AC_MSG_RESULT([none]) - else - AC_MSG_RESULT([${tcl_flags}]) - fi -]) - -#-------------------------------------------------------------------- -# TEA_TCL_64BIT_FLAGS -# -# Check for what is defined in the way of 64-bit features. -# -# Arguments: -# None -# -# Results: -# -# Might define the following vars: -# TCL_WIDE_INT_IS_LONG -# TCL_WIDE_INT_TYPE -# HAVE_STRUCT_DIRENT64, HAVE_DIR64 -# HAVE_STRUCT_STAT64 -# HAVE_TYPE_OFF64_T -# _TIME_BITS -# -#-------------------------------------------------------------------- - -AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ - AC_MSG_CHECKING([for 64-bit integer type]) - AC_CACHE_VAL(tcl_cv_type_64bit,[ - tcl_cv_type_64bit=none - # See if the compiler knows natively about __int64 - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[__int64 value = (__int64) 0;]])], - [tcl_type_64bit=__int64],[tcl_type_64bit="long long"]) - # See if we could use long anyway Note that we substitute in the - # type that is our current guess for a 64-bit type inside this check - # program, so it should be modified only carefully... - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[switch (0) { - case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; - }]])],[tcl_cv_type_64bit=${tcl_type_64bit}],[])]) - if test "${tcl_cv_type_64bit}" = none ; then - AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Do 'long' and 'long long' have the same size (64-bit)?]) - AC_MSG_RESULT([yes]) - elif test "${tcl_cv_type_64bit}" = "__int64" \ - -a "${TEA_PLATFORM}" = "windows" ; then - # TEA specific: We actually want to use the default tcl.h checks in - # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* - AC_MSG_RESULT([using Tcl header defaults]) - else - AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, - [What type should be used to define wide integers?]) - AC_MSG_RESULT([${tcl_cv_type_64bit}]) - - # Now check for auxiliary declarations - if test "${TCL_MAJOR_VERSION}" -ne 8 ; then - AC_CACHE_CHECK([for 64-bit time_t], tcl_cv_time_t_64,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])], - [tcl_cv_time_t_64=yes],[tcl_cv_time_t_64=no])]) - if test "x${tcl_cv_time_t_64}" = "xno" ; then - # Note that _TIME_BITS=64 requires _FILE_OFFSET_BITS=64 - # which SC_TCL_EARLY_FLAGS has defined if necessary. - AC_CACHE_CHECK([if _TIME_BITS=64 enables 64-bit time_t], tcl_cv__time_bits,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define _TIME_BITS 64 -#include ]], - [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])], - [tcl_cv__time_bits=yes],[tcl_cv__time_bits=no])]) - if test "x${tcl_cv__time_bits}" = "xyes" ; then - AC_DEFINE(_TIME_BITS, 64, [_TIME_BITS=64 enables 64-bit time_t.]) - fi - fi - fi - - AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], [[struct dirent64 p;]])], - [tcl_cv_struct_dirent64=yes],[tcl_cv_struct_dirent64=no])]) - if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then - AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) - fi - - AC_CACHE_CHECK([for DIR64], tcl_cv_DIR64,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include -#include ]], [[struct dirent64 *p; DIR64 d = opendir64("."); - p = readdir64(d); rewinddir64(d); closedir64(d);]])], - [tcl_cv_DIR64=yes], [tcl_cv_DIR64=no])]) - if test "x${tcl_cv_DIR64}" = "xyes" ; then - AC_DEFINE(HAVE_DIR64, 1, [Is 'DIR64' in ?]) - fi - - AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct stat64 p; -]])], - [tcl_cv_struct_stat64=yes], [tcl_cv_struct_stat64=no])]) - if test "x${tcl_cv_struct_stat64}" = "xyes" ; then - AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) - fi - - AC_CHECK_FUNCS(open64 lseek64) - AC_MSG_CHECKING([for off64_t]) - AC_CACHE_VAL(tcl_cv_type_off64_t,[ - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[off64_t offset; -]])], - [tcl_cv_type_off64_t=yes], [tcl_cv_type_off64_t=no])]) - dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the - dnl functions lseek64 and open64 are defined. - if test "x${tcl_cv_type_off64_t}" = "xyes" && \ - test "x${ac_cv_func_lseek64}" = "xyes" && \ - test "x${ac_cv_func_open64}" = "xyes" ; then - AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - fi - fi -]) - -## -## Here ends the standard Tcl configuration bits and starts the -## TEA specific functions -## - -#------------------------------------------------------------------------ -# TEA_INIT -- -# -# Init various Tcl Extension Architecture (TEA) variables. -# This should be the first called TEA_* macro. -# -# Arguments: -# none -# -# Results: -# -# Defines and substs the following vars: -# CYGPATH -# EXEEXT -# Defines only: -# TEA_VERSION -# TEA_INITED -# TEA_PLATFORM (windows or unix) -# -# "cygpath" is used on windows to generate native path names for include -# files. These variables should only be used with the compiler and linker -# since they generate native path names. -# -# EXEEXT -# Select the executable extension based on the host type. This -# is a lightweight replacement for AC_EXEEXT that doesn't require -# a compiler. -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_INIT], [ - TEA_VERSION="3.13" - - AC_MSG_CHECKING([TEA configuration]) - if test x"${PACKAGE_NAME}" = x ; then - AC_MSG_ERROR([ -The PACKAGE_NAME variable must be defined by your TEA configure.ac]) - fi - AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) - - # If the user did not set CFLAGS, set it now to keep macros - # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". - if test "${CFLAGS+set}" != "set" ; then - CFLAGS="" - fi - - case "`uname -s`" in - *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*) - AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) - EXEEXT=".exe" - TEA_PLATFORM="windows" - ;; - *CYGWIN_*) - EXEEXT=".exe" - # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG - ;; - *) - CYGPATH=echo - # Maybe we are cross-compiling.... - case ${host_alias} in - *mingw32*) - EXEEXT=".exe" - TEA_PLATFORM="windows" - ;; - *) - EXEEXT="" - TEA_PLATFORM="unix" - ;; - esac - ;; - esac - - # Check if exec_prefix is set. If not use fall back to prefix. - # Note when adjusted, so that TEA_PREFIX can correct for this. - # This is needed for recursive configures, since autoconf propagates - # $prefix, but not $exec_prefix (doh!). - if test x$exec_prefix = xNONE ; then - exec_prefix_default=yes - exec_prefix=$prefix - fi - - AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) - - AC_SUBST(EXEEXT) - AC_SUBST(CYGPATH) - - # This package name must be replaced statically for AC_SUBST to work - AC_SUBST(PKG_LIB_FILE) - AC_SUBST(PKG_LIB_FILE8) - AC_SUBST(PKG_LIB_FILE9) - - # We AC_SUBST these here to ensure they are subst'ed, - # in case the user doesn't call TEA_ADD_... - AC_SUBST(PKG_STUB_SOURCES) - AC_SUBST(PKG_STUB_OBJECTS) - AC_SUBST(PKG_TCL_SOURCES) - AC_SUBST(PKG_HEADERS) - AC_SUBST(PKG_INCLUDES) - AC_SUBST(PKG_LIBS) - AC_SUBST(PKG_CFLAGS) - - # Configure the installer. - TEA_INSTALLER -]) - -#------------------------------------------------------------------------ -# TEA_ADD_SOURCES -- -# -# Specify one or more source files. Users should check for -# the right platform before adding to their list. -# It is not important to specify the directory, as long as it is -# in the generic, win or unix subdirectory of $(srcdir). -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_SOURCES -# PKG_OBJECTS -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_SOURCES], [ - vars="$@" - for i in $vars; do - case $i in - [\$]*) - # allow $-var names - PKG_SOURCES="$PKG_SOURCES $i" - PKG_OBJECTS="$PKG_OBJECTS $i" - ;; - *) - # check for existence - allows for generic/win/unix VPATH - # To add more dirs here (like 'src'), you have to update VPATH - # in Makefile.in as well - if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ - -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ - -a ! -f "${srcdir}/macosx/$i" \ - ; then - AC_MSG_ERROR([could not find source file '$i']) - fi - PKG_SOURCES="$PKG_SOURCES $i" - # this assumes it is in a VPATH dir - i=`basename $i` - # handle user calling this before or after TEA_SETUP_COMPILER - if test x"${OBJEXT}" != x ; then - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" - else - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" - fi - PKG_OBJECTS="$PKG_OBJECTS $j" - ;; - esac - done - AC_SUBST(PKG_SOURCES) - AC_SUBST(PKG_OBJECTS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_STUB_SOURCES -- -# -# Specify one or more source files. Users should check for -# the right platform before adding to their list. -# It is not important to specify the directory, as long as it is -# in the generic, win or unix subdirectory of $(srcdir). -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_STUB_SOURCES -# PKG_STUB_OBJECTS -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_STUB_SOURCES], [ - vars="$@" - for i in $vars; do - # check for existence - allows for generic/win/unix VPATH - if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ - -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ - -a ! -f "${srcdir}/macosx/$i" \ - ; then - AC_MSG_ERROR([could not find stub source file '$i']) - fi - PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" - # this assumes it is in a VPATH dir - i=`basename $i` - # handle user calling this before or after TEA_SETUP_COMPILER - if test x"${OBJEXT}" != x ; then - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" - else - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" - fi - PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" - done - AC_SUBST(PKG_STUB_SOURCES) - AC_SUBST(PKG_STUB_OBJECTS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_TCL_SOURCES -- -# -# Specify one or more Tcl source files. These should be platform -# independent runtime files. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_TCL_SOURCES -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_TCL_SOURCES], [ - vars="$@" - for i in $vars; do - # check for existence, be strict because it is installed - if test ! -f "${srcdir}/$i" ; then - AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) - fi - PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" - done - AC_SUBST(PKG_TCL_SOURCES) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_HEADERS -- -# -# Specify one or more source headers. Users should check for -# the right platform before adding to their list. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_HEADERS -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_HEADERS], [ - vars="$@" - for i in $vars; do - # check for existence, be strict because it is installed - if test ! -f "${srcdir}/$i" ; then - AC_MSG_ERROR([could not find header file '${srcdir}/$i']) - fi - PKG_HEADERS="$PKG_HEADERS $i" - done - AC_SUBST(PKG_HEADERS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_INCLUDES -- -# -# Specify one or more include dirs. Users should check for -# the right platform before adding to their list. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_INCLUDES -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_INCLUDES], [ - vars="$@" - for i in $vars; do - PKG_INCLUDES="$PKG_INCLUDES $i" - done - AC_SUBST(PKG_INCLUDES) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_LIBS -- -# -# Specify one or more libraries. Users should check for -# the right platform before adding to their list. For Windows, -# libraries provided in "foo.lib" format will be converted to -# "-lfoo" when using GCC (mingw). -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_LIBS -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_LIBS], [ - vars="$@" - for i in $vars; do - if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then - # Convert foo.lib to -lfoo for GCC. No-op if not *.lib - i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.[[lL]][[iI]][[bB]][$]/-l\1/'` - fi - PKG_LIBS="$PKG_LIBS $i" - done - AC_SUBST(PKG_LIBS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_CFLAGS -- -# -# Specify one or more CFLAGS. Users should check for -# the right platform before adding to their list. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_CFLAGS -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_CFLAGS], [ - PKG_CFLAGS="$PKG_CFLAGS $@" - AC_SUBST(PKG_CFLAGS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_CLEANFILES -- -# -# Specify one or more CLEANFILES. -# -# Arguments: -# one or more file names to clean target -# -# Results: -# -# Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG -#------------------------------------------------------------------------ -AC_DEFUN([TEA_ADD_CLEANFILES], [ - CLEANFILES="$CLEANFILES $@" -]) - -#------------------------------------------------------------------------ -# TEA_PREFIX -- -# -# Handle the --prefix=... option by defaulting to what Tcl gave -# -# Arguments: -# none -# -# Results: -# -# If --prefix or --exec-prefix was not specified, $prefix and -# $exec_prefix will be set to the values given to Tcl when it was -# configured. -#------------------------------------------------------------------------ -AC_DEFUN([TEA_PREFIX], [ - if test "${prefix}" = "NONE"; then - prefix_default=yes - if test x"${TCL_PREFIX}" != x; then - AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) - prefix=${TCL_PREFIX} - else - AC_MSG_NOTICE([--prefix defaulting to /usr/local]) - prefix=/usr/local - fi - fi - if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ - -o x"${exec_prefix_default}" = x"yes" ; then - if test x"${TCL_EXEC_PREFIX}" != x; then - AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) - exec_prefix=${TCL_EXEC_PREFIX} - else - AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) - exec_prefix=$prefix - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_SETUP_COMPILER_CC -- -# -# Do compiler checks the way we want. This is just a replacement -# for AC_PROG_CC in TEA configure.ac files to make them cleaner. -# -# Arguments: -# none -# -# Results: -# -# Sets up CC var and other standard bits we need to make executables. -#------------------------------------------------------------------------ -AC_DEFUN([TEA_SETUP_COMPILER_CC], [ - # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) - # in this macro, they need to go into TEA_SETUP_COMPILER instead. - - AC_PROG_CC - AC_PROG_CPP - - #-------------------------------------------------------------------- - # Checks to see if the make program sets the $MAKE variable. - #-------------------------------------------------------------------- - - AC_PROG_MAKE_SET - - #-------------------------------------------------------------------- - # Find ranlib - #-------------------------------------------------------------------- - - AC_CHECK_TOOL(RANLIB, ranlib) - - #-------------------------------------------------------------------- - # Determines the correct binary file extension (.o, .obj, .exe etc.) - #-------------------------------------------------------------------- - - AC_OBJEXT - AC_EXEEXT -]) - -#------------------------------------------------------------------------ -# TEA_SETUP_COMPILER -- -# -# Do compiler checks that use the compiler. This must go after -# TEA_SETUP_COMPILER_CC, which does the actual compiler check. -# -# Arguments: -# none -# -# Results: -# -# Sets up CC var and other standard bits we need to make executables. -#------------------------------------------------------------------------ -AC_DEFUN([TEA_SETUP_COMPILER], [ - # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. - AC_REQUIRE([TEA_SETUP_COMPILER_CC]) - - #------------------------------------------------------------------------ - # If we're using GCC, see if the compiler understands -pipe. If so, use it. - # It makes compiling go faster. (This is only a performance feature.) - #------------------------------------------------------------------------ - - if test -z "$no_pipe" -a -n "$GCC"; then - AC_CACHE_CHECK([if the compiler understands -pipe], - tcl_cv_cc_pipe, [ - hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_pipe=yes],[tcl_cv_cc_pipe=no]) - CFLAGS=$hold_cflags]) - if test $tcl_cv_cc_pipe = yes; then - CFLAGS="$CFLAGS -pipe" - fi - fi - - if test "${TCL_MAJOR_VERSION}" -lt 9 -a "${TCL_MINOR_VERSION}" -lt 7; then - AC_DEFINE(Tcl_Size, int, [Is 'Tcl_Size' in ?]) - fi - - #-------------------------------------------------------------------- - # Common compiler flag setup - #-------------------------------------------------------------------- - - AC_C_BIGENDIAN(,,,[#]) -]) - -#------------------------------------------------------------------------ -# TEA_MAKE_LIB -- -# -# Generate a line that can be used to build a shared/unshared library -# in a platform independent manner. -# -# Arguments: -# none -# -# Requires: -# -# Results: -# -# Defines the following vars: -# CFLAGS - Done late here to note disturb other AC macros -# MAKE_LIB - Command to execute to build the Tcl library; -# differs depending on whether or not Tcl is being -# compiled as a shared library. -# MAKE_SHARED_LIB Makefile rule for building a shared library -# MAKE_STATIC_LIB Makefile rule for building a static library -# MAKE_STUB_LIB Makefile rule for building a stub library -# VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL -# VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_MAKE_LIB], [ - if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then - MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" - MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" - AC_EGREP_CPP([manifest needed], [ -#if defined(_MSC_VER) && _MSC_VER >= 1400 -print("manifest needed") -#endif - ], [ - # Could do a CHECK_PROG for mt, but should always be with MSVC8+ - VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" - VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" - MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" - TEA_ADD_CLEANFILES([*.manifest]) - ]) - MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" - else - MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" - MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" - MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" - fi - - if test "${SHARED_BUILD}" = "1" ; then - MAKE_LIB="${MAKE_SHARED_LIB} " - else - MAKE_LIB="${MAKE_STATIC_LIB} " - fi - - #-------------------------------------------------------------------- - # Shared libraries and static libraries have different names. - # Use the double eval to make sure any variables in the suffix is - # substituted. (@@@ Might not be necessary anymore) - #-------------------------------------------------------------------- - - PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" - PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" - if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then - PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" - else - PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" - AC_DEFINE(TCL_MAJOR_VERSION, 8, [Compile for Tcl8?]) - fi - if test "${TEA_PLATFORM}" = "windows" ; then - if test "${SHARED_BUILD}" = "1" ; then - # We force the unresolved linking of symbols that are really in - # the private libraries of Tcl and Tk. - if test x"${TK_BIN_DIR}" != x ; then - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" - fi - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" - if test "$GCC" = "yes"; then - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" - fi - eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - else - if test "$GCC" = "yes"; then - PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX} - fi - eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - fi - # Some packages build their own stubs libraries - if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then - eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a" - else - eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" - fi - if test "$GCC" = "yes"; then - PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} - fi - # These aren't needed on Windows (either MSVC or gcc) - RANLIB=: - RANLIB_STUB=: - else - RANLIB_STUB="${RANLIB}" - if test "${SHARED_BUILD}" = "1" ; then - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" - if test x"${TK_BIN_DIR}" != x ; then - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" - fi - eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - RANLIB=: - else - eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - fi - # Some packages build their own stubs libraries - if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then - eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a" - else - eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" - fi - fi - - # These are escaped so that only CFLAGS is picked up at configure time. - # The other values will be substituted at make time. - CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" - if test "${SHARED_BUILD}" = "1" ; then - CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" - fi - - AC_SUBST(MAKE_LIB) - AC_SUBST(MAKE_SHARED_LIB) - AC_SUBST(MAKE_STATIC_LIB) - AC_SUBST(MAKE_STUB_LIB) - # Substitute STUB_LIB_FILE in case package creates a stub library too. - AC_SUBST(PKG_STUB_LIB_FILE) - AC_SUBST(RANLIB_STUB) - AC_SUBST(VC_MANIFEST_EMBED_DLL) - AC_SUBST(VC_MANIFEST_EMBED_EXE) -]) - -#------------------------------------------------------------------------ -# TEA_LIB_SPEC -- -# -# Compute the name of an existing object library located in libdir -# from the given base name and produce the appropriate linker flags. -# -# Arguments: -# basename The base name of the library without version -# numbers, extensions, or "lib" prefixes. -# extra_dir Extra directory in which to search for the -# library. This location is used first, then -# $prefix/$exec-prefix, then some defaults. -# -# Requires: -# TEA_INIT and TEA_PREFIX must be called first. -# -# Results: -# -# Defines the following vars: -# ${basename}_LIB_NAME The computed library name. -# ${basename}_LIB_SPEC The computed linker flags. -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_LIB_SPEC], [ - AC_MSG_CHECKING([for $1 library]) - - # Look in exec-prefix for the library (defined by TEA_PREFIX). - - tea_lib_name_dir="${exec_prefix}/lib" - - # Or in a user-specified location. - - if test x"$2" != x ; then - tea_extra_lib_dir=$2 - else - tea_extra_lib_dir=NONE - fi - - for i in \ - `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ - `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ - `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ - `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ - `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do - if test -f "$i" ; then - tea_lib_name_dir=`dirname $i` - $1_LIB_NAME=`basename $i` - $1_LIB_PATH_NAME=$i - break - fi - done - - if test "${TEA_PLATFORM}" = "windows"; then - $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" - else - # Strip off the leading "lib" and trailing ".a" or ".so" - - tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` - $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" - fi - - if test "x${$1_LIB_NAME}" = x ; then - AC_MSG_ERROR([not found]) - else - AC_MSG_RESULT([${$1_LIB_SPEC}]) - fi -]) - -#------------------------------------------------------------------------ -# TEA_PRIVATE_TCL_HEADERS -- -# -# Locate the private Tcl include files -# -# Arguments: -# -# Requires: -# TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has -# already been called. -# -# Results: -# -# Substitutes the following vars: -# TCL_TOP_DIR_NATIVE -# TCL_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ - # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} - AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) - AC_MSG_CHECKING([for Tcl private include files]) - - TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` - TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" - - # Check to see if tclPort.h isn't already with the public headers - # Don't look for tclInt.h because that resides with tcl.h in the core - # sources, but the Port headers are in a different directory - if test "${TEA_PLATFORM}" = "windows" -a \ - -f "${ac_cv_c_tclh}/tclWinPort.h"; then - result="private headers found with public headers" - elif test "${TEA_PLATFORM}" = "unix" -a \ - -f "${ac_cv_c_tclh}/tclUnixPort.h"; then - result="private headers found with public headers" - else - TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" - if test "${TEA_PLATFORM}" = "windows"; then - TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" - else - TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" - fi - # Overwrite the previous TCL_INCLUDES as this should capture both - # public and private headers in the same set. - # We want to ensure these are substituted so as not to require - # any *_NATIVE vars be defined in the Makefile - TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" - if test "`uname -s`" = "Darwin"; then - # If Tcl was built as a framework, attempt to use - # the framework's Headers and PrivateHeaders directories - case ${TCL_DEFS} in - *TCL_FRAMEWORK*) - if test -d "${TCL_BIN_DIR}/Headers" -a \ - -d "${TCL_BIN_DIR}/PrivateHeaders"; then - TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" - else - TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" - fi - ;; - esac - result="Using ${TCL_INCLUDES}" - else - if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then - AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) - fi - result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" - fi - fi - - AC_SUBST(TCL_TOP_DIR_NATIVE) - - AC_SUBST(TCL_INCLUDES) - AC_MSG_RESULT([${result}]) -]) - -#------------------------------------------------------------------------ -# TEA_PUBLIC_TCL_HEADERS -- -# -# Locate the installed public Tcl header files -# -# Arguments: -# None. -# -# Requires: -# CYGPATH must be set -# -# Results: -# -# Adds a --with-tclinclude switch to configure. -# Result is cached. -# -# Substitutes the following vars: -# TCL_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ - AC_MSG_CHECKING([for Tcl public headers]) - - AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) - - AC_CACHE_VAL(ac_cv_c_tclh, [ - # Use the value from --with-tclinclude, if it was given - - if test x"${with_tclinclude}" != x ; then - if test -f "${with_tclinclude}/tcl.h" ; then - ac_cv_c_tclh=${with_tclinclude} - else - AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) - fi - else - list="" - if test "`uname -s`" = "Darwin"; then - # If Tcl was built as a framework, attempt to use - # the framework's Headers directory - case ${TCL_DEFS} in - *TCL_FRAMEWORK*) - list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" - ;; - esac - fi - - # Look in the source dir only if Tcl is not installed, - # and in that situation, look there before installed locations. - if test -f "${TCL_BIN_DIR}/Makefile" ; then - list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" - fi - - # Check order: pkg --prefix location, Tcl's --prefix location, - # relative to directory of tclConfig.sh. - - eval "temp_includedir=${includedir}" - list="$list \ - `ls -d ${temp_includedir} 2>/dev/null` \ - `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ - `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" - if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then - list="$list /usr/local/include /usr/include" - if test x"${TCL_INCLUDE_SPEC}" != x ; then - d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` - list="$list `ls -d ${d} 2>/dev/null`" - fi - fi - for i in $list ; do - if test -f "$i/tcl.h" ; then - ac_cv_c_tclh=$i - break - fi - done - fi - ]) - - # Print a message based on how we determined the include path - - if test x"${ac_cv_c_tclh}" = x ; then - AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) - else - AC_MSG_RESULT([${ac_cv_c_tclh}]) - fi - - # Convert to a native path and substitute into the output files. - - INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` - - TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" - - AC_SUBST(TCL_INCLUDES) -]) - -#------------------------------------------------------------------------ -# TEA_PRIVATE_TK_HEADERS -- -# -# Locate the private Tk include files -# -# Arguments: -# -# Requires: -# TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has -# already been called. -# -# Results: -# -# Substitutes the following vars: -# TK_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ - # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} - AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) - AC_MSG_CHECKING([for Tk private include files]) - - TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` - TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" - - # Check to see if tkPort.h isn't already with the public headers - # Don't look for tkInt.h because that resides with tk.h in the core - # sources, but the Port headers are in a different directory - if test "${TEA_PLATFORM}" = "windows" -a \ - -f "${ac_cv_c_tkh}/tkWinPort.h"; then - result="private headers found with public headers" - elif test "${TEA_PLATFORM}" = "unix" -a \ - -f "${ac_cv_c_tkh}/tkUnixPort.h"; then - result="private headers found with public headers" - else - TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" - TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" - if test "${TEA_PLATFORM}" = "windows"; then - TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" - else - TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" - fi - # Overwrite the previous TK_INCLUDES as this should capture both - # public and private headers in the same set. - # We want to ensure these are substituted so as not to require - # any *_NATIVE vars be defined in the Makefile - TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" - # Detect and add ttk subdir - if test -d "${TK_SRC_DIR}/generic/ttk"; then - TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" - fi - if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then - TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" - fi - if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then - TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" - fi - if test "`uname -s`" = "Darwin"; then - # If Tk was built as a framework, attempt to use - # the framework's Headers and PrivateHeaders directories - case ${TK_DEFS} in - *TK_FRAMEWORK*) - if test -d "${TK_BIN_DIR}/Headers" -a \ - -d "${TK_BIN_DIR}/PrivateHeaders"; then - TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" - else - TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" - fi - ;; - esac - result="Using ${TK_INCLUDES}" - else - if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then - AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) - fi - result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" - fi - fi - - AC_SUBST(TK_TOP_DIR_NATIVE) - AC_SUBST(TK_XLIB_DIR_NATIVE) - - AC_SUBST(TK_INCLUDES) - AC_MSG_RESULT([${result}]) -]) - -#------------------------------------------------------------------------ -# TEA_PUBLIC_TK_HEADERS -- -# -# Locate the installed public Tk header files -# -# Arguments: -# None. -# -# Requires: -# CYGPATH must be set -# -# Results: -# -# Adds a --with-tkinclude switch to configure. -# Result is cached. -# -# Substitutes the following vars: -# TK_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ - AC_MSG_CHECKING([for Tk public headers]) - - AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) - - AC_CACHE_VAL(ac_cv_c_tkh, [ - # Use the value from --with-tkinclude, if it was given - - if test x"${with_tkinclude}" != x ; then - if test -f "${with_tkinclude}/tk.h" ; then - ac_cv_c_tkh=${with_tkinclude} - else - AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) - fi - else - list="" - if test "`uname -s`" = "Darwin"; then - # If Tk was built as a framework, attempt to use - # the framework's Headers directory. - case ${TK_DEFS} in - *TK_FRAMEWORK*) - list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" - ;; - esac - fi - - # Look in the source dir only if Tk is not installed, - # and in that situation, look there before installed locations. - if test -f "${TK_BIN_DIR}/Makefile" ; then - list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" - fi - - # Check order: pkg --prefix location, Tk's --prefix location, - # relative to directory of tkConfig.sh, Tcl's --prefix location, - # relative to directory of tclConfig.sh. - - eval "temp_includedir=${includedir}" - list="$list \ - `ls -d ${temp_includedir} 2>/dev/null` \ - `ls -d ${TK_PREFIX}/include 2>/dev/null` \ - `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ - `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ - `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" - if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then - list="$list /usr/local/include /usr/include" - if test x"${TK_INCLUDE_SPEC}" != x ; then - d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` - list="$list `ls -d ${d} 2>/dev/null`" - fi - fi - for i in $list ; do - if test -f "$i/tk.h" ; then - ac_cv_c_tkh=$i - break - fi - done - fi - ]) - - # Print a message based on how we determined the include path - - if test x"${ac_cv_c_tkh}" = x ; then - AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) - else - AC_MSG_RESULT([${ac_cv_c_tkh}]) - fi - - # Convert to a native path and substitute into the output files. - - INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` - - TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" - - AC_SUBST(TK_INCLUDES) - - if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then - # On Windows and Aqua, we need the X compat headers - AC_MSG_CHECKING([for X11 header files]) - if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then - INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" - TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" - AC_SUBST(TK_XINCLUDES) - fi - AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) - fi -]) - -#------------------------------------------------------------------------ -# TEA_PATH_CONFIG -- -# -# Locate the ${1}Config.sh file and perform a sanity check on -# the ${1} compile flags. These are used by packages like -# [incr Tk] that load *Config.sh files from more than Tcl and Tk. -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --with-$1=... -# -# Defines the following vars: -# $1_BIN_DIR Full path to the directory containing -# the $1Config.sh file -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_PATH_CONFIG], [ - # - # Ok, lets find the $1 configuration - # First, look for one uninstalled. - # the alternative search directory is invoked by --with-$1 - # - - if test x"${no_$1}" = x ; then - # we reset no_$1 in case something fails here - no_$1=true - AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) - AC_MSG_CHECKING([for $1 configuration]) - AC_CACHE_VAL(ac_cv_c_$1config,[ - - # First check to see if --with-$1 was specified. - if test x"${with_$1config}" != x ; then - case ${with_$1config} in - */$1Config.sh ) - if test -f ${with_$1config}; then - AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) - with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` - fi;; - esac - if test -f "${with_$1config}/$1Config.sh" ; then - ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` - else - AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) - fi - fi - - # then check for a private $1 installation - if test x"${ac_cv_c_$1config}" = x ; then - for i in \ - ../$1 \ - `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ../../$1 \ - `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ../../../$1 \ - `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ${srcdir}/../$1 \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ; do - if test -f "$i/$1Config.sh" ; then - ac_cv_c_$1config=`(cd $i; pwd)` - break - fi - if test -f "$i/unix/$1Config.sh" ; then - ac_cv_c_$1config=`(cd $i/unix; pwd)` - break - fi - done - fi - - # check in a few common install locations - if test x"${ac_cv_c_$1config}" = x ; then - for i in `ls -d ${libdir} 2>/dev/null` \ - `ls -d ${exec_prefix}/lib 2>/dev/null` \ - `ls -d ${prefix}/lib 2>/dev/null` \ - `ls -d /usr/local/lib 2>/dev/null` \ - `ls -d /usr/contrib/lib 2>/dev/null` \ - `ls -d /usr/pkg/lib 2>/dev/null` \ - `ls -d /usr/lib 2>/dev/null` \ - `ls -d /usr/lib64 2>/dev/null` \ - ; do - if test -f "$i/$1Config.sh" ; then - ac_cv_c_$1config=`(cd $i; pwd)` - break - fi - done - fi - ]) - - if test x"${ac_cv_c_$1config}" = x ; then - $1_BIN_DIR="# no $1 configs found" - AC_MSG_WARN([Cannot find $1 configuration definitions]) - exit 0 - else - no_$1= - $1_BIN_DIR=${ac_cv_c_$1config} - AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_LOAD_CONFIG -- -# -# Load the $1Config.sh file -# -# Arguments: -# -# Requires the following vars to be set: -# $1_BIN_DIR -# -# Results: -# -# Substitutes the following vars: -# $1_SRC_DIR -# $1_LIB_FILE -# $1_LIB_SPEC -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_LOAD_CONFIG], [ - AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) - - if test -f "${$1_BIN_DIR}/$1Config.sh" ; then - AC_MSG_RESULT([loading]) - . "${$1_BIN_DIR}/$1Config.sh" - else - AC_MSG_RESULT([file not found]) - fi - - # - # If the $1_BIN_DIR is the build directory (not the install directory), - # then set the common variable name to the value of the build variables. - # For example, the variable $1_LIB_SPEC will be set to the value - # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC - # instead of $1_BUILD_LIB_SPEC since it will work with both an - # installed and uninstalled version of Tcl. - # - - if test -f "${$1_BIN_DIR}/Makefile" ; then - AC_MSG_WARN([Found Makefile - using build library specs for $1]) - $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} - $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} - $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} - $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} - $1_LIBRARY_PATH=${$1_LIBRARY_PATH} - fi - - AC_SUBST($1_VERSION) - AC_SUBST($1_BIN_DIR) - AC_SUBST($1_SRC_DIR) - - AC_SUBST($1_LIB_FILE) - AC_SUBST($1_LIB_SPEC) - - AC_SUBST($1_STUB_LIB_FILE) - AC_SUBST($1_STUB_LIB_SPEC) - AC_SUBST($1_STUB_LIB_PATH) - - # Allow the caller to prevent this auto-check by specifying any 2nd arg - AS_IF([test "x$2" = x], [ - # Check both upper and lower-case variants - # If a dev wanted non-stubs libs, this function could take an option - # to not use _STUB in the paths below - AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], - [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], - [TEA_LOAD_CONFIG_LIB($1_STUB)]) - ]) -]) - -#------------------------------------------------------------------------ -# TEA_LOAD_CONFIG_LIB -- -# -# Helper function to load correct library from another extension's -# ${PACKAGE}Config.sh. -# -# Results: -# Adds to LIBS the appropriate extension library -#------------------------------------------------------------------------ -AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ - AC_MSG_CHECKING([For $1 library for LIBS]) - # This simplifies the use of stub libraries by automatically adding - # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, - # but this is called before CONFIG_CFLAGS. More importantly, this adds - # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. - if test "x${$1_LIB_SPEC}" != "x" ; then - if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then - TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) - AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) - else - TEA_ADD_LIBS([${$1_LIB_SPEC}]) - AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) - fi - else - AC_MSG_RESULT([file not found]) - fi -]) - -#------------------------------------------------------------------------ -# TEA_EXPORT_CONFIG -- -# -# Define the data to insert into the ${PACKAGE}Config.sh file -# -# Arguments: -# -# Requires the following vars to be set: -# $1 -# -# Results: -# Substitutes the following vars: -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_EXPORT_CONFIG], [ - #-------------------------------------------------------------------- - # These are for $1Config.sh - #-------------------------------------------------------------------- - - # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) - eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" - if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then - eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}" - eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}" - else - eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`" - eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`" - fi - if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then - eval $1_STUB_LIB_FLAG="-l$1stub" - fi - - $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" - $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" - $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" - $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" - $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" - $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" - - AC_SUBST($1_BUILD_LIB_SPEC) - AC_SUBST($1_LIB_SPEC) - AC_SUBST($1_BUILD_STUB_LIB_SPEC) - AC_SUBST($1_STUB_LIB_SPEC) - AC_SUBST($1_BUILD_STUB_LIB_PATH) - AC_SUBST($1_STUB_LIB_PATH) - - AC_SUBST(MAJOR_VERSION) - AC_SUBST(MINOR_VERSION) - AC_SUBST(PATCHLEVEL) -]) - - -#------------------------------------------------------------------------ -# TEA_INSTALLER -- -# -# Configure the installer. -# -# Arguments: -# none -# -# Results: -# Substitutes the following vars: -# INSTALL -# INSTALL_DATA_DIR -# INSTALL_DATA -# INSTALL_PROGRAM -# INSTALL_SCRIPT -# INSTALL_LIBRARY -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_INSTALLER], [ - INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' - INSTALL_DATA_DIR='${INSTALL} -d -m 755' - INSTALL_DATA='${INSTALL} -m 644' - INSTALL_PROGRAM='${INSTALL} -m 755' - INSTALL_SCRIPT='${INSTALL} -m 755' - - TEA_CONFIG_SYSTEM - case $system in - HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; - *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; - esac - - AC_SUBST(INSTALL) - AC_SUBST(INSTALL_DATA_DIR) - AC_SUBST(INSTALL_DATA) - AC_SUBST(INSTALL_PROGRAM) - AC_SUBST(INSTALL_SCRIPT) - AC_SUBST(INSTALL_LIBRARY) -]) - -### -# Tip 430 - ZipFS Modifications -### -#------------------------------------------------------------------------ -# TEA_ZIPFS_SUPPORT -# Locate a zip encoder installed on the system path, or none. -# -# Arguments: -# none -# -# Results: -# Substitutes the following vars: -# MACHER_PROG -# ZIP_PROG -# ZIP_PROG_OPTIONS -# ZIP_PROG_VFSSEARCH -# ZIP_INSTALL_OBJS -#------------------------------------------------------------------------ - -AC_DEFUN([TEA_ZIPFS_SUPPORT], [ - MACHER_PROG="" - ZIP_PROG="" - ZIP_PROG_OPTIONS="" - ZIP_PROG_VFSSEARCH="" - ZIP_INSTALL_OBJS="" - - AC_MSG_CHECKING([for macher]) - AC_CACHE_VAL(ac_cv_path_macher, [ - search_path=`echo ${PATH} | sed -e 's/:/ /g'` - for dir in $search_path ; do - for j in `ls -r $dir/macher 2> /dev/null` \ - `ls -r $dir/macher 2> /dev/null` ; do - if test x"$ac_cv_path_macher" = x ; then - if test -f "$j" ; then - ac_cv_path_macher=$j - break - fi - fi - done - done - ]) - if test -f "$ac_cv_path_macher" ; then - MACHER_PROG="$ac_cv_path_macher" - AC_MSG_RESULT([$MACHER_PROG]) - AC_MSG_RESULT([Found macher in environment]) - fi - AC_MSG_CHECKING([for zip]) - AC_CACHE_VAL(ac_cv_path_zip, [ - search_path=`echo ${PATH} | sed -e 's/:/ /g'` - for dir in $search_path ; do - for j in `ls -r $dir/zip 2> /dev/null` \ - `ls -r $dir/zip 2> /dev/null` ; do - if test x"$ac_cv_path_zip" = x ; then - if test -f "$j" ; then - ac_cv_path_zip=$j - break - fi - fi - done - done - ]) - if test -f "$ac_cv_path_zip" ; then - ZIP_PROG="$ac_cv_path_zip" - AC_MSG_RESULT([$ZIP_PROG]) - ZIP_PROG_OPTIONS="-rq" - ZIP_PROG_VFSSEARCH="*" - AC_MSG_RESULT([Found INFO Zip in environment]) - # Use standard arguments for zip - else - # It is not an error if an installed version of Zip can't be located. - # We can use the locally distributed minizip instead - ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}" - ZIP_PROG_OPTIONS="-o -r" - ZIP_PROG_VFSSEARCH="*" - ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}" - AC_MSG_RESULT([No zip found on PATH. Building minizip]) - fi - AC_SUBST(MACHER_PROG) - AC_SUBST(ZIP_PROG) - AC_SUBST(ZIP_PROG_OPTIONS) - AC_SUBST(ZIP_PROG_VFSSEARCH) - AC_SUBST(ZIP_INSTALL_OBJS) -]) - -# Local Variables: -# mode: autoconf -# End: diff --git a/autoconf/tea/teaish.tcl b/autoconf/tea/teaish.tcl new file mode 100644 index 0000000000..eedd9bdaf4 --- /dev/null +++ b/autoconf/tea/teaish.tcl @@ -0,0 +1,524 @@ +# Teaish configure script for the SQLite TCL extension + +apply {{} { + set version [proj-file-content -trim [get-define TEAISH_DIR]/../VERSION] + proj-assert {[string match 3.*.* $version]} + teaish-pkginfo-set \ + -name sqlite \ + -pkgName sqlite3 \ + -version $version \ + -loadPrefix Sqlite3 \ + -vsatisfies 8.6- \ + -libDir sqlite$version +}} + +# +# Object for communicating certain config-time state across various +# auto.def-related pieces. +# +array set sqliteConfig [subst [proj-strip-hash-comments { + # + # The list of feature --flags which the --all flag implies. This + # requires special handling in a few places. + # + all-flag-enables {fts3 fts4 fts5 rtree geopoly} +}]] + +# +# Must return either an empty string or a list in the form accepted by +# autosetup's [options] function. +# +proc teaish-options {} { + return [proj-strip-hash-comments [subst -nocommands -nobackslashes { + with-system-sqlite=0 + => {Use the system-level SQLite instead of the copy in this tree. + Also requires use of --override-sqlite-version so that the build + knows what version number to associate with the system-level SQLite.} + override-sqlite-version:VERSION + => {For use with --with-system-sqlite to set the version number.} + threadsafe=1 => {Disable mutexing} + with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always} + load-extension=0 => {Enable loading of external extensions} + math=1 => {Disable math functions} + json=1 => {Disable JSON functions} + 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=1 => {Disable $::sqliteConfig(all-flag-enables)} + with-icu-ldflags:LDFLAGS + => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the + ICU libraries. e.g. on Ubuntu systems, try '-licui18n -licuuc -licudata'.} + with-icu-cflags:CFLAGS + => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU. + e.g. -I/usr/local/include} + with-icu-config:=auto + => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config, + /path/to/icu-config} + icu-collations=0 + => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=... + or --with-icu-config} + }]] +} + +# +# Gets called by tea-configure-core. Must perform any configuration +# work needed for this extension. +# +proc teaish-configure {} { + teaish-enable-dist 0 + use teaish/feature-tests + + set srcdir [get-define TEAISH_DIR] + teaish-src-add -dist -dir generic/tclsqlite3.c + teaish-cflags-add -I${srcdir}/.. + if {[proj-opt-was-provided override-sqlite-version]} { + teaish-pkginfo-set -version [opt-val override-sqlite-version] + proj-warn "overriding sqlite version number:" [teaish-pkginfo-get -version] + } elseif {[proj-opt-was-provided with-system-sqlite] + && [opt-val with-system-sqlite] ne "0"} { + proj-fatal "when using --with-system-sqlite also use" \ + "--override-sqlite-version to specify a library version number." + } + + define CFLAGS [proj-get-env CFLAGS {-O2}] + sqlite-munge-cflags + + # + # Add feature flags from legacy configure.ac which are not covered by + # --flags. + # + sqlite-add-feature-flag { + -DSQLITE_3_SUFFIX_ONLY=1 + -DSQLITE_ENABLE_DESERIALIZE=1 + -DSQLITE_ENABLE_DBPAGE_VTAB=1 + -DSQLITE_ENABLE_BYTECODE_VTAB=1 + -DSQLITE_ENABLE_DBSTAT_VTAB=1 + } + + if {[opt-bool with-system-sqlite]} { + msg-result "Using system-level sqlite3." + teaish-cflags-add -DUSE_SYSTEM_SQLITE + teaish-ldflags-add -lsqlite3 + } + + teaish-check-librt + teaish-check-libz + sqlite-handle-threadsafe + sqlite-handle-tempstore + sqlite-handle-load-extension + sqlite-handle-math + sqlite-handle-icu + + sqlite-handle-common-feature-flags; # must be late in the process +}; # teaish-configure + + +define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags. +######################################################################## +# Adds $args, if not empty, to OPT_FEATURE_FLAGS. This is intended only for holding +# -DSQLITE_ENABLE/OMIT/... flags, but that is not enforced here. +proc sqlite-add-feature-flag {args} { + if {"" ne $args} { + define-append OPT_FEATURE_FLAGS {*}$args + } +} + +######################################################################## +# 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 sqlite-affirm-have-math {featureName} { + if {"" eq [get-define LDFLAGS_MATH ""]} { + if {![msg-quiet proj-check-function-in-lib log m]} { + user-error "Missing math APIs for $featureName" + } + set lfl [get-define lib_log ""] + undefine lib_log + if {"" ne $lfl} { + user-notice "Forcing requirement of $lfl for $featureName" + } + define LDFLAGS_MATH $lfl + teaish-ldflags-prepend $lfl + } +} + +######################################################################## +# Handle various SQLITE_ENABLE/OMIT_... feature flags. +proc sqlite-handle-common-feature-flags {} { + msg-result "Feature flags..." + if {![opt-bool all]} { + # Special handling for --disable-all + foreach flag $::sqliteConfig(all-flag-enables) { + if {![proj-opt-was-provided $flag]} { + proj-opt-set $flag 0 + } + } + } + foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments { + all {} { + # The 'all' option must be first in this list. This impl makes + # an effort to only apply flags which the user did not already + # apply, so that combinations like (--all --disable-geopoly) + # will indeed disable geopoly. There are corner cases where + # flags which depend on each other will behave in non-intuitive + # ways: + # + # --all --disable-rtree + # + # Will NOT disable geopoly, though geopoly depends on rtree. + # The --geopoly flag, though, will automatically re-enable + # --rtree, so --disable-rtree won't actually disable anything in + # that case. + foreach k $::sqliteConfig(all-flag-enables) { + if {![proj-opt-was-provided $k]} { + proj-opt-set $k 1 + } + } + } + fts3 -DSQLITE_ENABLE_FTS3 {sqlite-affirm-have-math fts3} + fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4} + fts5 -DSQLITE_ENABLE_FTS5 {sqlite-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 {} + scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {} + }] { + if {$boolFlag ni $::autosetup(options)} { + # Skip flags which are in the canonical build but not + # the autoconf bundle. + continue + } + 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 SQLITE_OMIT_... cases. If + # config option $boolFlag is false, [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" + } + } + + ######################################################################### + # Remove duplicates from the final feature flag sets and show them + # to the user. + 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]" + } + if {[lsearch [get-define TARGET_DEBUG ""] -DSQLITE_DEBUG=1] > -1} { + msg-result "Note: this is a debug build, so performance will suffer." + } + teaish-cflags-add -define OPT_FEATURE_FLAGS +}; # sqlite-handle-common-feature-flags + +######################################################################## +# If --enable-threadsafe is set, this adds -DSQLITE_THREADSAFE=1 to +# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags +# needed for linking pthread (possibly an empty string). If +# --enable-threadsafe is not set, adds -DSQLITE_THREADSAFE=0 to +# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to an empty string. +# +# It prepends the flags to the global LDFLAGS. +proc sqlite-handle-threadsafe {} { + msg-checking "Support threadsafe operation? " + define LDFLAGS_PTHREAD "" + set enable 0 + if {[proj-opt-was-provided threadsafe]} { + proj-if-opt-truthy threadsafe { + if {[proj-check-function-in-lib pthread_create pthread] + && [proj-check-function-in-lib pthread_mutexattr_init pthread]} { + incr enable + set ldf [get-define lib_pthread_create] + define LDFLAGS_PTHREAD $ldf + teaish-ldflags-prepend $ldf + undefine lib_pthread_create + undefine lib_pthread_mutexattr_init + } elseif {[proj-opt-was-provided threadsafe]} { + user-error "Missing required pthread libraries. Use --disable-threadsafe to disable this check." + } else { + msg-result "pthread support not detected" + } + # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if + # found because it's in -lc on some platforms. + } { + msg-result "Disabled using --disable-threadsafe" + } + } else { + # + # If user does not specify --[disable-]threadsafe then select a + # default based on whether it looks like TCL has threading + # support. + # + #puts "TCL_LIBS = [get-define TCL_LIBS]" + if {[string match *pthread* [get-define TCL_LIBS]]} { + # ^^^ FIXME: there must be a better way of testing this + set flagName "--threadsafe" + set lblAbled "enabled" + set enable 1 + msg-result "yes" + } else { + set flagName "--disable-threadsafe" + set lblAbled "disabled" + set enable 0 + msg-result "no" + } + msg-result "NOTICE: defaulting to ${flagName} because TCL has threading ${lblAbled}." + # ^^^ We don't need to link against -lpthread in the is-enabled case. + } + sqlite-add-feature-flag -DSQLITE_THREADSAFE=${enable} + return $enable +} + +######################################################################## +# Handles the --enable-load-extension flag. Returns 1 if the support +# is enabled, else 0. If support for that feature is not found, a +# fatal error is triggered if --enable-load-extension is explicitly +# provided, else a loud warning is instead emitted. If +# --disable-load-extension is used, no check is performed. +# +# Makes the following environment changes: +# +# - defines LDFLAGS_DLOPEN to any linker flags needed for this +# feature. It may legally be empty on some systems where dlopen() +# is in libc. +# +# - If the feature is not available, adds +# -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list. +proc sqlite-handle-load-extension {} { + define LDFLAGS_DLOPEN "" + set found 0 + proj-if-opt-truthy load-extension { + set found [proj-check-function-in-lib dlopen dl] + if {$found} { + set ldf [get-define lib_dlopen] + define LDFLAGS_DLOPEN $ldf + teaish-ldflags-prepend $ldf + undefine lib_dlopen + } else { + if {[proj-opt-was-provided load-extension]} { + # Explicit --enable-load-extension: fail if not found + proj-indented-notice -error { + --enable-load-extension was provided but dlopen() + not found. Use --disable-load-extension to bypass this + check. + } + } else { + # It was implicitly enabled: warn if not found + proj-indented-notice { + WARNING: dlopen() not found, so loadable module support will + be disabled. Use --disable-load-extension to bypass this + check. + } + } + } + } + if {$found} { + msg-result "Loadable extension support enabled." + } else { + msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them." + sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1 + } + return $found +} + +######################################################################## +# ICU - International Components for Unicode +# +# Handles these flags: +# +# --with-icu-ldflags=LDFLAGS +# --with-icu-cflags=CFLAGS +# --with-icu-config[=auto | pkg-config | /path/to/icu-config] +# --enable-icu-collations +# +# --with-icu-config values: +# +# - auto: use the first one of (pkg-config, icu-config) found on the +# system. +# - pkg-config: use only pkg-config to determine flags +# - /path/to/icu-config: use that to determine flags +# +# If --with-icu-config is used as neither pkg-config nor icu-config +# are found, fail fatally. +# +# If both --with-icu-ldflags and --with-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 could automatically enable ICU if the +# icu-config binary or (pkg-config icu-io) are found, we specifically +# do not. ICU is always an opt-in feature. +proc sqlite-handle-icu {} { + define LDFLAGS_LIBICU [join [opt-val with-icu-ldflags ""]] + define CFLAGS_LIBICU [join [opt-val with-icu-cflags ""]] + if {[proj-opt-was-provided with-icu-config]} { + msg-result "Checking for ICU support..." + set icuConfigBin [opt-val with-icu-config] + set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config + if {$icuConfigBin in {auto pkg-config}} { + uplevel 3 { use pkg-config } + if {[pkg-config-init 0] && [pkg-config icu-io]} { + # Maintenance reminder: historical docs say to use both of + # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has + # all of them on tested OSes. + set tryIcuConfigBin 0 + define LDFLAGS_LIBICU [get-define PKG_ICU_IO_LDFLAGS] + define-append LDFLAGS_LIBICU [get-define PKG_ICU_IO_LIBS] + define CFLAGS_LIBICU [get-define PKG_ICU_IO_CFLAGS] + } elseif {"pkg-config" eq $icuConfigBin} { + proj-fatal "pkg-config cannot find package icu-io" + } else { + proj-assert {"auto" eq $icuConfigBin} + } + } + if {$tryIcuConfigBin} { + if {"auto" eq $icuConfigBin} { + set icuConfigBin [proj-first-bin-of \ + /usr/local/bin/icu-config \ + /usr/bin/icu-config] + if {"" eq $icuConfigBin} { + proj-indented-notice -error { + --with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary. + On Ubuntu-like systems try: + --with-icu-ldflags='-licui18n -licuuc -licudata' + } + } + } + if {[file-isexec $icuConfigBin]} { + set x [exec $icuConfigBin --ldflags] + if {"" eq $x} { + proj-indented-notice -error \ + [subst { + $icuConfigBin --ldflags returned no data. + On Ubuntu-like systems try: + --with-icu-ldflags='-licui18n -licuuc -licudata' + }] + } + define-append LDFLAGS_LIBICU $x + set x [exec $icuConfigBin --cppflags] + define-append CFLAGS_LIBICU $x + } else { + proj-fatal "--with-icu-config=$icuConfigBin does not refer to an executable" + } + } + } + set ldflags [define LDFLAGS_LIBICU [string trim [get-define LDFLAGS_LIBICU]]] + set cflags [define CFLAGS_LIBICU [string trim [get-define CFLAGS_LIBICU]]] + if {"" ne $ldflags} { + sqlite-add-feature-flag -DSQLITE_ENABLE_ICU + msg-result "Enabling ICU support with flags: $ldflags $cflags" + if {[opt-bool icu-collations]} { + msg-result "Enabling ICU collations." + sqlite-add-feature-flag -DSQLITE_ENABLE_ICU_COLLATIONS + } + teaish-ldflags-prepend $ldflags + teaish-cflags-add $cflags + } 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-handle-icu + + +######################################################################## +# Handles the --with-tempstore flag. +# +# The test fixture likes to set SQLITE_TEMP_STORE on its own, so do +# not set that feature flag unless it was explicitly provided to the +# configure script. +proc sqlite-handle-tempstore {} { + if {[proj-opt-was-provided with-tempstore]} { + set ts [opt-val with-tempstore no] + set tsn 1 + msg-checking "Use an in-RAM database for temporary tables? " + switch -exact -- $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 + sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn + } +} + +######################################################################## +# Handles the --enable-math flag. +proc sqlite-handle-math {} { + 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." + } + set lfl [get-define lib_ceil] + undefine lib_ceil + define LDFLAGS_MATH $lfl + teaish-ldflags-prepend $lfl + sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS + msg-result "Enabling math SQL functions" + } { + define LDFLAGS_MATH "" + msg-result "Disabling math SQL functions" + } +} + +######################################################################## +# Move -DSQLITE_OMIT... and -DSQLITE_ENABLE... flags from CFLAGS and +# CPPFLAGS to OPT_FEATURE_FLAGS and remove them from BUILD_CFLAGS. +proc sqlite-munge-cflags {} { + # Move CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and + # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived + # from the legacy build and was missing the 3.48.0 release (the + # initial Autosetup port). + # https://sqlite.org/forum/forumpost/9801e54665afd728 + # + # Handling of CPPFLAGS, as well as removing ENABLE/OMIT from + # CFLAGS/CPPFLAGS, was missing in the 3.49.0 release as well. + # + # If any configure flags for features are in conflict with + # CFLAGS/CPPFLAGS-specified feature flags, all bets are off. There + # are no guarantees about which one will take precedence. + foreach flagDef {CFLAGS CPPFLAGS} { + set tmp "" + foreach cf [get-define $flagDef ""] { + switch -glob -- $cf { + -DSQLITE_OMIT* - + -DSQLITE_ENABLE* { + sqlite-add-feature-flag $cf + } + default { + lappend tmp $cf + } + } + } + define $flagDef $tmp + } +} diff --git a/autoconf/tea/teaish.test.tcl b/autoconf/tea/teaish.test.tcl new file mode 100644 index 0000000000..b63c9426e3 --- /dev/null +++ b/autoconf/tea/teaish.test.tcl @@ -0,0 +1,14 @@ +test-expect 1.0-open { + sqlite3 db :memory: +} {} + +test-assert 1.1-version-3.x { + [string match 3.* [db eval {select sqlite_version()}]] +} + +test-expect 1.2-select { + db eval {select 'hi, world',1,2,3} +} {{hi, world} 1 2 3} + + +test-expect 99.0-db-close {db close} {} diff --git a/autoconf/tea/teaish.tester.tcl.in b/autoconf/tea/teaish.tester.tcl.in new file mode 100644 index 0000000000..315d82350b --- /dev/null +++ b/autoconf/tea/teaish.tester.tcl.in @@ -0,0 +1,33 @@ +# -*- tcl -*- +# +# Unless this file is named teaish.tester.tcl.in, you are probably +# looking at an automatically generated/filtered copy and should +# probably not edit it. +# +# This is the wrapper script invoked by teaish's "make test" recipe. +@if TEAISH_VSATISFIES_TCL +if {![package vsatisfies [package provide Tcl] @TEAISH_VSATISFIES_TCL@]} { + error "Package @TEAISH_PKGNAME@ @TEAISH_VERSION@ requires Tcl @TEAISH_VSATISFIES_TCL@" +} +@endif +load [lindex $::argv 0] [lindex $::argv 1]; +source [lindex $::argv 2]; # teaish/tester.tcl +@if TEAISH_PKGINIT_TCL +apply {{file} { + set dir [file dirname $::argv0] + source $file +}} [join {@TEAISH_PKGINIT_TCL@}] +@endif +@if TEAISH_TEST_TCL +apply {{file} { + # Populate state for [tester.tcl::teaish-build-flag*] + array set ::teaish__BuildFlags @TEAISH__DEFINES_MAP@ + set dir [file normalize [file dirname $file]] + #test-fail "Just testing" + source $file +}} [join {@TEAISH_TEST_TCL@}] +@else # TEAISH_TEST_TCL +# No $TEAISH_TEST_TCL provided, so here's a default test which simply +# loads the extension. +puts {Extension @TEAISH_NAME@ @TEAISH_VERSION@ successfully loaded from @TEAISH_TESTER_TCL@} +@endif diff --git a/autoconf/tea/win/makefile.vc b/autoconf/tea/win/makefile.vc deleted file mode 100644 index bb32f1a75c..0000000000 --- a/autoconf/tea/win/makefile.vc +++ /dev/null @@ -1,61 +0,0 @@ -#------------------------------------------------------------- -*- makefile -*- -# -# Sample makefile for building Tcl extensions. -# -# Basic build, test and install -# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl -# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl test -# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl install -# -# For other build options (debug, static etc.) -# See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for -# detailed documentation. -# -# See the file "license.terms" for information on usage and redistribution -# of this file, and for a DISCLAIMER OF ALL WARRANTIES. -# -#------------------------------------------------------------------------------ - -# PROJECT is sqlite, not sqlite3 to match TEA AC_INIT definition. -# This makes the generated DLL name also consistent between the two -# except for the "t" suffix which is the convention for nmake builds. -PROJECT = sqlite -PRJ_PACKAGE_TCLNAME = sqlite3 - -!include "rules-ext.vc" - -PRJ_OBJS = $(TMP_DIR)\tclsqlite3.obj - -# Preprocessor macros specific to sqlite3. -PRJ_DEFINES = -I"$(ROOT)\.." -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE \ - -DSQLITE_ENABLE_DBPAGE_VTAB=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 \ - -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS4=1 \ - -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 \ - -DSQLITE_ENABLE_JSON1=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 \ - -DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \ - -DSQLITE_UNTESTABLE=1 -DSQLITE_OMIT_LOOKASIDE=1 \ - -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_GEOPOLY=1 \ - -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 \ - -DSQLITE_ENABLE_MATH_FUNCTIONS=1 -DDSQLITE_USE_ALLOCA=1 \ - -DSQLITE_ENABLE_STAT4=1 -DSQLITE_OMIT_DEPRECATED=1 \ - -DSQLITE_WIN32_GETVERSIONEX=0 -DSQLITE_WIN32_NO_ANSI=1 -PRJ_DEFINES = $(PRJ_DEFINES) -I$(TMP_DIR) - -# Standard targets to build, install, test etc. -!include "$(_RULESDIR)\targets.vc" - -# The built-in pkgindex does no suffice for our extension as -# the PROJECT name (sqlite) is not same as init function name (Sqlite3) -pkgindex: - @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl - @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ - [list load [file join $$dir $(PRJLIBNAME9)] [string totitle $(PRJ_PACKAGE_TCLNAME)]] >> $(OUT_DIR)\pkgIndex.tcl - @echo } else { >> $(OUT_DIR)\pkgIndex.tcl - @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ - [list load [file join $$dir $(PRJLIBNAME8)] [string totitle $(PRJ_PACKAGE_TCLNAME)]] >> $(OUT_DIR)\pkgIndex.tcl - @echo } >> $(OUT_DIR)\pkgIndex.tcl - -# Install the manpage though on Windows, doubt it does much good -install: default-install-docs-n - -# Explicit dependency rules diff --git a/autoconf/tea/win/nmakehlp.c b/autoconf/tea/win/nmakehlp.c deleted file mode 100644 index 2dc33cc657..0000000000 --- a/autoconf/tea/win/nmakehlp.c +++ /dev/null @@ -1,815 +0,0 @@ -/* - * ---------------------------------------------------------------------------- - * nmakehlp.c -- - * - * This is used to fix limitations within nmake and the environment. - * - * Copyright (c) 2002 by David Gravereaux. - * Copyright (c) 2006 by Pat Thoyts - * - * See the file "license.terms" for information on usage and redistribution of - * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * ---------------------------------------------------------------------------- - */ - -#define _CRT_SECURE_NO_DEPRECATE -#include -#ifdef _MSC_VER -#pragma comment (lib, "user32.lib") -#pragma comment (lib, "kernel32.lib") -#endif -#include -#include - -/* - * This library is required for x64 builds with _some_ versions of MSVC - */ -#if defined(_M_IA64) || defined(_M_AMD64) -#if _MSC_VER >= 1400 && _MSC_VER < 1500 -#pragma comment(lib, "bufferoverflowU") -#endif -#endif - -/* ISO hack for dumb VC++ */ -#ifdef _MSC_VER -#define snprintf _snprintf -#endif - - -/* protos */ - -static int CheckForCompilerFeature(const char *option); -static int CheckForLinkerFeature(char **options, int count); -static int IsIn(const char *string, const char *substring); -static int SubstituteFile(const char *substs, const char *filename); -static int QualifyPath(const char *path); -static int LocateDependency(const char *keyfile); -static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); -static DWORD WINAPI ReadFromPipe(LPVOID args); - -/* globals */ - -#define CHUNK 25 -#define STATICBUFFERSIZE 1000 -typedef struct { - HANDLE pipe; - char buffer[STATICBUFFERSIZE]; -} pipeinfo; - -pipeinfo Out = {INVALID_HANDLE_VALUE, ""}; -pipeinfo Err = {INVALID_HANDLE_VALUE, ""}; - -/* - * exitcodes: 0 == no, 1 == yes, 2 == error - */ - -int -main( - int argc, - char *argv[]) -{ - char msg[300]; - DWORD dwWritten; - int chars; - const char *s; - - /* - * Make sure children (cl.exe and link.exe) are kept quiet. - */ - - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); - - /* - * Make sure the compiler and linker aren't effected by the outside world. - */ - - SetEnvironmentVariable("CL", ""); - SetEnvironmentVariable("LINK", ""); - - if (argc > 1 && *argv[1] == '-') { - switch (*(argv[1]+1)) { - case 'c': - if (argc != 3) { - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -c \n" - "Tests for whether cl.exe supports an option\n" - "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, - &dwWritten, NULL); - return 2; - } - return CheckForCompilerFeature(argv[2]); - case 'l': - if (argc < 3) { - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -l ? ...?\n" - "Tests for whether link.exe supports an option\n" - "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, - &dwWritten, NULL); - return 2; - } - return CheckForLinkerFeature(&argv[2], argc-2); - case 'f': - if (argc == 2) { - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -f \n" - "Find a substring within another\n" - "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, - &dwWritten, NULL); - return 2; - } else if (argc == 3) { - /* - * If the string is blank, there is no match. - */ - - return 0; - } else { - return IsIn(argv[2], argv[3]); - } - case 's': - if (argc == 2) { - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -s \n" - "Perform a set of string map type substutitions on a file\n" - "exitcodes: 0\n", - argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, - &dwWritten, NULL); - return 2; - } - return SubstituteFile(argv[2], argv[3]); - case 'V': - if (argc != 4) { - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -V filename matchstring\n" - "Extract a version from a file:\n" - "eg: pkgIndex.tcl \"package ifneeded http\"", - argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, - &dwWritten, NULL); - return 0; - } - s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'); - if (s && *s) { - printf("%s\n", s); - return 0; - } else - return 1; /* Version not found. Return non-0 exit code */ - - case 'Q': - if (argc != 3) { - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -Q path\n" - "Emit the fully qualified path\n" - "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, - &dwWritten, NULL); - return 2; - } - return QualifyPath(argv[2]); - - case 'L': - if (argc != 3) { - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -L keypath\n" - "Emit the fully qualified path of directory containing keypath\n" - "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, - &dwWritten, NULL); - return 2; - } - return LocateDependency(argv[2]); - } - } - chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -c|-f|-l|-Q|-s|-V ...\n" - "This is a little helper app to equalize shell differences between WinNT and\n" - "Win9x and get nmake.exe to accomplish its job.\n", - argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); - return 2; -} - -static int -CheckForCompilerFeature( - const char *option) -{ - STARTUPINFO si; - PROCESS_INFORMATION pi; - SECURITY_ATTRIBUTES sa; - DWORD threadID; - char msg[300]; - BOOL ok; - HANDLE hProcess, h, pipeThreads[2]; - char cmdline[100]; - - hProcess = GetCurrentProcess(); - - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = INVALID_HANDLE_VALUE; - - ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = FALSE; - - /* - * Create a non-inheritible pipe. - */ - - CreatePipe(&Out.pipe, &h, &sa, 0); - - /* - * Dupe the write side, make it inheritible, and close the original. - */ - - DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - - /* - * Same as above, but for the error side. - */ - - CreatePipe(&Err.pipe, &h, &sa, 0); - DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - - /* - * Base command line. - */ - - lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); - - /* - * Append our option for testing - */ - - lstrcat(cmdline, option); - - /* - * Filename to compile, which exists, but is nothing and empty. - */ - - lstrcat(cmdline, " .\\nul"); - - ok = CreateProcess( - NULL, /* Module name. */ - cmdline, /* Command line. */ - NULL, /* Process handle not inheritable. */ - NULL, /* Thread handle not inheritable. */ - TRUE, /* yes, inherit handles. */ - DETACHED_PROCESS, /* No console for you. */ - NULL, /* Use parent's environment block. */ - NULL, /* Use parent's starting directory. */ - &si, /* Pointer to STARTUPINFO structure. */ - &pi); /* Pointer to PROCESS_INFORMATION structure. */ - - if (!ok) { - DWORD err = GetLastError(); - int chars = snprintf(msg, sizeof(msg) - 1, - "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars], - (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); - return 2; - } - - /* - * Close our references to the write handles that have now been inherited. - */ - - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - WaitForInputIdle(pi.hProcess, 5000); - CloseHandle(pi.hThread); - - /* - * Start the pipe reader threads. - */ - - pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); - pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); - - /* - * Block waiting for the process to end. - */ - - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - - /* - * Wait for our pipe to get done reading, should it be a little slow. - */ - - WaitForMultipleObjects(2, pipeThreads, TRUE, 500); - CloseHandle(pipeThreads[0]); - CloseHandle(pipeThreads[1]); - - /* - * Look for the commandline warning code in both streams. - * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. - */ - - return !(strstr(Out.buffer, "D4002") != NULL - || strstr(Err.buffer, "D4002") != NULL - || strstr(Out.buffer, "D9002") != NULL - || strstr(Err.buffer, "D9002") != NULL - || strstr(Out.buffer, "D2021") != NULL - || strstr(Err.buffer, "D2021") != NULL); -} - -static int -CheckForLinkerFeature( - char **options, - int count) -{ - STARTUPINFO si; - PROCESS_INFORMATION pi; - SECURITY_ATTRIBUTES sa; - DWORD threadID; - char msg[300]; - BOOL ok; - HANDLE hProcess, h, pipeThreads[2]; - int i; - char cmdline[255]; - - hProcess = GetCurrentProcess(); - - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = INVALID_HANDLE_VALUE; - - ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - - /* - * Create a non-inheritible pipe. - */ - - CreatePipe(&Out.pipe, &h, &sa, 0); - - /* - * Dupe the write side, make it inheritible, and close the original. - */ - - DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - - /* - * Same as above, but for the error side. - */ - - CreatePipe(&Err.pipe, &h, &sa, 0); - DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - - /* - * Base command line. - */ - - lstrcpy(cmdline, "link.exe -nologo "); - - /* - * Append our option for testing. - */ - - for (i = 0; i < count; i++) { - lstrcat(cmdline, " \""); - lstrcat(cmdline, options[i]); - lstrcat(cmdline, "\""); - } - - ok = CreateProcess( - NULL, /* Module name. */ - cmdline, /* Command line. */ - NULL, /* Process handle not inheritable. */ - NULL, /* Thread handle not inheritable. */ - TRUE, /* yes, inherit handles. */ - DETACHED_PROCESS, /* No console for you. */ - NULL, /* Use parent's environment block. */ - NULL, /* Use parent's starting directory. */ - &si, /* Pointer to STARTUPINFO structure. */ - &pi); /* Pointer to PROCESS_INFORMATION structure. */ - - if (!ok) { - DWORD err = GetLastError(); - int chars = snprintf(msg, sizeof(msg) - 1, - "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars], - (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); - return 2; - } - - /* - * Close our references to the write handles that have now been inherited. - */ - - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - WaitForInputIdle(pi.hProcess, 5000); - CloseHandle(pi.hThread); - - /* - * Start the pipe reader threads. - */ - - pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); - pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); - - /* - * Block waiting for the process to end. - */ - - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - - /* - * Wait for our pipe to get done reading, should it be a little slow. - */ - - WaitForMultipleObjects(2, pipeThreads, TRUE, 500); - CloseHandle(pipeThreads[0]); - CloseHandle(pipeThreads[1]); - - /* - * Look for the commandline warning code in the stderr stream. - */ - - return !(strstr(Out.buffer, "LNK1117") != NULL || - strstr(Err.buffer, "LNK1117") != NULL || - strstr(Out.buffer, "LNK4044") != NULL || - strstr(Err.buffer, "LNK4044") != NULL || - strstr(Out.buffer, "LNK4224") != NULL || - strstr(Err.buffer, "LNK4224") != NULL); -} - -static DWORD WINAPI -ReadFromPipe( - LPVOID args) -{ - pipeinfo *pi = (pipeinfo *) args; - char *lastBuf = pi->buffer; - DWORD dwRead; - BOOL ok; - - again: - if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { - CloseHandle(pi->pipe); - return (DWORD)-1; - } - ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); - if (!ok || dwRead == 0) { - CloseHandle(pi->pipe); - return 0; - } - lastBuf += dwRead; - goto again; - - return 0; /* makes the compiler happy */ -} - -static int -IsIn( - const char *string, - const char *substring) -{ - return (strstr(string, substring) != NULL); -} - -/* - * GetVersionFromFile -- - * Looks for a match string in a file and then returns the version - * following the match where a version is anything acceptable to - * package provide or package ifneeded. - */ - -static const char * -GetVersionFromFile( - const char *filename, - const char *match, - int numdots) -{ - static char szBuffer[100]; - char *szResult = NULL; - FILE *fp = fopen(filename, "rt"); - - if (fp != NULL) { - /* - * Read data until we see our match string. - */ - - while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) { - LPSTR p, q; - - p = strstr(szBuffer, match); - if (p != NULL) { - /* - * Skip to first digit after the match. - */ - - p += strlen(match); - while (*p && !isdigit((unsigned char)*p)) { - ++p; - } - - /* - * Find ending whitespace. - */ - - q = p; - while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q) - && !strchr("ab", q[-1])) || --numdots))) { - ++q; - } - - *q = 0; - szResult = p; - break; - } - } - fclose(fp); - } - return szResult; -} - -/* - * List helpers for the SubstituteFile function - */ - -typedef struct list_item_t { - struct list_item_t *nextPtr; - char * key; - char * value; -} list_item_t; - -/* insert a list item into the list (list may be null) */ -static list_item_t * -list_insert(list_item_t **listPtrPtr, const char *key, const char *value) -{ - list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t)); - if (itemPtr) { - itemPtr->key = strdup(key); - itemPtr->value = strdup(value); - itemPtr->nextPtr = NULL; - - while(*listPtrPtr) { - listPtrPtr = &(*listPtrPtr)->nextPtr; - } - *listPtrPtr = itemPtr; - } - return itemPtr; -} - -static void -list_free(list_item_t **listPtrPtr) -{ - list_item_t *tmpPtr, *listPtr = *listPtrPtr; - while (listPtr) { - tmpPtr = listPtr; - listPtr = listPtr->nextPtr; - free(tmpPtr->key); - free(tmpPtr->value); - free(tmpPtr); - } -} - -/* - * SubstituteFile -- - * As windows doesn't provide anything useful like sed and it's unreliable - * to use the tclsh you are building against (consider x-platform builds - - * eg compiling AMD64 target from IX86) we provide a simple substitution - * option here to handle autoconf style substitutions. - * The substitution file is whitespace and line delimited. The file should - * consist of lines matching the regular expression: - * \s*\S+\s+\S*$ - * - * Usage is something like: - * nmakehlp -S << $** > $@ - * @PACKAGE_NAME@ $(PACKAGE_NAME) - * @PACKAGE_VERSION@ $(PACKAGE_VERSION) - * << - */ - -static int -SubstituteFile( - const char *substitutions, - const char *filename) -{ - static char szBuffer[1024], szCopy[1024]; - list_item_t *substPtr = NULL; - FILE *fp, *sp; - - fp = fopen(filename, "rt"); - if (fp != NULL) { - - /* - * Build a list of substutitions from the first filename - */ - - sp = fopen(substitutions, "rt"); - if (sp != NULL) { - while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) { - unsigned char *ks, *ke, *vs, *ve; - ks = (unsigned char*)szBuffer; - while (ks && *ks && isspace(*ks)) ++ks; - ke = ks; - while (ke && *ke && !isspace(*ke)) ++ke; - vs = ke; - while (vs && *vs && isspace(*vs)) ++vs; - ve = vs; - while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; - *ke = 0, *ve = 0; - list_insert(&substPtr, (char*)ks, (char*)vs); - } - fclose(sp); - } - - /* debug: dump the list */ -#ifndef NDEBUG - { - int n = 0; - list_item_t *p = NULL; - for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { - fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); - } - } -#endif - - /* - * Run the substitutions over each line of the input - */ - - while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) { - list_item_t *p = NULL; - for (p = substPtr; p != NULL; p = p->nextPtr) { - char *m = strstr(szBuffer, p->key); - if (m) { - char *cp, *op, *sp; - cp = szCopy; - op = szBuffer; - while (op != m) *cp++ = *op++; - sp = p->value; - while (sp && *sp) *cp++ = *sp++; - op += strlen(p->key); - while (*op) *cp++ = *op++; - *cp = 0; - memcpy(szBuffer, szCopy, sizeof(szCopy)); - } - } - printf("%s", szBuffer); - } - - list_free(&substPtr); - } - fclose(fp); - return 0; -} - -BOOL FileExists(LPCTSTR szPath) -{ -#ifndef INVALID_FILE_ATTRIBUTES - #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - DWORD pathAttr = GetFileAttributes(szPath); - return (pathAttr != INVALID_FILE_ATTRIBUTES && - !(pathAttr & FILE_ATTRIBUTE_DIRECTORY)); -} - - -/* - * QualifyPath -- - * - * This composes the current working directory with a provided path - * and returns the fully qualified and normalized path. - * Mostly needed to setup paths for testing. - */ - -static int -QualifyPath( - const char *szPath) -{ - char szCwd[MAX_PATH + 1]; - - GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL); - printf("%s\n", szCwd); - return 0; -} - -/* - * Implements LocateDependency for a single directory. See that command - * for an explanation. - * Returns 0 if found after printing the directory. - * Returns 1 if not found but no errors. - * Returns 2 on any kind of error - * Basically, these are used as exit codes for the process. - */ -static int LocateDependencyHelper(const char *dir, const char *keypath) -{ - HANDLE hSearch; - char path[MAX_PATH+1]; - size_t dirlen; - int keylen, ret; - WIN32_FIND_DATA finfo; - - if (dir == NULL || keypath == NULL) - return 2; /* Have no real error reporting mechanism into nmake */ - dirlen = strlen(dir); - if ((dirlen + 3) > sizeof(path)) - return 2; - strncpy(path, dir, dirlen); - strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */ - keylen = strlen(keypath); - -#if 0 /* This function is not available in Visual C++ 6 */ - /* - * Use numerics 0 -> FindExInfoStandard, - * 1 -> FindExSearchLimitToDirectories, - * as these are not defined in Visual C++ 6 - */ - hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0); -#else - hSearch = FindFirstFile(path, &finfo); -#endif - if (hSearch == INVALID_HANDLE_VALUE) - return 1; /* Not found */ - - /* Loop through all subdirs checking if the keypath is under there */ - ret = 1; /* Assume not found */ - do { - int sublen; - /* - * We need to check it is a directory despite the - * FindExSearchLimitToDirectories in the above call. See SDK docs - */ - if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) - continue; - sublen = strlen(finfo.cFileName); - if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) - continue; /* Path does not fit, assume not matched */ - strncpy(path+dirlen+1, finfo.cFileName, sublen); - path[dirlen+1+sublen] = '\\'; - strncpy(path+dirlen+1+sublen+1, keypath, keylen+1); - if (FileExists(path)) { - /* Found a match, print to stdout */ - path[dirlen+1+sublen] = '\0'; - QualifyPath(path); - ret = 0; - break; - } - } while (FindNextFile(hSearch, &finfo)); - FindClose(hSearch); - return ret; -} - -/* - * LocateDependency -- - * - * Locates a dependency for a package. - * keypath - a relative path within the package directory - * that is used to confirm it is the correct directory. - * The search path for the package directory is currently only - * the parent and grandparent of the current working directory. - * If found, the command prints - * name_DIRPATH= - * and returns 0. If not found, does not print anything and returns 1. - */ -static int LocateDependency(const char *keypath) -{ - size_t i; - int ret; - static const char *paths[] = {"..", "..\\..", "..\\..\\.."}; - - for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) { - ret = LocateDependencyHelper(paths[i], keypath); - if (ret == 0) - return ret; - } - return ret; -} - - -/* - * Local variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * indent-tabs-mode: t - * tab-width: 8 - * End: - */ diff --git a/autoconf/tea/win/rules-ext.vc b/autoconf/tea/win/rules-ext.vc deleted file mode 100644 index 479720a4bc..0000000000 --- a/autoconf/tea/win/rules-ext.vc +++ /dev/null @@ -1,123 +0,0 @@ -# This file should only be included in makefiles for Tcl extensions, -# NOT in the makefile for Tcl itself. - -!ifndef _RULES_EXT_VC - -# We need to run from the directory the parent makefile is located in. -# nmake does not tell us what makefile was used to invoke it so parent -# makefile has to set the MAKEFILEVC macro or we just make a guess and -# warn if we think that is not the case. -!if "$(MAKEFILEVC)" == "" - -!if exist("$(PROJECT).vc") -MAKEFILEVC = $(PROJECT).vc -!elseif exist("makefile.vc") -MAKEFILEVC = makefile.vc -!endif -!endif # "$(MAKEFILEVC)" == "" - -!if !exist("$(MAKEFILEVC)") -MSG = ^ -You must run nmake from the directory containing the project makefile.^ -If you are doing that and getting this message, set the MAKEFILEVC^ -macro to the name of the project makefile. -!message WARNING: $(MSG) -!endif - -!if "$(PROJECT)" == "tcl" -!error The rules-ext.vc file is not intended for Tcl itself. -!endif - -# We extract version numbers using the nmakehlp program. For now use -# the local copy of nmakehlp. Once we locate Tcl, we will use that -# one if it is newer. -!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" -!if [$(CC) -nologo -DNDEBUG "nmakehlp.c" -link -subsystem:console > nul] -!endif -!else -!if [copy x86_64-w64-mingw32-nmakehlp.exe nmakehlp.exe >NUL] -!endif -!endif - -# First locate the Tcl directory that we are working with. -!if "$(TCLDIR)" != "" - -_RULESDIR = $(TCLDIR:/=\) - -!else - -# If an installation path is specified, that is also the Tcl directory. -# Also Tk never builds against an installed Tcl, it needs Tcl sources -!if defined(INSTALLDIR) && "$(PROJECT)" != "tk" -_RULESDIR=$(INSTALLDIR:/=\) -!else -# Locate Tcl sources -!if [echo _RULESDIR = \> nmakehlp.out] \ - || [nmakehlp -L generic\tcl.h >> nmakehlp.out] -_RULESDIR = ..\..\tcl -!else -!include nmakehlp.out -!endif - -!endif # defined(INSTALLDIR).... - -!endif # ifndef TCLDIR - -# Now look for the targets.vc file under the Tcl root. Note we check this -# file and not rules.vc because the latter also exists on older systems. -!if exist("$(_RULESDIR)\lib\nmake\targets.vc") # Building against installed Tcl -_RULESDIR = $(_RULESDIR)\lib\nmake -!elseif exist("$(_RULESDIR)\win\targets.vc") # Building against Tcl sources -_RULESDIR = $(_RULESDIR)\win -!else -# If we have not located Tcl's targets file, most likely we are compiling -# against an older version of Tcl and so must use our own support files. -_RULESDIR = . -!endif - -!if "$(_RULESDIR)" != "." -# Potentially using Tcl's support files. If this extension has its own -# nmake support files, need to compare the versions and pick newer. - -!if exist("rules.vc") # The extension has its own copy - -!if [echo TCL_RULES_MAJOR = \> versions.vc] \ - && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MAJOR >> versions.vc] -!endif -!if [echo TCL_RULES_MINOR = \>> versions.vc] \ - && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MINOR >> versions.vc] -!endif - -!if [echo OUR_RULES_MAJOR = \>> versions.vc] \ - && [nmakehlp -V "rules.vc" RULES_VERSION_MAJOR >> versions.vc] -!endif -!if [echo OUR_RULES_MINOR = \>> versions.vc] \ - && [nmakehlp -V "rules.vc" RULES_VERSION_MINOR >> versions.vc] -!endif -!include versions.vc -# We have a newer version of the support files, use them -!if ($(TCL_RULES_MAJOR) != $(OUR_RULES_MAJOR)) || ($(TCL_RULES_MINOR) < $(OUR_RULES_MINOR)) -_RULESDIR = . -!endif - -!endif # if exist("rules.vc") - -!endif # if $(_RULESDIR) != "." - -# Let rules.vc know what copy of nmakehlp.c to use. -NMAKEHLPC = $(_RULESDIR)\nmakehlp.c - -# Get rid of our internal defines before calling rules.vc -!undef TCL_RULES_MAJOR -!undef TCL_RULES_MINOR -!undef OUR_RULES_MAJOR -!undef OUR_RULES_MINOR - -!if exist("$(_RULESDIR)\rules.vc") -!message *** Using $(_RULESDIR)\rules.vc -!include "$(_RULESDIR)\rules.vc" -!else -!error *** Could not locate rules.vc in $(_RULESDIR) -!endif - -!endif # _RULES_EXT_VC \ No newline at end of file diff --git a/autoconf/tea/win/rules.vc b/autoconf/tea/win/rules.vc deleted file mode 100644 index 8ecce0e106..0000000000 --- a/autoconf/tea/win/rules.vc +++ /dev/null @@ -1,1913 +0,0 @@ -#------------------------------------------------------------- -*- makefile -*- -# rules.vc -- -# -# Part of the nmake based build system for Tcl and its extensions. -# This file does all the hard work in terms of parsing build options, -# compiler switches, defining common targets and macros. The Tcl makefile -# directly includes this. Extensions include it via "rules-ext.vc". -# -# See TIP 477 (https://core.tcl-lang.org/tips/doc/main/tip/477.md) for -# detailed documentation. -# -# See the file "license.terms" for information on usage and redistribution -# of this file, and for a DISCLAIMER OF ALL WARRANTIES. -# -# Copyright (c) 2001-2003 David Gravereaux. -# Copyright (c) 2003-2008 Patrick Thoyts -# Copyright (c) 2017 Ashok P. Nadkarni -#------------------------------------------------------------------------------ - -!ifndef _RULES_VC -_RULES_VC = 1 - -# The following macros define the version of the rules.vc nmake build system -# For modifications that are not backward-compatible, you *must* change -# the major version. -RULES_VERSION_MAJOR = 1 -RULES_VERSION_MINOR = 12 - -# The PROJECT macro must be defined by parent makefile. -!if "$(PROJECT)" == "" -!error *** Error: Macro PROJECT not defined! Please define it before including rules.vc -!endif - -!if "$(PRJ_PACKAGE_TCLNAME)" == "" -PRJ_PACKAGE_TCLNAME = $(PROJECT) -!endif - -# Also special case Tcl and Tk to save some typing later -DOING_TCL = 0 -DOING_TK = 0 -!if "$(PROJECT)" == "tcl" -DOING_TCL = 1 -!elseif "$(PROJECT)" == "tk" -DOING_TK = 1 -!endif - -!ifndef NEED_TK -# Backwards compatibility -!ifdef PROJECT_REQUIRES_TK -NEED_TK = $(PROJECT_REQUIRES_TK) -!else -NEED_TK = 0 -!endif -!endif - -!ifndef NEED_TCL_SOURCE -NEED_TCL_SOURCE = 0 -!endif - -!ifdef NEED_TK_SOURCE -!if $(NEED_TK_SOURCE) -NEED_TK = 1 -!endif -!else -NEED_TK_SOURCE = 0 -!endif - -################################################################ -# Nmake is a pretty weak environment in syntax and capabilities -# so this file is necessarily verbose. It's broken down into -# the following parts. -# -# 0. Sanity check that compiler environment is set up and initialize -# any built-in settings from the parent makefile -# 1. First define the external tools used for compiling, copying etc. -# as this is independent of everything else. -# 2. Figure out our build structure in terms of the directory, whether -# we are building Tcl or an extension, etc. -# 3. Determine the compiler and linker versions -# 4. Build the nmakehlp helper application -# 5. Determine the supported compiler options and features -# 6. Extract Tcl, Tk, and possibly extensions, version numbers from the -# headers -# 7. Parse the OPTS macro value for user-specified build configuration -# 8. Parse the STATS macro value for statistics instrumentation -# 9. Parse the CHECKS macro for additional compilation checks -# 10. Based on this selected configuration, construct the output -# directory and file paths -# 11. Construct the paths where the package is to be installed -# 12. Set up the actual options passed to compiler and linker based -# on the information gathered above. -# 13. Define some standard build targets and implicit rules. These may -# be optionally disabled by the parent makefile. -# 14. (For extensions only.) Compare the configuration of the target -# Tcl and the extensions and warn against discrepancies. -# -# One final note about the macro names used. They are as they are -# for historical reasons. We would like legacy extensions to -# continue to work with this make include file so be wary of -# changing them for consistency or clarity. - -# 0. Sanity check compiler environment - -# Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or -# VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir) - -!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) -MSG = ^ -Visual C++ compiler environment not initialized. -!error $(MSG) -!endif - -# We need to run from the directory the parent makefile is located in. -# nmake does not tell us what makefile was used to invoke it so parent -# makefile has to set the MAKEFILEVC macro or we just make a guess and -# warn if we think that is not the case. -!if "$(MAKEFILEVC)" == "" - -!if exist("$(PROJECT).vc") -MAKEFILEVC = $(PROJECT).vc -!elseif exist("makefile.vc") -MAKEFILEVC = makefile.vc -!endif -!endif # "$(MAKEFILEVC)" == "" - -!if !exist("$(MAKEFILEVC)") -MSG = ^ -You must run nmake from the directory containing the project makefile.^ -If you are doing that and getting this message, set the MAKEFILEVC^ -macro to the name of the project makefile. -!message WARNING: $(MSG) -!endif - - -################################################################ -# 1. Define external programs being used - -#---------------------------------------------------------- -# Set the proper copy method to avoid overwrite questions -# to the user when copying files and selecting the right -# "delete all" method. -#---------------------------------------------------------- - -RMDIR = rmdir /S /Q -CPY = xcopy /i /y >NUL -CPYDIR = xcopy /e /i /y >NUL -COPY = copy /y >NUL -MKDIR = mkdir - -###################################################################### -# 2. Figure out our build environment in terms of what we're building. -# -# (a) Tcl itself -# (b) Tk -# (c) a Tcl extension using libraries/includes from an *installed* Tcl -# (d) a Tcl extension using libraries/includes from Tcl source directory -# -# This last is needed because some extensions still need -# some Tcl interfaces that are not publicly exposed. -# -# The fragment will set the following macros: -# ROOT - root of this module sources -# COMPATDIR - source directory that holds compatibility sources -# DOCDIR - source directory containing documentation files -# GENERICDIR - platform-independent source directory -# WIN_DIR - Windows-specific source directory -# TESTDIR - directory containing test files -# TOOLSDIR - directory containing build tools -# _TCLDIR - root of the Tcl installation OR the Tcl sources. Not set -# when building Tcl itself. -# _INSTALLDIR - native form of the installation path. For Tcl -# this will be the root of the Tcl installation. For extensions -# this will be the lib directory under the root. -# TCLINSTALL - set to 1 if _TCLDIR refers to -# headers and libraries from an installed Tcl, and 0 if built against -# Tcl sources. Not set when building Tcl itself. Yes, not very well -# named. -# _TCL_H - native path to the tcl.h file -# -# If Tk is involved, also sets the following -# _TKDIR - native form Tk installation OR Tk source. Not set if building -# Tk itself. -# TKINSTALL - set 1 if _TKDIR refers to installed Tk and 0 if Tk sources -# _TK_H - native path to the tk.h file - -# Root directory for sources and assumed subdirectories -ROOT = $(MAKEDIR)\.. -# The following paths CANNOT have spaces in them as they appear on the -# left side of implicit rules. -!ifndef COMPATDIR -COMPATDIR = $(ROOT)\compat -!endif -!ifndef DOCDIR -DOCDIR = $(ROOT)\doc -!endif -!ifndef GENERICDIR -GENERICDIR = $(ROOT)\generic -!endif -!ifndef TOOLSDIR -TOOLSDIR = $(ROOT)\tools -!endif -!ifndef TESTDIR -TESTDIR = $(ROOT)\tests -!endif -!ifndef LIBDIR -!if exist("$(ROOT)\library") -LIBDIR = $(ROOT)\library -!else -LIBDIR = $(ROOT)\lib -!endif -!endif -!ifndef DEMODIR -!if exist("$(LIBDIR)\demos") -DEMODIR = $(LIBDIR)\demos -!else -DEMODIR = $(ROOT)\demos -!endif -!endif # ifndef DEMODIR -# Do NOT use WINDIR because it is Windows internal environment -# variable to point to c:\windows! -WIN_DIR = $(ROOT)\win - -!ifndef RCDIR -!if exist("$(WIN_DIR)\rc") -RCDIR = $(WIN_DIR)\rc -!else -RCDIR = $(WIN_DIR) -!endif -!endif -RCDIR = $(RCDIR:/=\) - -# The target directory where the built packages and binaries will be installed. -# INSTALLDIR is the (optional) path specified by the user. -# _INSTALLDIR is INSTALLDIR using the backslash separator syntax -!ifdef INSTALLDIR -### Fix the path separators. -_INSTALLDIR = $(INSTALLDIR:/=\) -!else -### Assume the normal default. -_INSTALLDIR = $(HOMEDRIVE)\Tcl -!endif - -!if $(DOING_TCL) - -# BEGIN Case 2(a) - Building Tcl itself - -# Only need to define _TCL_H -_TCL_H = ..\generic\tcl.h - -# END Case 2(a) - Building Tcl itself - -!elseif $(DOING_TK) - -# BEGIN Case 2(b) - Building Tk - -TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl -!if "$(TCLDIR)" == "" -!if [echo TCLDIR = \> nmakehlp.out] \ - || [nmakehlp -L generic\tcl.h >> nmakehlp.out] -!error *** Could not locate Tcl source directory. -!endif -!include nmakehlp.out -!endif # TCLDIR == "" - -_TCLDIR = $(TCLDIR:/=\) -_TCL_H = $(_TCLDIR)\generic\tcl.h -!if !exist("$(_TCL_H)") -!error Could not locate tcl.h. Please set the TCLDIR macro to point to the Tcl *source* directory. -!endif - -_TK_H = ..\generic\tk.h - -# END Case 2(b) - Building Tk - -!else - -# BEGIN Case 2(c) or (d) - Building an extension other than Tk - -# If command line has specified Tcl location through TCLDIR, use it -# else default to the INSTALLDIR setting -!if "$(TCLDIR)" != "" - -_TCLDIR = $(TCLDIR:/=\) -!if exist("$(_TCLDIR)\include\tcl.h") # Case 2(c) with TCLDIR defined -TCLINSTALL = 1 -_TCL_H = $(_TCLDIR)\include\tcl.h -!elseif exist("$(_TCLDIR)\generic\tcl.h") # Case 2(d) with TCLDIR defined -TCLINSTALL = 0 -_TCL_H = $(_TCLDIR)\generic\tcl.h -!endif - -!else # # Case 2(c) for extensions with TCLDIR undefined - -# Need to locate Tcl depending on whether it needs Tcl source or not. -# If we don't, check the INSTALLDIR for an installed Tcl first - -!if exist("$(_INSTALLDIR)\include\tcl.h") && !$(NEED_TCL_SOURCE) - -TCLINSTALL = 1 -TCLDIR = $(_INSTALLDIR)\.. -# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions -# later so the \.. accounts for the /lib -_TCLDIR = $(_INSTALLDIR)\.. -_TCL_H = $(_TCLDIR)\include\tcl.h - -!else # exist(...) && !$(NEED_TCL_SOURCE) - -!if [echo _TCLDIR = \> nmakehlp.out] \ - || [nmakehlp -L generic\tcl.h >> nmakehlp.out] -!error *** Could not locate Tcl source directory. -!endif -!include nmakehlp.out -TCLINSTALL = 0 -TCLDIR = $(_TCLDIR) -_TCL_H = $(_TCLDIR)\generic\tcl.h - -!endif # exist(...) && !$(NEED_TCL_SOURCE) - -!endif # TCLDIR - -!ifndef _TCL_H -MSG =^ -Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h. -!error $(MSG) -!endif - -# Now do the same to locate Tk headers and libs if project requires Tk -!if $(NEED_TK) - -!if "$(TKDIR)" != "" - -_TKDIR = $(TKDIR:/=\) -!if exist("$(_TKDIR)\include\tk.h") -TKINSTALL = 1 -_TK_H = $(_TKDIR)\include\tk.h -!elseif exist("$(_TKDIR)\generic\tk.h") -TKINSTALL = 0 -_TK_H = $(_TKDIR)\generic\tk.h -!endif - -!else # TKDIR not defined - -# Need to locate Tcl depending on whether it needs Tcl source or not. -# If we don't, check the INSTALLDIR for an installed Tcl first - -!if exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) - -TKINSTALL = 1 -# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions -# later so the \.. accounts for the /lib -_TKDIR = $(_INSTALLDIR)\.. -_TK_H = $(_TKDIR)\include\tk.h -TKDIR = $(_TKDIR) - -!else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) - -!if [echo _TKDIR = \> nmakehlp.out] \ - || [nmakehlp -L generic\tk.h >> nmakehlp.out] -!error *** Could not locate Tk source directory. -!endif -!include nmakehlp.out -TKINSTALL = 0 -TKDIR = $(_TKDIR) -_TK_H = $(_TKDIR)\generic\tk.h - -!endif # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) - -!endif # TKDIR - -!ifndef _TK_H -MSG =^ -Failed to find tk.h. The TKDIR macro is set incorrectly or is not set and default path does not contain tk.h. -!error $(MSG) -!endif - -!endif # NEED_TK - -!if $(NEED_TCL_SOURCE) && $(TCLINSTALL) -MSG = ^ -*** Warning: This extension requires the source distribution of Tcl.^ -*** Please set the TCLDIR macro to point to the Tcl sources. -!error $(MSG) -!endif - -!if $(NEED_TK_SOURCE) -!if $(TKINSTALL) -MSG = ^ -*** Warning: This extension requires the source distribution of Tk.^ -*** Please set the TKDIR macro to point to the Tk sources. -!error $(MSG) -!endif -!endif - - -# If INSTALLDIR set to Tcl installation root dir then reset to the -# lib dir for installing extensions -!if exist("$(_INSTALLDIR)\include\tcl.h") -_INSTALLDIR=$(_INSTALLDIR)\lib -!endif - -# END Case 2(c) or (d) - Building an extension -!endif # if $(DOING_TCL) - -################################################################ -# 3. Determine compiler version and architecture -# In this section, we figure out the compiler version and the -# architecture for which we are building. This sets the -# following macros: -# VCVERSION - the internal compiler version as 1200, 1400, 1910 etc. -# This is also printed by the compiler in dotted form 19.10 etc. -# VCVER - the "marketing version", for example Visual C++ 6 for internal -# compiler version 1200. This is kept only for legacy reasons as it -# does not make sense for recent Microsoft compilers. Only used for -# output directory names. -# ARCH - set to IX86, ARM64 or AMD64 depending on 32- or 64-bit target -# NATIVE_ARCH - set to IX86, ARM64 or AMD64 for the host machine -# MACHINE - same as $(ARCH) - legacy -# _VC_MANIFEST_EMBED_{DLL,EXE} - commands for embedding a manifest if needed - -cc32 = $(CC) # built-in default. -link32 = link -lib32 = lib -rc32 = $(RC) # built-in default. - -#---------------------------------------------------------------- -# Figure out the compiler architecture and version by writing -# the C macros to a file, preprocessing them with the C -# preprocessor and reading back the created file - -_HASH=^# -_VC_MANIFEST_EMBED_EXE= -_VC_MANIFEST_EMBED_DLL= -VCVER=0 -!if ![echo VCVERSION=_MSC_VER > vercl.x] \ - && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ - && ![echo ARCH=IX86 >> vercl.x] \ - && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ - && ![echo ARCH=AMD64 >> vercl.x] \ - && ![echo $(_HASH)elif defined(_M_ARM64) >> vercl.x] \ - && ![echo ARCH=ARM64 >> vercl.x] \ - && ![echo $(_HASH)endif >> vercl.x] \ - && ![$(cc32) -nologo -TC -P vercl.x 2>NUL] -!include vercl.i -!if $(VCVERSION) < 1900 -!if ![echo VCVER= ^\> vercl.vc] \ - && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] -!include vercl.vc -!endif -!else -# The simple calculation above does not apply to new Visual Studio releases -# Keep the compiler version in its native form. -VCVER = $(VCVERSION) -!endif -!endif - -!if ![del 2>NUL /q/f vercl.x vercl.i vercl.vc] -!endif - -#---------------------------------------------------------------- -# The MACHINE macro is used by legacy makefiles so set it as well -!ifdef MACHINE -!if "$(MACHINE)" == "x86" -!undef MACHINE -MACHINE = IX86 -!elseif "$(MACHINE)" == "arm64" -!undef MACHINE -MACHINE = ARM64 -!elseif "$(MACHINE)" == "x64" -!undef MACHINE -MACHINE = AMD64 -!endif -!if "$(MACHINE)" != "$(ARCH)" -!error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH). -!endif -!else -MACHINE=$(ARCH) -!endif - -#--------------------------------------------------------------- -# The PLATFORM_IDENTIFY macro matches the values returned by -# the Tcl platform::identify command -!if "$(MACHINE)" == "AMD64" -PLATFORM_IDENTIFY = win32-x86_64 -!elseif "$(MACHINE)" == "ARM64" -PLATFORM_IDENTIFY = win32-arm -!else -PLATFORM_IDENTIFY = win32-ix86 -!endif - -# The MULTIPLATFORM macro controls whether binary extensions are installed -# in platform-specific directories. Intended to be set/used by extensions. -!ifndef MULTIPLATFORM_INSTALL -MULTIPLATFORM_INSTALL = 0 -!endif - -#------------------------------------------------------------ -# Figure out the *host* architecture by reading the registry - -!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] -NATIVE_ARCH=IX86 -!elseif ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i ARM | findstr /i 64-bit] -NATIVE_ARCH=ARM64 -!else -NATIVE_ARCH=AMD64 -!endif - -# Since MSVC8 we must deal with manifest resources. -!if $(VCVERSION) >= 1400 -_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 -_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 -!endif - -################################################################ -# 4. Build the nmakehlp program -# This is a helper app we need to overcome nmake's limiting -# environment. We will call out to it to get various bits of -# information about supported compiler options etc. -# -# Tcl itself will always use the nmakehlp.c program which is -# in its own source. It will be kept updated there. -# -# Extensions built against an installed Tcl will use the installed -# copy of Tcl's nmakehlp.c if there is one and their own version -# otherwise. In the latter case, they would also be using their own -# rules.vc. Note that older versions of Tcl do not install nmakehlp.c -# or rules.vc. -# -# Extensions built against Tcl sources will use the one from the Tcl source. -# -# When building an extension using a sufficiently new version of Tcl, -# rules-ext.vc will define NMAKEHLPC appropriately to point to the -# copy of nmakehlp.c to be used. - -!ifndef NMAKEHLPC -# Default to the one in the current directory (the extension's own nmakehlp.c) -NMAKEHLPC = nmakehlp.c - -!if !$(DOING_TCL) -!if $(TCLINSTALL) -!if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c") -NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c -!endif -!else # !$(TCLINSTALL) -!if exist("$(_TCLDIR)\win\nmakehlp.c") -NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c -!endif -!endif # $(TCLINSTALL) -!endif # !$(DOING_TCL) - -!endif # NMAKEHLPC - -# We always build nmakehlp even if it exists since we do not know -# what source it was built from. -!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" -!if [$(cc32) -nologo "$(NMAKEHLPC)" -link -subsystem:console > nul] -!endif -!else -!if [copy $(NMAKEHLPC:nmakehlp.c=x86_64-w64-mingw32-nmakehlp.exe) nmakehlp.exe >NUL] -!endif -!endif - -################################################################ -# 5. Test for compiler features -# Visual C++ compiler options have changed over the years. Check -# which options are supported by the compiler in use. -# -# The following macros are set: -# OPTIMIZATIONS - the compiler flags to be used for optimized builds -# DEBUGFLAGS - the compiler flags to be used for debug builds -# LINKERFLAGS - Flags passed to the linker -# -# Note that these are the compiler settings *available*, not those -# that will be *used*. The latter depends on the OPTS macro settings -# which we have not yet parsed. -# -# Also note that some of the flags in OPTIMIZATIONS are not really -# related to optimization. They are placed there only for legacy reasons -# as some extensions expect them to be included in that macro. - -# -Op improves float consistency. Note only needed for older compilers -# Newer compilers do not need or support this option. -!if [nmakehlp -c -Op] -FPOPTS = -Op -!endif - -# Strict floating point semantics - present in newer compilers in lieu of -Op -!if [nmakehlp -c -fp:strict] -FPOPTS = $(FPOPTS) -fp:strict -!endif - -!if "$(MACHINE)" == "IX86" -### test for pentium errata -!if [nmakehlp -c -QI0f] -!message *** Compiler has 'Pentium 0x0f fix' -FPOPTS = $(FPOPTS) -QI0f -!else -!message *** Compiler does not have 'Pentium 0x0f fix' -!endif -!endif - -### test for optimizations -# /O2 optimization includes /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy as per -# documentation. Note we do NOT want /Gs as that inserts a _chkstk -# stack probe at *every* function entry, not just those with more than -# a page of stack allocation resulting in a performance hit. However, -# /O2 documentation is misleading as its stack probes are simply the -# default page size locals allocation probes and not what is implied -# by an explicit /Gs option. - -OPTIMIZATIONS = $(FPOPTS) - -!if [nmakehlp -c -O2] -OPTIMIZING = 1 -OPTIMIZATIONS = $(OPTIMIZATIONS) -O2 -!else -# Legacy, really. All modern compilers support this -!message *** Compiler does not have 'Optimizations' -OPTIMIZING = 0 -!endif - -# Checks for buffer overflows in local arrays -!if [nmakehlp -c -GS] -OPTIMIZATIONS = $(OPTIMIZATIONS) -GS -!endif - -# Link time optimization. Note that this option (potentially) makes -# generated libraries only usable by the specific VC++ version that -# created it. Requires /LTCG linker option -!if [nmakehlp -c -GL] -OPTIMIZATIONS = $(OPTIMIZATIONS) -GL -CC_GL_OPT_ENABLED = 1 -!else -# In newer compilers -GL and -YX are incompatible. -!if [nmakehlp -c -YX] -OPTIMIZATIONS = $(OPTIMIZATIONS) -YX -!endif -!endif # [nmakehlp -c -GL] - -DEBUGFLAGS = $(FPOPTS) - -# Run time error checks. Not available or valid in a release, non-debug build -# RTC is for modern compilers, -GZ is legacy -!if [nmakehlp -c -RTC1] -DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 -!elseif [nmakehlp -c -GZ] -DEBUGFLAGS = $(DEBUGFLAGS) -GZ -!endif - -#---------------------------------------------------------------- -# Linker flags - -# LINKER_TESTFLAGS are for internal use when we call nmakehlp to test -# if the linker supports a specific option. Without these flags link will -# return "LNK1561: entry point must be defined" error compiling from VS-IDE: -# They are not passed through to the actual application / extension -# link rules. -!ifndef LINKER_TESTFLAGS -LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmakehlp.out -!endif - -LINKERFLAGS = - -# If compiler has enabled link time optimization, linker must too with -ltcg -!ifdef CC_GL_OPT_ENABLED -!if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)] -LINKERFLAGS = $(LINKERFLAGS) -ltcg -!endif -!endif - - -################################################################ -# 6. Extract various version numbers from headers -# For Tcl and Tk, version numbers are extracted from tcl.h and tk.h -# respectively. For extensions, versions are extracted from the -# configure.in or configure.ac from the TEA configuration if it -# exists, and unset otherwise. -# Sets the following macros: -# TCL_MAJOR_VERSION -# TCL_MINOR_VERSION -# TCL_RELEASE_SERIAL -# TCL_PATCH_LEVEL -# TCL_PATCH_LETTER -# TCL_VERSION -# TK_MAJOR_VERSION -# TK_MINOR_VERSION -# TK_RELEASE_SERIAL -# TK_PATCH_LEVEL -# TK_PATCH_LETTER -# TK_VERSION -# DOTVERSION - set as (for example) 2.5 -# VERSION - set as (for example 25) -#-------------------------------------------------------------- - -!if [echo REM = This file is generated from rules.vc > versions.vc] -!endif -!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ - && [nmakehlp -V "$(_TCL_H)" "define TCL_MAJOR_VERSION" >> versions.vc] -!endif -!if [echo TCL_MINOR_VERSION = \>> versions.vc] \ - && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc] -!endif -!if [echo TCL_RELEASE_SERIAL = \>> versions.vc] \ - && [nmakehlp -V "$(_TCL_H)" TCL_RELEASE_SERIAL >> versions.vc] -!endif -!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ - && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] -!endif - -!if defined(_TK_H) -!if [echo TK_MAJOR_VERSION = \>> versions.vc] \ - && [nmakehlp -V $(_TK_H) "define TK_MAJOR_VERSION" >> versions.vc] -!endif -!if [echo TK_MINOR_VERSION = \>> versions.vc] \ - && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc] -!endif -!if [echo TK_RELEASE_SERIAL = \>> versions.vc] \ - && [nmakehlp -V "$(_TK_H)" TK_RELEASE_SERIAL >> versions.vc] -!endif -!if [echo TK_PATCH_LEVEL = \>> versions.vc] \ - && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] -!endif -!endif # _TK_H - -!include versions.vc - -TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) -TCL_DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) -!if [nmakehlp -f $(TCL_PATCH_LEVEL) "a"] -TCL_PATCH_LETTER = a -!elseif [nmakehlp -f $(TCL_PATCH_LEVEL) "b"] -TCL_PATCH_LETTER = b -!else -TCL_PATCH_LETTER = . -!endif - -!if defined(_TK_H) - -TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) -TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) -!if [nmakehlp -f $(TK_PATCH_LEVEL) "a"] -TK_PATCH_LETTER = a -!elseif [nmakehlp -f $(TK_PATCH_LEVEL) "b"] -TK_PATCH_LETTER = b -!else -TK_PATCH_LETTER = . -!endif - -!endif - -# Set DOTVERSION and VERSION -!if $(DOING_TCL) - -DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) -VERSION = $(TCL_VERSION) - -!elseif $(DOING_TK) - -DOTVERSION = $(TK_DOTVERSION) -VERSION = $(TK_VERSION) - -!else # Doing a non-Tk extension - -# If parent makefile has not defined DOTVERSION, try to get it from TEA -# first from a configure.in file, and then from configure.ac -!ifndef DOTVERSION -!if [echo DOTVERSION = \> versions.vc] \ - || [nmakehlp -V $(ROOT)\configure.in ^[$(PROJECT)^] >> versions.vc] -!if [echo DOTVERSION = \> versions.vc] \ - || [nmakehlp -V $(ROOT)\configure.ac ^[$(PROJECT)^] >> versions.vc] -!error *** Could not figure out extension version. Please define DOTVERSION in parent makefile before including rules.vc. -!endif -!endif -!include versions.vc -!endif # DOTVERSION -VERSION = $(DOTVERSION:.=) - -!endif # $(DOING_TCL) ... etc. - -# Windows RC files have 3 version components. Ensure this irrespective -# of how many components the package has specified. Basically, ensure -# minimum 4 components by appending 4 0's and then pick out the first 4. -# Also take care of the fact that DOTVERSION may have "a" or "b" instead -# of "." separating the version components. -DOTSEPARATED=$(DOTVERSION:a=.) -DOTSEPARATED=$(DOTSEPARATED:b=.) -!if [echo RCCOMMAVERSION = \> versions.vc] \ - || [for /f "tokens=1,2,3,4,5* delims=." %a in ("$(DOTSEPARATED).0.0.0.0") do echo %a,%b,%c,%d >> versions.vc] -!error *** Could not generate RCCOMMAVERSION *** -!endif -!include versions.vc - -######################################################################## -# 7. Parse the OPTS macro to work out the requested build configuration. -# Based on this, we will construct the actual switches to be passed to the -# compiler and linker using the macros defined in the previous section. -# The following macros are defined by this section based on OPTS -# STATIC_BUILD - 0 -> Tcl is to be built as a shared library -# 1 -> build as a static library and shell -# TCL_THREADS - legacy but always 1 on Windows since winsock requires it. -# DEBUG - 1 -> debug build, 0 -> release builds -# SYMBOLS - 1 -> generate PDB's, 0 -> no PDB's -# PROFILE - 1 -> generate profiling info, 0 -> no profiling -# PGO - 1 -> profile based optimization, 0 -> no -# MSVCRT - 1 -> link to dynamic C runtime even when building static Tcl build -# 0 -> link to static C runtime for static Tcl build. -# Does not impact shared Tcl builds (STATIC_BUILD == 0) -# Default: 1 for Tcl 8.7 and up, 0 otherwise. -# TCL_USE_STATIC_PACKAGES - 1 -> statically link the registry and dde extensions -# in the Tcl and Wish shell. 0 -> keep them as shared libraries. Does -# not impact shared Tcl builds. Implied by STATIC_BUILD since Tcl 8.7. -# USE_THREAD_ALLOC - 1 -> Use a shared global free pool for allocation. -# 0 -> Use the non-thread allocator. -# UNCHECKED - 1 -> when doing a debug build with symbols, use the release -# C runtime, 0 -> use the debug C runtime. -# USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking -# CONFIG_CHECK - 1 -> check current build configuration against Tcl -# configuration (ignored for Tcl itself) -# _USE_64BIT_TIME_T - forces a build using 64-bit time_t for 32-bit build -# (CRT library should support this, not needed for Tcl 9.x) -# Further, LINKERFLAGS are modified based on above. - -# Default values for all the above -STATIC_BUILD = 0 -TCL_THREADS = 1 -DEBUG = 0 -SYMBOLS = 0 -PROFILE = 0 -PGO = 0 -MSVCRT = 1 -TCL_USE_STATIC_PACKAGES = 0 -USE_THREAD_ALLOC = 1 -UNCHECKED = 0 -CONFIG_CHECK = 1 -!if $(DOING_TCL) -USE_STUBS = 0 -!else -USE_STUBS = 1 -!endif - -# If OPTS is not empty AND does not contain "none" which turns off all OPTS -# set the above macros based on OPTS content -!if "$(OPTS)" != "" && ![nmakehlp -f "$(OPTS)" "none"] - -# OPTS are specified, parse them - -!if [nmakehlp -f $(OPTS) "static"] -!message *** Doing static -STATIC_BUILD = 1 -!endif - -!if [nmakehlp -f $(OPTS) "nostubs"] -!message *** Not using stubs -USE_STUBS = 0 -!endif - -!if [nmakehlp -f $(OPTS) "nomsvcrt"] -!message *** Doing nomsvcrt -MSVCRT = 0 -!else -!if [nmakehlp -f $(OPTS) "msvcrt"] -!message *** Doing msvcrt -!else -!if $(TCL_MAJOR_VERSION) == 8 && $(TCL_MINOR_VERSION) < 7 && $(STATIC_BUILD) -MSVCRT = 0 -!endif -!endif -!endif # [nmakehlp -f $(OPTS) "nomsvcrt"] - -!if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) -!message *** Doing staticpkg -TCL_USE_STATIC_PACKAGES = 1 -!endif - -!if [nmakehlp -f $(OPTS) "nothreads"] -!message *** Compile explicitly for non-threaded tcl -TCL_THREADS = 0 -USE_THREAD_ALLOC= 0 -!endif - -!if [nmakehlp -f $(OPTS) "tcl8"] -!message *** Build for Tcl8 -TCL_BUILD_FOR = 8 -!endif - -!if $(TCL_MAJOR_VERSION) == 8 -!if [nmakehlp -f $(OPTS) "time64bit"] -!message *** Force 64-bit time_t -_USE_64BIT_TIME_T = 1 -!endif -!endif - -# Yes, it's weird that the "symbols" option controls DEBUG and -# the "pdbs" option controls SYMBOLS. That's historical. -!if [nmakehlp -f $(OPTS) "symbols"] -!message *** Doing symbols -DEBUG = 1 -!else -DEBUG = 0 -!endif - -!if [nmakehlp -f $(OPTS) "pdbs"] -!message *** Doing pdbs -SYMBOLS = 1 -!else -SYMBOLS = 0 -!endif - -!if [nmakehlp -f $(OPTS) "profile"] -!message *** Doing profile -PROFILE = 1 -!else -PROFILE = 0 -!endif - -!if [nmakehlp -f $(OPTS) "pgi"] -!message *** Doing profile guided optimization instrumentation -PGO = 1 -!elseif [nmakehlp -f $(OPTS) "pgo"] -!message *** Doing profile guided optimization -PGO = 2 -!else -PGO = 0 -!endif - -!if [nmakehlp -f $(OPTS) "loimpact"] -!message *** Warning: ignoring option "loimpact" - deprecated on modern Windows. -!endif - -# TBD - should get rid of this option -!if [nmakehlp -f $(OPTS) "thrdalloc"] -!message *** Doing thrdalloc -USE_THREAD_ALLOC = 1 -!endif - -!if [nmakehlp -f $(OPTS) "tclalloc"] -USE_THREAD_ALLOC = 0 -!endif - -!if [nmakehlp -f $(OPTS) "unchecked"] -!message *** Doing unchecked -UNCHECKED = 1 -!else -UNCHECKED = 0 -!endif - -!if [nmakehlp -f $(OPTS) "noconfigcheck"] -CONFIG_CHECK = 1 -!else -CONFIG_CHECK = 0 -!endif - -!endif # "$(OPTS)" != "" && ... parsing of OPTS - -# Set linker flags based on above - -!if $(PGO) > 1 -!if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)] -LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize -!else -MSG=^ -This compiler does not support profile guided optimization. -!error $(MSG) -!endif -!elseif $(PGO) > 0 -!if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)] -LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument -!else -MSG=^ -This compiler does not support profile guided optimization. -!error $(MSG) -!endif -!endif - -################################################################ -# 8. Parse the STATS macro to configure code instrumentation -# The following macros are set by this section: -# TCL_MEM_DEBUG - 1 -> enables memory allocation instrumentation -# 0 -> disables -# TCL_COMPILE_DEBUG - 1 -> enables byte compiler logging -# 0 -> disables - -# Default both are off -TCL_MEM_DEBUG = 0 -TCL_COMPILE_DEBUG = 0 - -!if "$(STATS)" != "" && ![nmakehlp -f "$(STATS)" "none"] - -!if [nmakehlp -f $(STATS) "memdbg"] -!message *** Doing memdbg -TCL_MEM_DEBUG = 1 -!else -TCL_MEM_DEBUG = 0 -!endif - -!if [nmakehlp -f $(STATS) "compdbg"] -!message *** Doing compdbg -TCL_COMPILE_DEBUG = 1 -!else -TCL_COMPILE_DEBUG = 0 -!endif - -!endif - -#################################################################### -# 9. Parse the CHECKS macro to configure additional compiler checks -# The following macros are set by this section: -# WARNINGS - compiler switches that control the warnings level -# TCL_NO_DEPRECATED - 1 -> disable support for deprecated functions -# 0 -> enable deprecated functions - -# Defaults - Permit deprecated functions and warning level 3 -TCL_NO_DEPRECATED = 0 -WARNINGS = -W3 - -!if "$(CHECKS)" != "" && ![nmakehlp -f "$(CHECKS)" "none"] - -!if [nmakehlp -f $(CHECKS) "nodep"] -!message *** Doing nodep check -TCL_NO_DEPRECATED = 1 -!endif - -!if [nmakehlp -f $(CHECKS) "fullwarn"] -!message *** Doing full warnings check -WARNINGS = -W4 -!if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)] -LINKERFLAGS = $(LINKERFLAGS) -warn:3 -!endif -!endif - -!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] -!message *** Doing 64bit portability warnings -WARNINGS = $(WARNINGS) -Wp64 -!endif - -!endif - - -################################################################ -# 10. Construct output directory and file paths -# Figure-out how to name our intermediate and output directories. -# In order to avoid inadvertent mixing of object files built using -# different compilers, build configurations etc., -# -# Naming convention (suffixes): -# t = full thread support. (Not used for Tcl >= 8.7) -# s = static library (as opposed to an import library) -# g = linked to the debug enabled C run-time. -# x = special static build when it links to the dynamic C run-time. -# -# The following macros are set in this section: -# SUFX - the suffix to use for binaries based on above naming convention -# BUILDDIRTOP - the toplevel default output directory -# is of the form {Release,Debug}[_AMD64][_COMPILERVERSION] -# TMP_DIR - directory where object files are created -# OUT_DIR - directory where output executables are created -# Both TMP_DIR and OUT_DIR are defaulted only if not defined by the -# parent makefile (or command line). The default values are -# based on BUILDDIRTOP. -# STUBPREFIX - name of the stubs library for this project -# PRJIMPLIB - output path of the generated project import library -# PRJLIBNAME - name of generated project library -# PRJLIB - output path of generated project library -# PRJSTUBLIBNAME - name of the generated project stubs library -# PRJSTUBLIB - output path of the generated project stubs library -# RESFILE - output resource file (only if not static build) - -SUFX = tsgx - -!if $(DEBUG) -BUILDDIRTOP = Debug -!else -BUILDDIRTOP = Release -!endif - -!if "$(MACHINE)" != "IX86" -BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) -!endif -!if $(VCVER) > 6 -BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) -!endif - -!if !$(DEBUG) || $(TCL_VERSION) > 86 || $(DEBUG) && $(UNCHECKED) -SUFX = $(SUFX:g=) -!endif - -TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX - -!if !$(STATIC_BUILD) -TMP_DIRFULL = $(TMP_DIRFULL:Static=) -SUFX = $(SUFX:s=) -EXT = dll -TMP_DIRFULL = $(TMP_DIRFULL:X=) -SUFX = $(SUFX:x=) -!else -TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) -EXT = lib -!if $(MSVCRT) && $(TCL_VERSION) > 86 || !$(MSVCRT) && $(TCL_VERSION) < 87 -TMP_DIRFULL = $(TMP_DIRFULL:X=) -SUFX = $(SUFX:x=) -!endif -!endif - -!if !$(TCL_THREADS) || $(TCL_VERSION) > 86 -TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) -SUFX = $(SUFX:t=) -!endif - -!ifndef TMP_DIR -TMP_DIR = $(TMP_DIRFULL) -!ifndef OUT_DIR -OUT_DIR = .\$(BUILDDIRTOP) -!endif -!else -!ifndef OUT_DIR -OUT_DIR = $(TMP_DIR) -!endif -!endif - -# Relative paths -> absolute -!if [echo OUT_DIR = \> nmakehlp.out] \ - || [nmakehlp -Q "$(OUT_DIR)" >> nmakehlp.out] -!error *** Could not fully qualify path OUT_DIR=$(OUT_DIR) -!endif -!if [echo TMP_DIR = \>> nmakehlp.out] \ - || [nmakehlp -Q "$(TMP_DIR)" >> nmakehlp.out] -!error *** Could not fully qualify path TMP_DIR=$(TMP_DIR) -!endif -!include nmakehlp.out - -# The name of the stubs library for the project being built -STUBPREFIX = $(PROJECT)stub - -# -# Set up paths to various Tcl executables and libraries needed by extensions -# - -# TIP 430. Unused for 8.6 but no harm defining it to allow a common rules.vc -TCL_ZIP_FILE = libtcl$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)$(TCL_PATCH_LETTER)$(TCL_RELEASE_SERIAL).zip -TK_ZIP_FILE = libtk$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)$(TK_PATCH_LETTER)$(TK_RELEASE_SERIAL).zip - -!if $(DOING_TCL) -TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe -TCLSH = $(OUT_DIR)\$(TCLSHNAME) -TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib -TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) -TCLLIB = $(OUT_DIR)\$(TCLLIBNAME) -TCLSCRIPTZIP = $(OUT_DIR)\$(TCL_ZIP_FILE) - -!if $(TCL_MAJOR_VERSION) == 8 -TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib -!else -TCLSTUBLIBNAME = $(STUBPREFIX).lib -!endif -TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME) -TCL_INCLUDES = -I"$(WIN_DIR)" -I"$(GENERICDIR)" - -!else # !$(DOING_TCL) - -!if $(TCLINSTALL) # Building against an installed Tcl - -# When building extensions, we need to locate tclsh. Depending on version -# of Tcl we are building against, this may or may not have a "t" suffix. -# Try various possibilities in turn. -TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe -!if !exist("$(TCLSH)") -TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX:t=).exe -!endif - -!if $(TCL_MAJOR_VERSION) == 8 -TCLSTUBLIB = $(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib -!else -TCLSTUBLIB = $(_TCLDIR)\lib\tclstub.lib -!endif -TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib -# When building extensions, may be linking against Tcl that does not add -# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. -!if !exist("$(TCLIMPLIB)") -TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)t$(SUFX:t=).lib -!endif -TCL_LIBRARY = $(_TCLDIR)\lib -TCLREGLIB = $(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib -TCLDDELIB = $(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib -TCLSCRIPTZIP = $(_TCLDIR)\lib\$(TCL_ZIP_FILE) -TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target -TCL_INCLUDES = -I"$(_TCLDIR)\include" - -!else # Building against Tcl sources - -TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX:t=).exe -!if !exist($(TCLSH)) -TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX:t=).exe -!endif -!if $(TCL_MAJOR_VERSION) == 8 -TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib -!else -TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub.lib -!endif -TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib -# When building extensions, may be linking against Tcl that does not add -# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. -!if !exist("$(TCLIMPLIB)") -TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)t$(SUFX:t=).lib -!endif -TCL_LIBRARY = $(_TCLDIR)\library -TCLREGLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib -TCLDDELIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib -TCLSCRIPTZIP = $(_TCLDIR)\win\$(BUILDDIRTOP)\$(TCL_ZIP_FILE) -TCLTOOLSDIR = $(_TCLDIR)\tools -TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" - -!endif # TCLINSTALL - -!if !$(STATIC_BUILD) && "$(TCL_BUILD_FOR)" == "8" -tcllibs = "$(TCLSTUBLIB)" -!else -tcllibs = "$(TCLSTUBLIB)" "$(TCLIMPLIB)" -!endif - -!endif # $(DOING_TCL) - -# We need a tclsh that will run on the host machine as part of the build. -# IX86 runs on all architectures. -!ifndef TCLSH_NATIVE -!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" -TCLSH_NATIVE = $(TCLSH) -!else -!error You must explicitly set TCLSH_NATIVE for cross-compilation -!endif -!endif - -# Do the same for Tk and Tk extensions that require the Tk libraries -!if $(DOING_TK) || $(NEED_TK) -WISHNAMEPREFIX = wish -WISHNAME = $(WISHNAMEPREFIX)$(TK_VERSION)$(SUFX).exe -TKLIBNAME8 = tk$(TK_VERSION)$(SUFX).$(EXT) -TKLIBNAME9 = tcl9tk$(TK_VERSION)$(SUFX).$(EXT) -!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8" -TKLIBNAME = tk$(TK_VERSION)$(SUFX).$(EXT) -TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX).lib -!else -TKLIBNAME = tcl9tk$(TK_VERSION)$(SUFX).$(EXT) -TKIMPLIBNAME = tcl9tk$(TK_VERSION)$(SUFX).lib -!endif -!if $(TK_MAJOR_VERSION) == 8 -TKSTUBLIBNAME = tkstub$(TK_VERSION).lib -!else -TKSTUBLIBNAME = tkstub.lib -!endif - -!if $(DOING_TK) -WISH = $(OUT_DIR)\$(WISHNAME) -TKSTUBLIB = $(OUT_DIR)\$(TKSTUBLIBNAME) -TKIMPLIB = $(OUT_DIR)\$(TKIMPLIBNAME) -TKLIB = $(OUT_DIR)\$(TKLIBNAME) -TK_INCLUDES = -I"$(WIN_DIR)" -I"$(GENERICDIR)" -TKSCRIPTZIP = $(OUT_DIR)\$(TK_ZIP_FILE) - -!else # effectively NEED_TK - -!if $(TKINSTALL) # Building against installed Tk -WISH = $(_TKDIR)\bin\$(WISHNAME) -TKSTUBLIB = $(_TKDIR)\lib\$(TKSTUBLIBNAME) -TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME) -# When building extensions, may be linking against Tk that does not add -# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. -!if !exist("$(TKIMPLIB)") -TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib -TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME) -!endif -TK_INCLUDES = -I"$(_TKDIR)\include" -TKSCRIPTZIP = $(_TKDIR)\lib\$(TK_ZIP_FILE) - -!else # Building against Tk sources - -WISH = $(_TKDIR)\win\$(BUILDDIRTOP)\$(WISHNAME) -TKSTUBLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKSTUBLIBNAME) -TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME) -# When building extensions, may be linking against Tk that does not add -# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. -!if !exist("$(TKIMPLIB)") -TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib -TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME) -!endif -TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" -TKSCRIPTZIP = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TK_ZIP_FILE) - -!endif # TKINSTALL - -tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)" - -!endif # $(DOING_TK) -!endif # $(DOING_TK) || $(NEED_TK) - -# Various output paths -PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib -PRJLIBNAME8 = $(PROJECT)$(VERSION)$(SUFX).$(EXT) -# Even when building against Tcl 8, PRJLIBNAME9 must not have "t" -PRJLIBNAME9 = tcl9$(PROJECT)$(VERSION)$(SUFX:t=).$(EXT) -!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8" -PRJLIBNAME = $(PRJLIBNAME8) -!else -PRJLIBNAME = $(PRJLIBNAME9) -!endif -PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) - -!if $(TCL_MAJOR_VERSION) == 8 -PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib -!else -PRJSTUBLIBNAME = $(STUBPREFIX).lib -!endif -PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) - -# If extension parent makefile has not defined a resource definition file, -# we will generate one from standard template. -!if !$(DOING_TCL) && !$(DOING_TK) && !$(STATIC_BUILD) -!ifdef RCFILE -RESFILE = $(TMP_DIR)\$(RCFILE:.rc=.res) -!else -RESFILE = $(TMP_DIR)\$(PROJECT).res -!endif -!endif - -################################################################### -# 11. Construct the paths for the installation directories -# The following macros get defined in this section: -# LIB_INSTALL_DIR - where libraries should be installed -# BIN_INSTALL_DIR - where the executables should be installed -# DOC_INSTALL_DIR - where documentation should be installed -# SCRIPT_INSTALL_DIR - where scripts should be installed -# INCLUDE_INSTALL_DIR - where C include files should be installed -# DEMO_INSTALL_DIR - where demos should be installed -# PRJ_INSTALL_DIR - where package will be installed (not set for Tcl and Tk) - -!if $(DOING_TCL) || $(DOING_TK) -LIB_INSTALL_DIR = $(_INSTALLDIR)\lib -BIN_INSTALL_DIR = $(_INSTALLDIR)\bin -DOC_INSTALL_DIR = $(_INSTALLDIR)\doc -!if $(DOING_TCL) -SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) -MODULE_INSTALL_DIR = $(_INSTALLDIR)\lib\tcl$(TCL_MAJOR_VERSION) -!else # DOING_TK -SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) -!endif -DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos -INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include - -!else # extension other than Tk - -PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) -!if $(MULTIPLATFORM_INSTALL) -LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY) -BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY) -!else -LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) -BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) -!endif -DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) -SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) -DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos -INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include - -!endif - -################################################################### -# 12. Set up actual options to be passed to the compiler and linker -# Now we have all the information we need, set up the actual flags and -# options that we will pass to the compiler and linker. The main -# makefile should use these in combination with whatever other flags -# and switches are specific to it. -# The following macros are defined, names are for historical compatibility: -# OPTDEFINES - /Dxxx C macro flags based on user-specified OPTS -# COMPILERFLAGS - /Dxxx C macro flags independent of any configuration options -# crt - Compiler switch that selects the appropriate C runtime -# cdebug - Compiler switches related to debug AND optimizations -# cwarn - Compiler switches that set warning levels -# cflags - complete compiler switches (subsumes cdebug and cwarn) -# ldebug - Linker switches controlling debug information and optimization -# lflags - complete linker switches (subsumes ldebug) except subsystem type -# dlllflags - complete linker switches to build DLLs (subsumes lflags) -# conlflags - complete linker switches for console program (subsumes lflags) -# guilflags - complete linker switches for GUI program (subsumes lflags) -# baselibs - minimum Windows libraries required. Parent makefile can -# define PRJ_LIBS before including rules.rc if additional libs are needed - -OPTDEFINES = /DSTDC_HEADERS /DUSE_NMAKE=1 -!if $(VCVERSION) > 1600 -OPTDEFINES = $(OPTDEFINES) /DHAVE_STDINT_H=1 -!else -OPTDEFINES = $(OPTDEFINES) /DMP_NO_STDINT=1 -!endif -!if $(VCVERSION) >= 1800 -OPTDEFINES = $(OPTDEFINES) /DHAVE_INTTYPES_H=1 /DHAVE_STDBOOL_H=1 -!endif - -!if $(TCL_MEM_DEBUG) -OPTDEFINES = $(OPTDEFINES) /DTCL_MEM_DEBUG -!endif -!if $(TCL_COMPILE_DEBUG) -OPTDEFINES = $(OPTDEFINES) /DTCL_COMPILE_DEBUG /DTCL_COMPILE_STATS -!endif -!if $(TCL_THREADS) && $(TCL_VERSION) < 87 -OPTDEFINES = $(OPTDEFINES) /DTCL_THREADS=1 -!if $(USE_THREAD_ALLOC) && $(TCL_VERSION) < 87 -OPTDEFINES = $(OPTDEFINES) /DUSE_THREAD_ALLOC=1 -!endif -!endif -!if $(STATIC_BUILD) -OPTDEFINES = $(OPTDEFINES) /DSTATIC_BUILD -!elseif $(TCL_VERSION) > 86 -OPTDEFINES = $(OPTDEFINES) /DTCL_WITH_EXTERNAL_TOMMATH -!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64" -OPTDEFINES = $(OPTDEFINES) /DMP_64BIT -!endif -!endif -!if $(TCL_NO_DEPRECATED) -OPTDEFINES = $(OPTDEFINES) /DTCL_NO_DEPRECATED -!endif - -!if $(USE_STUBS) -# Note we do not define USE_TCL_STUBS even when building tk since some -# test targets in tk do not use stubs -!if !$(DOING_TCL) -USE_STUBS_DEFS = /DUSE_TCL_STUBS /DUSE_TCLOO_STUBS -!if $(NEED_TK) -USE_STUBS_DEFS = $(USE_STUBS_DEFS) /DUSE_TK_STUBS -!endif -!endif -!endif # USE_STUBS - -!if !$(DEBUG) -OPTDEFINES = $(OPTDEFINES) /DNDEBUG -!if $(OPTIMIZING) -OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_OPTIMIZED -!endif -!endif -!if $(PROFILE) -OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_PROFILED -!endif -!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64" -OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_DO64BIT -!endif -!if $(VCVERSION) < 1300 -OPTDEFINES = $(OPTDEFINES) /DNO_STRTOI64=1 -!endif - -!if $(TCL_MAJOR_VERSION) == 8 -!if "$(_USE_64BIT_TIME_T)" == "1" -OPTDEFINES = $(OPTDEFINES) /D_USE_64BIT_TIME_T=1 -!endif -!endif -!if "$(TCL_BUILD_FOR)" == "8" -OPTDEFINES = $(OPTDEFINES) /DTCL_MAJOR_VERSION=8 -!endif - -# Like the TEA system only set this non empty for non-Tk extensions -# Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME -# so we pass both -!if !$(DOING_TCL) && !$(DOING_TK) -PKGNAMEFLAGS = /DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ - /DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ - /DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ - /DMODULE_SCOPE=extern -!endif - -# crt picks the C run time based on selected OPTS -!if $(MSVCRT) -!if $(DEBUG) && !$(UNCHECKED) -crt = -MDd -!else -crt = -MD -!endif -!else -!if $(DEBUG) && !$(UNCHECKED) -crt = -MTd -!else -crt = -MT -!endif -!endif - -# cdebug includes compiler options for debugging as well as optimization. -!if $(DEBUG) - -# In debugging mode, optimizations need to be disabled -cdebug = -Zi -Od $(DEBUGFLAGS) - -!else - -cdebug = $(OPTIMIZATIONS) -!if $(SYMBOLS) -cdebug = $(cdebug) -Zi -!endif - -!endif # $(DEBUG) - -# cwarn includes default warning levels, also C4090 (buggy) and C4146 is useless. -cwarn = $(WARNINGS) -wd4090 -wd4146 - -!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64" -# Disable pointer<->int warnings related to cast between different sizes -# There are a gadzillion of these due to use of ClientData and -# clutter up compiler -# output increasing chance of a real warning getting lost. So disable them. -# Eventually some day, Tcl will be 64-bit clean. -cwarn = $(cwarn) -wd4311 -wd4312 -!endif - -### Common compiler options that are architecture specific -!if "$(MACHINE)" == "ARM" -carch = /D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE -!else -carch = -!endif - -# cpuid is only available on intel machines -!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "AMD64" -carch = $(carch) /DHAVE_CPUID=1 -!endif - -!if $(DEBUG) -# Turn warnings into errors -cwarn = $(cwarn) -WX -!endif - -INCLUDES = $(TCL_INCLUDES) $(TK_INCLUDES) $(PRJ_INCLUDES) -!if !$(DOING_TCL) && !$(DOING_TK) -INCLUDES = $(INCLUDES) -I"$(GENERICDIR)" -I"$(WIN_DIR)" -I"$(COMPATDIR)" -!endif - -# These flags are defined roughly in the order of the pre-reform -# rules.vc/makefile.vc to help visually compare that the pre- and -# post-reform build logs - -# cflags contains generic flags used for building practically all object files -cflags = -nologo -c $(COMPILERFLAGS) $(carch) $(cwarn) -Fp$(TMP_DIR)^\ $(cdebug) - -!if $(TCL_MAJOR_VERSION) == 8 && $(TCL_MINOR_VERSION) < 7 -cflags = $(cflags) -DTcl_Size=int -!endif - -# appcflags contains $(cflags) and flags for building the application -# object files (e.g. tclsh, or wish) pkgcflags contains $(cflags) plus -# flags used for building shared object files The two differ in the -# BUILD_$(PROJECT) macro which should be defined only for the shared -# library *implementation* and not for its caller interface - -appcflags_nostubs = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES) -appcflags = $(appcflags_nostubs) $(USE_STUBS_DEFS) -pkgcflags = $(appcflags) $(PKGNAMEFLAGS) /DBUILD_$(PROJECT) -pkgcflags_nostubs = $(appcflags_nostubs) $(PKGNAMEFLAGS) /DBUILD_$(PROJECT) - -# stubscflags contains $(cflags) plus flags used for building a stubs -# library for the package. Note: /DSTATIC_BUILD is defined in -# $(OPTDEFINES) only if the OPTS configuration indicates a static -# library. However the stubs library is ALWAYS static hence included -# here irrespective of the OPTS setting. -# -# TBD - tclvfs has a comment that stubs libs should not be compiled with -GL -# without stating why. Tcl itself compiled stubs libs with this flag. -# so we do not remove it from cflags. -GL may prevent extensions -# compiled with one VC version to fail to link against stubs library -# compiled with another VC version. Check for this and fix accordingly. -stubscflags = $(cflags) $(PKGNAMEFLAGS) $(PRJ_DEFINES) $(OPTDEFINES) /Zl /GL- /DSTATIC_BUILD $(INCLUDES) $(USE_STUBS_DEFS) - -# Link flags - -!if $(DEBUG) -ldebug = -debug -debugtype:cv -!else -ldebug = -release -opt:ref -opt:icf,3 -!if $(SYMBOLS) -ldebug = $(ldebug) -debug -debugtype:cv -!endif -!endif - -# Note: Profiling is currently only possible with the Visual Studio Enterprise -!if $(PROFILE) -ldebug= $(ldebug) -profile -!endif - -### Declarations common to all linker versions -lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) - -!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 -lflags = $(lflags) -nodefaultlib:libucrt.lib -!endif - -dlllflags = $(lflags) -dll -conlflags = $(lflags) -subsystem:console -guilflags = $(lflags) -subsystem:windows - -# Libraries that are required for every image. -# Extensions should define any additional libraries with $(PRJ_LIBS) -winlibs = kernel32.lib advapi32.lib - -!if $(NEED_TK) -winlibs = $(winlibs) gdi32.lib user32.lib uxtheme.lib -!endif - -# Avoid 'unresolved external symbol __security_cookie' errors. -# c.f. http://support.microsoft.com/?id=894573 -!if "$(MACHINE)" == "AMD64" -!if $(VCVERSION) > 1399 && $(VCVERSION) < 1500 -winlibs = $(winlibs) bufferoverflowU.lib -!endif -!endif - -baselibs = $(winlibs) $(PRJ_LIBS) - -!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 -baselibs = $(baselibs) ucrt.lib -!endif - -################################################################ -# 13. Define standard commands, common make targets and implicit rules - -CCPKGCMD = $(cc32) $(pkgcflags) -Fo$(TMP_DIR)^\ -CCAPPCMD = $(cc32) $(appcflags) -Fo$(TMP_DIR)^\ -CCSTUBSCMD = $(cc32) $(stubscflags) -Fo$(TMP_DIR)^\ - -LIBCMD = $(lib32) -nologo $(LINKERFLAGS) -out:$@ -DLLCMD = $(link32) $(dlllflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) - -CONEXECMD = $(link32) $(conlflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) -GUIEXECMD = $(link32) $(guilflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) -RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \ - $(TCL_INCLUDES) /DSTATIC_BUILD=$(STATIC_BUILD) \ - /DDEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \ - /DCOMMAVERSION=$(RCCOMMAVERSION) \ - /DDOTVERSION=\"$(DOTVERSION)\" \ - /DVERSION=\"$(VERSION)\" \ - /DSUFX=\"$(SUFX)\" \ - /DPROJECT=\"$(PROJECT)\" \ - /DPRJLIBNAME=\"$(PRJLIBNAME)\" - -!ifndef DEFAULT_BUILD_TARGET -DEFAULT_BUILD_TARGET = $(PROJECT) -!endif - -default-target: $(DEFAULT_BUILD_TARGET) - -!if $(MULTIPLATFORM_INSTALL) -default-pkgindex: - @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl - @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ - [list load [file join $$dir $(PLATFORM_IDENTIFY) $(PRJLIBNAME9)]] >> $(OUT_DIR)\pkgIndex.tcl - @echo } else { >> $(OUT_DIR)\pkgIndex.tcl - @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ - [list load [file join $$dir $(PLATFORM_IDENTIFY) $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl - @echo } >> $(OUT_DIR)\pkgIndex.tcl -!else -default-pkgindex: - @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl - @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ - [list load [file join $$dir $(PRJLIBNAME9)]] >> $(OUT_DIR)\pkgIndex.tcl - @echo } else { >> $(OUT_DIR)\pkgIndex.tcl - @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ - [list load [file join $$dir $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl - @echo } >> $(OUT_DIR)\pkgIndex.tcl -!endif - -default-pkgindex-tea: - @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl -@PACKAGE_VERSION@ $(DOTVERSION) -@PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME) -@PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME) -@PKG_LIB_FILE@ $(PRJLIBNAME) -@PKG_LIB_FILE8@ $(PRJLIBNAME8) -@PKG_LIB_FILE9@ $(PRJLIBNAME9) -<< - -default-install: default-install-binaries default-install-libraries -!if $(SYMBOLS) -default-install: default-install-pdbs -!endif - -# Again to deal with historical brokenness, there is some confusion -# in terminlogy. For extensions, the "install-binaries" was used to -# locate target directory for *binary shared libraries* and thus -# the appropriate macro is LIB_INSTALL_DIR since BIN_INSTALL_DIR is -# for executables (exes). On the other hand the "install-libraries" -# target is for *scripts* and should have been called "install-scripts". -default-install-binaries: $(PRJLIB) - @echo Installing binaries to '$(LIB_INSTALL_DIR)' - @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)" - @$(CPY) $(PRJLIB) "$(LIB_INSTALL_DIR)" >NUL - -# Alias for default-install-scripts -default-install-libraries: default-install-scripts - -default-install-scripts: $(OUT_DIR)\pkgIndex.tcl - @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' - @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" - @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' - @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR) - -default-install-stubs: - @echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)' - @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" - @$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL - -default-install-pdbs: - @echo Installing PDBs to '$(LIB_INSTALL_DIR)' - @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)" - @$(CPY) "$(OUT_DIR)\*.pdb" "$(LIB_INSTALL_DIR)\" - -# "emacs font-lock highlighting fix - -default-install-docs-html: - @echo Installing documentation files to '$(DOC_INSTALL_DIR)' - @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" - @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)" - -default-install-docs-n: - @echo Installing documentation files to '$(DOC_INSTALL_DIR)' - @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" - @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.n") do @$(COPY) %f "$(DOC_INSTALL_DIR)" - -default-install-demos: - @echo Installing demos to '$(DEMO_INSTALL_DIR)' - @if not exist "$(DEMO_INSTALL_DIR)" mkdir "$(DEMO_INSTALL_DIR)" - @if exist $(DEMODIR) $(CPYDIR) "$(DEMODIR)" "$(DEMO_INSTALL_DIR)" - -default-clean: - @echo Cleaning $(TMP_DIR)\* ... - @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) - @echo Cleaning $(WIN_DIR)\nmakehlp.obj, nmakehlp.exe ... - @if exist $(WIN_DIR)\nmakehlp.obj del $(WIN_DIR)\nmakehlp.obj - @if exist $(WIN_DIR)\nmakehlp.exe del $(WIN_DIR)\nmakehlp.exe - @if exist $(WIN_DIR)\nmakehlp.out del $(WIN_DIR)\nmakehlp.out - @echo Cleaning $(WIN_DIR)\nmhlp-out.txt ... - @if exist $(WIN_DIR)\nmhlp-out.txt del $(WIN_DIR)\nmhlp-out.txt - @echo Cleaning $(WIN_DIR)\_junk.pch ... - @if exist $(WIN_DIR)\_junk.pch del $(WIN_DIR)\_junk.pch - @echo Cleaning $(WIN_DIR)\vercl.x, vercl.i ... - @if exist $(WIN_DIR)\vercl.x del $(WIN_DIR)\vercl.x - @if exist $(WIN_DIR)\vercl.i del $(WIN_DIR)\vercl.i - @echo Cleaning $(WIN_DIR)\versions.vc, version.vc ... - @if exist $(WIN_DIR)\versions.vc del $(WIN_DIR)\versions.vc - @if exist $(WIN_DIR)\version.vc del $(WIN_DIR)\version.vc - -default-hose: default-clean - @echo Hosing $(OUT_DIR)\* ... - @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) - -# Only for backward compatibility -default-distclean: default-hose - -default-setup: - @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) - @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) - -!if "$(TESTPAT)" != "" -TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) -!endif - -default-test: default-setup $(PROJECT) - @set TCLLIBPATH=$(OUT_DIR:\=/) - @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" - cd "$(TESTDIR)" && $(DEBUGGER) $(TCLSH) all.tcl $(TESTFLAGS) - -default-shell: default-setup $(PROJECT) - @set TCLLIBPATH=$(OUT_DIR:\=/) - @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" - $(DEBUGGER) $(TCLSH) - -# Generation of Windows version resource -!ifdef RCFILE - -# Note: don't use $** in below rule because there may be other dependencies -# and only the "main" rc must be passed to the resource compiler -$(TMP_DIR)\$(PROJECT).res: $(RCDIR)\$(PROJECT).rc - $(RESCMD) $(RCDIR)\$(PROJECT).rc - -!else - -# If parent makefile has not defined a resource definition file, -# we will generate one from standard template. -$(TMP_DIR)\$(PROJECT).res: $(TMP_DIR)\$(PROJECT).rc - -$(TMP_DIR)\$(PROJECT).rc: - @$(COPY) << $(TMP_DIR)\$(PROJECT).rc -#include - -VS_VERSION_INFO VERSIONINFO - FILEVERSION COMMAVERSION - PRODUCTVERSION COMMAVERSION - FILEFLAGSMASK 0x3fL -#ifdef DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "FileDescription", "Tcl extension " PROJECT - VALUE "OriginalFilename", PRJLIBNAME - VALUE "FileVersion", DOTVERSION - VALUE "ProductName", "Package " PROJECT " for Tcl" - VALUE "ProductVersion", DOTVERSION - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -<< - -!endif # ifdef RCFILE - -!ifndef DISABLE_IMPLICIT_RULES -DISABLE_IMPLICIT_RULES = 0 -!endif - -!if !$(DISABLE_IMPLICIT_RULES) -# Implicit rule definitions - only for building library objects. For stubs and -# main application, the makefile should define explicit rules. - -{$(ROOT)}.c{$(TMP_DIR)}.obj:: - $(CCPKGCMD) @<< -$< -<< - -{$(WIN_DIR)}.c{$(TMP_DIR)}.obj:: - $(CCPKGCMD) @<< -$< -<< - -{$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: - $(CCPKGCMD) @<< -$< -<< - -{$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: - $(CCPKGCMD) @<< -$< -<< - -{$(RCDIR)}.rc{$(TMP_DIR)}.res: - $(RESCMD) $< - -{$(WIN_DIR)}.rc{$(TMP_DIR)}.res: - $(RESCMD) $< - -{$(TMP_DIR)}.rc{$(TMP_DIR)}.res: - $(RESCMD) $< - -.SUFFIXES: -.SUFFIXES:.c .rc - -!endif - -################################################################ -# 14. Sanity check selected options against Tcl build options -# When building an extension, certain configuration options should -# match the ones used when Tcl was built. Here we check and -# warn on a mismatch. -!if !$(DOING_TCL) - -!if $(TCLINSTALL) # Building against an installed Tcl -!if exist("$(_TCLDIR)\lib\nmake\tcl.nmake") -TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake" -!endif -!else # !$(TCLINSTALL) - building against Tcl source -!if exist("$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl.nmake") -TCLNMAKECONFIG = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl.nmake" -!endif -!endif # TCLINSTALL - -!if $(CONFIG_CHECK) -!ifdef TCLNMAKECONFIG -!include $(TCLNMAKECONFIG) - -!if defined(CORE_MACHINE) && "$(CORE_MACHINE)" != "$(MACHINE)" -!error ERROR: Build target ($(MACHINE)) does not match the Tcl library architecture ($(CORE_MACHINE)). -!endif -!if $(TCL_VERSION) < 87 && defined(CORE_USE_THREAD_ALLOC) && $(CORE_USE_THREAD_ALLOC) != $(USE_THREAD_ALLOC) -!message WARNING: Value of USE_THREAD_ALLOC ($(USE_THREAD_ALLOC)) does not match its Tcl core value ($(CORE_USE_THREAD_ALLOC)). -!endif -!if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG) -!message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)). -!endif -!endif - -!endif # TCLNMAKECONFIG - -!endif # !$(DOING_TCL) - - -#---------------------------------------------------------- -# Display stats being used. -#---------------------------------------------------------- - -!if !$(DOING_TCL) -!message *** Building against Tcl at '$(_TCLDIR)' -!endif -!if !$(DOING_TK) && $(NEED_TK) -!message *** Building against Tk at '$(_TKDIR)' -!endif -!message *** Intermediate directory will be '$(TMP_DIR)' -!message *** Output directory will be '$(OUT_DIR)' -!message *** Installation, if selected, will be in '$(_INSTALLDIR)' -!message *** Suffix for binaries will be '$(SUFX)' -!message *** Compiler version $(VCVER). Target $(MACHINE), host $(NATIVE_ARCH). - -!endif # ifdef _RULES_VC diff --git a/autoconf/tea/win/targets.vc b/autoconf/tea/win/targets.vc deleted file mode 100644 index 49ed7d4a41..0000000000 --- a/autoconf/tea/win/targets.vc +++ /dev/null @@ -1,98 +0,0 @@ -#------------------------------------------------------------- -*- makefile -*- -# targets.vc -- -# -# Part of the nmake based build system for Tcl and its extensions. -# This file defines some standard targets for the convenience of extensions -# and can be optionally included by the extension makefile. -# See TIP 477 (https://core.tcl-lang.org/tips/doc/main/tip/477.md) for docs. - -$(PROJECT): setup pkgindex $(PRJLIB) - -!ifdef PRJ_STUBOBJS -$(PROJECT): $(PRJSTUBLIB) -$(PRJSTUBLIB): $(PRJ_STUBOBJS) - $(LIBCMD) $** - -$(PRJ_STUBOBJS): - $(CCSTUBSCMD) %s -!endif # PRJ_STUBOBJS - -!ifdef PRJ_MANIFEST -$(PROJECT): $(PRJLIB).manifest -$(PRJLIB).manifest: $(PRJ_MANIFEST) - @nmakehlp -s << $** >$@ -@MACHINE@ $(MACHINE:IX86=X86) -<< -!endif - -!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" -$(PRJLIB): $(PRJ_OBJS) $(RESFILE) -!if $(STATIC_BUILD) - $(LIBCMD) $** -!else - $(DLLCMD) $** - $(_VC_MANIFEST_EMBED_DLL) -!endif - -@del $*.exp -!endif - -!if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != "" -$(PRJ_OBJS): $(PRJ_HEADERS) -!endif - -# If parent makefile has defined stub objects, add their installation -# to the default install -!if "$(PRJ_STUBOBJS)" != "" -default-install: default-install-stubs -!endif - -# Unlike the other default targets, these cannot be in rules.vc because -# the executed command depends on existence of macro PRJ_HEADERS_PUBLIC -# that the parent makefile will not define until after including rules-ext.vc -!if "$(PRJ_HEADERS_PUBLIC)" != "" -default-install: default-install-headers -default-install-headers: - @echo Installing headers to '$(INCLUDE_INSTALL_DIR)' - @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)" -!endif - -!if "$(DISABLE_STANDARD_TARGETS)" == "" -DISABLE_STANDARD_TARGETS = 0 -!endif - -!if "$(DISABLE_TARGET_setup)" == "" -DISABLE_TARGET_setup = 0 -!endif -!if "$(DISABLE_TARGET_install)" == "" -DISABLE_TARGET_install = 0 -!endif -!if "$(DISABLE_TARGET_clean)" == "" -DISABLE_TARGET_clean = 0 -!endif -!if "$(DISABLE_TARGET_test)" == "" -DISABLE_TARGET_test = 0 -!endif -!if "$(DISABLE_TARGET_shell)" == "" -DISABLE_TARGET_shell = 0 -!endif - -!if !$(DISABLE_STANDARD_TARGETS) -!if !$(DISABLE_TARGET_setup) -setup: default-setup -!endif -!if !$(DISABLE_TARGET_install) -install: default-install -!endif -!if !$(DISABLE_TARGET_clean) -clean: default-clean -realclean: hose -hose: default-hose -distclean: realclean default-distclean -!endif -!if !$(DISABLE_TARGET_test) -test: default-test -!endif -!if !$(DISABLE_TARGET_shell) -shell: default-shell -!endif -!endif # DISABLE_STANDARD_TARGETS diff --git a/autosetup/README.md b/autosetup/README.md index a61f94fbda..3301f57395 100644 --- a/autosetup/README.md +++ b/autosetup/README.md @@ -15,6 +15,8 @@ build infrastructure. It is not an [Autosetup][] reference. - Do Not Update Global Shared State - [Updating Autosetup](#updating) - ***[Patching Autosetup for Project-local changes](#patching)*** +- [Branch-specific Customization](#branch-customization) + ------------------------------------------------------------------------ @@ -385,6 +387,60 @@ If autosetup is upgraded and this patch is _not_ applied the invoking `./configure` will fail loudly because of the declaration of the `debug` flag in `auto.def` - duplicated flags are not permitted. + +Branch-specific Customization +======================================================================== + +Certain vendor-specific branches require slight configure script +customization. Rather than editing `sqlite-config.tcl` for this, +which frequently leads to merge conflicts, the following approach +is recommended: + +In the vendor-specific branch, create a file named +`autosetup/sqlite-custom.tcl`. + +That file should contain the following content... + +If flag customization is required, add: + +> +``` +proc sqlite-custom-flags {} { + # If any existing --flags require different default values + # then call: + options-defaults { + flag-name new-default-value + ... + } + # ^^^ That will replace the default value but will not update + # the --help text, which may lead to some confusion: + # https://github.com/msteveb/autosetup/issues/77 + + return { + {*} { + new-flag-name => {Help text} + ... + } + }; #see below +} +``` + +That function must return either an empty string or a list in the form +used internally by `sqlite-config.tcl:sqlite-configure`. + +Next, define: + +> +``` +proc sqlite-custom-handle-flags {} { + ... do any custom flag handling here ... +} +``` + +That function, if defined, will be called relatively late in the +configure process, before any filtered files are generated but after +all other significant processing. + [Autosetup]: https://msteveb.github.io/autosetup/ [auto.def]: /file/auto.def diff --git a/tool/find_tclconfig.tcl b/autosetup/find_tclconfig.tcl similarity index 100% rename from tool/find_tclconfig.tcl rename to autosetup/find_tclconfig.tcl diff --git a/autosetup/proj.tcl b/autosetup/proj.tcl index 3e703d007a..2e272a3b52 100644 --- a/autosetup/proj.tcl +++ b/autosetup/proj.tcl @@ -15,12 +15,16 @@ # The intent is that these routines be relatively generic, independent # of a given project. # +# For practical purposes, the copy of this file hosted in the SQLite +# project is the "canonical" one: +# +# https://sqlite.org/src/file/autosetup/proj.tcl +# # This file was initially derived from one used in the libfossil # project, authored by the same person who ported it here, and this is # noted here only as an indication that there are no licensing issues # despite this code having a handful of near-twins running around a # handful of third-party source trees. -# ######################################################################## # # Design notes: @@ -50,37 +54,82 @@ # ----- @module proj.tcl ----- # @section Project Helper APIs -######################################################################## -# $proj_ is an internal-use-only array for storing whatever generic +# +# $proj__Config is an internal-use-only array for storing whatever generic # internal stuff we need stored. -array set proj_ {} -set proj_(isatty) [isatty? stdout] +# +array set proj__Config { + self-tests 0 +} -######################################################################## + +# +# List of dot-in files to filter in the final stages of +# configuration. Some configuration steps may append to this. Each +# one in this list which exists will trigger the generation of a +# file with that same name, minus the ".in", in the build directory +# (which differ from the source dir in out-of-tree builds). +# +# See: proj-dot-ins-append and proj-dot-ins-process +# +set proj__Config(dot-in-files) [list] +set proj__Config(isatty) [isatty? stdout] + +# # @proj-warn msg # -# Emits a warning message to stderr. -proc proj-warn {msg} { - show-notices - puts stderr "WARNING: $msg" -} -######################################################################## -# @proj-error msg +# Emits a warning message to stderr. All args are appended with a +# space between each. # -# Emits an error message to stderr and exits with non-0. -proc proj-fatal {msg} { +proc proj-warn {args} { show-notices - puts stderr "ERROR: $msg" + puts stderr [join [list "WARNING:" {*}$args] " "] +} + +# +# @proj-fatal ?-up...? msg... +# +# Emits an error message to stderr and exits with non-0. All args are +# appended with a space between each. +# +# The calling scope's name is used in the error message. To instead +# use the name of a call higher up in the stack, use -up once for each +# additional level. +# +proc proj-fatal {args} { + show-notices + set lvl 1 + while {"-up" eq [lindex $args 0]} { + set args [lassign $args -] + incr lvl + } + puts stderr [join [list "FATAL: \[[proj-current-scope $lvl]]: " {*}$args]] exit 1 } -######################################################################## +# +# @proj-error ?-up...? msg... +# +# Works like prop-fatal but uses [error] intead of [exit]. +# +proc proj-error {args} { + show-notices + set lvl 1 + while {"-up" eq [lindex $args 0]} { + set args [lassign $args -] + incr lvl + } + error [join [list "\[[proj-current-scope $lvl]]:" {*}$args]] +} + +# # @proj-assert script ?message? # # Kind of like a C assert: if uplevel (eval) of [expr {$script}] is # false, a fatal error is triggered. The error message, by default, # includes the body of the failed assertion, but if $msg is set then # that is used instead. +# proc proj-assert {script {msg ""}} { if {1 == [get-env proj-assert 0]} { msg-result [proj-bold "asserting: $script"] @@ -94,23 +143,25 @@ proc proj-assert {script {msg ""}} { } } -######################################################################## +# # @proj-bold str # # If this function believes that the current console might support # ANSI escape sequences then this returns $str wrapped in a sequence # to bold that text, else it returns $str as-is. -proc proj-bold {str} { - if {$::autosetup(iswin) || !$::proj_(isatty)} { - return $str +# +proc proj-bold {args} { + if {$::autosetup(iswin) || !$::proj__Config(isatty)} { + return [join $args] } - return "\033\[1m${str}\033\[0m" + return "\033\[1m${args}\033\[0m" } -######################################################################## +# # @proj-indented-notice ?-error? ?-notice? msg # # Takes a multi-line message and emits it with consistent indentation. +# It does not perform any line-wrapping of its own. # # If the -notice flag it used then it emits using [user-notice], which # means its rendering will (A) go to stderr and (B) be delayed until @@ -121,6 +172,7 @@ proc proj-bold {str} { # # If neither -notice nor -error are used, the message will be sent to # stdout without delay. +# proc proj-indented-notice {args} { set fErr "" set outFunc "puts" @@ -154,35 +206,16 @@ proc proj-indented-notice {args} { } } -######################################################################## +# # @proj-is-cross-compiling # # Returns 1 if cross-compiling, else 0. +# proc proj-is-cross-compiling {} { return [expr {[get-define host] ne [get-define build]}] } -######################################################################## -# proj-lshift_ shifts $count elements from the list named $listVar -# and returns them as a new list. On empty input, returns "". # -# Modified slightly from: https://wiki.tcl-lang.org/page/lshift -proc proj-lshift_ {listVar {count 1}} { - upvar 1 $listVar l - if {![info exists l]} { - # make the error message show the real variable name - error "can't read \"$listVar\": no such variable" - } - if {![llength $l]} { - # error Empty - return "" - } - set r [lrange $l 0 [incr count -1]] - set l [lreplace $l [set l 0] $count] - return $r -} - -######################################################################## # @proj-strip-hash-comments value # # Expects to receive string input, which it splits on newlines, strips @@ -190,6 +223,7 @@ proc proj-lshift_ {listVar {count 1}} { # a '#', and returns a value containing the [append]ed results of each # remaining line with a \n between each. It does not strip out # comments which appear after the first non-whitespace character. +# proc proj-strip-hash-comments {val} { set x {} foreach line [split $val \n] { @@ -200,12 +234,13 @@ proc proj-strip-hash-comments {val} { return $x } -######################################################################## +# # @proj-cflags-without-werror # # Fetches [define $var], strips out any -Werror entries, and returns # the new value. This is intended for temporarily stripping -Werror # from CFLAGS or CPPFLAGS within the scope of a [define-push] block. +# proc proj-cflags-without-werror {{var CFLAGS}} { set rv {} foreach f [get-define $var ""] { @@ -217,7 +252,7 @@ proc proj-cflags-without-werror {{var CFLAGS}} { return [join $rv " "] } -######################################################################## +# # @proj-check-function-in-lib # # A proxy for cc-check-function-in-lib with the following differences: @@ -230,6 +265,7 @@ proc proj-cflags-without-werror {{var CFLAGS}} { # Returns the result of cc-check-function-in-lib (i.e. true or false). # The resulting linker flags are stored in the [define] named # lib_${function}. +# proc proj-check-function-in-lib {function libs {otherlibs {}}} { set found 0 define-push {LIBS CFLAGS} { @@ -241,13 +277,14 @@ proc proj-check-function-in-lib {function libs {otherlibs {}}} { return $found } -######################################################################## +# # @proj-search-for-header-dir ?-dirs LIST? ?-subdirs LIST? header # # Searches for $header in a combination of dirs and subdirs, specified # by the -dirs {LIST} and -subdirs {LIST} flags (each of which have # sane defaults). Returns either the first matching dir or an empty # string. The return value does not contain the filename part. +# proc proj-search-for-header-dir {header args} { set subdirs {include} set dirs {/usr /usr/local /mingw} @@ -274,7 +311,7 @@ proc proj-search-for-header-dir {header args} { return "" } -######################################################################## +# # @proj-find-executable-path ?-v? binaryName # # Works similarly to autosetup's [find-executable-path $binName] but: @@ -282,6 +319,7 @@ proc proj-search-for-header-dir {header args} { # - If the first arg is -v, it's verbose about searching, else it's quiet. # # Returns the full path to the result or an empty string. +# proc proj-find-executable-path {args} { set binName $args set verbose 0 @@ -301,7 +339,7 @@ proc proj-find-executable-path {args} { return $check } -######################################################################## +# # @proj-bin-define binName ?defName? # # Uses [proj-find-executable-path $binName] to (verbosely) search for @@ -311,6 +349,7 @@ proc proj-find-executable-path {args} { # The define'd name is: If $defName is not empty, it is used as-is. If # $defName is empty then "BIN_X" is used, where X is the upper-case # form of $binName with any '-' characters replaced with '_'. +# proc proj-bin-define {binName {defName {}}} { set check [proj-find-executable-path -v $binName] if {"" eq $defName} { @@ -320,7 +359,7 @@ proc proj-bin-define {binName {defName {}}} { return $check } -######################################################################## +# # @proj-first-bin-of bin... # # Looks for the first binary found of the names passed to this @@ -331,6 +370,7 @@ proc proj-bin-define {binName {defName {}}} { # any define'd name that function stores for the result (because the # caller has no sensible way of knowing which result it was unless # they pass only a single argument). +# proc proj-first-bin-of {args} { set rc "" foreach b $args { @@ -345,7 +385,7 @@ proc proj-first-bin-of {args} { return $rc } -######################################################################## +# # @proj-opt-was-provided key # # Returns 1 if the user specifically provided the given configure flag @@ -363,6 +403,9 @@ proc proj-first-bin-of {args} { # to the default value of baz. If the user does not explicitly pass in # --foo-bar (with or without a value) then this returns 0. # +# Calling [proj-opt-set] is, for purposes of the above, equivalent to +# explicitly passing in the flag. +# # Note: unlike most functions which deal with configure --flags, this # one does not validate that $key refers to a pre-defined flag. i.e. # it accepts arbitrary keys, even those not defined via an [options] @@ -370,17 +413,19 @@ proc proj-first-bin-of {args} { # that new options set via that function will cause this function to # return true. (That's an unintended and unavoidable side-effect, not # specifically a feature which should be made use of.) +# proc proj-opt-was-provided {key} { dict exists $::autosetup(optset) $key } -######################################################################## +# # @proj-opt-set flag ?val? # # Force-set autosetup option $flag to $val. The value can be fetched # later with [opt-val], [opt-bool], and friends. # # Returns $val. +# proc proj-opt-set {flag {val 1}} { if {$flag ni $::autosetup(options)} { # We have to add this to autosetup(options) or else future calls @@ -391,29 +436,32 @@ proc proj-opt-set {flag {val 1}} { return $val } -######################################################################## +# # @proj-opt-exists flag # # Returns 1 if the given flag has been defined as a legal configure # option, else returns 0. +# proc proj-opt-exists {flag} { expr {$flag in $::autosetup(options)}; } -######################################################################## +# # @proj-val-truthy val # # Returns 1 if $val appears to be a truthy value, else returns # 0. Truthy values are any of {1 on true yes enabled} +# proc proj-val-truthy {val} { expr {$val in {1 on true yes enabled}} } -######################################################################## +# # @proj-opt-truthy flag # # Returns 1 if [opt-val $flag] appears to be a truthy value or # [opt-bool $flag] is true. See proj-val-truthy. +# proc proj-opt-truthy {flag} { if {[proj-val-truthy [opt-val $flag]]} { return 1 } set rc 0 @@ -424,10 +472,11 @@ proc proj-opt-truthy {flag} { return $rc } -######################################################################## +# # @proj-if-opt-truthy boolFlag thenScript ?elseScript? # # If [proj-opt-truthy $flag] is true, eval $then, else eval $else. +# proc proj-if-opt-truthy {boolFlag thenScript {elseScript {}}} { if {[proj-opt-truthy $boolFlag]} { uplevel 1 $thenScript @@ -436,13 +485,14 @@ proc proj-if-opt-truthy {boolFlag thenScript {elseScript {}}} { } } -######################################################################## +# # @proj-define-for-opt flag def ?msg? ?iftrue? ?iffalse? # # If [proj-opt-truthy $flag] then [define $def $iftrue] else [define # $def $iffalse]. If $msg is not empty, output [msg-checking $msg] and # a [msg-results ...] which corresponds to the result. Returns 1 if # the opt-truthy check passes, else 0. +# proc proj-define-for-opt {flag def {msg ""} {iftrue 1} {iffalse 0}} { if {"" ne $msg} { msg-checking "$msg " @@ -465,7 +515,7 @@ proc proj-define-for-opt {flag def {msg ""} {iftrue 1} {iffalse 0}} { return $rc } -######################################################################## +# # @proj-opt-define-bool ?-v? optName defName ?descr? # # Checks [proj-opt-truthy $optName] and calls [define $defName X] @@ -475,20 +525,21 @@ proc proj-define-for-opt {flag def {msg ""} {iftrue 1} {iffalse 0}} { # If args[0] is -v then the boolean semantics are inverted: if # the option is set, it gets define'd to 0, else 1. Returns the # define'd value. +# proc proj-opt-define-bool {args} { set invert 0 if {[lindex $args 0] eq "-v"} { set invert 1 - set args [lrange $args 1 end] + lassign $args - optName defName descr + } else { + lassign $args optName defName descr } - set optName [proj-lshift_ args] - set defName [proj-lshift_ args] - set descr [proj-lshift_ args] if {"" eq $descr} { set descr $defName } + #puts "optName=$optName defName=$defName descr=$descr" set rc 0 - msg-checking "$descr ... " + msg-checking "[join $descr] ... " if {[proj-opt-truthy $optName]} { if {0 eq $invert} { set rc 1 @@ -503,7 +554,7 @@ proc proj-opt-define-bool {args} { return $rc } -######################################################################## +# # @proj-check-module-loader # # Check for module-loading APIs (libdl/libltdl)... @@ -523,6 +574,7 @@ proc proj-opt-define-bool {args} { # # Note that if it finds LIBLTDL it does not look for LIBDL, so will # report only that is has LIBLTDL. +# proc proj-check-module-loader {} { msg-checking "Looking for module-loader APIs... " if {99 ne [get-define LDFLAGS_MODULE_LOADER 99]} { @@ -568,25 +620,27 @@ proc proj-check-module-loader {} { return $rc } -######################################################################## +# # @proj-no-check-module-loader # # Sets all flags which would be set by proj-check-module-loader to # empty/falsy values, as if those checks had failed to find a module # loader. Intended to be called in place of that function when # a module loader is explicitly not desired. +# proc proj-no-check-module-loader {} { define HAVE_LIBDL 0 define HAVE_LIBLTDL 0 define LDFLAGS_MODULE_LOADER "" } -######################################################################## +# # @proj-file-conent ?-trim? filename # # Opens the given file, reads all of its content, and returns it. If # the first arg is -trim, the contents of the file named by the second # argument are trimmed before returning them. +# proc proj-file-content {args} { set trim 0 set fname $args @@ -594,20 +648,21 @@ proc proj-file-content {args} { set trim 1 lassign $args - fname } - set fp [open $fname r] + set fp [open $fname rb] set rc [read $fp] close $fp if {$trim} { return [string trim $rc] } return $rc } -######################################################################## +# # @proj-file-conent filename # # Returns the contents of the given file as an array of lines, with # the EOL stripped from each input line. +# proc proj-file-content-list {fname} { - set fp [open $fname r] + set fp [open $fname rb] set rc {} while { [gets $fp line] >= 0 } { lappend rc $line @@ -616,7 +671,33 @@ proc proj-file-content-list {fname} { return $rc } -######################################################################## +# +# @proj-file-write ?-ro? fname content +# +# Works like autosetup's [writefile] but explicitly uses binary mode +# to avoid EOL translation on Windows. If $fname already exists, it is +# overwritten, even if it's flagged as read-only. +# +proc proj-file-write {args} { + if {"-ro" eq [lindex $args 0]} { + lassign $args ro fname content + } else { + set ro "" + lassign $args fname content + } + file delete -force -- $fname; # in case it's read-only + set f [open $fname wb] + puts -nonewline $f $content + close $f + if {"" ne $ro} { + catch { + exec chmod -w $fname + #file attributes -w $fname; #jimtcl has no 'attributes' + } + } +} + +# # @proj-check-compile-commands ?configFlag? # # Checks the compiler for compile_commands.json support. If passed an @@ -624,10 +705,13 @@ proc proj-file-content-list {fname} { # which controls whether to run/skip this check. # # Returns 1 if supported, else 0. Defines MAKE_COMPILATION_DB to "yes" -# if supported, "no" if not. +# if supported, "no" if not. The use of MAKE_COMPILATION_DB is +# deprecated/discouraged. It also sets HAVE_COMPILE_COMMANDS to 0 or +# 1, and that's the preferred usage. +# +# ACHTUNG: this test has a long history of false positive results +# because of compilers reacting differently to the -MJ flag. # -# This test has a long history of false positive results because of -# compilers reacting differently to the -MJ flag. proc proj-check-compile-commands {{configFlag {}}} { msg-checking "compile_commands.json support... " if {"" ne $configFlag && ![proj-opt-truthy $configFlag]} { @@ -640,31 +724,41 @@ proc proj-check-compile-commands {{configFlag {}}} { # Martin G.'s older systems. drh also reports a false # positive on an unspecified older Mac system. msg-result "compiler supports compile_commands.json" - define MAKE_COMPILATION_DB yes + define MAKE_COMPILATION_DB yes; # deprecated + define HAVE_COMPILE_COMMANDS 1 return 1 } else { msg-result "compiler does not support compile_commands.json" define MAKE_COMPILATION_DB no + define HAVE_COMPILE_COMMANDS 0 return 0 } } } -######################################################################## +# # @proj-touch filename # # Runs the 'touch' external command on one or more files, ignoring any # errors. +# proc proj-touch {filename} { catch { exec touch {*}$filename } } -######################################################################## -# @proj-make-from-dot-in ?-touch? filename... # -# Uses [make-template] to create makefile(-like) file(s) $filename -# from $filename.in but explicitly makes the output read-only, to -# avoid inadvertent editing (who, me?). +# @proj-make-from-dot-in ?-touch? infile ?outfile? +# +# Uses [make-template] to create makefile(-like) file(s) $outfile from +# $infile but explicitly makes the output read-only, to avoid +# inadvertent editing (who, me?). +# +# If $outfile is empty then: +# +# - If $infile is a 2-element list, it is assumed to be an in/out pair, +# and $outfile is set from the 2nd entry in that list. Else... +# +# - $outfile is set to $infile stripped of its extension. # # If the first argument is -touch then the generated file is touched # to update its timestamp. This can be used as a workaround for @@ -673,25 +767,40 @@ proc proj-touch {filename} { # please the build process. # # Failures when running chmod or touch are silently ignored. +# proc proj-make-from-dot-in {args} { - set filename $args + set fIn "" + set fOut "" set touch 0 if {[lindex $args 0] eq "-touch"} { set touch 1 - set filename [lrange $args 1 end] + lassign $args - fIn fOut + } else { + lassign $args fIn fOut } - foreach f $filename { - set f [string trim $f] - catch { exec chmod u+w $f } - make-template $f.in $f - if {$touch} { - proj-touch $f + if {"" eq $fOut} { + if {[llength $fIn]>1} { + lassign $fIn fIn fOut + } else { + set fOut [file rootname $fIn] } - catch { exec chmod -w $f } + } + #puts "filenames=$filename" + if {[file exists $fOut]} { + catch { exec chmod u+w $fOut } + } + #puts "making template: $fIn ==> $fOut" + make-template $fIn $fOut + if {$touch} { + proj-touch $fOut + } + catch { + exec chmod -w $fOut + #file attributes -w $f; #jimtcl has no 'attributes' } } -######################################################################## +# # @proj-check-profile-flag ?flagname? # # Checks for the boolean configure option named by $flagname. If set, @@ -704,6 +813,7 @@ proc proj-make-from-dot-in {args} { # order to avoid potential problems with escaping, space-containing # tokens, and interfering with autosetup's use of these vars, this # routine does not directly modify CFLAGS or LDFLAGS. +# proc proj-check-profile-flag {{flagname profile}} { #puts "flagname=$flagname ?[proj-opt-truthy $flagname]?" if {[proj-opt-truthy $flagname]} { @@ -723,7 +833,7 @@ proc proj-check-profile-flag {{flagname profile}} { return 0 } -######################################################################## +# # @proj-looks-like-windows ?key? # # Returns 1 if this appears to be a Windows environment (MinGw, @@ -734,6 +844,7 @@ proc proj-check-profile-flag {{flagname profile}} { # machine, i.e. the local host). If $key == "build" then some # additional checks may be performed which are not applicable when # $key == "host". +# proc proj-looks-like-windows {{key host}} { global autosetup switch -glob -- [get-define $key] { @@ -745,20 +856,21 @@ proc proj-looks-like-windows {{key host}} { # These apply only to the local OS, not a cross-compilation target, # as the above check potentially can. if {$::autosetup(iswin)} { return 1 } - if {[find-an-executable cygpath] ne "" || $::tcl_platform(os)=="Windows NT"} { + if {[find-an-executable cygpath] ne "" || $::tcl_platform(os) eq "Windows NT"} { return 1 } } return 0 } -######################################################################## +# # @proj-looks-like-mac ?key? # # Looks at either the 'host' (==compilation target platform) or # 'build' (==the being-built-on platform) define value and returns if # if that value seems to indicate that it represents a Mac platform, # else returns 0. +# proc proj-looks-like-mac {{key host}} { switch -glob -- [get-define $key] { *apple* { @@ -770,7 +882,7 @@ proc proj-looks-like-mac {{key host}} { } } -######################################################################## +# # @proj-exe-extension # # Checks autosetup's "host" and "build" defines to see if the build @@ -778,6 +890,7 @@ proc proj-looks-like-mac {{key host}} { # build environment is then BUILD_EXEEXT is [define]'d to ".exe", else # "". If the target, a.k.a. "host", is then TARGET_EXEEXT is # [define]'d to ".exe", else "". +# proc proj-exe-extension {} { set rH "" set rB "" @@ -791,7 +904,7 @@ proc proj-exe-extension {} { define TARGET_EXEEXT $rH } -######################################################################## +# # @proj-dll-extension # # Works like proj-exe-extension except that it defines BUILD_DLLEXT @@ -799,6 +912,7 @@ proc proj-exe-extension {} { # # Trivia: for .dylib files, the linker needs the -dynamiclib flag # instead of -shared. +# proc proj-dll-extension {} { set inner {{key} { switch -glob -- [get-define $key] { @@ -817,12 +931,13 @@ proc proj-dll-extension {} { define TARGET_DLLEXT [apply $inner host] } -######################################################################## +# # @proj-lib-extension # # Static-library counterpart of proj-dll-extension. Defines # BUILD_LIBEXT and TARGET_LIBEXT to the conventional static library # extension for the being-built-on resp. the target platform. +# proc proj-lib-extension {} { set inner {{key} { switch -glob -- [get-define $key] { @@ -840,23 +955,25 @@ proc proj-lib-extension {} { define TARGET_LIBEXT [apply $inner host] } -######################################################################## +# # @proj-file-extensions # # Calls all of the proj-*-extension functions. +# proc proj-file-extensions {} { proj-exe-extension proj-dll-extension proj-lib-extension } -######################################################################## +# # @proj-affirm-files-exist ?-v? filename... # # Expects a list of file names. If any one of them does not exist in # the filesystem, it fails fatally with an informative message. # Returns the last file name it checks. If the first argument is -v # then it emits msg-checking/msg-result messages for each file. +# proc proj-affirm-files-exist {args} { set rc "" set verbose 0 @@ -875,7 +992,7 @@ proc proj-affirm-files-exist {args} { return rc } -######################################################################## +# # @proj-check-emsdk # # Emscripten is used for doing in-tree builds of web-based WASM stuff, @@ -907,6 +1024,7 @@ proc proj-affirm-files-exist {args} { # but BIN_EMCC is then emcc was not found in the EMSDK_HOME, in which # case we have to rely on the fact that sourcing $EMSDK_ENV_SH from a # shell will add emcc to the $PATH. +# proc proj-check-emsdk {} { set emsdkHome [opt-val with-emsdk] define EMSDK_HOME "" @@ -944,7 +1062,7 @@ proc proj-check-emsdk {} { return $rc } -######################################################################## +# # @proj-cc-check-Wl-flag ?flag ?args?? # # Checks whether the given linker flag (and optional arguments) can be @@ -955,6 +1073,7 @@ proc proj-check-emsdk {} { # # If so, that flag string is returned, else an empty string is # returned. +# proc proj-cc-check-Wl-flag {args} { cc-with {-link 1} { # Try -Wl,flag,...args @@ -973,7 +1092,7 @@ proc proj-cc-check-Wl-flag {args} { } } -######################################################################## +# # @proj-check-rpath # # Tries various approaches to handling the -rpath link-time @@ -984,6 +1103,7 @@ proc proj-cc-check-Wl-flag {args} { # --exec-prefix=... or --libdir=... are explicitly passed to # configure then [get-define libdir] is used (noting that it derives # from exec-prefix by default). +# proc proj-check-rpath {} { if {[proj-opt-was-provided libdir] || [proj-opt-was-provided exec-prefix]} { @@ -1009,7 +1129,7 @@ proc proj-check-rpath {} { expr {"" ne [get-define LDFLAGS_RPATH]} } -######################################################################## +# # @proj-check-soname ?libname? # # Checks whether CC supports the -Wl,soname,lib... flag. If so, it @@ -1022,6 +1142,7 @@ proc proj-check-rpath {} { # LDFLAGS_SONAME_PREFIX. It is provided so that clients may # potentially avoid some end-user confusion by using their own lib's # name here (which shows up in the "checking..." output). +# proc proj-check-soname {{libname "libfoo.so.0"}} { cc-with {-link 1} { if {[cc-check-flags "-Wl,-soname,${libname}"]} { @@ -1034,7 +1155,7 @@ proc proj-check-soname {{libname "libfoo.so.0"}} { } } -######################################################################## +# # @proj-check-fsanitize ?list-of-opts? # # Checks whether CC supports -fsanitize=X, where X is each entry of @@ -1049,6 +1170,7 @@ proc proj-check-soname {{libname "libfoo.so.0"}} { # # Will, on many systems, resolve to "-fsanitize=address,bounds-check", # but may also resolve to "-fsanitize=address". +# proc proj-check-fsanitize {{opts {address bounds-strict}}} { set sup {} foreach opt $opts { @@ -1067,12 +1189,13 @@ proc proj-check-fsanitize {{opts {address bounds-strict}}} { return "" } -######################################################################## +# # Internal helper for proj-dump-defs-json. Expects to be passed a # [define] name and the variadic $args which are passed to # proj-dump-defs-json. If it finds a pattern match for the given # $name in the various $args, it returns the type flag for that $name, # e.g. "-str" or "-bare", else returns an empty string. +# proc proj-defs-type_ {name spec} { foreach {type patterns} $spec { foreach pattern $patterns { @@ -1084,28 +1207,30 @@ proc proj-defs-type_ {name spec} { return "" } -######################################################################## +# # Internal helper for proj-defs-format_: returns a JSON-ish quoted # form of the given string-type values. It only performs the most # basic of escaping. The input must not contain any control # characters. +# proc proj-quote-str_ {value} { return \"[string map [list \\ \\\\ \" \\\"] $value]\" } -######################################################################## +# # An internal impl detail of proj-dump-defs-json. Requires a data # type specifier, as used by make-config-header, and a value. Returns -# the formatted value or the value $::proj_(defs-skip) if the caller +# the formatted value or the value $::proj__Config(defs-skip) if the caller # should skip emitting that value. -set proj_(defs-skip) "-proj-defs-format_ sentinel" +# +set proj__Config(defs-skip) "-proj-defs-format_ sentinel" proc proj-defs-format_ {type value} { switch -exact -- $type { -bare { # Just output the value unchanged } -none { - set value $::proj_(defs-skip) + set value $::proj__Config(defs-skip) } -str { set value [proj-quote-str_ $value] @@ -1120,14 +1245,14 @@ proc proj-defs-format_ {type value} { set ar {} foreach v $value { set v [proj-defs-format_ -auto $v] - if {$::proj_(defs-skip) ne $v} { + if {$::proj__Config(defs-skip) ne $v} { lappend ar $v } } set value "\[ [join $ar {, }] \]" } "" { - set value $::proj_(defs-skip) + set value $::proj__Config(defs-skip) } default { proj-fatal "Unknown type in proj-dump-defs-json: $type" @@ -1136,7 +1261,7 @@ proc proj-defs-format_ {type value} { return $value } -######################################################################## +# # This function works almost identically to autosetup's # make-config-header but emits its output in JSON form. It is not a # fully-functional JSON emitter, and will emit broken JSON for @@ -1166,6 +1291,7 @@ proc proj-defs-format_ {type value} { # Neither is especially satisfactory (and the second is useless), and # handling of such values is subject to change if any such values ever # _really_ need to be processed by our source trees. +# proc proj-dump-defs-json {file args} { file mkdir [file dirname $file] set lines {} @@ -1173,7 +1299,7 @@ proc proj-dump-defs-json {file args} { foreach n [lsort [dict keys [all-defines]]] { set type [proj-defs-type_ $n $args] set value [proj-defs-format_ $type [get-define $n]] - if {$::proj_(defs-skip) ne $value} { + if {$::proj__Config(defs-skip) ne $value} { lappend lines "\"$n\": ${value}" } } @@ -1184,7 +1310,7 @@ proc proj-dump-defs-json {file args} { } } -######################################################################## +# # @proj-xfer-option-aliases map # # Expects a list of pairs of configure flags which have been @@ -1214,6 +1340,12 @@ proc proj-dump-defs-json {file args} { # over any values from hidden aliases into their canonical names, such # that [opt-value canonical] will return X if --alias=X is passed to # configure. +# +# That said: autosetup's [opt-src] does support alias forms, but it +# requires that the caller know all possible aliases. It's simpler, in +# terms of options handling, if there's only a single canonical name +# which each down-stream call of [opt-...] has to know. +# proc proj-xfer-options-aliases {mapping} { foreach {hidden - canonical} [proj-strip-hash-comments $mapping] { if {[proj-opt-was-provided $hidden]} { @@ -1226,7 +1358,7 @@ proc proj-xfer-options-aliases {mapping} { } } -######################################################################## +# # Arguable/debatable... # # When _not_ cross-compiling and CC_FOR_BUILD is _not_ explicitly @@ -1242,6 +1374,7 @@ proc proj-xfer-options-aliases {mapping} { # Sidebar: if we do this before the cc package is installed, it gets # reverted by that package. Ergo, the cc package init will tell the # user "Build C compiler...cc" shortly before we tell them otherwise. +# proc proj-redefine-cc-for-build {} { if {![proj-is-cross-compiling] && [get-define CC] ne [get-define CC_FOR_BUILD] @@ -1251,13 +1384,14 @@ proc proj-redefine-cc-for-build {} { } } -######################################################################## +# # @proj-which-linenoise headerFile # # Attempts to determine whether the given linenoise header file is of # the "antirez" or "msteveb" flavor. It returns 2 for msteveb, else 1 # (it does not validate that the header otherwise contains the # linenoise API). +# proc proj-which-linenoise {dotH} { set srcHeader [proj-file-content $dotH] if {[string match *userdata* $srcHeader]} { @@ -1267,7 +1401,7 @@ proc proj-which-linenoise {dotH} { } } -######################################################################## +# # @proj-remap-autoconf-dir-vars # # "Re-map" the autoconf-conventional --XYZdir flags into something @@ -1304,6 +1438,7 @@ proc proj-which-linenoise {dotH} { # post-processing, libdir would be cemented in as FOO/lib at # configure-time, so could be tedious to override properly via a make # invocation. +# proc proj-remap-autoconf-dir-vars {} { set prefix [get-define prefix] set exec_prefix [get-define exec_prefix $prefix] @@ -1337,13 +1472,14 @@ proc proj-remap-autoconf-dir-vars {} { } } -######################################################################## +# # @proj-env-file flag ?default? # # If a file named .env-$flag exists, this function returns a # trimmed copy of its contents, else it returns $dflt. The intended # usage is that things like developer-specific CFLAGS preferences can # be stored in .env-CFLAGS. +# proc proj-env-file {flag {dflt ""}} { set fn ".env-${flag}" if {[file readable $fn]} { @@ -1352,7 +1488,7 @@ proc proj-env-file {flag {dflt ""}} { return $dflt } -######################################################################## +# # @proj-get-env var ?default? # # Extracts the value of "environment" variable $var from the first of @@ -1363,17 +1499,713 @@ proc proj-env-file {flag {dflt ""}} { # - A file named .env-$var (see [proj-env-file]) # # If none of those are set, $dflt is returned. +# proc proj-get-env {var {dflt ""}} { return [get-env $var [proj-env-file $var $dflt]] } -######################################################################## -# @proj-current-proc-name +# +# @proj-current-scope ?lvl? # # Returns the name of the _calling_ proc from ($lvl + 1) levels up the # call stack (where the caller's level will be 1 up from _this_ -# call). It is not legal to call this from the top scope. -proc proj-current-proc-name {{lvl 0}} { +# call). If $lvl would resolve to global scope "global scope" is +# returned and if it would be negative then a string indicating such +# is returned (as opposed to throwing an error). +# +proc proj-current-scope {{lvl 0}} { #uplevel [expr {$lvl + 1}] {lindex [info level 0] 0} - lindex [info level [expr {-$lvl - 1}]] 0 + set ilvl [info level] + set offset [expr {$ilvl - $lvl - 1}] + if { $offset < 0} { + return "invalid scope ($offset)" + } elseif { $offset == 0} { + return "global scope" + } else { + return [lindex [info level $offset] 0] + } +} + + +# +# Converts parts of tclConfig.sh to autosetup [define]s. +# +# Expects to be passed the name of a value tclConfig.sh or an empty +# string. It converts certain parts of that file's contents to +# [define]s (see the code for the whole list). If $tclConfigSh is an +# empty string then it [define]s the various vars as empty strings. +# +proc proj-tclConfig-sh-to-autosetup {tclConfigSh} { + set shBody {} + set tclVars { + TCL_INCLUDE_SPEC + TCL_LIBS + TCL_LIB_SPEC + TCL_STUB_LIB_SPEC + TCL_EXEC_PREFIX + TCL_PREFIX + TCL_VERSION + TCL_MAJOR_VERSION + TCL_MINOR_VERSION + TCL_PATCH_LEVEL + TCL_SHLIB_SUFFIX + } + # Build a small shell script which proxies the $tclVars from + # $tclConfigSh into autosetup code... + lappend shBody "if test x = \"x${tclConfigSh}\"; then" + foreach v $tclVars { + lappend shBody "$v= ;" + } + lappend shBody "else . \"${tclConfigSh}\"; fi" + foreach v $tclVars { + lappend shBody "echo define $v {\$$v} ;" + } + lappend shBody "exit" + set shBody [join $shBody "\n"] + #puts "shBody=$shBody\n"; exit + if {0} { + # This doesn't work but would be preferable to using a temp file... + set fd [open "| sh" "rw"] + #puts "fd = $fd"; exit + puts $fd $shBody + flush $fd + set rd [read $fd] + close $fd + puts "rd=$rd"; exit 1 + eval $rd + } else { + set shName ".tclConfigSh.tcl" + proj-file-write $shName $shBody + eval [exec sh $shName $tclConfigSh] + file delete -force $shName + } +} + +# +# @proj-tweak-default-env-dirs +# +# This function is not useful before [use system] is called to set up +# --prefix and friends. It should be called as soon after [use system] +# as feasible. +# +# For certain target environments, if --prefix is _not_ passed in by +# the user, set the prefix to an environment-specific default. For +# such environments its does [define prefix ...] and [proj-opt-set +# prefix ...], but it does not process vars derived from the prefix, +# e.g. exec-prefix. To do so it is generally necessary to also call +# proj-remap-autoconf-dir-vars late in the config process (immediately +# before ".in" files are filtered). +# +# Similar modifications may be made for --mandir. +# +# Returns 1 if it modifies the environment, else 0. +# +proc proj-tweak-default-env-dirs {} { + set rc 0 + switch -glob -- [get-define host] { + *-haiku { + if {![proj-opt-was-provided prefix]} { + set hdir /boot/home/config/non-packaged + proj-opt-set prefix $hdir + define prefix $hdir + incr rc + } + if {![proj-opt-was-provided mandir]} { + set hdir /boot/system/documentation/man + proj-opt-set mandir $hdir + define mandir $hdir + incr rc + } + } + } + return $rc +} + +# +# @proj-dot-ins-append file ?fileOut ?postProcessScript?? +# +# Queues up an autosetup [make-template]-style file to be processed +# at a later time using [proj-dot-ins-process]. +# +# $file is the input file. If $fileOut is empty then this function +# derives $fileOut from $file, stripping both its directory and +# extension parts. i.e. it defaults to writing the output to the +# current directory (typically $::autosetup(builddir)). +# +# If $postProcessScript is not empty then, during +# [proj-dot-ins-process], it will be eval'd immediately after +# processing the file. In the context of that script, the vars +# $fileIn and $fileOut will be set to the input and output file +# names. This can be used, for example, to make the output file +# executable or perform validation on its contents. +# +# See [proj-dot-ins-process], [proj-dot-ins-list] +# +proc proj-dot-ins-append {fileIn args} { + set srcdir $::autosetup(srcdir) + switch -exact -- [llength $args] { + 0 { + lappend fileIn [file rootname [file tail $fileIn]] "" + } + 1 { + lappend fileIn [join $args] "" + } + 2 { + lappend fileIn {*}$args + } + default { + proj-fatal "Too many arguments: $fileIn $args" + } + } + #puts "******* [proj-current-scope]: adding $fileIn" + lappend ::proj__Config(dot-in-files) $fileIn +} + +# +# @proj-dot-ins-list +# +# Returns the current list of [proj-dot-ins-append]'d files, noting +# that each entry is a 3-element list of (inputFileName, +# outputFileName, postProcessScript). +# +proc proj-dot-ins-list {} { + return $::proj__Config(dot-in-files) +} + +# +# @proj-dot-ins-process ?-touch? ?-validate? ?-clear? +# +# Each file which has previously been passed to [proj-dot-ins-append] +# is processed, with its passing its in-file out-file names to +# [proj-make-from-dot-in]. +# +# The intent is that a project accumulate any number of files to +# filter and delay their actual filtering until the last stage of the +# configure script, calling this function at that time. +# +# Optional flags: +# +# -touch: gets passed on to [proj-make-from-dot-in] +# +# -validate: after processing each file, before running the file's +# associated script, if any, it runs the file through +# proj-validate-no-unresolved-ats, erroring out if that does. +# +# -clear: after processing, empty the dot-ins list. This effectively +# makes proj-dot-ins-append available for re-use. +# +proc proj-dot-ins-process {args} { + proj-parse-simple-flags args flags { + -touch "" {return "-touch"} + -clear 0 {expr 1} + -validate 0 {expr 1} + } + if {[llength $args] > 0} { + error "Invalid argument to [proj-current-scope]: $args" + } + foreach f $::proj__Config(dot-in-files) { + proj-assert {3==[llength $f]} \ + "Expecting proj-dot-ins-list to be stored in 3-entry lists" + lassign $f fIn fOut fScript + #puts "DOING $fIn ==> $fOut" + proj-make-from-dot-in {*}$flags(-touch) $fIn $fOut + if {$flags(-validate)} { + proj-validate-no-unresolved-ats $fOut + } + if {"" ne $fScript} { + uplevel 1 "set fileIn $fIn; set fileOut $fOut; eval {$fScript}" + } + } + if {$flags(-clear)} { + set ::proj__Config(dot-in-files) [list] + } +} + +# +# @proj-validate-no-unresolved-ats filenames... +# +# For each filename given to it, it validates that the file has no +# unresolved @VAR@ references. If it finds any, it produces an error +# with location information. +# +# Exception: if a filename matches the pattern {*[Mm]ake*} AND a given +# line begins with a # (not including leading whitespace) then that +# line is ignored for purposes of this validation. The intent is that +# @VAR@ inside of makefile comments should not (necessarily) cause +# validation to fail, as it's sometimes convenient to comment out +# sections during development of a configure script and its +# corresponding makefile(s). +# +proc proj-validate-no-unresolved-ats {args} { + foreach f $args { + set lnno 1 + set isMake [string match {*[Mm]ake*} $f] + foreach line [proj-file-content-list $f] { + if {!$isMake || ![string match "#*" [string trimleft $line]]} { + if {[regexp {(@[A-Za-z0-9_]+@)} $line match]} { + error "Unresolved reference to $match at line $lnno of $f" + } + } + incr lnno + } + } +} + +# +# @proj-first-found fileList tgtVar +# +# Searches $fileList for an existing file. If one is found, its name is +# assigned to tgtVar and 1 is returned, else tgtVar is not modified +# and 0 is returned. +# +proc proj-first-file-found {fileList tgtVar} { + upvar $tgtVar tgt + foreach f $fileList { + if {[file exists $f]} { + set tgt $f + return 1 + } + } + return 0 +} + +# +# Defines $defName to contain makefile recipe commands for re-running +# the configure script with its current set of $::argv flags. This +# can be used to automatically reconfigure. +# +proc proj-setup-autoreconfig {defName} { + set squote {{arg} { + # Wrap $arg in single-quotes if it looks like it might need that + # to avoid mis-handling as a shell argument. We assume that $arg + # will never contain any single-quote characters. + if {[string match {*[ &;$*"]*} $arg]} { return '$arg' } + return $arg + }} + define-append $defName cd [apply $squote $::autosetup(builddir)] \ + && [apply $squote $::autosetup(srcdir)/configure] + #{*}$::autosetup(argv) breaks with --flag='val with spaces', so... + foreach arg $::autosetup(argv) { + define-append $defName [apply $squote $arg] + } +} + +# +# @prop-append-to defineName args... +# +# A proxy for Autosetup's [define-append]. Appends all non-empty $args +# to [define-append $defineName]. +# +proc proj-define-append {defineName args} { + foreach a $args { + if {"" ne $a} { + define-append $defineName {*}$a + } + } +} + +# +# @prod-define-amend ?-p|-prepend? ?-define? FLAG args... +# +# A proxy for Autosetup's [define-append]. +# +# Appends all non-empty $args to the define named by $FLAG unless. If +# one of (-p | -prepend) are used it instead prepends them, in their +# given order, to $FLAG. +# +# If -define is used then each argument is assumed to be a [define]'d +# flag and [get-define X ""] is used to fetch it. +# +# Typically, -lXYZ flags need to be in "reverse" order, with each -lY +# resolving symbols for -lX's to its left. This order is largely +# historical, and not relevant on all environments, but it is +# technically correct and still relevant on some environments. +# +# See: proj-append-to +# +proc proj-define-amend {args} { + set defName "" + set prepend 0 + set isdefs 0 + set xargs [list] + foreach arg $args { + switch -exact -- $arg { + -p - -prepend { set prepend 1 } + -d - -define { set isdefs 1 } + "" {} + default { + if {"" eq $defName} { + set defName $arg + } else { + lappend xargs $arg + } + } + } + } + if {$isdefs} { + set args $xargs + set xargs [list] + foreach arg $args { + lappend xargs [get-define $arg ""] + } + set args $xargs + } +# puts "**** args=$args" +# puts "**** xargs=$xargs" + + set args $xargs + if {$prepend} { + lappend args {*}[get-define $defName ""] + define $defName [join $args]; # join to eliminate {} entries + } else { + proj-define-append $defName {*}$args + } +} + +# +# @proj-define-to-cflag ?-list? defineName... +# +# Treat each argument as the name of a [define] +# and attempt to render it like a CFLAGS value: +# +# -D$name +# -D$name=value +# +# If treats integers as numbers and everything else as a quoted +# string, noting that it does not handle strings which themselves +# contain quotes. +# +# By default it returns the result as string of all -D... flags, +# but if passed the -list flag it will return a list of the +# individual CFLAGS. +# +proc proj-define-to-cflag {args} { + set rv {} + set xargs {} + set returnList 0; + foreach arg $args { + switch -exact -- $arg { + -list {incr returnList} + default { + lappend xargs $arg + } + } + } + foreach d $xargs { + set v [get-define $d ""] + set li [list -D${d}] + if {[string is integer -strict $v]} { + lappend li = $v + } elseif {"" eq $d} { + } else { + lappend li = {"} $v {"} + } + lappend rv [join $li ""] + } + if {$returnList} { return $rv } + return [join $rv] +} + + +if {0} { + # Turns out that autosetup's [options-add] essentially does exactly + # this... + + # A list of lists of Autosetup [options]-format --flags definitions. + # Append to this using [proj-options-add] and use + # [proj-options-combine] to merge them into a single list for passing + # to [options]. + # + set ::proj__Config(extra-options) {} + + # @proj-options-add list + # + # Adds a list of options to the pending --flag processing. It must be + # in the format used by Autosetup's [options] function. + # + # This will have no useful effect if called from after [options] + # is called. + # + # Use [proj-options-combine] to get a combined list of all added + # options. + # + # PS: when writing this i wasn't aware of autosetup's [options-add], + # works quite similarly. Only the timing is different. + proc proj-options-add {list} { + lappend ::proj__Config(extra-options) $list + } + + # @proj-options-combine list1 ?...listN? + # + # Expects each argument to be a list of options compatible with + # autosetup's [options] function. This function concatenates the + # contents of each list into a new top-level list, stripping the outer + # list part of each argument, and returning that list + # + # If passed no arguments, it uses the list generated by calls to + # [proj-options-add]. + proc proj-options-combine {args} { + set rv [list] + if {0 == [llength $args]} { + set args $::proj__Config(extra-options) + } + foreach e $args { + lappend rv {*}$e + } + return $rv + } +}; # proj-options-* + +# Internal cache for use via proj-cache-*. +array set proj__Cache {} + +# +# @proj-cache-key ?addLevel? arg +# +# Helper to generate cache keys for [proj-cache-*]. +# +# Returns a cache key for the given argument: +# +# integer: relative call stack levels to get the scope name of for +# use as a key. [proj-current-scope [expr {1 + $arg + addLevel}]] is +# then used to generate the key. i.e. the default of 0 uses the +# calling scope's name as the key. +# +# "-": same as 0 +# +# Anything else: returned as-is +# +proc proj-cache-key {{addLevel 0} arg} { + if {"-" eq $arg} {set arg 0} + if {[string is integer -strict $arg]} { + return [proj-current-scope [expr {$arg + $addLevel + 1}]] + } + return $arg +} + +# +# @proj-cache-set ?key? ?addLevel? value +# +# Sets a feature-check cache entry with the given key. +# +# See proj-cache-key for $key's and $addLevel's semantics, noting that +# this function adds one to $addLevel for purposes of that call. +proc proj-cache-set {{key 0} {addLevel 0} val} { + set key [proj-cache-key [expr {1 + $addLevel}] $key] + #puts "** fcheck set $key = $val" + set ::proj__Cache($key) $val +} + +# +# @proj-cache-remove ?key? ?addLevel? +# +# Removes an entry from the proj-cache. +proc proj-cache-remove {{key 0} {addLevel 0}} { + set key [proj-cache-key [expr {1 + $addLevel}] $key] + set rv "" + if {[info exists ::proj__Cache($key)]} { + set rv $::proj__Cache($key) + unset ::proj__Cache($key) + } + return $rv; +} + +# +# @proj-cache-check ?$key? ?addLevel? tgtVarName +# +# Checks for a feature-check cache entry with the given key. +# +# If the feature-check cache has a matching entry then this function +# assigns its value to tgtVar and returns 1, else it assigns tgtVar to +# "" and returns 0. +# +# See proj-cache-key for $key's and $addLevel's semantics, noting that +# this function adds one to $addLevel for purposes of that call. +proc proj-cache-check {{key 0} {addLevel 0} tgtVar} { + upvar $tgtVar tgt + set rc 0 + set key [proj-cache-key [expr {1 + $addLevel}] $key] + #puts "** fcheck get key=$key" + if {[info exists ::proj__Cache($key)]} { + set tgt $::proj__Cache($key) + incr rc + } else { + set tgt "" + } + return $rc +} + +# +# @proj-coalesce ...args +# +# Returns the first argument which is not empty (eq ""), or an empty +# string on no match. +proc proj-coalesce {args} { + foreach arg $args { + if {"" ne $arg} { + return $arg + } + } + return "" +} + +# +# @proj-parse-simple-flags ... +# +# An experiment. Do not use. +# +# A helper to parse flags from proc argument lists. +# +# Expects a list of arguments to parse, an array name to store any +# -flag values to, and a prototype object which declares the flags. +# +# The prototype must be a list in one of the following forms: +# +# -flag defaultValue {script} +# +# -flag => defaultValue +# -----^--^ (wiith spaces there!) +# +# Repeated for each flag. +# +# The first form represents a basic flag with no associated +# following argument. The second form extracts its value +# from the following argument in $argvName. +# +# The first argument to this function is the name of a var holding the +# args to parse. It will be overwritten, possibly with a smaller list. +# +# The second argument the name of an array variable to create in the +# caller's scope. (Pneumonic: => points to the next argument.) +# +# For the first form of flag, $script is run in the caller's scope if +# $argv contains -flag, and the result of that script is the new value +# for $tgtArrayName(-flag). This function intercepts [return $val] +# from $script. Any empty script will result in the flag having "" +# assigned to it. +# +# The args list is only inspected until the first argument which is +# not described by $prototype. i.e. the first "non-flag" (not counting +# values consumed for flags defined like --flag=>default). +# +# If a "--" flag is encountered, no more arguments are inspected as +# flags. If "--" is the first non-flag argument, the "--" flag is +# removed from the results but all remaining arguments are passed +# through. If "--" appears after the first non-flag, it is retained. +# +# This function assumes that each flag is unique, and using a flag +# more than once behaves in a last-one-wins fashion. +# +# Any $argv entries not described in $prototype are not treated +# as flags. +# +# Returns the number of flags it processed in $argvName. +# +# Example: +# +# set args [list -foo -bar {blah} 8 9 10] +# set args [proj-parse-simple-flags args flags { +# -foo 0 {expr 1} +# -bar => 0 +# -no-baz 2 {return 0} +# } +# +# After that $flags would contain {-foo 1 -bar {blah} -no-baz 2} +# and $args would be {8 9 10}. +# +proc proj-parse-simple-flags {argvName tgtArrayName prototype} { + upvar $argvName argv + upvar $tgtArrayName tgt + array set dflt {} + array set scripts {} + array set consuming {} + set n [llength $prototype] + # Figure out what our flags are... + for {set i 0} {$i < $n} {} { + set k [lindex $prototype $i] + #puts "**** #$i of $n k=$k" + proj-assert {[string match -* $k]} \ + "Invalid flag value for [proj-current-scope]: $k" + set v "" + set s "" + if {"=>" eq [lindex $prototype [expr {$i + 1}]]} { + incr i 2 + if {$i >= $n} { + proj-fatal "Missing argument for $k => flag" + } + set consuming($k) 1 + set v [lindex $prototype $i] + } else { + set v [lindex $prototype [incr i]] + set s [lindex $prototype [incr i]] + set scripts($k) $s + } + incr i + #puts "**** #$i of $n k=$k v=$v s=$s" + set dflt($k) $v + } + # Now look for those flags in the source list + array set tgt [array get dflt] + unset dflt + set rc 0 + set rv {} + set skipMode 0 + set n [llength $argv] + for {set i 0} {$i < $n} {incr i} { + set arg [lindex $argv $i] + if {$skipMode} { + lappend rv $arg + } elseif {"--" eq $arg} { + incr skipMode + } elseif {[info exists tgt($arg)]} { + if {[info exists consuming($arg)]} { + if {$i + 1 >= $n} { + proj-fatal "Missing argument for $arg flag" + } + set tgt($arg) [lindex $argv [incr i]] + } elseif {"" eq $scripts($arg)} { + set tgt($arg) "" + } else { + #puts "**** running scripts($arg) $scripts($arg)" + set code [catch {uplevel 1 $scripts($arg)} xrc xopt] + #puts "**** tgt($arg)=$scripts($arg) code=$code rc=$rc" + if {$code in {0 2}} { + set tgt($arg) $xrc + } else { + return {*}$xopt $xrc + } + } + incr rc + } else { + incr skipMode + lappend rv $arg + } + } + set argv $rv + return $rc +} + +if {$::proj__Config(self-tests)} { + apply {{} { + proj-warn "Test code for proj-cache" + proj-assert {![proj-cache-check here check]} + proj-assert {"here" eq [proj-cache-key here]} + proj-assert {"" eq $check} + proj-cache-set here thevalue + proj-assert {[proj-cache-check here check]} + proj-assert {"thevalue" eq $check} + + proj-assert {![proj-cache-check check]} + #puts "*** key = ([proj-cache-key -])" + proj-assert {"" eq $check} + proj-cache-set abc + proj-assert {[proj-cache-check check]} + proj-assert {"abc" eq $check} + + #parray ::proj__Cache; + proj-assert {"" ne [proj-cache-remove]} + proj-assert {![proj-cache-check check]} + proj-assert {"" eq [proj-cache-remove]} + proj-assert {"" eq $check} + }} } diff --git a/autosetup/sqlite-config.tcl b/autosetup/sqlite-config.tcl index 15c0995500..3f7d174d7a 100644 --- a/autosetup/sqlite-config.tcl +++ b/autosetup/sqlite-config.tcl @@ -11,7 +11,7 @@ if {[string first " " $autosetup(builddir)] != -1} { user-error "The pathname of the build directory\ may not contain space characters" } - +#parray ::autosetup; exit 0 use proj # # We want the package version info to be emitted early on, but doing @@ -24,6 +24,7 @@ if {"--help" ni $::argv} { } use system ; # Will output "Host System" and "Build System" lines if {"--help" ni $::argv} { + proj-tweak-default-env-dirs msg-result "Source dir = $::autosetup(srcdir)" msg-result "Build dir = $::autosetup(builddir)" use cc cc-db cc-shared cc-lib pkg-config @@ -59,12 +60,24 @@ array set sqliteConfig [subst [proj-strip-hash-comments { # (dump-defines-txt) but also a JSON file named after this option's # value. dump-defines-json "" + + # + # The list of feature --flags which the --all flag implies. This + # requires special handling in a few places. + # + all-flag-enables {fts4 fts5 rtree geopoly session} + + # + # Default value for the --all flag. Can hypothetically be modified + # by non-canonical builds. + # + all-flag-default 0 }]] ######################################################################## # Processes all configure --flags for this build, run build-specific # config checks, then finalize the configure process. $buildMode must -# be either "canonical" or "autoconf", and others may be added in the +# be one of (canonical, autoconf), and others may be added in the # future. After bootstrapping, $configScript is eval'd in the caller's # scope, then post-configuration finalization is run. $configScript is # intended to hold configure code which is specific to the given @@ -87,6 +100,12 @@ proc sqlite-configure {buildMode configScript} { if {$buildMode ni $allBuildModes} { user-error "Invalid build mode: $buildMode. Expecting one of: $allBuildModes" } + if {$::sqliteConfig(all-flag-default)} { + set allFlagHelp "Disable these extensions: $::sqliteConfig(all-flag-enables)" + } else { + set allFlagHelp "Enable these extensions: $::sqliteConfig(all-flag-enables)" + } + set ::sqliteConfig(build-mode) $buildMode ######################################################################## # A gentle introduction to flags handling in autosetup @@ -165,7 +184,7 @@ proc sqlite-configure {buildMode configScript} { # Options for how to build the library build-modes { - {*} { + {canonical autoconf} { shared=1 => {Disable build of shared library} static=1 => {Disable build of static library} } @@ -180,6 +199,8 @@ proc sqlite-configure {buildMode configScript} { threadsafe=1 => {Disable mutexing} with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always} load-extension=1 => {Disable loading of external extensions} + # ^^^ one of the downstream custom builds overrides the load-extension default to 0, which + # confuses the --help text generator. https://github.com/msteveb/autosetup/issues/77 math=1 => {Disable math functions} json=1 => {Disable JSON functions} memsys5 => {Enable MEMSYS5} @@ -191,7 +212,7 @@ proc sqlite-configure {buildMode configScript} { geopoly => {Enable the GEOPOLY extension} rtree => {Enable the RTREE extension} session => {Enable the SESSION extension} - all => {Enable FTS4, FTS5, Geopoly, RTree, Sessions} + all=$::sqliteConfig(all-flag-default) => {$allFlagHelp} largefile=1 => {This legacy flag has no effect on the library but may influence the generated sqlite_cfg.h by adding #define HAVE_LFS} @@ -200,6 +221,13 @@ proc sqlite-configure {buildMode configScript} { # Options for TCL support tcl { + {canonical} { + tcl=1 + => {Disable components which require TCL, including all tests. + 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 the + test code require a canonical tclsh.} + } {canonical} { with-tcl:DIR => {Directory containing tclConfig.sh or a directory one level up from @@ -211,17 +239,20 @@ proc sqlite-configure {buildMode configScript} { 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!} - tcl=1 - => {Disable components which require TCL, including all tests. - 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 the - test code require a canonical tclsh.} + } + {canonical} { + static-tclsqlite3=0 + => {Statically-link tclsqlite3. This only works if TCL support is + enabled and all requisite libraries are available in + static form. Note that glibc is unable to fully statically + link certain libraries required by tclsqlite3, so this won't + work on most Linux environments.} } } # Options for line-editing modes for the CLI shell line-editing { - {*} { + {canonical autoconf} { readline=1 => {Disable readline support} # --with-readline-lib is a backwards-compatible alias for @@ -263,11 +294,25 @@ proc sqlite-configure {buildMode configScript} { # Options for exotic/alternative build modes alternative-builds { - {*} { + {canonical autoconf} { with-wasi-sdk:=/opt/wasi-sdk => {Top-most dir of the wasi-sdk for a WASI build} } + + {*} { + # Note that --static-cli-shell has a completely different + # meaning from --static-shell in the autoconf build! + # --[disable-]static-shell is a legacy flag which we can't + # remove without breaking downstream builds. + static-cli-shell=0 + => {Statically-link the sqlite3 CLI shell. + This only works if the requisite libraries are all available in + static form.} + } + {canonical} { + static-shells=0 + => {Shorthand for --static-cli-shell --static-tclsqlite3} with-emsdk:=auto => {Top-most dir of the Emscripten SDK installation. @@ -283,10 +328,12 @@ proc sqlite-configure {buildMode configScript} { packaging { {autoconf} { # --disable-static-shell: https://sqlite.org/forum/forumpost/cc219ee704 + # Note that this has a different meaning from --static-cli-shell in the + # canonical build! static-shell=1 => {Link the sqlite3 shell app against the DLL instead of embedding sqlite3.c} } - {*} { + {canonical autoconf} { # A potential TODO without a current use case: #rpath=1 => {Disable use of the rpath linker flag} # soname: https://sqlite.org/src/forumpost/5a3b44f510df8ded @@ -307,9 +354,9 @@ proc sqlite-configure {buildMode configScript} { # out-implib: https://sqlite.org/forum/forumpost/0c7fc097b2 out-implib:=auto => {Enable use of --out-implib linker flag to generate an - "import library" for the DLL. The output's base name name is - specified by the value, with "auto" meaning to figure out a - name automatically. On some platforms this flag gets + "import library" for the DLL. The output's base name is + specified by this flag's value, with "auto" meaning to figure + out a name automatically. On some platforms this flag gets automatically enabled if it is not provided. Use "none" to explicitly disable this feature on such platforms.} } @@ -353,22 +400,40 @@ proc sqlite-configure {buildMode configScript} { (for build debugging)} } } - }; # $allOpts + }; # $allFlags - # Filter allOpts to create the set of [options] legal for this build - set opts {} - foreach {group XY} [subst -nobackslashes -nocommands \ - [proj-strip-hash-comments $allFlags]] { + set allFlags [proj-strip-hash-comments $allFlags] + # ^^^ lappend of [sqlite-custom-flags] introduces weirdness if + # we delay [proj-strip-hash-comments] until after that. + + + ######################################################################## + # sqlite-custom.tcl is intended only for vendor-branch-specific + # customization. See autosetup/README.md#branch-customization for + # details. + if {[file exists $::autosetup(libdir)/sqlite-custom.tcl]} { + uplevel 1 {source $::autosetup(libdir)/sqlite-custom.tcl} + } + + if {[llength [info proc sqlite-custom-flags]] > 0} { + # sqlite-custom-flags is assumed to be imported via + # autosetup/sqlite-custom.tcl. + set scf [sqlite-custom-flags] + if {"" ne $scf} { + lappend allFlags sqlite-custom-flags $scf + } + } + + # Filter allFlags to create the set of [options] legal for this build + foreach {group XY} [subst -nobackslashes -nocommands $allFlags] { foreach {X Y} $XY { if { $buildMode in $X || "*" in $X } { - foreach y $Y { - lappend opts $y - } + options-add $Y } } } #lappend opts "soname:=duplicateEntry => {x}"; #just testing - if {[catch {options $opts} msg xopts]} { + if {[catch {options {}} msg xopts]} { # Workaround for # where [options] behaves oddly on _some_ TCL builds when it's # called from deeper than the global scope. @@ -399,7 +464,7 @@ proc sqlite-configure-phase1 {buildMode} { } set ::sqliteConfig(msg-debug-enabled) [proj-val-truthy [get-env msg-debug 0]] proc-debug "msg-debug is enabled" - sqlite-autoreconfig + proj-setup-autoreconfig SQLITE_AUTORECONFIG proj-file-extensions if {".exe" eq [get-define TARGET_EXEEXT]} { define SQLITE_OS_UNIX 0 @@ -409,7 +474,6 @@ proc sqlite-configure-phase1 {buildMode} { define SQLITE_OS_WIN 0 } sqlite-setup-default-cflags - sqlite-handle-debug define HAVE_LFS 0 if {[opt-bool largefile]} { # @@ -421,6 +485,11 @@ proc sqlite-configure-phase1 {buildMode} { # may not) define HAVE_LFS. cc-check-lfs } + set srcdir $::autosetup(srcdir) + proj-dot-ins-append $srcdir/Makefile.in + if {[file exists $srcdir/sqlite3.pc.in]} { + proj-dot-ins-append $srcdir/sqlite3.pc.in + } }; # sqlite-configure-phase1 ######################################################################## @@ -434,22 +503,25 @@ proc sqlite-configure-finalize {} { sqlite-handle-load-extension sqlite-handle-math sqlite-handle-icu - sqlite-handle-line-editing - - proj-define-for-opt shared ENABLE_LIB_SHARED "Build shared library?" - if {![proj-define-for-opt static ENABLE_LIB_STATIC "Build static library?"]} { - # This notice really only applies to the canonical build... - proj-indented-notice { - NOTICE: static lib build may be implicitly re-activated by - other components, e.g. some test apps. + if {[proj-opt-exists readline]} { + sqlite-handle-line-editing + } + if {[proj-opt-exists shared]} { + proj-define-for-opt shared ENABLE_LIB_SHARED "Build shared library?" + } + if {[proj-opt-exists static]} { + if {![proj-define-for-opt static ENABLE_LIB_STATIC "Build static library?"]} { + # This notice really only applies to the canonical build... + proj-indented-notice { + NOTICE: static lib build may be implicitly re-activated by + other components, e.g. some test apps. + } } } - sqlite-handle-env-quirks sqlite-handle-common-feature-flags sqlite-finalize-feature-flags sqlite-process-dot-in-files; # do not [define] anything after this - sqlite-post-config-validation sqlite-dump-defines } @@ -466,28 +538,7 @@ proc msg-debug {msg} { # the debug message. It is not legal to call this from the global # scope. proc proc-debug {msg} { - msg-debug "\[[proj-current-proc-name 1]\]: $msg" -} - -######################################################################## -# Sets up the SQLITE_AUTORECONFIG define. -proc sqlite-autoreconfig {} { - # 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. - set squote {{arg} { - # Wrap $arg in single-quotes if it looks like it might need that - # to avoid mis-handling as a shell argument. We assume that $arg - # will never contain any single-quote characters. - if {[string match {*[ &;$*"]*} $arg]} { return '$arg' } - return $arg - }} - define-append SQLITE_AUTORECONFIG cd [apply $squote $::autosetup(builddir)] \ - && [apply $squote $::autosetup(srcdir)/configure] - #{*}$::autosetup(argv) breaks with --flag='val with spaces', so... - foreach arg $::autosetup(argv) { - define-append SQLITE_AUTORECONFIG [apply $squote $arg] - } + msg-debug "\[[proj-current-scope 1]\]: $msg" } define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags. @@ -496,7 +547,8 @@ define OPT_SHELL {} ; # Feature-related 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 the # sqlite-add-shell-opt in addition to adding them to -# OPT_FEATURE_FLAGS. +# OPT_FEATURE_FLAGS. This is intended only for holding +# -DSQLITE_ENABLE/OMIT/... flags, but that is not enforced here. proc sqlite-add-feature-flag {args} { set shell "" if {"-shell" eq [lindex $args 0]} { @@ -529,8 +581,12 @@ proc sqlite-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 ""] + set lfl [get-define lib_log ""] undefine lib_log + if {"" ne $lfl} { + user-notice "Forcing requirement of $lfl for $featureName" + } + define LDFLAGS_MATH $lfl } } @@ -562,15 +618,21 @@ proc sqlite-check-common-system-deps {} { cc-check-functions gmtime_r isnan localtime_r localtime_s \ malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64 - set ldrt "" - # Collapse funcs from librt into LDFLAGS_RT. - # Some systems (ex: SunOS) require -lrt in order to use nanosleep - foreach func {fdatasync nanosleep} { - if {[proj-check-function-in-lib $func rt]} { - lappend ldrt [get-define lib_${func}] + apply {{} { + set ldrt "" + # Collapse funcs from librt into LDFLAGS_RT. + # Some systems (ex: SunOS) require -lrt in order to use nanosleep + foreach func {fdatasync nanosleep} { + if {[proj-check-function-in-lib $func rt]} { + set ldrt [get-define lib_${func} ""] + undefine lib_${func} + if {"" ne $ldrt} { + break + } + } } - } - define LDFLAGS_RT [join [lsort -unique $ldrt] ""] + define LDFLAGS_RT $ldrt + }} # Check for needed/wanted headers cc-check-includes \ @@ -665,15 +727,36 @@ proc sqlite-setup-default-cflags {} { # Handle various SQLITE_ENABLE/OMIT_... feature flags. proc sqlite-handle-common-feature-flags {} { msg-result "Feature flags..." - foreach {boolFlag featureFlag ifSetEvalThis} { - all {} { - # The 'all' option must be first in this list. - proj-opt-set fts4 - proj-opt-set fts5 - proj-opt-set geopoly - proj-opt-set rtree - proj-opt-set session + if {![opt-bool all]} { + # Special handling for --disable-all + foreach flag $::sqliteConfig(all-flag-enables) { + if {![proj-opt-was-provided $flag]} { + proj-opt-set $flag 0 + } } + } + foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments { + all {} { + # The 'all' option must be first in this list. This impl makes + # an effort to only apply flags which the user did not already + # apply, so that combinations like (--all --disable-geopoly) + # will indeed disable geopoly. There are corner cases where + # flags which depend on each other will behave in non-intuitive + # ways: + # + # --all --disable-rtree + # + # Will NOT disable geopoly, though geopoly depends on rtree. + # The --geopoly flag, though, will automatically re-enable + # --rtree, so --disable-rtree won't actually disable anything in + # that case. + foreach k $::sqliteConfig(all-flag-enables) { + if {![proj-opt-was-provided $k]} { + proj-opt-set $k 1 + } + } + } + fts3 -DSQLITE_ENABLE_FTS3 {sqlite-affirm-have-math fts3} fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4} fts5 -DSQLITE_ENABLE_FTS5 {sqlite-affirm-have-math fts5} geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree} @@ -690,7 +773,7 @@ proc sqlite-handle-common-feature-flags {} { } } scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {} - } { + }] { if {$boolFlag ni $::autosetup(options)} { # Skip flags which are in the canonical build but not # the autoconf bundle. @@ -742,6 +825,9 @@ proc sqlite-finalize-feature-flags {} { proj-assert {"canonical" eq $::sqliteConfig(build-mode)} msg-result "Appending source files to amalgamation: $extraSrc" } + if {[lsearch [get-define TARGET_DEBUG ""] -DSQLITE_DEBUG=1] > -1} { + msg-result "Note: this is a debug build, so performance will suffer." + } } ######################################################################## @@ -751,7 +837,8 @@ proc sqlite-finalize-feature-flags {} { proc sqlite-handle-debug {} { msg-checking "SQLITE_DEBUG build? " proj-if-opt-truthy debug { - define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall} + define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -O0 -Wall} + sqlite-add-feature-flag -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE proj-opt-set memsys5 msg-result yes } { @@ -906,8 +993,10 @@ proc sqlite-handle-emsdk {} { # Maybe there's a copy in the path? proj-bin-define wasm-opt BIN_WASM_OPT } - proj-make-from-dot-in $emccSh $extWasmConfig - catch {exec chmod u+x $emccSh} + proj-dot-ins-append $emccSh.in $emccSh { + catch {exec chmod u+x $fileOut} + } + proj-dot-ins-append $extWasmConfig.in $extWasmConfig } else { define EMCC_WRAPPER "" file delete -force -- $emccSh $extWasmConfig @@ -1201,9 +1290,10 @@ proc sqlite-check-line-editing {} { }; # sqlite-check-line-editing ######################################################################## -# Runs sqlite-check-line-editing and adds a message around it In the +# Runs sqlite-check-line-editing and adds a message around it. In the # canonical build this must not be called before -# sqlite-determine-codegen-tcl. +# sqlite-determine-codegen-tcl for reasons now lost to history (and +# might not still be applicable). proc sqlite-handle-line-editing {} { msg-result "Line-editing support for the sqlite3 shell: [sqlite-check-line-editing]" } @@ -1353,8 +1443,8 @@ proc sqlite-handle-load-extension {} { if {$found} { msg-result "Loadable extension support enabled." } else { - msg-result "Disabling loadable extension support. Use --enable-load-extensions to enable them." - sqlite-add-feature-flag {-DSQLITE_OMIT_LOAD_EXTENSION=1} + msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them." + sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1 } return $found } @@ -1368,7 +1458,7 @@ proc sqlite-handle-math {} { } define LDFLAGS_MATH [get-define lib_ceil] undefine lib_ceil - sqlite-add-feature-flag {-DSQLITE_ENABLE_MATH_FUNCTIONS} + sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS msg-result "Enabling math SQL functions" } { define LDFLAGS_MATH "" @@ -1408,6 +1498,28 @@ proc sqlite-handle-mac-cversion {} { return $rc } +######################################################################## +# If this is a Mac platform, check for support for +# -Wl,-install_name,... and, if it's available, define +# LDFLAGS_MAC_INSTALL_NAME to a variant of that string which is +# intended to expand at make-time, else set LDFLAGS_MAC_INSTALL_NAME +# to an empty string. +# +# https://sqlite.org/forum/forumpost/5651662b8875ec0a +proc sqlite-handle-mac-install-name {} { + define LDFLAGS_MAC_INSTALL_NAME ""; # {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"} + set rc 0 + if {[proj-looks-like-mac]} { + cc-with {-link 1} { + if {[cc-check-flags "-Wl,-install_name,/usr/local/lib/libsqlite3.dylib"]} { + define LDFLAGS_MAC_INSTALL_NAME {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"} + set rc 1 + } + } + } + return $rc +} + ######################################################################## # Handles the --dll-basename configure flag. [define]'s # SQLITE_DLL_BASENAME to the DLL's preferred base name (minus @@ -1437,14 +1549,15 @@ proc sqlite-handle-dll-basename {} { # [define]s LDFLAGS_OUT_IMPLIB to either an empty string or to a # -Wl,... flag for the platform-specific --out-implib flag, which is # used for building an "import library .dll.a" file on some platforms -# (e.g. msys2, mingw). Returns 1 if supported, else 0. +# (e.g. msys2, mingw). SQLITE_OUT_IMPLIB is defined to the name of the +# import lib or an empty string. Returns 1 if supported, else 0. # # The name of the import library is [define]d in SQLITE_OUT_IMPLIB. # # If the configure flag --out-implib is not used (or programmatically -# set) then this is a no-op (but see [sqlite-handle-env-quirks]). If -# that flag is used but the capability is not available, a fatal error -# is triggered. +# set) then this simply sets the above-listed defines to empty strings +# (but see [sqlite-handle-env-quirks]). If that flag is used but the +# capability is not available, a fatal error is triggered. # # This feature is specifically opt-in because it's supported on far # more platforms than actually need it and enabling it causes creation @@ -1579,6 +1692,12 @@ proc sqlite-handle-env-quirks {} { sqlite-handle-dll-basename sqlite-handle-out-implib sqlite-handle-mac-cversion + sqlite-handle-mac-install-name + if {[llength [info proc sqlite-custom-handle-flags]] > 0} { + # sqlite-custom-handle-flags is assumed to be imported via a + # client-specific import: autosetup/sqlite-custom.tcl. + sqlite-custom-handle-flags + } } ######################################################################## @@ -1596,7 +1715,7 @@ proc sqlite-process-dot-in-files {} { # (e.g. [proj-check-rpath]) may do so before we "mangle" them here. proj-remap-autoconf-dir-vars - proj-make-from-dot-in -touch Makefile sqlite3.pc + proj-dot-ins-process -validate make-config-header sqlite_cfg.h \ -bare {SIZEOF_* HAVE_DECL_*} \ -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG @@ -1606,32 +1725,6 @@ proc sqlite-process-dot-in-files {} { proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@ } -######################################################################## -# Perform some high-level validation on the generated files... -# -# 1) Ensure that no unresolved @VAR@ placeholders are in files which -# use those. -# -# 2) TBD -proc sqlite-post-config-validation {} { - # Check #1: ensure that files which get filtered for @VAR@ do not - # contain any unresolved @VAR@ refs. That may indicate an - # unexported/unused var or a typo. - set srcdir $::autosetup(srcdir) - foreach f [list Makefile sqlite3.pc \ - $srcdir/tool/emcc.sh \ - $srcdir/ext/wasm/config.make] { - if {![file exists $f]} continue - set lnno 1 - foreach line [proj-file-content-list $f] { - if {[regexp {(@[A-Za-z0-9_]+@)} $line match]} { - error "Unresolved reference to $match at line $lnno of $f" - } - incr lnno - } - } -} - ######################################################################## # Handle --with-wasi-sdk[=DIR] # @@ -1666,7 +1759,7 @@ proc sqlite-handle-wasi-sdk {} { threadsafe } { if {[proj-opt-exists $opt] && [opt-bool $opt]} { - # -^^^^ distinguish between canonical and autoconf builds + # -^^^^ not all builds define all of these flags msg-result " --disable-$opt" proj-opt-set $opt 0 } @@ -1743,12 +1836,10 @@ proc sqlite-check-tcl {} { define TCLLIBDIR "" ; # Installation dir for TCL extension lib define TCL_CONFIG_SH ""; # full path to tclConfig.sh - # Clear out all vars which would be set by tclConfigToAutoDef.sh, so - # that the late-config validation of @VARS@ works even if - # --disable-tcl is used. - foreach k {TCL_INCLUDE_SPEC TCL_LIB_SPEC TCL_STUB_LIB_SPEC TCL_EXEC_PREFIX TCL_VERSION} { - define $k "" - } + # Clear out all vars which would harvest from tclConfig.sh so that + # the late-config validation of @VARS@ works even if --disable-tcl + # is used. + proj-tclConfig-sh-to-autosetup "" file delete -force ".tclenv.sh"; # ensure no stale state from previous configures. if {![opt-bool tcl]} { @@ -1775,7 +1866,7 @@ proc sqlite-check-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] + set with_tclsh [proj-first-bin-of tclsh9.1 tclsh9.0 tclsh8.6 tclsh] proc-debug "with_tclsh=${with_tclsh}" } @@ -1790,7 +1881,7 @@ proc sqlite-check-tcl {} { #msg-result "Using tclsh: $with_tclsh" } if {$doConfigLookup && - [catch {exec $with_tclsh $srcdir/tool/find_tclconfig.tcl} result] == 0} { + [catch {exec $with_tclsh $::autosetup(libdir)/find_tclconfig.tcl} result] == 0} { set with_tcl $result } if {"" ne $with_tcl && [file isdir $with_tcl]} { @@ -1801,7 +1892,7 @@ proc sqlite-check-tcl {} { } } set cfg "" - set tclSubdirs {tcl9.0 tcl8.6 lib} + set tclSubdirs {tcl9.1 tcl9.0 tcl8.6 lib} while {$use_tcl} { if {"" ne $with_tcl} { # Ensure that we can find tclConfig.sh under ${with_tcl}/... @@ -1847,9 +1938,7 @@ proc sqlite-check-tcl {} { # Export a subset of tclConfig.sh to the current TCL-space. If $cfg # is an empty string, this emits empty-string entries for the # various options we're interested in. - eval [exec sh "$srcdir/tool/tclConfigShToAutoDef.sh" "$cfg"] - # ---------^^ a Windows/msys workaround, without which it cannot - # exec a .sh file: https://sqlite.org/forum/forumpost/befb352a42a7cd6d + proj-tclConfig-sh-to-autosetup $cfg if {"" eq $with_tclsh && $cfg ne ""} { # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh @@ -2018,10 +2107,13 @@ proc sqlite-determine-codegen-tcl {} { }; # sqlite-determine-codegen-tcl ######################################################################## -# Runs sqlite-check-tcl and sqlite-determine-codegen-tcl. +# Runs sqlite-check-tcl and, if this is the canonical build, +# sqlite-determine-codegen-tcl. proc sqlite-handle-tcl {} { sqlite-check-tcl - msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]" + if {"canonical" eq $::sqliteConfig(build-mode)} { + msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]" + } } ######################################################################## diff --git a/doc/lemon.html b/doc/lemon.html index 24bccce082..965f305c04 100644 --- a/doc/lemon.html +++ b/doc/lemon.html @@ -846,7 +846,7 @@ or more tokens. The alternative meaning is tried if the original token would have generated a syntax error.

The %fallback directive was added to support robust parsing of SQL -syntax in SQLite. +syntax in SQLite. The SQL language contains a large assortment of keywords, each of which appears as a different token to the language parser. SQL contains so many keywords that it can be difficult for programmers to keep up with diff --git a/doc/tcl-extension-testing.md b/doc/tcl-extension-testing.md index df5f6537ba..eb2a8c3a3b 100644 --- a/doc/tcl-extension-testing.md +++ b/doc/tcl-extension-testing.md @@ -35,84 +35,69 @@ perspective on how to compile SQLite on unix-like systems. ### 2.1 Setup

    -
  1. - [Fossil](https://fossil-scm.org/) installed. +
  2. + [Fossil][] installed.
  3. Check out source code and set environment variables:
    1. **TCLSOURCE** → - The top-level directory of a Fossil check-out of the TCL source tree. + The top-level directory of a [Fossil][] check-out of the + [TCL source tree][tcl-fossil].
    2. **SQLITESOURCE** → A Fossil check-out of the SQLite source tree. -
    3. **TCLBUILD** → +
    4. **TCLHOME** → A directory that does not exist at the start of the test and which will be deleted at the end of the test, and that will contain the test builds of the TCL libraries and the SQLite TCL Extensions. + It is the top-most installation directory, i.e. the one provided + to Tcl's `./configure --prefix=/path/to/tcl`. +
    5. **TCLVERSION** → + The `X.Y`-form version of Tcl being used: 8.6, 9.0, 9.1...
-### 2.2 Testing TCL 8.6 on unix +### 2.2 Testing TCL 8.x and 9.x on unix + +From a checked-out copy of [the core Tcl tree][tcl-fossil]
    -
  1. `mkdir -p $TCLBUILD/tcl86` -
  2. `cd $TCLSOURCE/unix` -
  3. `fossil up core-8-6-16`
    - ↑ Or some other version of Tcl8.6. +
  4. `TCLVERSION=8.6`
    + ↑ A version of your choice. This process has been tested with + values of 8.6, 9.0, and 9.1 (as of 2025-04-16). The out-of-life + version 8.5 fails some of `make devtest` for undetermined reasons. +
  5. `TCLHOME=$HOME/tcl/$TCLVERSION` +
  6. `TCLSOURCE=/path/to/tcl/checkout` +
  7. `SQLITESOURCE=/path/to/sqlite/checkout` +
  8. `rm -fr $TCLHOME`
    + ↑ Ensure that no stale Tcl installation is laying around. +
  9. `cd $TCLSOURCE` +
  10. `fossil up core-8-6-branch`
    + ↑ The branch corresponding to `$TCLVERSION`, e.g. + `core-9-0-branch` or `trunk`.
  11. `fossil clean -x` -
  12. `./configure --prefix=$TCLBUILD/tcl86 --disable-shared`
    - ↑ The --disable-shared is to avoid the need to set LD_LIBRARY_PATH +
  13. `cd unix` +
  14. `./configure --prefix=$TCLHOME --disable-shared`
    + ↑ The `--disable-shared` is to avoid the need to set `LD_LIBRARY_PATH` when using this Tcl build.
  15. `make install`
  16. `cd $SQLITESOURCE`
  17. `fossil clean -x` -
  18. `./configure --with-tclsh=$TCLBUILD/tcl86/bin/tclsh8.6 --all` +
  19. `./configure --with-tcl=$TCLHOME --all`
  20. `make tclextension-install`
    - ↑ Verify extension installed at $TCLBUILD/tcl86/lib/tcl8.6/sqlite3.* + ↑ Verify extension installed at + `$TCLHOME/lib/tcl${TCLVERSION}/sqlite`.
  21. `make tclextension-list`
    ↑ Verify TCL extension correctly installed.
  22. `make tclextension-verify`
    ↑ Verify that the correct version is installed. -
  23. `$TCLBUILD/tcl86/bin/tclsh8.6 test/testrunner.tcl release --explain`
    +
  24. `$TCLHOME/bin/tclsh[89].[0-9] test/testrunner.tcl release --explain`
    ↑ Verify thousands of lines of output with no errors. Or consider running "devtest" without --explain instead of "release".
-### 2.3 Testing TCL 9.0 on unix - -
    -
  1. `mkdir -p $TCLBUILD/tcl90` -
  2. `fossil up core-9-0-0`
    - ↑ Or some other version of Tcl9 -
  3. `fossil clean -x` -
  4. `./configure --prefix=$TCLBUILD/tcl90 --disable-shared`
    - ↑ The --disable-shared is to avoid the need to set LD_LIBRARY_PATH - when using this Tcl build. -
  5. `make install` -
  6. `cp -r ../library $TCLBUILD/tcl90/lib/tcl9.0`
    - ↑ The Tcl library is not installed by "make install" for Tcl9.0 unless - you also include the --disable-zipfs to ./configure. But if you do that - then the generated tclsh9.0 is no longer stand-alone. On the other hand, - if you don't install the Tcl library, other programs like testfixture - won't be able to find the Tcl library and hence won't work. This - extra installation step resolves the dilemma. - This step is not required when building Tcl8.6, which lacks support for - zipfs and hence always installs its Tcl library. -
  7. `cd $SQLITESOURCE` -
  8. `fossil clean -x` -
  9. `./configure --with-tclsh=$TCLBUILD/tcl90/bin/tclsh9.0 --all` -
  10. `make tclextension-install`
    - ↑ Verify extension installed at $TCLBUILD/tcl90/lib/sqlite3.* -
  11. `make tclextension-list`
    - ↑ Verify TCL extension correctly installed. -
  12. `make tclextension-verify` -
  13. `$TCLBUILD/tcl90/bin/tclsh9.0 test/testrunner.tcl release --explain`
    - ↑ Verify thousands of lines of output with no errors. Or - consider running "devtest" without --explain instead of "release". -
- -### 2.4 Cleanup +### 2.3 Cleanup
    -
  1. `rm -rf $TCLBUILD` +
  2. `rm -rf $TCLHOME`
@@ -123,9 +108,11 @@ perspective on how to compile SQLite on Windows. ### 3.1 Setup for Windows +(These docs are not as up-to-date as the Unix docs, above.) +
    -
  1. - [Fossil](https://fossil-scm.org/) installed. +
  2. + [Fossil][] installed.
  3. Unix-like command-line tools installed. Example: [unxutils](https://unxutils.sourceforge.net/) @@ -206,3 +193,72 @@ perspective on how to compile SQLite on Windows.
    1. `rm -rf %TCLBUILD%`
    + +## 4.0 Testing the TEA(ish) Build (unix only) + +This part requires following the setup instructions for Unix systems, +at the top of this document. + +The former TEA, now TEA(ish), build of this extension uses the same +code as the builds described above but is provided in a form more +convenient for downstream Tcl users. + +It lives in `autoconf/tea` and, as part of the `autoconf` bundle, +_cannot be tested directly from the canonical tree_. Instead it has to +be packaged. + +### 4.1 Teaish Setup + +Follow the same Tcl- and environment-related related setup described +in the first section of this document, up to and including the +installation of Tcl (unless, of course, it was already installed using +those same instructions). + +### 4.2 Teaish Testing + +
      +
    1. `cd $SQLITESOURCE` +
    2. Run either `make snapshot-tarball` or `make amalgamation-tarball` + ↑ + Those steps will leave behind a temp dir called `mkpkg_tmp_dir`, + under which the extension is most readily reached. It can optionally + be extracted from the generated tarball, but that tarball was + generated from this dir, and reusing this dir is a time saver + during development. +
    3. `cd mkpkg_tmp/tea` +
    4. `./configure --with-tcl=$TCLHOME` +
    5. `make test install`
      + ↑ Should run to completion without any errors. +
    6. `make uninstall`
      + ↑ Will uninstall the extension. This _can_ be run + in the same invocation as the `install` target, but only + if the `-j#` make flag is _not_ used. If it is, the + install/uninstall steps will race and make a mess of things. + Parallel builds do not help in this build, anyway, as there's + only a single C file to compile. +
    + +When actively developing and testing the teaish build, which requires +going through the tarball generation, there's a caveat about the +`mkpkg_tmp_dir` dir: it will be deleted every time a tarball is +built, the shell console which is parked in that +directory for testing needs to add `cd $PWD &&` to the start of the +build commands, like: + +> +``` +[user@host:.../mkpkg_tmp_dir/tea]$ \ + cd $PWD && ./configure CFLAGS=-O0 --with-tcl=$TCLHOME \ + && make test install uninstall +``` + +### 4.3 Teaish Cleanup + + +
      +
    1. `rm -rf $TCLHOME` +
    2. `cd $SQLITESOURCE; rm -fr mkpkg_tmp_dir; fossil clean -x` +
    + +[Fossil]: https://fossil-scm.org/home +[tcl-fossil]: https://core.tcl-lang.org/tcl diff --git a/ext/README.md b/ext/README.md index 933a33d053..78312819ab 100644 --- a/ext/README.md +++ b/ext/README.md @@ -1,6 +1,6 @@ ## Loadable Extensions -Various [loadable extensions](https://www.sqlite.org/loadext.html) for +Various [loadable extensions](https://sqlite.org/loadext.html) for SQLite are found in subfolders. Most subfolders are dedicated to a single loadable extension (for diff --git a/ext/expert/test_expert.c b/ext/expert/test_expert.c index cae5d0f258..4383d7c7bb 100644 --- a/ext/expert/test_expert.c +++ b/ext/expert/test_expert.c @@ -28,7 +28,7 @@ static int dbHandleFromObj(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **pDb){ Tcl_CmdInfo info; if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(pObj), &info) ){ - Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(pObj), 0); + Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(pObj), NULL); return TCL_ERROR; } diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 3771aa8ba2..f178abafed 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -295,12 +295,6 @@ # define SQLITE_CORE 1 #endif -#include -#include -#include -#include -#include -#include #include "fts3.h" #ifndef SQLITE_CORE diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index a53ecdf17c..d438549de1 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -14,6 +14,13 @@ #ifndef _FTSINT_H #define _FTSINT_H +#include +#include +#include +#include +#include +#include + #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index 36ee94a48b..9c7f0ade97 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -1027,16 +1027,16 @@ static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ break; case FTS3_MATCHINFO_LHITS: - nVal = pInfo->nCol * pInfo->nPhrase; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase; break; case FTS3_MATCHINFO_LHITS_BM: - nVal = pInfo->nPhrase * ((pInfo->nCol + 31) / 32); + nVal = (size_t)pInfo->nPhrase * ((pInfo->nCol + 31) / 32); break; default: assert( cArg==FTS3_MATCHINFO_HITS ); - nVal = pInfo->nCol * pInfo->nPhrase * 3; + nVal = (size_t)pInfo->nCol * pInfo->nPhrase * 3; break; } diff --git a/ext/fts3/fts3_test.c b/ext/fts3/fts3_test.c index 3c42a7bf02..70bccf0c52 100644 --- a/ext/fts3/fts3_test.c +++ b/ext/fts3/fts3_test.c @@ -219,7 +219,7 @@ static int SQLITE_TCLAPI fts3_near_match_cmd( rc = Tcl_ListObjGetElements(interp, pPhrase, &nToken, &apToken); if( rc!=TCL_OK ) goto near_match_out; if( nToken>NM_MAX_TOKEN ){ - Tcl_AppendResult(interp, "Too many tokens in phrase", 0); + Tcl_AppendResult(interp, "Too many tokens in phrase", NULL); rc = TCL_ERROR; goto near_match_out; } @@ -547,7 +547,7 @@ static int SQLITE_TCLAPI fts3_test_varint_cmd( if( w!=w2 || nByte!=nByte2 ){ char *zErr = sqlite3_mprintf("error testing %lld", w); Tcl_ResetResult(interp); - Tcl_AppendResult(interp, zErr, 0); + Tcl_AppendResult(interp, zErr, NULL); return TCL_ERROR; } @@ -557,7 +557,7 @@ static int SQLITE_TCLAPI fts3_test_varint_cmd( if( (int)w!=i || nByte!=nByte2 ){ char *zErr = sqlite3_mprintf("error testing %lld (32-bit)", w); Tcl_ResetResult(interp); - Tcl_AppendResult(interp, zErr, 0); + Tcl_AppendResult(interp, zErr, NULL); return TCL_ERROR; } } diff --git a/ext/fts3/fts3_tokenize_vtab.c b/ext/fts3/fts3_tokenize_vtab.c index 7e8d09bd48..b9d83982c8 100644 --- a/ext/fts3/fts3_tokenize_vtab.c +++ b/ext/fts3/fts3_tokenize_vtab.c @@ -346,7 +346,7 @@ static int fts3tokFilterMethod( fts3tokResetCursor(pCsr); if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); - int nByte = sqlite3_value_bytes(apVal[0]); + sqlite3_int64 nByte = sqlite3_value_bytes(apVal[0]); pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; diff --git a/ext/fts5/fts5_test_mi.c b/ext/fts5/fts5_test_mi.c index f56c890cd7..e8648a4d22 100644 --- a/ext/fts5/fts5_test_mi.c +++ b/ext/fts5/fts5_test_mi.c @@ -14,7 +14,7 @@ ** versions of FTS5. It contains the implementation of an FTS5 auxiliary ** function very similar to the FTS4 function matchinfo(): ** -** https://www.sqlite.org/fts3.html#matchinfo +** https://sqlite.org/fts3.html#matchinfo ** ** Known differences are that: ** diff --git a/ext/fts5/fts5_unicode2.c b/ext/fts5/fts5_unicode2.c index cc164a4569..2133d5d5b8 100644 --- a/ext/fts5/fts5_unicode2.c +++ b/ext/fts5/fts5_unicode2.c @@ -778,4 +778,3 @@ void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ } aAscii[0] = 0; /* 0x00 is never a token character */ } - diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index 668b6e0841..f2fc7fb7bd 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -429,7 +429,7 @@ $(doc.index): $(JAVA_FILES.main) $(MAKEFILE) .FORCE: doc doc: $(doc.index) javadoc: $(doc.index) -# Force rebild of docs +# Force rebuild of docs redoc: @rm -f $(doc.index) @$(MAKE) doc diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 6bd6daaec8..d6723453d0 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -133,7 +133,7 @@ ** Which sqlite3.c we're using needs to be configurable to enable ** building against a custom copy, e.g. the SEE variant. We have to ** include sqlite3.c, as opposed to sqlite3.h, in order to get access -** to some interal details like SQLITE_MAX_... and friends. This +** to some internal details like SQLITE_MAX_... and friends. This ** increases the rebuild time considerably but we need this in order ** to access some internal functionality and keep the to-Java-exported ** values of SQLITE_MAX_... and SQLITE_LIMIT_... in sync with the C @@ -5512,7 +5512,7 @@ static inline jobject new_java_fts5_api(JNIEnv * const env, fts5_api *sv){ ** Returns a per-JNIEnv global ref to the Fts5ExtensionApi singleton ** instance, or NULL on OOM. */ -static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){ +static jobject s3jni_getFts5ExtensionApi(JNIEnv * const env){ if( !SJG.fts5.jExt ){ S3JniGlobal_mutex_enter; if( !SJG.fts5.jExt ){ @@ -5578,7 +5578,7 @@ JniDeclFtsApi(jobject,getInstanceForDb)(JniArgsEnvClass,jobject jDb){ JniDeclFtsXA(jobject,getInstance)(JniArgsEnvClass){ - return s3jni_getFts5ExensionApi(env); + return s3jni_getFts5ExtensionApi(env); } JniDeclFtsXA(jint,xColumnCount)(JniArgsEnvObj,jobject jCtx){ @@ -5641,7 +5641,7 @@ static void s3jni_fts5_extension_function(Fts5ExtensionApi const *pApi, S3JniDeclLocal_env; assert(pAux); - jFXA = s3jni_getFts5ExensionApi(env); + jFXA = s3jni_getFts5ExtensionApi(env); if( !jFXA ) goto error_oom; jpFts = new_java_Fts5Context(env, pFts); if( !jpFts ) goto error_oom; diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h index 082a202122..6f93bf8ab7 100644 --- a/ext/jni/src/c/sqlite3-jni.h +++ b/ext/jni/src/c/sqlite3-jni.h @@ -1342,7 +1342,7 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1data_1count * Method: sqlite3_db_config * Signature: (Lorg/sqlite/jni/capi/sqlite3;IILorg/sqlite/jni/capi/OutputPointer/Int32;)I */ -JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1db_1config__Lorg_sqlite_jni_capi_sqlite3_2IILorg_sqlite_jni_capi_OutputPointer_Int32_2 +JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1db_1config__Lorg_sqlite_jni_capi_sqlite3_2IILorg_sqlite_jni_capi_OutputPointer_00024Int32_2 (JNIEnv *, jclass, jobject, jint, jint, jobject); /* diff --git a/ext/jni/src/org/sqlite/jni/annotation/NotNull.java b/ext/jni/src/org/sqlite/jni/annotation/NotNull.java index 0c31782f23..2873082446 100644 --- a/ext/jni/src/org/sqlite/jni/annotation/NotNull.java +++ b/ext/jni/src/org/sqlite/jni/annotation/NotNull.java @@ -31,11 +31,11 @@ import java.lang.annotation.*; never pass a null value to the callback for that parameter.

    Passing a null, for this annotation's definition of null, for - any parameter marked with this annoation specifically invokes + any parameter marked with this annotation specifically invokes undefined behavior (see below).

    Passing 0 (i.e. C NULL) or a negative value for any long-type - parameter marked with this annoation specifically invokes undefined + parameter marked with this annotation specifically invokes undefined behavior (see below). Such values are treated as C pointers in the JNI layer.

    diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 13367a6102..731fb0ac3b 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -12,14 +12,9 @@ ** This file declares the main JNI bindings for the sqlite3 C API. */ package org.sqlite.jni.capi; -import java.nio.charset.StandardCharsets; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import org.sqlite.jni.annotation.*; import java.util.Arrays; +import java.nio.charset.StandardCharsets; +import org.sqlite.jni.annotation.*; /** This class contains the entire C-style sqlite3 JNI API binding, @@ -169,7 +164,7 @@ public final class CApi {

    Like the C API, it returns 0 if allocation fails or if initialize is false and no prior aggregate context was allocated for cx. If initialize is true then it returns 0 only on - allocation error. In all casses, 0 is considered the sentinel + allocation error. In all cases, 0 is considered the sentinel "not a key" value. */ public static native long sqlite3_aggregate_context(sqlite3_context cx, boolean initialize); @@ -563,7 +558,7 @@ public final class CApi { sqlite3_blob_open(db.getNativePointer(), dbName, tableName, columnName, iRow, flags, out); return out.take(); - }; + } private static native int sqlite3_blob_read( @NotNull long ptrToBlob, @NotNull byte[] target, int srcOffset @@ -1298,7 +1293,7 @@ public final class CApi { final OutputPointer.sqlite3 out = new OutputPointer.sqlite3(); sqlite3_open(filename, out); return out.take(); - }; + } public static native int sqlite3_open_v2( @Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb, @@ -1314,7 +1309,7 @@ public final class CApi { final OutputPointer.sqlite3 out = new OutputPointer.sqlite3(); sqlite3_open_v2(filename, out, flags, zVfs); return out.take(); - }; + } /** The sqlite3_prepare() family of functions require slightly @@ -1410,7 +1405,7 @@ public final class CApi { /** Works like the canonical sqlite3_prepare_v2() but its "tail" - output paramter is returned as the index offset into the given + output parameter is returned as the index offset into the given byte array at which SQL parsing stopped. */ public static int sqlite3_prepare_v2( @@ -1462,7 +1457,7 @@ public final class CApi { /** Works like the canonical sqlite3_prepare_v2() but its "tail" - output paramter is returned as the index offset into the given + output parameter is returned as the index offset into the given byte array at which SQL parsing stopped. */ public static int sqlite3_prepare_v3( @@ -1542,7 +1537,7 @@ public final class CApi { int rc = 0; final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt(); while( 0==rc && pos0 ){ sqlChunk = Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length); diff --git a/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java b/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java index ffd7761190..04000a3f31 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java +++ b/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java @@ -13,7 +13,7 @@ */ package org.sqlite.jni.capi; /** - This marker interface exists soley for use as a documentation and + This marker interface exists solely for use as a documentation and class-grouping tool. It should be applied to interfaces or classes which have a call() method implementing some specific callback interface on behalf of the C library. @@ -34,7 +34,7 @@ package org.sqlite.jni.capi; proxying for, minus the {@code sqlite3_} prefix, plus a {@code Callback} suffix. e.g. {@code sqlite3_busy_handler()}'s callback is named {@code BusyHandlerCallback}. Exceptions are made where that - would potentially be ambiguous, e.g. {@link ConfigSqllogCallback} + would potentially be ambiguous, e.g. {@link ConfigSqlLogCallback} instead of {@code ConfigCallback} because the {@code sqlite3_config()} interface may need to support more callback types in the future. diff --git a/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java b/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java index 7bf7529da1..f50d0c57cb 100644 --- a/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java +++ b/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java @@ -20,7 +20,7 @@ package org.sqlite.jni.capi; from the native JNI code is unduly quirky due to a lack of autoboxing at that level. -

    The usage is similar for all of thes types: +

    The usage is similar for all of these types:

    {@code
        OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
    @@ -55,9 +55,9 @@ public final class OutputPointer {
         /** Sets the current value to null. */
         public void clear(){value = null;}
         /** Returns the current value. */
    -    public final org.sqlite.jni.capi.sqlite3 get(){return value;}
    +    public org.sqlite.jni.capi.sqlite3 get(){return value;}
         /** Equivalent to calling get() then clear(). */
    -    public final org.sqlite.jni.capi.sqlite3 take(){
    +    public org.sqlite.jni.capi.sqlite3 take(){
           final org.sqlite.jni.capi.sqlite3 v = value;
           value = null;
           return v;
    @@ -76,9 +76,9 @@ public final class OutputPointer {
         /** Sets the current value to null. */
         public void clear(){value = null;}
         /** Returns the current value. */
    -    public final org.sqlite.jni.capi.sqlite3_blob get(){return value;}
    +    public org.sqlite.jni.capi.sqlite3_blob get(){return value;}
         /** Equivalent to calling get() then clear(). */
    -    public final org.sqlite.jni.capi.sqlite3_blob take(){
    +    public org.sqlite.jni.capi.sqlite3_blob take(){
           final org.sqlite.jni.capi.sqlite3_blob v = value;
           value = null;
           return v;
    @@ -98,9 +98,9 @@ public final class OutputPointer {
         /** Sets the current value to null. */
         public void clear(){value = null;}
         /** Returns the current value. */
    -    public final org.sqlite.jni.capi.sqlite3_stmt get(){return value;}
    +    public org.sqlite.jni.capi.sqlite3_stmt get(){return value;}
         /** Equivalent to calling get() then clear(). */
    -    public final org.sqlite.jni.capi.sqlite3_stmt take(){
    +    public org.sqlite.jni.capi.sqlite3_stmt take(){
           final org.sqlite.jni.capi.sqlite3_stmt v = value;
           value = null;
           return v;
    @@ -120,9 +120,9 @@ public final class OutputPointer {
         /** Sets the current value to null. */
         public void clear(){value = null;}
         /** Returns the current value. */
    -    public final org.sqlite.jni.capi.sqlite3_value get(){return value;}
    +    public org.sqlite.jni.capi.sqlite3_value get(){return value;}
         /** Equivalent to calling get() then clear(). */
    -    public final org.sqlite.jni.capi.sqlite3_value take(){
    +    public org.sqlite.jni.capi.sqlite3_value take(){
           final org.sqlite.jni.capi.sqlite3_value v = value;
           value = null;
           return v;
    @@ -144,9 +144,9 @@ public final class OutputPointer {
         /** Initializes with the value v. */
         public Bool(boolean v){value = v;}
         /** Returns the current value. */
    -    public final boolean get(){return value;}
    +    public boolean get(){return value;}
         /** Sets the current value to v. */
    -    public final void set(boolean v){value = v;}
    +    public void set(boolean v){value = v;}
       }
     
       /**
    @@ -164,9 +164,9 @@ public final class OutputPointer {
         /** Initializes with the value v. */
         public Int32(int v){value = v;}
         /** Returns the current value. */
    -    public final int get(){return value;}
    +    public int get(){return value;}
         /** Sets the current value to v. */
    -    public final void set(int v){value = v;}
    +    public void set(int v){value = v;}
       }
     
       /**
    @@ -184,9 +184,9 @@ public final class OutputPointer {
         /** Initializes with the value v. */
         public Int64(long v){value = v;}
         /** Returns the current value. */
    -    public final long get(){return value;}
    +    public long get(){return value;}
         /** Sets the current value. */
    -    public final void set(long v){value = v;}
    +    public void set(long v){value = v;}
       }
     
       /**
    @@ -204,9 +204,9 @@ public final class OutputPointer {
         /** Initializes with the value v. */
         public String(java.lang.String v){value = v;}
         /** Returns the current value. */
    -    public final java.lang.String get(){return value;}
    +    public java.lang.String get(){return value;}
         /** Sets the current value. */
    -    public final void set(java.lang.String v){value = v;}
    +    public void set(java.lang.String v){value = v;}
       }
     
       /**
    @@ -224,9 +224,9 @@ public final class OutputPointer {
         /** Initializes with the value v. */
         public ByteArray(byte[] v){value = v;}
         /** Returns the current value. */
    -    public final byte[] get(){return value;}
    +    public byte[] get(){return value;}
         /** Sets the current value. */
    -    public final void set(byte[] v){value = v;}
    +    public void set(byte[] v){value = v;}
       }
     
       /**
    @@ -246,8 +246,8 @@ public final class OutputPointer {
         /** Initializes with the value v. */
         public ByteBuffer(java.nio.ByteBuffer v){value = v;}
         /** Returns the current value. */
    -    public final java.nio.ByteBuffer get(){return value;}
    +    public java.nio.ByteBuffer get(){return value;}
         /** Sets the current value. */
    -    public final void set(java.nio.ByteBuffer v){value = v;}
    +    public void set(java.nio.ByteBuffer v){value = v;}
       }
     }
    diff --git a/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java b/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java
    index af242fb3c1..35bb069c49 100644
    --- a/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java
    +++ b/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java
    @@ -65,7 +65,7 @@ public interface PrepareMultiCallback extends CallbackProxy {
          A PrepareMultiCallback impl which steps entirely through a result set,
          ignoring all non-error results.
       */
    -  public static final class StepAll implements PrepareMultiCallback {
    +  final class StepAll implements PrepareMultiCallback {
         public StepAll(){}
         /**
            Calls sqlite3_step() on st until it returns something other than
    diff --git a/ext/jni/src/org/sqlite/jni/capi/SQLTester.java b/ext/jni/src/org/sqlite/jni/capi/SQLTester.java
    index 634f844c24..bc2e75f8be 100644
    --- a/ext/jni/src/org/sqlite/jni/capi/SQLTester.java
    +++ b/ext/jni/src/org/sqlite/jni/capi/SQLTester.java
    @@ -13,7 +13,6 @@
     ** SQLTester framework.
     */
     package org.sqlite.jni.capi;
    -import java.util.List;
     import java.util.ArrayList;
     import java.util.Arrays;
     import java.nio.charset.StandardCharsets;
    @@ -31,7 +30,7 @@ enum ResultBufferMode {
       ESCAPED,
       //! Append output as-is
       ASIS
    -};
    +}
     
     /**
        Modes to specify how to emit multi-row output from
    @@ -42,7 +41,7 @@ enum ResultRowMode {
       ONELINE,
       //! Add a newline between each result row.
       NEWLINE
    -};
    +}
     
     /**
        Base exception type for test-related failures.
    @@ -278,7 +277,7 @@ public class SQLTester {
       }
     
       private StringBuilder clearBuffer(StringBuilder b){
    -    b.setLength(0);;
    +    b.setLength(0);
         return b;
       }
     
    @@ -334,7 +333,7 @@ public class SQLTester {
         return this;
       }
     
    -  sqlite3 setCurrentDb(int n) throws Exception{
    +  sqlite3 setCurrentDb(int n){
         affirmDbId(n);
         iCurrentDb = n;
         return this.aDb[n];
    @@ -342,7 +341,7 @@ public class SQLTester {
     
       sqlite3 getCurrentDb(){ return aDb[iCurrentDb]; }
     
    -  sqlite3 getDbById(int id) throws Exception{
    +  sqlite3 getDbById(int id){
         return affirmDbId(id).aDb[id];
       }
     
    @@ -363,7 +362,7 @@ public class SQLTester {
         }
       }
     
    -  sqlite3 openDb(String name, boolean createIfNeeded) throws DbException {
    +  sqlite3 openDb(String name, boolean createIfNeeded) {
         closeDb();
         int flags = SQLITE_OPEN_READWRITE;
         if( createIfNeeded ) flags |= SQLITE_OPEN_CREATE;
    @@ -755,7 +754,7 @@ abstract class Command {
          fall in the inclusive range (min,max) then this function throws. Use
          a max value of -1 to mean unlimited.
       */
    -  protected final void argcCheck(TestScript ts, String[] argv, int min, int max) throws Exception{
    +  protected final void argcCheck(TestScript ts, String[] argv, int min, int max){
         int argc = argv.length-1;
         if(argc=0 && argc>max)){
           if( min==max ){
    @@ -771,16 +770,16 @@ abstract class Command {
       /**
          Equivalent to argcCheck(argv,argc,argc).
       */
    -  protected final void argcCheck(TestScript ts, String[] argv, int argc) throws Exception{
    +  protected final void argcCheck(TestScript ts, String[] argv, int argc){
         argcCheck(ts, argv, argc, argc);
       }
     }
     
     //! --close command
     class CloseDbCommand extends Command {
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,0,1);
    -    Integer id;
    +    int id;
         if(argv.length>1){
           String arg = argv[1];
           if("all".equals(arg)){
    @@ -801,7 +800,7 @@ class CloseDbCommand extends Command {
     class ColumnNamesCommand extends Command {
       public void process(
         SQLTester st, TestScript ts, String[] argv
    -  ) throws Exception{
    +  ){
         argcCheck(ts,argv,1);
         st.outputColumnNames( Integer.parseInt(argv[1])!=0 );
       }
    @@ -809,7 +808,7 @@ class ColumnNamesCommand extends Command {
     
     //! --db command
     class DbCommand extends Command {
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,1);
         t.setCurrentDb( Integer.parseInt(argv[1]) );
       }
    @@ -821,7 +820,7 @@ class GlobCommand extends Command {
       public GlobCommand(){}
       protected GlobCommand(boolean negate){ this.negate = negate; }
     
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,1,-1);
         t.incrementTestCounter();
         final String sql = t.takeInputBuffer();
    @@ -851,7 +850,7 @@ class JsonBlockCommand extends TableResultCommand {
     //! --new command
     class NewDbCommand extends OpenDbCommand {
       public NewDbCommand(){ super(true); }
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         if(argv.length>1){
           Util.unlink(argv[1]);
         }
    @@ -867,7 +866,7 @@ class NoopCommand extends Command {
         this.verbose = verbose;
       }
       public NoopCommand(){}
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         if( this.verbose ){
           t.outln("Skipping unhandled command: "+argv[0]);
         }
    @@ -885,7 +884,7 @@ class NotGlobCommand extends GlobCommand {
     class NullCommand extends Command {
       public void process(
         SQLTester st, TestScript ts, String[] argv
    -  ) throws Exception{
    +  ){
         argcCheck(ts,argv,1);
         st.setNullValue( argv[1] );
       }
    @@ -896,7 +895,7 @@ class OpenDbCommand extends Command {
       private boolean createIfNeeded = false;
       public OpenDbCommand(){}
       protected OpenDbCommand(boolean c){createIfNeeded = c;}
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,1);
         t.openDb(argv[1], createIfNeeded);
       }
    @@ -906,7 +905,7 @@ class OpenDbCommand extends Command {
     class PrintCommand extends Command {
       public void process(
         SQLTester st, TestScript ts, String[] argv
    -  ) throws Exception{
    +  ){
         st.out(ts.getOutputPrefix(),": ");
         if( 1==argv.length ){
           st.out( st.getInputText() );
    @@ -921,7 +920,7 @@ class ResultCommand extends Command {
       private final ResultBufferMode bufferMode;
       protected ResultCommand(ResultBufferMode bm){ bufferMode = bm; }
       public ResultCommand(){ this(ResultBufferMode.ESCAPED); }
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,0,-1);
         t.incrementTestCounter();
         final String sql = t.takeInputBuffer();
    @@ -939,7 +938,7 @@ class ResultCommand extends Command {
     
     //! --run command
     class RunCommand extends Command {
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,0,1);
         final sqlite3 db = (1==argv.length)
           ? t.getCurrentDb() : t.getDbById( Integer.parseInt(argv[1]) );
    @@ -959,7 +958,7 @@ class TableResultCommand extends Command {
       private final boolean jsonMode;
       protected TableResultCommand(boolean jsonMode){ this.jsonMode = jsonMode; }
       public TableResultCommand(){ this(false); }
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,0);
         t.incrementTestCounter();
         String body = ts.fetchCommandBody(t);
    @@ -1002,7 +1001,7 @@ class TableResultCommand extends Command {
     
     //! --testcase command
     class TestCaseCommand extends Command {
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,1);
         ts.setTestCaseName(argv[1]);
         t.clearResultBuffer();
    @@ -1012,7 +1011,7 @@ class TestCaseCommand extends Command {
     
     //! --verbosity command
     class VerbosityCommand extends Command {
    -  public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
    +  public void process(SQLTester t, TestScript ts, String[] argv){
         argcCheck(ts,argv,1);
         ts.setVerbosity( Integer.parseInt(argv[1]) );
       }
    @@ -1020,7 +1019,7 @@ class VerbosityCommand extends Command {
     
     class CommandDispatcher {
     
    -  private static java.util.Map commandMap =
    +  private static final java.util.Map commandMap =
         new java.util.HashMap<>();
     
       /**
    @@ -1244,7 +1243,7 @@ class TestScript {
         }
         cur.pos = i;
         final String rv = cur.sb.toString();
    -    if( i==cur.src.length && 0==rv.length() ){
    +    if( i==cur.src.length && rv.isEmpty() ){
           return null /* EOF */;
         }
         return rv;
    @@ -1364,7 +1363,7 @@ class TestScript {
         if( m.find() ){
           throw new IncompatibleDirective(this, m.group(1)+": "+m.group(3));
         }
    -    if( line.indexOf("\n|")>=0 ){
    +    if( line.contains("\n|") ){
           throw new IncompatibleDirective(this, "newline-pipe combination.");
         }
         return;
    diff --git a/ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java b/ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java
    index d8b6226ac9..54808cd1ca 100644
    --- a/ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java
    +++ b/ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java
    @@ -18,11 +18,11 @@ package org.sqlite.jni.capi;
        They are populated only via that interface.
     */
     public final class TableColumnMetadata {
    -  OutputPointer.Bool pNotNull = new OutputPointer.Bool();
    -  OutputPointer.Bool pPrimaryKey = new OutputPointer.Bool();
    -  OutputPointer.Bool pAutoinc = new OutputPointer.Bool();
    -  OutputPointer.String pzCollSeq = new OutputPointer.String();
    -  OutputPointer.String pzDataType = new OutputPointer.String();
    +  final OutputPointer.Bool pNotNull = new OutputPointer.Bool();
    +  final OutputPointer.Bool pPrimaryKey = new OutputPointer.Bool();
    +  final OutputPointer.Bool pAutoinc = new OutputPointer.Bool();
    +  final OutputPointer.String pzCollSeq = new OutputPointer.String();
    +  final OutputPointer.String pzDataType = new OutputPointer.String();
     
       public TableColumnMetadata(){
       }
    diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java
    index 05b1cfeaed..a9b766e9f3 100644
    --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java
    +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java
    @@ -19,7 +19,6 @@ import java.util.ArrayList;
     import java.util.List;
     import java.util.concurrent.ExecutorService;
     import java.util.concurrent.Executors;
    -import java.util.concurrent.Future;
     
     /**
        An annotation for Tester1 tests which we do not want to run in
    @@ -62,13 +61,13 @@ public class Tester1 implements Runnable {
       //! List of test*() methods to run.
       private static List testMethods = null;
       //! List of exceptions collected by run()
    -  private static List listErrors = new ArrayList<>();
    +  private static final List listErrors = new ArrayList<>();
       private static final class Metrics {
         //! Number of times createNewDb() (or equivalent) is invoked.
         volatile int dbOpen = 0;
       }
     
    -  private Integer tId;
    +  private final Integer tId;
     
       Tester1(Integer id){
         tId = id;
    @@ -78,7 +77,7 @@ public class Tester1 implements Runnable {
     
       public static synchronized void outln(){
         if( !quietMode ){
    -      System.out.println("");
    +      System.out.println();
         }
       }
     
    @@ -523,7 +522,7 @@ public class Tester1 implements Runnable {
         }
         sqlite3_finalize(stmt);
         affirm(3 == n);
    -    affirm("w😃rldhell🤩!🤩".equals(sbuf.toString()));
    +    affirm("w😃rldhell🤩!🤩".contentEquals(sbuf));
     
         try( sqlite3_stmt stmt2 = prepare(db, "SELECT ?, ?") ){
           rc = sqlite3_bind_text(stmt2, 1, "");
    @@ -668,7 +667,7 @@ public class Tester1 implements Runnable {
         execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
         final ValueHolder xDestroyCalled = new ValueHolder<>(0);
         final CollationCallback myCollation = new CollationCallback() {
    -        private String myState =
    +        private final String myState =
               "this is local state. There is much like it, but this is mine.";
             @Override
             // Reverse-sorts its inputs...
    @@ -847,7 +846,7 @@ public class Tester1 implements Runnable {
         SQLFunction funcAgg = new AggregateFunction(){
             @Override public void xStep(sqlite3_context cx, sqlite3_value[] args){
               /** Throwing from here should emit loud noise on stdout or stderr
    -              but the exception is supressed because we have no way to inform
    +              but the exception is suppressed because we have no way to inform
                   sqlite about it from these callbacks. */
               //throw new RuntimeException("Throwing from an xStep");
             }
    @@ -1850,7 +1849,7 @@ public class Tester1 implements Runnable {
           "; insert into t(a) values(1),(2),(3);",
           "select a from t;"
         };
    -    final List liStmt = new ArrayList();
    +    final List liStmt = new ArrayList<>();
         final PrepareMultiCallback proxy = new PrepareMultiCallback.StepAll();
         final ValueHolder toss = new ValueHolder<>(null);
         PrepareMultiCallback m = new PrepareMultiCallback() {
    @@ -1984,9 +1983,9 @@ public class Tester1 implements Runnable {
          -v: emit some developer-mode info at the end.
       */
       public static void main(String[] args) throws Exception {
    -    Integer nThread = 1;
    +    int nThread = 1;
         boolean doSomethingForDev = false;
    -    Integer nRepeat = 1;
    +    int nRepeat = 1;
         boolean forceFail = false;
         boolean sqlLog = false;
         boolean configLog = false;
    @@ -2048,7 +2047,7 @@ public class Tester1 implements Runnable {
           final ConfigLogCallback log = new ConfigLogCallback() {
               @Override public void call(int code, String msg){
                 outln("ConfigLogCallback: ",ResultCode.getEntryForInt(code),": ", msg);
    -          };
    +          }
             };
           int rc = sqlite3_config( log );
           affirm( 0==rc );
    diff --git a/ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java b/ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java
    index 372e4ec8d0..ce6c6a6abf 100644
    --- a/ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java
    +++ b/ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java
    @@ -33,5 +33,5 @@ public interface XDestroyCallback {
          each individual reference, leading to memory corruption or a
          crash via duplicate free().
       */
    -  public void xDestroy();
    +  void xDestroy();
     }
    diff --git a/ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java b/ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java
    index 594f3eaad6..f409f4961d 100644
    --- a/ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java
    +++ b/ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java
    @@ -12,7 +12,6 @@
     ** This file is part of the JNI bindings for the sqlite3 C API.
     */
     package org.sqlite.jni.fts5;
    -import java.nio.charset.StandardCharsets;
     import org.sqlite.jni.capi.*;
     import org.sqlite.jni.annotation.*;
     
    @@ -24,7 +23,7 @@ public final class Fts5ExtensionApi extends NativePointerHolder aOut = new ArrayList();
    +    List aOut = new ArrayList<>();
     
         /* Iterate through the list of SQL statements. For each, step through
         ** it and add any results to the aOut[] array.  */
    @@ -137,14 +136,14 @@ public class TesterFts5 {
       **     fts5_columncount()
       */
       private static void create_test_functions(sqlite3 db){
    -    /* 
    +    /*
         ** A user-defined-function fts5_rowid() that uses xRowid()
         */
         fts5_extension_function fts5_rowid = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             long rowid = ext.xRowid(fCx);
    @@ -153,14 +152,14 @@ public class TesterFts5 {
           public void xDestroy(){ }
         };
     
    -    /* 
    -    ** fts5_columncount() - xColumnCount() 
    +    /*
    +    ** fts5_columncount() - xColumnCount()
         */
         fts5_extension_function fts5_columncount = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             int nCol = ext.xColumnCount(fCx);
    @@ -169,14 +168,14 @@ public class TesterFts5 {
           public void xDestroy(){ }
         };
     
    -    /* 
    -    ** fts5_columnsize() - xColumnSize() 
    +    /*
    +    ** fts5_columnsize() - xColumnSize()
         */
         fts5_extension_function fts5_columnsize = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=1 ){
    @@ -194,14 +193,14 @@ public class TesterFts5 {
           public void xDestroy(){ }
         };
     
    -    /* 
    -    ** fts5_columntext() - xColumnText() 
    +    /*
    +    ** fts5_columntext() - xColumnText()
         */
         fts5_extension_function fts5_columntext = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=1 ){
    @@ -219,14 +218,14 @@ public class TesterFts5 {
           public void xDestroy(){ }
         };
     
    -    /* 
    -    ** fts5_columntotalsize() - xColumnTotalSize() 
    +    /*
    +    ** fts5_columntotalsize() - xColumnTotalSize()
         */
         fts5_extension_function fts5_columntsize = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=1 ){
    @@ -251,9 +250,9 @@ public class TesterFts5 {
         */
         class fts5_aux implements fts5_extension_function {
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length>1 ){
    @@ -268,13 +267,13 @@ public class TesterFts5 {
     
             if( argv.length==1 ){
               String val = sqlite3_value_text16(argv[0]);
    -          if( !val.equals("") ){
    +          if( !val.isEmpty() ){
                 ext.xSetAuxdata(fCx, val);
               }
             }
           }
           public void xDestroy(){ }
    -    };
    +    }
     
         /*
         ** fts5_inst();
    @@ -286,9 +285,9 @@ public class TesterFts5 {
         */
         fts5_extension_function fts5_inst = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=0 ){
    @@ -299,7 +298,7 @@ public class TesterFts5 {
             OutputPointer.Int32 piPhrase = new OutputPointer.Int32();
             OutputPointer.Int32 piCol = new OutputPointer.Int32();
             OutputPointer.Int32 piOff = new OutputPointer.Int32();
    -        String ret = new String();
    +        String ret = "";
     
             int rc = ext.xInstCount(fCx, pnInst);
             int nInst = pnInst.get();
    @@ -327,9 +326,9 @@ public class TesterFts5 {
         */
         fts5_extension_function fts5_pinst = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=0 ){
    @@ -338,7 +337,7 @@ public class TesterFts5 {
     
             OutputPointer.Int32 piCol = new OutputPointer.Int32();
             OutputPointer.Int32 piOff = new OutputPointer.Int32();
    -        String ret = new String();
    +        String ret = "";
             int rc = SQLITE_OK;
     
             int nPhrase = ext.xPhraseCount(fCx);
    @@ -350,7 +349,7 @@ public class TesterFts5 {
                   rc==SQLITE_OK && piCol.get()>=0;
                   ext.xPhraseNext(fCx, pIter, piCol, piOff)
               ){
    -            if( !ret.equals("") ) ret += " ";
    +            if( !ret.isEmpty() ) ret += " ";
                 ret += "{"+ii+" "+piCol.get()+" "+piOff.get()+"}";
               }
             }
    @@ -374,9 +373,9 @@ public class TesterFts5 {
         */
         fts5_extension_function fts5_pcolinst = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=0 ){
    @@ -384,7 +383,7 @@ public class TesterFts5 {
             }
     
             OutputPointer.Int32 piCol = new OutputPointer.Int32();
    -        String ret = new String();
    +        String ret = "";
             int rc = SQLITE_OK;
     
             int nPhrase = ext.xPhraseCount(fCx);
    @@ -396,7 +395,7 @@ public class TesterFts5 {
                   rc==SQLITE_OK && piCol.get()>=0;
                   ext.xPhraseNextColumn(fCx, pIter, piCol)
               ){
    -            if( !ret.equals("") ) ret += " ";
    +            if( !ret.isEmpty() ) ret += " ";
                 ret += "{"+ii+" "+piCol.get()+"}";
               }
             }
    @@ -415,9 +414,9 @@ public class TesterFts5 {
         */
         fts5_extension_function fts5_rowcount = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=0 ){
    @@ -440,9 +439,9 @@ public class TesterFts5 {
         */
         fts5_extension_function fts5_phrasesize = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=1 ){
    @@ -464,9 +463,9 @@ public class TesterFts5 {
         */
         fts5_extension_function fts5_phrasehits = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=1 ){
    @@ -503,9 +502,9 @@ public class TesterFts5 {
         */
         fts5_extension_function fts5_tokenize = new fts5_extension_function(){
           @Override public void call(
    -          Fts5ExtensionApi ext, 
    +          Fts5ExtensionApi ext,
               Fts5Context fCx,
    -          sqlite3_context pCx, 
    +          sqlite3_context pCx,
               sqlite3_value argv[]
           ){
             if( argv.length!=1 ){
    @@ -515,7 +514,7 @@ public class TesterFts5 {
             int rc = SQLITE_OK;
     
             class MyCallback implements XTokenizeCallback {
    -          private List myList = new ArrayList();
    +          private List myList = new ArrayList<>();
     
               public String getval() {
                 return String.join("+", myList);
    @@ -524,7 +523,7 @@ public class TesterFts5 {
               @Override
               public int call(int tFlags, byte[] txt, int iStart, int iEnd){
                 try {
    -              String str = new String(txt, "UTF-8");
    +              String str = new String(txt, StandardCharsets.UTF_8);
                   myList.add(str);
                 } catch (Exception e) {
                 }
    diff --git a/ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java b/ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java
    index 5e47633baa..6e98f64ff3 100644
    --- a/ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java
    +++ b/ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java
    @@ -39,7 +39,11 @@ public interface fts5_extension_function {
       */
       void xDestroy();
     
    -  public static abstract class Abstract implements fts5_extension_function {
    +  /**
    +     A base implementation of fts5_extension_function() which has a
    +     no-op xDestroy() method.
    +  */
    +  abstract class Abstract implements fts5_extension_function {
         @Override public abstract void call(Fts5ExtensionApi ext, Fts5Context fCx,
                                             sqlite3_context pCx, sqlite3_value argv[]);
         @Override public void xDestroy(){}
    diff --git a/ext/jni/src/org/sqlite/jni/test-script-interpreter.md b/ext/jni/src/org/sqlite/jni/test-script-interpreter.md
    index c10122349e..cc7b7e7f9a 100644
    --- a/ext/jni/src/org/sqlite/jni/test-script-interpreter.md
    +++ b/ext/jni/src/org/sqlite/jni/test-script-interpreter.md
    @@ -4,7 +4,7 @@
     
     The purpose of the Test Script Interpreter is to read and interpret
     script files that contain SQL commands and desired results.  The
    -interpreter will check results and report any discrepencies found.
    +interpreter will check results and report any discrepancies found.
     
     The test script files are ASCII text files.  The filename always ends with
     ".test".  Each script is evaluated independently; context does not carry
    @@ -160,7 +160,7 @@ the result buffer.  This distinction does not matter for the --result
     command itself, but it is important for related commands like --glob
     and --notglob.  Sometimes test cases will contains a bunch of SQL
     followed by multiple --glob and/or --notglob statements.  All of the
    -globs should be evaluated agains the result buffer, but the SQL should
    +globs should be evaluated against the result buffer, but the SQL should
     only be run once.  This is accomplished by resetting the input buffer
     but not the result buffer.
     
    diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java
    index 067a6983eb..c616ae7393 100644
    --- a/ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java
    +++ b/ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java
    @@ -12,10 +12,6 @@
     ** This file is part of the wrapper1 interface for sqlite3.
     */
     package org.sqlite.jni.wrapper1;
    -import org.sqlite.jni.capi.CApi;
    -import org.sqlite.jni.annotation.*;
    -import org.sqlite.jni.capi.sqlite3_context;
    -import org.sqlite.jni.capi.sqlite3_value;
     
     /**
        The SqlFunction type for scalar SQL functions.
    diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java
    index dcfc2ebebd..bb0fd0ccd4 100644
    --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java
    +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java
    @@ -22,13 +22,13 @@ import org.sqlite.jni.capi.sqlite3_value;
     */
     public interface SqlFunction  {
     
    -  public static final int DETERMINISTIC = CApi.SQLITE_DETERMINISTIC;
    -  public static final int INNOCUOUS = CApi.SQLITE_INNOCUOUS;
    -  public static final int DIRECTONLY = CApi.SQLITE_DIRECTONLY;
    -  public static final int SUBTYPE = CApi.SQLITE_SUBTYPE;
    -  public static final int RESULT_SUBTYPE = CApi.SQLITE_RESULT_SUBTYPE;
    -  public static final int UTF8 = CApi.SQLITE_UTF8;
    -  public static final int UTF16 = CApi.SQLITE_UTF16;
    +  int DETERMINISTIC = CApi.SQLITE_DETERMINISTIC;
    +  int INNOCUOUS = CApi.SQLITE_INNOCUOUS;
    +  int DIRECTONLY = CApi.SQLITE_DIRECTONLY;
    +  int SUBTYPE = CApi.SQLITE_SUBTYPE;
    +  int RESULT_SUBTYPE = CApi.SQLITE_RESULT_SUBTYPE;
    +  int UTF8 = CApi.SQLITE_UTF8;
    +  int UTF16 = CApi.SQLITE_UTF16;
     
       /**
          The Arguments type is an abstraction on top of the lower-level
    @@ -36,7 +36,7 @@ public interface SqlFunction  {
          of the lower-level interface, insofar as possible without "leaking"
          those types into this API.
       */
    -  public final static class Arguments implements Iterable{
    +  final class Arguments implements Iterable{
         private final sqlite3_context cx;
         private final sqlite3_value args[];
         public final int length;
    @@ -144,7 +144,7 @@ public interface SqlFunction  {
            range.
         */
         public void setAuxData(int argNdx, Object o){
    -      /* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html
    +      /* From the API docs: https://sqlite.org/c3ref/get_auxdata.html
     
              The value of the N parameter to these interfaces should be
              non-negative. Future enhancements may make use of negative N
    @@ -207,7 +207,7 @@ public interface SqlFunction  {
          Internal-use adapter for wrapping this package's ScalarFunction
          for use with the org.sqlite.jni.capi.ScalarFunction interface.
       */
    -  static final class ScalarAdapter extends org.sqlite.jni.capi.ScalarFunction {
    +  final class ScalarAdapter extends org.sqlite.jni.capi.ScalarFunction {
         private final ScalarFunction impl;
         ScalarAdapter(ScalarFunction impl){
           this.impl = impl;
    @@ -234,8 +234,8 @@ public interface SqlFunction  {
          Internal-use adapter for wrapping this package's AggregateFunction
          for use with the org.sqlite.jni.capi.AggregateFunction interface.
       */
    -  static /*cannot be final without duplicating the whole body in WindowAdapter*/
       class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction {
    +  /*cannot be final without duplicating the whole body in WindowAdapter*/
         private final AggregateFunction impl;
         AggregateAdapter(AggregateFunction impl){
           this.impl = impl;
    @@ -277,7 +277,7 @@ public interface SqlFunction  {
          Internal-use adapter for wrapping this package's WindowFunction
          for use with the org.sqlite.jni.capi.WindowFunction interface.
       */
    -  static final class WindowAdapter extends AggregateAdapter {
    +  final class WindowAdapter extends AggregateAdapter {
         private final WindowFunction impl;
         WindowAdapter(WindowFunction impl){
           super(impl);
    diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
    index 2855d4c25f..d259e0ce62 100644
    --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
    +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
    @@ -19,7 +19,6 @@ import org.sqlite.jni.capi.sqlite3_stmt;
     import org.sqlite.jni.capi.sqlite3_backup;
     import org.sqlite.jni.capi.sqlite3_blob;
     import org.sqlite.jni.capi.OutputPointer;
    -import java.nio.ByteBuffer;
     
     /**
        This class represents a database connection, analog to the C-side
    @@ -388,10 +387,10 @@ public final class Sqlite implements AutoCloseable  {
         return CApi.sqlite3_compileoption_used(optName);
       }
     
    -  private static boolean hasNormalizeSql =
    +  private static final boolean hasNormalizeSql =
         compileOptionUsed("ENABLE_NORMALIZE");
     
    -  private static boolean hasSqlLog =
    +  private static final boolean hasSqlLog =
         compileOptionUsed("ENABLE_SQLLOG");
     
       /**
    @@ -450,7 +449,7 @@ public final class Sqlite implements AutoCloseable  {
         long current;
         /** The peak value for the requested status() or libStatus() metric. */
         long peak;
    -  };
    +  }
     
       /**
          As per sqlite3_status64(), but returns its current and high-water
    @@ -696,7 +695,7 @@ public final class Sqlite implements AutoCloseable  {
         final org.sqlite.jni.capi.OutputPointer.Int32 oTail =
           new org.sqlite.jni.capi.OutputPointer.Int32();
         while( pos < sqlChunk.length ){
    -      sqlite3_stmt stmt = null;
    +      sqlite3_stmt stmt;
           if( pos>0 ){
             sqlChunk = java.util.Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length);
           }
    @@ -988,15 +987,15 @@ public final class Sqlite implements AutoCloseable  {
               }
             };
         checkRc( CApi.sqlite3_trace_v2(thisDb(), traceMask, tc) );
    -  };
    +  }
     
       /**
          Corresponds to the sqlite3_stmt class. Use Sqlite.prepare() to
          create new instances.
       */
       public static final class Stmt implements AutoCloseable {
    -    private Sqlite _db = null;
    -    private sqlite3_stmt stmt = null;
    +    private Sqlite _db;
    +    private sqlite3_stmt stmt;
     
         /** Only called by the prepare() factory functions. */
         Stmt(Sqlite db, sqlite3_stmt stmt){
    @@ -1379,9 +1378,9 @@ public final class Sqlite implements AutoCloseable  {
          Sqlite.initBackup() to create new instances.
       */
       public static final class Backup implements AutoCloseable {
    -    private sqlite3_backup b = null;
    -    private Sqlite dbTo = null;
    -    private Sqlite dbFrom = null;
    +    private sqlite3_backup b;
    +    private Sqlite dbTo;
    +    private Sqlite dbFrom;
     
         Backup(Sqlite dbDest, String schemaDest,Sqlite dbSrc, String schemaSrc){
           this.dbTo = dbDest;
    @@ -1491,7 +1490,7 @@ public final class Sqlite implements AutoCloseable  {
            Warning: the SQLite core has no mechanism for reporting errors
            from custom collations and its workflow does not accommodate
            propagation of exceptions from callbacks. Any exceptions thrown
    -       from collations will be silently supressed and sorting results
    +       from collations will be silently suppressed and sorting results
            will be unpredictable.
         */
         int call(byte[] lhs, byte[] rhs);
    @@ -1506,7 +1505,7 @@ public final class Sqlite implements AutoCloseable  {
       */
       public void createCollation(String name, int encoding, Collation c){
         thisDb();
    -    if( null==name || 0==name.length()){
    +    if( null==name || name.isEmpty()){
           throw new IllegalArgumentException("Collation name may not be null or empty.");
         }
         if( null==c ){
    @@ -1599,11 +1598,12 @@ public final class Sqlite implements AutoCloseable  {
       public void setBusyHandler( BusyHandler b ){
         org.sqlite.jni.capi.BusyHandlerCallback bhc = null;
         if( null!=b ){
    -      bhc = new org.sqlite.jni.capi.BusyHandlerCallback(){
    +      /*bhc = new org.sqlite.jni.capi.BusyHandlerCallback(){
               @Override public int call(int n){
                 return b.call(n);
               }
    -        };
    +        };*/
    +      bhc = b::call;
         }
         checkRc( CApi.sqlite3_busy_handler(thisDb(), bhc) );
       }
    @@ -1781,9 +1781,10 @@ public final class Sqlite implements AutoCloseable  {
       public void setProgressHandler( int n, ProgressHandler p ){
         org.sqlite.jni.capi.ProgressHandlerCallback phc = null;
         if( null!=p ){
    -      phc = new org.sqlite.jni.capi.ProgressHandlerCallback(){
    +      /*phc = new org.sqlite.jni.capi.ProgressHandlerCallback(){
               @Override public int call(){ return p.call(); }
    -        };
    +          };*/
    +      phc = p::call;
         }
         CApi.sqlite3_progress_handler( thisDb(), n, phc );
       }
    @@ -1808,11 +1809,12 @@ public final class Sqlite implements AutoCloseable  {
       public void setAuthorizer( Authorizer a ) {
         org.sqlite.jni.capi.AuthorizerCallback ac = null;
         if( null!=a ){
    -      ac = new org.sqlite.jni.capi.AuthorizerCallback(){
    +      /*ac = new org.sqlite.jni.capi.AuthorizerCallback(){
               @Override public int call(int opId, String s1, String s2, String s3, String s4){
                 return a.call(opId, s1, s2, s3, s4);
               }
    -        };
    +          };*/
    +      ac = a::call;
         }
         checkRc( CApi.sqlite3_set_authorizer( thisDb(), ac ) );
       }
    @@ -1932,11 +1934,12 @@ public final class Sqlite implements AutoCloseable  {
         final org.sqlite.jni.capi.ConfigLogCallback l =
           null==log
           ? null
    -      : new org.sqlite.jni.capi.ConfigLogCallback() {
    +      /*: new org.sqlite.jni.capi.ConfigLogCallback() {
               @Override public void call(int errCode, String msg){
                 log.call(errCode, msg);
               }
    -        };
    +          };*/
    +      : log::call;
           checkRcStatic(CApi.sqlite3_config(l));
       }
     
    diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
    index 5ac41323cb..528e1f61c6 100644
    --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
    +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
    @@ -13,7 +13,6 @@
     */
     package org.sqlite.jni.wrapper1;
     import java.nio.charset.StandardCharsets;
    -import java.util.Arrays;
     import java.util.ArrayList;
     import java.util.List;
     import java.util.concurrent.ExecutorService;
    @@ -53,14 +52,14 @@ public class Tester2 implements Runnable {
       //! List of test*() methods to run.
       private static List testMethods = null;
       //! List of exceptions collected by run()
    -  private static List listErrors = new ArrayList<>();
    +  private static final List listErrors = new ArrayList<>();
       private static final class Metrics {
         //! Number of times createNewDb() (or equivalent) is invoked.
         volatile int dbOpen = 0;
       }
     
       //! Instance ID.
    -  private Integer tId;
    +  private final Integer tId;
     
       Tester2(Integer id){
         tId = id;
    @@ -70,7 +69,7 @@ public class Tester2 implements Runnable {
     
       public static synchronized void outln(){
         if( !quietMode ){
    -      System.out.println("");
    +      System.out.println();
         }
       }
     
    @@ -547,7 +546,7 @@ public class Tester2 implements Runnable {
           err = e;
         }
         affirm( err!=null );
    -    affirm( err.getMessage().indexOf(toss.value)>=0 );
    +    affirm( err.getMessage().contains(toss.value) );
         toss.value = null;
     
         val.value = 0;
    @@ -616,7 +615,7 @@ public class Tester2 implements Runnable {
         final Sqlite db = openDb();
         execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
         final Sqlite.Collation myCollation = new Sqlite.Collation() {
    -        private String myState =
    +        private final String myState =
               "this is local state. There is much like it, but this is mine.";
             @Override
             // Reverse-sorts its inputs...
    @@ -1038,9 +1037,9 @@ public class Tester2 implements Runnable {
          -v: emit some developer-mode info at the end.
       */
       public static void main(String[] args) throws Exception {
    -    Integer nThread = 1;
    +    int nThread = 1;
    +    int nRepeat = 1;
         boolean doSomethingForDev = false;
    -    Integer nRepeat = 1;
         boolean forceFail = false;
         boolean sqlLog = false;
         boolean configLog = false;
    @@ -1097,7 +1096,7 @@ public class Tester2 implements Runnable {
           Sqlite.libConfigLog( new Sqlite.ConfigLog() {
               @Override public void call(int code, String msg){
                 outln("ConfigLog: ",Sqlite.errstr(code),": ", msg);
    -          };
    +          }
             }
           );
         }
    diff --git a/ext/misc/README.md b/ext/misc/README.md
    index 69cb230255..cfc9e867c0 100644
    --- a/ext/misc/README.md
    +++ b/ext/misc/README.md
    @@ -1,7 +1,7 @@
     ## Miscellaneous Extensions
     
     This folder contains a collection of smaller loadable extensions.
    -See  for instructions on how
    +See  for instructions on how
     to compile and use loadable extensions.
     Each extension in this folder is implemented in a single file of C code.
     
    @@ -10,9 +10,9 @@ header comments for details about each extension.  Additional notes are
     as follows:
     
       *  **carray.c** —  This module implements the
    -     [carray](https://www.sqlite.org/carray.html) table-valued function.
    +     [carray](https://sqlite.org/carray.html) table-valued function.
          It is a good example of how to go about implementing a custom
    -     [table-valued function](https://www.sqlite.org/vtab.html#tabfunc2).
    +     [table-valued function](https://sqlite.org/vtab.html#tabfunc2).
     
       *  **csv.c** —  A [virtual table](https://sqlite.org/vtab.html)
          for reading 
    @@ -21,7 +21,7 @@ as follows:
       *  **dbdump.c** —  This is not actually a loadable extension, but
          rather a library that implements an approximate equivalent to the
          ".dump" command of the
    -     [command-line shell](https://www.sqlite.org/cli.html).
    +     [command-line shell](https://sqlite.org/cli.html).
     
       *  **json1.c** —  Various SQL functions and table-valued functions
          for processing JSON.  This extension is already built into the
    @@ -29,7 +29,7 @@ as follows:
           for additional information.
     
       *  **memvfs.c** —  This file implements a custom
    -     [VFS](https://www.sqlite.org/vfs.html) that stores an entire database
    +     [VFS](https://sqlite.org/vfs.html) that stores an entire database
          file in a single block of RAM.  It serves as a good example of how
          to implement a simple custom VFS.
     
    @@ -38,7 +38,7 @@ as follows:
          new custom SQL functions for SQLite.
     
       *  **series.c** —  This is an implementation of the
    -     "generate_series" [virtual table](https://www.sqlite.org/vtab.html).
    +     "generate_series" [virtual table](https://sqlite.org/vtab.html).
          It can make a good template for new custom virtual table implementations.
     
       *  **shathree.c** —  An implementation of the sha3() and
    diff --git a/ext/misc/closure.c b/ext/misc/closure.c
    index 267ae1c424..14caf271f9 100644
    --- a/ext/misc/closure.c
    +++ b/ext/misc/closure.c
    @@ -137,7 +137,7 @@
     **       AND closure.idname='groupId'
     **       AND closure.parentname='parentId';
     **
    -** See the documentation at http://www.sqlite.org/loadext.html for information
    +** See the documentation at http://sqlite.org/loadext.html for information
     ** on how to compile and use loadable extensions such as this one.
     */
     #include "sqlite3ext.h"
    diff --git a/ext/misc/fossildelta.c b/ext/misc/fossildelta.c
    index e638737d2b..9f81270d7b 100644
    --- a/ext/misc/fossildelta.c
    +++ b/ext/misc/fossildelta.c
    @@ -22,7 +22,7 @@
     ** The delta format is the Fossil delta format, described in a comment
     ** on the delete_create() function implementation below, and also at
     **
    -**    https://www.fossil-scm.org/fossil/doc/trunk/www/delta_format.wiki
    +**    https://fossil-scm.org/fossil/doc/trunk/www/delta_format.wiki
     **
     ** This delta format is used by the RBU extension, which is the main
     ** reason that these routines are included in the extension library.
    diff --git a/ext/misc/memstat.c b/ext/misc/memstat.c
    index c56af9f297..8e69b46955 100644
    --- a/ext/misc/memstat.c
    +++ b/ext/misc/memstat.c
    @@ -401,8 +401,14 @@ static sqlite3_module memstatModule = {
     
     #endif /* SQLITE_OMIT_VIRTUALTABLE */
     
    -int sqlite3MemstatVtabInit(sqlite3 *db){
    +int sqlite3MemstatVtabInit(
    +  sqlite3 *db,
    +  char **NotUsed1,
    +  const sqlite3_api_routines *NotUsed2
    +){
       int rc = SQLITE_OK;
    +  (void)NotUsed1;
    +  (void)NotUsed2;
     #ifndef SQLITE_OMIT_VIRTUALTABLE
       rc = sqlite3_create_module(db, "sqlite_memstat", &memstatModule, 0);
     #endif
    @@ -421,7 +427,7 @@ int sqlite3_memstat_init(
       int rc = SQLITE_OK;
       SQLITE_EXTENSION_INIT2(pApi);
     #ifndef SQLITE_OMIT_VIRTUALTABLE
    -  rc = sqlite3MemstatVtabInit(db);
    +  rc = sqlite3MemstatVtabInit(db, 0, 0);
     #endif
       return rc;
     }
    diff --git a/ext/misc/series.c b/ext/misc/series.c
    index e8188f1c97..22e0f7edbe 100644
    --- a/ext/misc/series.c
    +++ b/ext/misc/series.c
    @@ -115,6 +115,7 @@ SQLITE_EXTENSION_INIT1
     #include 
     #include 
     #include 
    +#include 
     
     #ifndef SQLITE_OMIT_VIRTUALTABLE
     /*
    @@ -480,25 +481,52 @@ static int seriesFilter(
         ** constraints on the "value" column.
         */
         if( idxNum & 0x0080 ){
    -      iMin = iMax = sqlite3_value_int64(argv[i++]);
    +      if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
    +        double r = sqlite3_value_double(argv[i++]);
    +        if( r==ceil(r) ){
    +          iMin = iMax = (sqlite3_int64)r;
    +        }else{
    +          returnNoRows = 1;
    +        }
    +      }else{
    +        iMin = iMax = sqlite3_value_int64(argv[i++]);
    +      }
         }else{
           if( idxNum & 0x0300 ){
    -        iMin = sqlite3_value_int64(argv[i++]);
    -        if( idxNum & 0x0200 ){
    -          if( iMin==LARGEST_INT64 ){
    -            returnNoRows = 1;
    +        if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
    +          double r = sqlite3_value_double(argv[i++]);
    +          if( idxNum & 0x0200 && r==ceil(r) ){
    +            iMin = (sqlite3_int64)ceil(r+1.0);
               }else{
    -            iMin++;
    +            iMin = (sqlite3_int64)ceil(r);
    +          }
    +        }else{
    +          iMin = sqlite3_value_int64(argv[i++]);
    +          if( idxNum & 0x0200 ){
    +            if( iMin==LARGEST_INT64 ){
    +              returnNoRows = 1;
    +            }else{
    +              iMin++;
    +            }
               }
             }
           }
           if( idxNum & 0x3000 ){
    -        iMax = sqlite3_value_int64(argv[i++]);
    -        if( idxNum & 0x2000 ){
    -          if( iMax==SMALLEST_INT64 ){
    -            returnNoRows = 1;
    +        if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
    +          double r = sqlite3_value_double(argv[i++]);
    +          if( (idxNum & 0x2000)!=0 && r==floor(r) ){
    +            iMax = (sqlite3_int64)(r-1.0);
               }else{
    -            iMax--;
    +            iMax = (sqlite3_int64)floor(r);
    +          }
    +        }else{
    +          iMax = sqlite3_value_int64(argv[i++]);
    +          if( idxNum & 0x2000 ){
    +            if( iMax==SMALLEST_INT64 ){
    +              returnNoRows = 1;
    +            }else{
    +              iMax--;
    +            }
               }
             }
           }
    @@ -552,7 +580,7 @@ static int seriesFilter(
       for(i=0; inCol==0 ){
         u8 *abPK;
         assert( pTab->azCol==0 || pTab->abPK==0 );
    +    sqlite3_free(pTab->azCol);
    +    pTab->abPK = 0;
         rc = sessionTableInfo(pSession, db, zDb, 
             pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol, 
             &pTab->azDflt, &pTab->aiIdx, &abPK,
    @@ -2216,7 +2218,9 @@ int sqlite3session_diff(
         SessionTable *pTo;            /* Table zTbl */
     
         /* Locate and if necessary initialize the target table object */
    +    pSession->bAutoAttach++;
         rc = sessionFindTable(pSession, zTbl, &pTo);
    +    pSession->bAutoAttach--;
         if( pTo==0 ) goto diff_out;
         if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){
           rc = pSession->rc;
    @@ -2227,17 +2231,43 @@ int sqlite3session_diff(
         if( rc==SQLITE_OK ){
           int bHasPk = 0;
           int bMismatch = 0;
    -      int nCol;                   /* Columns in zFrom.zTbl */
    +      int nCol = 0;               /* Columns in zFrom.zTbl */
           int bRowid = 0;
    -      u8 *abPK;
    +      u8 *abPK = 0;
           const char **azCol = 0;
    -      rc = sessionTableInfo(0, db, zFrom, zTbl, 
    -          &nCol, 0, 0, &azCol, 0, 0, &abPK, 
    -          pSession->bImplicitPK ? &bRowid : 0
    -      );
    +      char *zDbExists = 0;
    +
    +      /* Check that database zFrom is attached.  */
    +      zDbExists = sqlite3_mprintf("SELECT * FROM %Q.sqlite_schema", zFrom);
    +      if( zDbExists==0 ){
    +        rc = SQLITE_NOMEM;
    +      }else{
    +        sqlite3_stmt *pDbExists = 0;
    +        rc = sqlite3_prepare_v2(db, zDbExists, -1, &pDbExists, 0);
    +        if( rc==SQLITE_ERROR ){
    +          rc = SQLITE_OK;
    +          nCol = -1;
    +        }
    +        sqlite3_finalize(pDbExists);
    +        sqlite3_free(zDbExists);
    +      }
    +
    +      if( rc==SQLITE_OK && nCol==0 ){
    +        rc = sessionTableInfo(0, db, zFrom, zTbl, 
    +            &nCol, 0, 0, &azCol, 0, 0, &abPK, 
    +            pSession->bImplicitPK ? &bRowid : 0
    +        );
    +      }
           if( rc==SQLITE_OK ){
             if( pTo->nCol!=nCol ){
    -          bMismatch = 1;
    +          if( nCol<=0 ){
    +            rc = SQLITE_SCHEMA;
    +            if( pzErrMsg ){
    +              *pzErrMsg = sqlite3_mprintf("no such table: %s.%s", zFrom, zTbl);
    +            }
    +          }else{
    +            bMismatch = 1;
    +          }
             }else{
               int i;
               for(i=0; iaiColumn[j] = pPk->aiColumn[i];
             pIdx->azColl[j] = pPk->azColl[i];
             if( pPk->aSortOrder[i] ){
    -          /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */
    +          /* See ticket https://sqlite.org/src/info/bba7b69f9849b5bf */
               pIdx->bAscKeyBug = 1;
             }
             j++;
    @@ -3835,7 +3835,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
         ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables
         ** with DESC primary keys, since those indexes have there keys in
         ** a different order from the main table.
    -    ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf
    +    ** See ticket: https://sqlite.org/src/info/bba7b69f9849b5bf
         */
         sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
       }
    @@ -4219,6 +4219,7 @@ void sqlite3CreateIndex(
           assert( j<=0x7fff );
           if( j<0 ){
             j = pTab->iPKey;
    +        pIndex->bIdxRowid = 1;
           }else{
             if( pTab->aCol[j].notNull==0 ){
               pIndex->uniqNotNull = 0;
    diff --git a/src/insert.c b/src/insert.c
    index 7dc9bfd8b1..fdd9c8da2a 100644
    --- a/src/insert.c
    +++ b/src/insert.c
    @@ -2113,7 +2113,7 @@ void sqlite3GenerateConstraintChecks(
       ** could happen in any order, but they are grouped up front for
       ** convenience.
       **
    -  ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43
    +  ** 2018-08-14: Ticket https://sqlite.org/src/info/908f001483982c43
       ** The order of constraints used to have OE_Update as (2) and OE_Abort
       ** and so forth as (1). But apparently PostgreSQL checks the OE_Update
       ** constraint before any others, so it had to be moved.
    diff --git a/src/json.c b/src/json.c
    index 5360831af0..9c38bde985 100644
    --- a/src/json.c
    +++ b/src/json.c
    @@ -23,8 +23,8 @@
     ** Beginning with version 3.45.0 (circa 2024-01-01), these routines also
     ** accept BLOB values that have JSON encoded using a binary representation
     ** called "JSONB".  The name JSONB comes from PostgreSQL, however the on-disk
    -** format SQLite JSONB is completely different and incompatible with
    -** PostgreSQL JSONB.
    +** format for SQLite-JSONB is completely different and incompatible with
    +** PostgreSQL-JSONB.
     **
     ** Decoding and interpreting JSONB is still O(N) where N is the size of
     ** the input, the same as text JSON.  However, the constant of proportionality
    @@ -81,7 +81,7 @@
     **
     ** The payload size need not be expressed in its minimal form.  For example,
     ** if the payload size is 10, the size can be expressed in any of 5 different
    -** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte,
    +** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by one 0x0a byte,
     ** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by
     ** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and
     ** a single byte of 0x0a.  The shorter forms are preferred, of course, but
    @@ -91,7 +91,7 @@
     ** the size when it becomes known, resulting in a non-minimal encoding.
     **
     ** The value (X>>4)==15 is not actually used in the current implementation
    -** (as SQLite is currently unable handle BLOBs larger than about 2GB)
    +** (as SQLite is currently unable to handle BLOBs larger than about 2GB)
     ** but is included in the design to allow for future enhancements.
     **
     ** The payload follows the header.  NULL, TRUE, and FALSE have no payload and
    @@ -151,23 +151,47 @@ static const char * const jsonbType[] = {
     ** increase for the text-JSON parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
     */
     static const char jsonIsSpace[] = {
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 1, 1, 0, 0, 1, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  1, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    +#ifdef SQLITE_ASCII
    +/*0  1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 1, 1, 0, 0, 1, 0, 0,  /* 0 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 1 */
    +  1, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 2 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 3 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 4 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 5 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 6 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 7 */
    +
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 8 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 9 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* a */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* b */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* c */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* d */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* e */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* f */
    +#endif
    +#ifdef SQLITE_EBCDIC
    +/*0  1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  */
    +  0, 0, 0, 0, 0, 1, 0, 0,  0, 0, 0, 0, 0, 1, 0, 0,  /* 0 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 1 */
    +  0, 0, 0, 0, 0, 1, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 2 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 3 */
    +  1, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 4 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 5 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 6 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 7 */
    +
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 8 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 9 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* a */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* b */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* c */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* d */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* e */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* f */
    +#endif
     
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     };
     #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
     
    @@ -175,7 +199,13 @@ static const char jsonIsSpace[] = {
     ** The set of all space characters recognized by jsonIsspace().
     ** Useful as the second argument to strspn().
     */
    +#ifdef SQLITE_ASCII
     static const char jsonSpaces[] = "\011\012\015\040";
    +#endif
    +#ifdef SQLITE_EBCDIC
    +static const char jsonSpaces[] = "\005\045\015\100";
    +#endif
    +
     
     /*
     ** Characters that are special to JSON.  Control characters,
    @@ -184,23 +214,46 @@ static const char jsonSpaces[] = "\011\012\015\040";
     ** it in the set of special characters.
     */
     static const char jsonIsOk[256] = {
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
    -  1, 1, 0, 1, 1, 1, 1, 0,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 0, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    +#ifdef SQLITE_ASCII
    +/*0  1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 0 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 1 */
    +  1, 1, 0, 1, 1, 1, 1, 0,  1, 1, 1, 1, 1, 1, 1, 1,  /* 2 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 3 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 4 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 0, 1, 1, 1,  /* 5 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 6 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 7 */
     
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,
    -  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 8 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 9 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* a */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* b */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* c */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* d */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* e */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1   /* f */
    +#endif
    +#ifdef SQLITE_EBCDIC
    +/*0  1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 0 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 1 */
    +  0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,  /* 2 */
    +  1, 1, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 1, 0,  /* 3 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 4 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 5 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 6 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 0, 1, 0,  /* 7 */
    +
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 8 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* 9 */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* a */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* b */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* c */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* d */
    +  0, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1,  /* e */
    +  1, 1, 1, 1, 1, 1, 1, 1,  1, 1, 1, 1, 1, 1, 1, 1   /* f */
    +#endif
     };
     
     /* Objects */
    @@ -1165,7 +1218,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode(
     }
     
     
    -/* Append an node type byte together with the payload size and
    +/* Append a node type byte together with the payload size and
     ** possibly also the payload.
     **
     ** If aPayload is not NULL, then it is a pointer to the payload which
    @@ -2500,6 +2553,82 @@ static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
       pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz);
     }
     
    +/*
    +** If the JSONB at aIns[0..nIns-1] can be expanded (by denormalizing the
    +** size field) by d bytes, then write the expansion into aOut[] and
    +** return true.  In this way, an overwrite happens without changing the
    +** size of the JSONB, which reduces memcpy() operations and also make it
    +** faster and easier to update the B-Tree entry that contains the JSONB
    +** in the database.
    +**
    +** If the expansion of aIns[] by d bytes cannot be (easily) accomplished
    +** then return false.
    +**
    +** The d parameter is guaranteed to be between 1 and 8.
    +**
    +** This routine is an optimization.  A correct answer is obtained if it
    +** always leaves the output unchanged and returns false.
    +*/
    +static int jsonBlobOverwrite(
    +  u8 *aOut,                 /* Overwrite here */
    +  const u8 *aIns,           /* New content */
    +  u32 nIns,                 /* Bytes of new content */
    +  u32 d                     /* Need to expand new content by this much */
    +){
    +  u32 szPayload;       /* Bytes of payload */
    +  u32 i;               /* New header size, after expansion & a loop counter */
    +  u8 szHdr;            /* Size of header before expansion */
    +
    +  /* Lookup table for finding the upper 4 bits of the first byte of the
    +  ** expanded aIns[], based on the size of the expanded aIns[] header:
    +  **
    +  **                             2     3  4     5  6  7  8     9 */
    +  static const u8 aType[] = { 0xc0, 0xd0, 0, 0xe0, 0, 0, 0, 0xf0 };
    +
    +  if( (aIns[0]&0x0f)<=2 ) return 0;    /* Cannot enlarge NULL, true, false */
    +  switch( aIns[0]>>4 ){
    +    default: {                         /* aIns[] header size 1 */
    +      if( ((1<=2 && i<=9 && aType[i-2]!=0 );
    +  aOut[0] = (aIns[0] & 0x0f) | aType[i-2];
    +  memcpy(&aOut[i], &aIns[szHdr], nIns-szHdr);
    +  szPayload = nIns - szHdr;
    +  while( 1/*edit-by-break*/ ){
    +    i--;
    +    aOut[i] = szPayload & 0xff;
    +    if( i==1 ) break;
    +    szPayload >>= 8;
    +  }
    +  assert( (szPayload>>8)==0 );
    +  return 1;
    +}
    +
     /*
     ** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of
     ** content beginning at iDel, and replacing them with nIns bytes of
    @@ -2521,6 +2650,11 @@ static void jsonBlobEdit(
       u32 nIns               /* Bytes of content to insert */
     ){
       i64 d = (i64)nIns - (i64)nDel;
    +  if( d<0 && d>=(-8) && aIns!=0
    +   && jsonBlobOverwrite(&pParse->aBlob[iDel], aIns, nIns, (int)-d)
    +  ){
    +    return;
    +  }
       if( d!=0 ){
         if( pParse->nBlob + d > pParse->nBlobAlloc ){
           jsonBlobExpand(pParse, pParse->nBlob+d);
    @@ -2532,7 +2666,9 @@ static void jsonBlobEdit(
         pParse->nBlob += d;
         pParse->delta += d;
       }
    -  if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns);
    +  if( nIns && aIns ){
    +    memcpy(&pParse->aBlob[iDel], aIns, nIns);
    +  }
     }
     
     /*
    @@ -3295,7 +3431,7 @@ static char *jsonBadPathError(
     }
     
     /* argv[0] is a BLOB that seems likely to be a JSONB.  Subsequent
    -** arguments come in parse where each pair contains a JSON path and
    +** arguments come in pairs where each pair contains a JSON path and
     ** content to insert or set at that patch.  Do the updates
     ** and return the result.
     **
    diff --git a/src/os_win.c b/src/os_win.c
    index dab8af34c4..0dd56af583 100644
    --- a/src/os_win.c
    +++ b/src/os_win.c
    @@ -617,7 +617,7 @@ static struct win_syscall {
       { "FileTimeToLocalFileTime", (SYSCALL)0,                       0 },
     #endif
     
    -#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(CONST FILETIME*, \
    +#define osFileTimeToLocalFileTime ((BOOL(WINAPI*)(const FILETIME*, \
             LPFILETIME))aSyscall[11].pCurrent)
     
     #if SQLITE_OS_WINCE
    @@ -626,7 +626,7 @@ static struct win_syscall {
       { "FileTimeToSystemTime",    (SYSCALL)0,                       0 },
     #endif
     
    -#define osFileTimeToSystemTime ((BOOL(WINAPI*)(CONST FILETIME*, \
    +#define osFileTimeToSystemTime ((BOOL(WINAPI*)(const FILETIME*, \
             LPSYSTEMTIME))aSyscall[12].pCurrent)
     
       { "FlushFileBuffers",        (SYSCALL)FlushFileBuffers,        0 },
    @@ -906,7 +906,7 @@ static struct win_syscall {
       { "LockFile",                (SYSCALL)0,                       0 },
     #endif
     
    -#ifndef osLockFile
    +#if !defined(osLockFile) && defined(SQLITE_WIN32_HAS_ANSI)
     #define osLockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
             DWORD))aSyscall[47].pCurrent)
     #endif
    @@ -970,7 +970,7 @@ static struct win_syscall {
     
       { "SystemTimeToFileTime",    (SYSCALL)SystemTimeToFileTime,    0 },
     
    -#define osSystemTimeToFileTime ((BOOL(WINAPI*)(CONST SYSTEMTIME*, \
    +#define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \
             LPFILETIME))aSyscall[56].pCurrent)
     
     #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
    @@ -979,7 +979,7 @@ static struct win_syscall {
       { "UnlockFile",              (SYSCALL)0,                       0 },
     #endif
     
    -#ifndef osUnlockFile
    +#if !defined(osUnlockFile) && defined(SQLITE_WIN32_HAS_ANSI)
     #define osUnlockFile ((BOOL(WINAPI*)(HANDLE,DWORD,DWORD,DWORD, \
             DWORD))aSyscall[57].pCurrent)
     #endif
    @@ -1207,6 +1207,63 @@ static struct win_syscall {
     
     #define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent)
     
    +#if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32)
    +  { "GetModuleHandleW",         (SYSCALL)GetModuleHandleW,       0 },
    +#else
    +  { "GetModuleHandleW",         (SYSCALL)0,                      0 },
    +#endif
    +
    +#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[82].pCurrent)
    +
    +#ifndef _WIN32
    +  { "getenv",                   (SYSCALL)getenv,                 0 },
    +#else
    +  { "getenv",                   (SYSCALL)0,                      0 },
    +#endif
    +
    +#define osGetenv ((const char *(*)(const char *))aSyscall[83].pCurrent)
    +
    +#ifndef _WIN32
    +  { "getcwd",                   (SYSCALL)getcwd,                 0 },
    +#else
    +  { "getcwd",                   (SYSCALL)0,                      0 },
    +#endif
    +
    +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[84].pCurrent)
    +
    +#ifndef _WIN32
    +  { "readlink",                 (SYSCALL)readlink,               0 },
    +#else
    +  { "readlink",                 (SYSCALL)0,                      0 },
    +#endif
    +
    +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[85].pCurrent)
    +
    +#ifndef _WIN32
    +  { "lstat",                    (SYSCALL)lstat,                  0 },
    +#else
    +  { "lstat",                    (SYSCALL)0,                      0 },
    +#endif
    +
    +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[86].pCurrent)
    +
    +#ifndef _WIN32
    +  { "__errno",                  (SYSCALL)__errno,                0 },
    +#else
    +  { "__errno",                  (SYSCALL)0,                      0 },
    +#endif
    +
    +#define osErrno (*((int*(*)(void))aSyscall[87].pCurrent)())
    +
    +#ifndef _WIN32
    +  { "cygwin_conv_path",         (SYSCALL)cygwin_conv_path,       0 },
    +#else
    +  { "cygwin_conv_path",         (SYSCALL)0,                      0 },
    +#endif
    +
    +#define osCygwin_conv_path ((size_t(*)(unsigned int, \
    +    const void *, void *, size_t))aSyscall[88].pCurrent)
    +
     }; /* End of the overrideable system calls */
     
     /*
    @@ -1380,6 +1437,7 @@ int sqlite3_win32_reset_heap(){
     }
     #endif /* SQLITE_WIN32_MALLOC */
     
    +#ifdef _WIN32
     /*
     ** This function outputs the specified (ANSI) string to the Win32 debugger
     ** (if available).
    @@ -1422,6 +1480,7 @@ void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
       }
     #endif
     }
    +#endif /* _WIN32 */
     
     /*
     ** The following routine suspends the current thread for at least ms
    @@ -1722,6 +1781,7 @@ void sqlite3MemSetDefault(void){
     }
     #endif /* SQLITE_WIN32_MALLOC */
     
    +#ifdef _WIN32
     /*
     ** Convert a UTF-8 string to Microsoft Unicode.
     **
    @@ -1747,6 +1807,7 @@ static LPWSTR winUtf8ToUnicode(const char *zText){
       }
       return zWideText;
     }
    +#endif /* _WIN32 */
     
     /*
     ** Convert a Microsoft Unicode string to UTF-8.
    @@ -1781,28 +1842,29 @@ static char *winUnicodeToUtf8(LPCWSTR zWideText){
     ** Space to hold the returned string is obtained from sqlite3_malloc().
     */
     static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
    -  int nByte;
    +  int nWideChar;
       LPWSTR zMbcsText;
       int codepage = useAnsi ? CP_ACP : CP_OEMCP;
     
    -  nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
    -                                0)*sizeof(WCHAR);
    -  if( nByte==0 ){
    +  nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
    +                                0);
    +  if( nWideChar==0 ){
         return 0;
       }
    -  zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
    +  zMbcsText = sqlite3MallocZero( nWideChar*sizeof(WCHAR) );
       if( zMbcsText==0 ){
         return 0;
       }
    -  nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
    -                                nByte);
    -  if( nByte==0 ){
    +  nWideChar = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
    +                                nWideChar);
    +  if( nWideChar==0 ){
         sqlite3_free(zMbcsText);
         zMbcsText = 0;
       }
       return zMbcsText;
     }
     
    +#ifdef _WIN32
     /*
     ** Convert a Microsoft Unicode string to a multi-byte character string,
     ** using the ANSI or OEM code page.
    @@ -1830,6 +1892,7 @@ static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
       }
       return zText;
     }
    +#endif /* _WIN32 */
     
     /*
     ** Convert a multi-byte character string to UTF-8.
    @@ -1849,6 +1912,7 @@ static char *winMbcsToUtf8(const char *zText, int useAnsi){
       return zTextUtf8;
     }
     
    +#ifdef _WIN32
     /*
     ** Convert a UTF-8 string to a multi-byte character string.
     **
    @@ -1898,6 +1962,7 @@ char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){
     #endif
       return winUnicodeToUtf8(zWideText);
     }
    +#endif /* _WIN32 */
     
     /*
     ** This is a public wrapper for the winMbcsToUtf8() function.
    @@ -1915,6 +1980,7 @@ char *sqlite3_win32_mbcs_to_utf8(const char *zText){
       return winMbcsToUtf8(zText, osAreFileApisANSI());
     }
     
    +#ifdef _WIN32
     /*
     ** This is a public wrapper for the winMbcsToUtf8() function.
     */
    @@ -2039,6 +2105,7 @@ int sqlite3_win32_set_directory(
     ){
       return sqlite3_win32_set_directory16(type, zValue);
     }
    +#endif /* _WIN32 */
     
     /*
     ** The return value of winGetLastErrorMsg
    @@ -2587,9 +2654,11 @@ static BOOL winLockFile(
         ovlp.Offset = offsetLow;
         ovlp.OffsetHigh = offsetHigh;
         return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
    +#ifdef SQLITE_WIN32_HAS_ANSI
       }else{
         return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
                           numBytesHigh);
    +#endif
       }
     #endif
     }
    @@ -2697,9 +2766,11 @@ static BOOL winUnlockFile(
         ovlp.Offset = offsetLow;
         ovlp.OffsetHigh = offsetHigh;
         return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
    +#ifdef SQLITE_WIN32_HAS_ANSI
       }else{
         return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
                             numBytesHigh);
    +#endif
       }
     #endif
     }
    @@ -4113,14 +4184,91 @@ static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){
     ** Convert a UTF-8 filename into whatever form the underlying
     ** operating system wants filenames in.  Space to hold the result
     ** is obtained from malloc and must be freed by the calling
    -** function.
    +** function
    +**
    +** On Cygwin, 3 possible input forms are accepted:
    +** - If the filename starts with ":/" or ":\",
    +**   it is converted to UTF-16 as-is.
    +** - If the filename contains '/', it is assumed to be a
    +**   Cygwin absolute path, it is converted to a win32
    +**   absolute path in UTF-16.
    +** - Otherwise it must be a filename only, the win32 filename
    +**   is returned in UTF-16.
    +** Note: If the function cygwin_conv_path() fails, only
    +**   UTF-8 -> UTF-16 conversion will be done. This can only
    +**   happen when the file path >32k, in which case winUtf8ToUnicode()
    +**   will fail too.
     */
     static void *winConvertFromUtf8Filename(const char *zFilename){
       void *zConverted = 0;
       if( osIsNT() ){
    +#ifdef __CYGWIN__
    +    int nChar;
    +    LPWSTR zWideFilename;
    +
    +    if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename)
    +        && winIsDirSep(zFilename[2])) ){
    +      int nByte;
    +      int convertflag = CCP_POSIX_TO_WIN_W;
    +      if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE;
    +      nByte = (int)osCygwin_conv_path(convertflag,
    +          zFilename, 0, 0);
    +      if( nByte>0 ){
    +        zConverted = sqlite3MallocZero(nByte+12);
    +        if ( zConverted==0 ){
    +          return zConverted;
    +        }
    +        zWideFilename = zConverted;
    +        /* Filenames should be prefixed, except when converted
    +         * full path already starts with "\\?\". */
    +        if( osCygwin_conv_path(convertflag, zFilename,
    +                             zWideFilename+4, nByte)==0 ){
    +          if( (convertflag&CCP_RELATIVE) ){
    +            memmove(zWideFilename, zWideFilename+4, nByte);
    +          }else if( memcmp(zWideFilename+4, L"\\\\", 4) ){
    +            memcpy(zWideFilename, L"\\\\?\\", 8);
    +          }else if( zWideFilename[6]!='?' ){
    +            memmove(zWideFilename+6, zWideFilename+4, nByte);
    +            memcpy(zWideFilename, L"\\\\?\\UNC", 14);
    +          }else{
    +            memmove(zWideFilename, zWideFilename+4, nByte);
    +          }
    +          return zConverted;
    +        }
    +        sqlite3_free(zConverted);
    +      }
    +    }
    +    nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
    +    if( nChar==0 ){
    +      return 0;
    +    }
    +    zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 );
    +    if( zWideFilename==0 ){
    +      return 0;
    +    }
    +    nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1,
    +                                  zWideFilename, nChar);
    +    if( nChar==0 ){
    +      sqlite3_free(zWideFilename);
    +      zWideFilename = 0;
    +    }else if( nChar>MAX_PATH
    +        && winIsDriveLetterAndColon(zFilename)
    +        && winIsDirSep(zFilename[2]) ){
    +      memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR));
    +      zWideFilename[2] = '\\';
    +      memcpy(zWideFilename, L"\\\\?\\", 8);
    +    }else if( nChar>MAX_PATH
    +        && winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1])
    +        && zFilename[2] != '?' ){
    +      memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR));
    +      memcpy(zWideFilename, L"\\\\?\\UNC", 14);
    +    }
    +    zConverted = zWideFilename;
    +#else
         zConverted = winUtf8ToUnicode(zFilename);
    +#endif /* __CYGWIN__ */
       }
    -#ifdef SQLITE_WIN32_HAS_ANSI
    +#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32)
       else{
         zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
       }
    @@ -4949,7 +5097,7 @@ static winVfsAppData winNolockAppData = {
     ** sqlite3_vfs object.
     */
     
    -#if defined(__CYGWIN__)
    +#if 0 /* No longer necessary */
     /*
     ** Convert a filename from whatever the underlying operating system
     ** supports for filenames into UTF-8.  Space to hold the result is
    @@ -4982,7 +5130,14 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
           if( winIsDirSep(zBuf[nLen-1]) ){
             return 1;
           }else if( nLen+1nOut ){
    +    /* SQLite assumes that xFullPathname() nul-terminates the output buffer
    +    ** even if it returns an error.  */
    +    zOut[iOff] = '\0';
    +    return SQLITE_CANTOPEN_BKPT;
    +  }
    +  sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
    +  return SQLITE_OK;
    +}
    +#endif /* __CYGWIN__ */
     
     /*
     ** Turn a relative pathname into a full pathname.  Write the full
    @@ -5863,8 +6103,8 @@ static int winFullPathnameNoMutex(
       int nFull,                    /* Size of output buffer in bytes */
       char *zFull                   /* Output buffer */
     ){
    -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
    -  DWORD nByte;
    +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
    +  int nByte;
       void *zConverted;
       char *zOut;
     #endif
    @@ -5877,64 +6117,110 @@ static int winFullPathnameNoMutex(
         zRelative++;
       }
     
    -#if defined(__CYGWIN__)
    +  SimulateIOError( return SQLITE_ERROR );
    +
    +#ifdef __CYGWIN__
    +  if( osGetcwd ){
    +    zFull[nFull-1] = '\0';
    +    if( !winIsDriveLetterAndColon(zRelative) || !winIsDirSep(zRelative[2]) ){
    +      int rc = SQLITE_OK;
    +      int nLink = 1;                /* Number of symbolic links followed so far */
    +      const char *zIn = zRelative;      /* Input path for each iteration of loop */
    +      char *zDel = 0;
    +      struct stat buf;
    +
    +      UNUSED_PARAMETER(pVfs);
    +
    +      do {
    +        /* Call lstat() on path zIn. Set bLink to true if the path is a symbolic
    +        ** link, or false otherwise.  */
    +        int bLink = 0;
    +        if( osLstat && osReadlink ) {
    +          if( osLstat(zIn, &buf)!=0 ){
    +            int myErrno = osErrno;
    +            if( myErrno!=ENOENT ){
    +              rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)myErrno, "lstat", zIn);
    +            }
    +          }else{
    +            bLink = ((buf.st_mode & 0170000) == 0120000);
    +          }
    +
    +          if( bLink ){
    +            if( zDel==0 ){
    +              zDel = sqlite3MallocZero(nFull);
    +              if( zDel==0 ) rc = SQLITE_NOMEM;
    +            }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
    +              rc = SQLITE_CANTOPEN_BKPT;
    +            }
    +
    +            if( rc==SQLITE_OK ){
    +              nByte = osReadlink(zIn, zDel, nFull-1);
    +              if( nByte ==(DWORD)-1 ){
    +                rc = winLogError(SQLITE_CANTOPEN_BKPT, (DWORD)osErrno, "readlink", zIn);
    +              }else{
    +                if( zDel[0]!='/' ){
    +                  int n;
    +                  for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
    +                  if( nByte+n+1>nFull ){
    +                    rc = SQLITE_CANTOPEN_BKPT;
    +                  }else{
    +                    memmove(&zDel[n], zDel, nByte+1);
    +                    memcpy(zDel, zIn, n);
    +                    nByte += n;
    +                  }
    +                }
    +                zDel[nByte] = '\0';
    +              }
    +            }
    +
    +            zIn = zDel;
    +          }
    +        }
    +
    +        assert( rc!=SQLITE_OK || zIn!=zFull || zIn[0]=='/' );
    +        if( rc==SQLITE_OK && zIn!=zFull ){
    +          rc = mkFullPathname(zIn, zFull, nFull);
    +        }
    +        if( bLink==0 ) break;
    +        zIn = zFull;
    +      }while( rc==SQLITE_OK );
    +
    +      sqlite3_free(zDel);
    +      winSimplifyName(zFull);
    +      return rc;
    +    }
    +  }
    +#endif /* __CYGWIN__ */
    +#if 0 /* This doesn't work correctly at all! See:
    +  
    +*/
       SimulateIOError( return SQLITE_ERROR );
       UNUSED_PARAMETER(nFull);
       assert( nFull>=pVfs->mxPathname );
    -  if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
    -    /*
    -    ** NOTE: We are dealing with a relative path name and the data
    -    **       directory has been set.  Therefore, use it as the basis
    -    **       for converting the relative path name to an absolute
    -    **       one by prepending the data directory and a slash.
    -    */
    -    char *zOut = sqlite3MallocZero( 1+(u64)pVfs->mxPathname );
    -    if( !zOut ){
    -      return SQLITE_IOERR_NOMEM_BKPT;
    -    }
    -    if( cygwin_conv_path(
    -            (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
    -            CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){
    -      sqlite3_free(zOut);
    -      return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
    -                         "winFullPathname1", zRelative);
    -    }else{
    -      char *zUtf8 = winConvertToUtf8Filename(zOut);
    -      if( !zUtf8 ){
    -        sqlite3_free(zOut);
    -        return SQLITE_IOERR_NOMEM_BKPT;
    -      }
    -      sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
    -                       sqlite3_data_directory, winGetDirSep(), zUtf8);
    -      sqlite3_free(zUtf8);
    -      sqlite3_free(zOut);
    -    }
    +  char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
    +  if( !zOut ){
    +    return SQLITE_IOERR_NOMEM_BKPT;
    +  }
    +  if( osCygwin_conv_path(
    +          CCP_POSIX_TO_WIN_W,
    +          zRelative, zOut, pVfs->mxPathname+1)<0 ){
    +    sqlite3_free(zOut);
    +    return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
    +                       "winFullPathname2", zRelative);
       }else{
    -    char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
    -    if( !zOut ){
    +    char *zUtf8 = winConvertToUtf8Filename(zOut);
    +    if( !zUtf8 ){
    +      sqlite3_free(zOut);
           return SQLITE_IOERR_NOMEM_BKPT;
         }
    -    if( cygwin_conv_path(
    -            (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
    -            zRelative, zOut, pVfs->mxPathname+1)<0 ){
    -      sqlite3_free(zOut);
    -      return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
    -                         "winFullPathname2", zRelative);
    -    }else{
    -      char *zUtf8 = winConvertToUtf8Filename(zOut);
    -      if( !zUtf8 ){
    -        sqlite3_free(zOut);
    -        return SQLITE_IOERR_NOMEM_BKPT;
    -      }
    -      sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
    -      sqlite3_free(zUtf8);
    -      sqlite3_free(zOut);
    -    }
    +    sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
    +    sqlite3_free(zUtf8);
    +    sqlite3_free(zOut);
       }
       return SQLITE_OK;
     #endif
     
    -#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__)
    +#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && defined(_WIN32)
       SimulateIOError( return SQLITE_ERROR );
       /* WinCE has no concept of a relative pathname, or so I am told. */
       /* WinRT has no way to convert a relative path to an absolute one. */
    @@ -5953,7 +6239,8 @@ static int winFullPathnameNoMutex(
       return SQLITE_OK;
     #endif
     
    -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
    +#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
    +#if defined(_WIN32)
       /* It's odd to simulate an io-error here, but really this is just
       ** using the io-error infrastructure to test that SQLite handles this
       ** function failing. This function could fail if, for example, the
    @@ -5971,6 +6258,7 @@ static int winFullPathnameNoMutex(
                          sqlite3_data_directory, winGetDirSep(), zRelative);
         return SQLITE_OK;
       }
    +#endif
       zConverted = winConvertFromUtf8Filename(zRelative);
       if( zConverted==0 ){
         return SQLITE_IOERR_NOMEM_BKPT;
    @@ -5983,12 +6271,13 @@ static int winFullPathnameNoMutex(
           return winLogError(SQLITE_CANTOPEN_FULLPATH, osGetLastError(),
                              "winFullPathname1", zRelative);
         }
    -    zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) + 3*sizeof(zTemp[0]) );
    +    nByte += 3;
    +    zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
         if( zTemp==0 ){
           sqlite3_free(zConverted);
           return SQLITE_IOERR_NOMEM_BKPT;
         }
    -    nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte+3, zTemp, 0);
    +    nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
         if( nByte==0 ){
           sqlite3_free(zConverted);
           sqlite3_free(zTemp);
    @@ -6026,7 +6315,26 @@ static int winFullPathnameNoMutex(
       }
     #endif
       if( zOut ){
    +#ifdef __CYGWIN__
    +    if( memcmp(zOut, "\\\\?\\", 4) ){
    +      sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
    +    }else if( memcmp(zOut+4, "UNC\\", 4) ){
    +      sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+4);
    +    }else{
    +      char *p = zOut+6;
    +      *p = '\\';
    +      if( osGetcwd ){
    +        /* On Cygwin, UNC paths use forward slashes */
    +        while( *p ){
    +          if( *p=='\\' ) *p = '/';
    +          ++p;
    +        }
    +      }
    +      sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut+6);
    +    }
    +#else
         sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zOut);
    +#endif /* __CYGWIN__ */
         sqlite3_free(zOut);
         return SQLITE_OK;
       }else{
    @@ -6056,7 +6364,9 @@ static int winFullPathname(
     */
     static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){
       HANDLE h;
    -#if defined(__CYGWIN__)
    +#if 0 /* This doesn't work correctly at all! See:
    +  
    +*/
       int nFull = pVfs->mxPathname+1;
       char *zFull = sqlite3MallocZero( nFull );
       void *zConverted = 0;
    @@ -6423,7 +6733,7 @@ int sqlite3_os_init(void){
     
       /* Double-check that the aSyscall[] array has been constructed
       ** correctly.  See ticket [bb3a86e890c8e96ab] */
    -  assert( ArraySize(aSyscall)==82 );
    +  assert( ArraySize(aSyscall)==89 );
     
       /* get memory map allocation granularity */
       memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
    diff --git a/src/os_win.h b/src/os_win.h
    index 27714ed079..a0845f0038 100644
    --- a/src/os_win.h
    +++ b/src/os_win.h
    @@ -22,6 +22,8 @@
     
     #ifdef __CYGWIN__
     # include 
    +# include  /* amalgamator: dontcache */
    +# include  /* amalgamator: dontcache */
     # include  /* amalgamator: dontcache */
     #endif
     
    diff --git a/src/printf.c b/src/printf.c
    index 166c11194e..8cb5a43c5e 100644
    --- a/src/printf.c
    +++ b/src/printf.c
    @@ -1344,6 +1344,15 @@ char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
       return zBuf;
     }
     
    +/* Maximum size of an sqlite3_log() message. */
    +#if defined(SQLITE_MAX_LOG_MESSAGE) 
    +  /* Leave the definition as supplied */
    +#elif SQLITE_PRINT_BUF_SIZE*10>10000
    +# define SQLITE_MAX_LOG_MESSAGE 10000
    +#else
    +# define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10)
    +#endif
    +
     /*
     ** This is the routine that actually formats the sqlite3_log() message.
     ** We house it in a separate routine from sqlite3_log() to avoid using
    @@ -1360,7 +1369,7 @@ char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
     */
     static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
       StrAccum acc;                          /* String accumulator */
    -  char zMsg[SQLITE_PRINT_BUF_SIZE*3];    /* Complete log message */
    +  char zMsg[SQLITE_MAX_LOG_MESSAGE];     /* Complete log message */
     
       sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
       sqlite3_str_vappendf(&acc, zFormat, ap);
    diff --git a/src/select.c b/src/select.c
    index b2f2cc7fb8..6e8ee58bc6 100644
    --- a/src/select.c
    +++ b/src/select.c
    @@ -4858,7 +4858,8 @@ static void constInsert(
           return;  /* Already present.  Return without doing anything. */
         }
       }
    -  if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
    +  assert( SQLITE_AFF_NONEbHasAffBlob = 1;
       }
     
    @@ -4933,7 +4934,8 @@ static int propagateConstantExprRewriteOne(
         if( pColumn==pExpr ) continue;
         if( pColumn->iTable!=pExpr->iTable ) continue;
         if( pColumn->iColumn!=pExpr->iColumn ) continue;
    -    if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
    +    assert( SQLITE_AFF_NONEnSelectRow ){
           p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
    +      if( pDest->eDest<=SRT_DistQueue && pDest->eDest>=SRT_DistFifo ){
    +        /* TUNING: For a UNION CTE, because UNION is implies DISTINCT,
    +        ** reduce the estimated output row count by 8 (LogEst 30). 
    +        ** Search for tag-20250414a to see other cases */
    +        p->nSelectRow -= 30;
    +      }
         }
         if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
           sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
    diff --git a/src/shell.c.in b/src/shell.c.in
    index 8272956ebd..ca76e4a6e9 100644
    --- a/src/shell.c.in
    +++ b/src/shell.c.in
    @@ -5238,6 +5238,7 @@ static const char *(azHelp[]) = {
     #ifndef SQLITE_SHELL_FIDDLE
       ".output ?FILE?           Send output to FILE or stdout if FILE is omitted",
       "   If FILE begins with '|' then open it as a pipe.",
    +  "   If FILE is 'off' then output is disabled.",
       "   Options:",
       "     --bom                 Prefix output with a UTF8 byte-order mark",
       "     -e                    Send output to the system text editor",
    @@ -6855,7 +6856,7 @@ static int shell_dbtotxt_command(ShellState *p, int nArg, char **azArg){
           for(j=0; j<16 && aLine[j]==0; j++){}
           if( j==16 ) continue;
           if( !seenPageLabel ){
    -        sqlite3_fprintf(p->out, "| page %lld offset %lld\n", pgno, pgno*pgSz);
    +        sqlite3_fprintf(p->out, "| page %lld offset %lld\n",pgno,(pgno-1)*pgSz);
             seenPageLabel = 1;
           }
           sqlite3_fprintf(p->out, "|  %5d:", i);
    @@ -10233,9 +10234,9 @@ static int do_meta_command(char *zLine, ShellState *p){
       ){
         char *zFile = 0;
         int i;
    -    int eMode = 0;
    -    int bOnce = 0;            /* 0: .output, 1: .once, 2: .excel/.www */
    -    int bPlain = 0;           /* --plain option */
    +    int eMode = 0;          /* 0: .outout/.once, 'x'=.excel, 'w'=.www */
    +    int bOnce = 0;          /* 0: .output, 1: .once, 2: .excel/.www */
    +    int bPlain = 0;         /* --plain option */
         static const char *zBomUtf8 = "\357\273\277";
         const char *zBom = 0;
     
    @@ -10264,14 +10265,22 @@ static int do_meta_command(char *zLine, ShellState *p){
             }else if( c=='o' && cli_strcmp(z,"-w")==0 ){
               eMode = 'w';  /* Web browser */
             }else{
    -          sqlite3_fprintf(p->out, 
    +          sqlite3_fprintf(p->out,
                               "ERROR: unknown option: \"%s\". Usage:\n", azArg[i]);
               showHelp(p->out, azArg[0]);
               rc = 1;
               goto meta_command_exit;
             }
           }else if( zFile==0 && eMode==0 ){
    -        zFile = sqlite3_mprintf("%s", z);
    +        if( cli_strcmp(z, "off")==0 ){
    +#ifdef _WIN32
    +          zFile = sqlite3_mprintf("nul");
    +#else
    +          zFile = sqlite3_mprintf("/dev/null");
    +#endif
    +        }else{
    +          zFile = sqlite3_mprintf("%s", z);
    +        }
             if( zFile && zFile[0]=='|' ){
               while( i+1Fossil configuration management
    +** Fossil configuration management
     ** system.  ^The SQLITE_SOURCE_ID macro evaluates to
     ** a string which identifies a particular check-in of SQLite
     ** within its configuration management system.  ^The SQLITE_SOURCE_ID
    diff --git a/src/sqlite3.rc b/src/sqlite3.rc
    index 5a856490d6..aad468d349 100644
    --- a/src/sqlite3.rc
    +++ b/src/sqlite3.rc
    @@ -70,7 +70,7 @@ BEGIN
           VALUE "FileDescription", "SQLite is a software library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine."
           VALUE "FileVersion", SQLITE_VERSION
           VALUE "InternalName", "sqlite3"
    -      VALUE "LegalCopyright", "http://www.sqlite.org/copyright.html"
    +      VALUE "LegalCopyright", "http://sqlite.org/copyright.html"
           VALUE "ProductName", "SQLite"
           VALUE "ProductVersion", SQLITE_VERSION
           VALUE "SourceId", SQLITE_SOURCE_ID
    diff --git a/src/sqliteInt.h b/src/sqliteInt.h
    index 35e5b94d71..edf925964b 100644
    --- a/src/sqliteInt.h
    +++ b/src/sqliteInt.h
    @@ -2792,6 +2792,7 @@ struct Index {
       unsigned bLowQual:1;     /* sqlite_stat1 says this is a low-quality index */
       unsigned bNoQuery:1;     /* Do not use this index to optimize queries */
       unsigned bAscKeyBug:1;   /* True if the bba7b69f9849b5bf bug applies */
    +  unsigned bIdxRowid:1;    /* One or more of the index keys is the ROWID */
       unsigned bHasVCol:1;     /* Index references one or more VIRTUAL columns */
       unsigned bHasExpr:1;     /* Index contains an expression, either a literal
                                ** expression, or a reference to a VIRTUAL column */
    diff --git a/src/tclsqlite.c b/src/tclsqlite.c
    index c619ffca4b..7675a91254 100644
    --- a/src/tclsqlite.c
    +++ b/src/tclsqlite.c
    @@ -76,7 +76,9 @@
     #     define SQLITE_PTRSIZE 8
     #   endif
     # endif /* SQLITE_PTRSIZE */
    -# if defined(HAVE_STDINT_H)
    +# if defined(HAVE_STDINT_H) || (defined(__STDC_VERSION__) &&  \
    +                                (__STDC_VERSION__ >= 199901L))
    +#   include 
         typedef uintptr_t uptr;
     # elif SQLITE_PTRSIZE==4
         typedef unsigned int uptr;
    @@ -2525,7 +2527,7 @@ static int SQLITE_TCLAPI DbObjCmd(
         Tcl_Channel in;             /* The input file */
         int lineno = 0;             /* Line number of input file */
         char zLineNum[80];          /* Line number print buffer */
    -    Tcl_DString str;
    +    Tcl_Obj *str;
         Tcl_Obj *pResult;           /* interp result */
     
         const char *zSep;
    @@ -2609,19 +2611,22 @@ static int SQLITE_TCLAPI DbObjCmd(
           sqlite3_finalize(pStmt);
           return TCL_ERROR;
         }
    +    Tcl_SetChannelOption(NULL, in, "-translation", "auto");
         azCol = malloc( sizeof(azCol[0])*(nCol+1) );
         if( azCol==0 ) {
           Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
           Tcl_Close(interp, in);
           return TCL_ERROR;
         }
    -    Tcl_DStringInit(&str);
    +    str = Tcl_NewObj();
    +    Tcl_IncrRefCount(str);
         (void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
         zCommit = "COMMIT";
    -    while( Tcl_Gets(in, &str)>=0 ) {
    +    while( Tcl_GetsObj(in, str)>=0 ) {
           char *z;
    +      Tcl_Size byteLen;
           lineno++;
    -      zLine = Tcl_DStringValue(&str);
    +      zLine = (char *)Tcl_GetByteArrayFromObj(str, &byteLen);
           azCol[0] = zLine;
           for(i=0, z=zLine; *z; z++){
             if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
    @@ -2659,14 +2664,14 @@ static int SQLITE_TCLAPI DbObjCmd(
           }
           sqlite3_step(pStmt);
           rc = sqlite3_reset(pStmt);
    -      Tcl_DStringSetLength(&str, 0);
    +      Tcl_SetObjLength(str, 0);
           if( rc!=SQLITE_OK ){
             Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0);
             zCommit = "ROLLBACK";
             break;
           }
         }
    -    Tcl_DStringFree(&str);
    +    Tcl_DecrRefCount(str);
         free(azCol);
         Tcl_Close(interp, in);
         sqlite3_finalize(pStmt);
    diff --git a/src/test1.c b/src/test1.c
    index e45a05fe47..bb2f2d3b9d 100644
    --- a/src/test1.c
    +++ b/src/test1.c
    @@ -102,7 +102,7 @@ static int SQLITE_TCLAPI get_sqlite_pointer(
       }
       p = (struct SqliteDb*)cmdInfo.objClientData;
       sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p->db);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -153,7 +153,7 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
            "error code %s (%d) does not match sqlite3_errcode %s (%d)",
            t1ErrorName(rc), rc, t1ErrorName(r2), r2);
         Tcl_ResetResult(interp);
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
         return 1;
       }
       return 0;
    @@ -504,7 +504,7 @@ static int SQLITE_TCLAPI test_mprintf_z(
       for(i=2; isizeof(zStr) ) n = sizeof(zStr);
       sqlite3_snprintf(sizeof(zStr), zStr, "abcdefghijklmnopqrstuvwxyz");
       sqlite3_snprintf(n, zStr, zFormat, a1);
    -  Tcl_AppendResult(interp, zStr, 0);
    +  Tcl_AppendResult(interp, zStr, NULL);
       return TCL_OK;
     }
     
    @@ -639,12 +639,12 @@ static int SQLITE_TCLAPI test_last_rowid(
       char zBuf[30];
     
       if( argc!=2 ){
    -    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
    +    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
       sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", sqlite3_last_insert_rowid(db));
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return SQLITE_OK;
     }
     
    @@ -1385,7 +1385,7 @@ static int SQLITE_TCLAPI sqlite3_mprintf_int(
         if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
       }
       z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1411,12 +1411,12 @@ static int SQLITE_TCLAPI sqlite3_mprintf_int64(
       }
       for(i=2; i<5; i++){
         if( sqlite3Atoi64(argv[i], &a[i-2], sqlite3Strlen30(argv[i]), SQLITE_UTF8) ){
    -      Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", 0);
    +      Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", NULL);
           return TCL_ERROR;
         }
       }
       z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1449,7 +1449,7 @@ static int SQLITE_TCLAPI sqlite3_mprintf_long(
         a[i-2] &= (((u64)1)<<(sizeof(int)*8))-1;
       }
       z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1476,7 +1476,7 @@ static int SQLITE_TCLAPI sqlite3_mprintf_str(
         if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
       }
       z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1502,7 +1502,7 @@ static int SQLITE_TCLAPI sqlite3_snprintf_str(
       }
       if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
       if( n<0 ){
    -    Tcl_AppendResult(interp, "N must be non-negative", 0);
    +    Tcl_AppendResult(interp, "N must be non-negative", NULL);
         return TCL_ERROR;
       }
       for(i=3; i<5; i++){
    @@ -1510,7 +1510,7 @@ static int SQLITE_TCLAPI sqlite3_snprintf_str(
       }
       z = sqlite3_malloc( n+1 );
       sqlite3_snprintf(n, z, argv[2], a[0], a[1], argc>4 ? argv[5] : NULL);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1539,7 +1539,7 @@ static int SQLITE_TCLAPI sqlite3_mprintf_double(
       }
       if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
       z = sqlite3_mprintf(argv[1], a[0], a[1], r);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1569,7 +1569,7 @@ static int SQLITE_TCLAPI sqlite3_mprintf_scaled(
         if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
       }
       z = sqlite3_mprintf(argv[1], r[0]*r[1]);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1594,7 +1594,7 @@ static int SQLITE_TCLAPI sqlite3_mprintf_stronly(
         return TCL_ERROR;
       }
       z = sqlite3_mprintf(argv[1], argv[2]);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1621,14 +1621,14 @@ static int SQLITE_TCLAPI sqlite3_mprintf_hexdouble(
         return TCL_ERROR;
       }
       if( sscanf(argv[2], "%08x%08x", &x2, &x1)!=2 ){
    -    Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", 0);
    +    Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", NULL);
         return TCL_ERROR;
       }
       d = x2;
       d = (d<<32) + x1;
       memcpy(&r, &d, sizeof(r));
       z = sqlite3_mprintf(argv[1], r);
    -  Tcl_AppendResult(interp, z, 0);
    +  Tcl_AppendResult(interp, z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     }
    @@ -1746,7 +1746,7 @@ static int SQLITE_TCLAPI test_table_column_metadata(
           &zDatatype, &zCollseq, ¬null, &primarykey, &autoincrement);
     
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, sqlite3_errmsg(db), NULL);
         return TCL_ERROR;
       }
     
    @@ -2023,7 +2023,7 @@ static int SQLITE_TCLAPI test_create_function_v2(
       );
       if( rc!=SQLITE_OK ){
         Tcl_ResetResult(interp);
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -2212,7 +2212,7 @@ static int SQLITE_TCLAPI test_register_func(
       rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 
           testFunc, 0, 0);
       if( rc!=0 ){
    -    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrStr(rc), NULL);
         return TCL_ERROR;
       }
       if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
    @@ -2773,7 +2773,7 @@ static int SQLITE_TCLAPI test_snapshot_open_blob(
       zName = Tcl_GetString(objv[2]);
       pBlob = Tcl_GetByteArrayFromObj(objv[3], &nBlob);
       if( nBlob!=sizeof(sqlite3_snapshot) ){
    -    Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
    +    Tcl_AppendResult(interp, "bad SNAPSHOT", NULL);
         return TCL_ERROR;
       }
       rc = sqlite3_snapshot_open(db, zName, (sqlite3_snapshot*)pBlob);
    @@ -2810,7 +2810,7 @@ static int SQLITE_TCLAPI test_snapshot_cmp_blob(
       p2 = Tcl_GetByteArrayFromObj(objv[2], &n2);
     
       if( n1!=sizeof(sqlite3_snapshot) || n1!=n2 ){
    -    Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
    +    Tcl_AppendResult(interp, "bad SNAPSHOT", NULL);
         return TCL_ERROR;
       }
     
    @@ -2867,7 +2867,7 @@ static int SQLITE_TCLAPI test_atomic_batch_write(
     
       rc = sqlite3_open(zFile, &db);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, sqlite3_errmsg(db), NULL);
         sqlite3_close(db);
         return TCL_ERROR;
       }
    @@ -2909,7 +2909,7 @@ static int SQLITE_TCLAPI test_next_stmt(
       pStmt = sqlite3_next_stmt(db, pStmt);
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
       }
       return TCL_OK;
     }
    @@ -3211,7 +3211,7 @@ static int SQLITE_TCLAPI test_bind(
       if( rc ){
         char zBuf[50];
         sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
    -    Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
    +    Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -3343,14 +3343,14 @@ static int SQLITE_TCLAPI test_collate(
       if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
       
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
     
     bad_args:
       Tcl_AppendResult(interp, "wrong # args: should be \"",
    -      Tcl_GetStringFromObj(objv[0], 0), "    ", 0);
    +      Tcl_GetStringFromObj(objv[0], 0), "    ", NULL);
       return TCL_ERROR;
     }
     
    @@ -3629,7 +3629,7 @@ static int SQLITE_TCLAPI test_function(
       return TCL_OK;
     bad_args:
       Tcl_AppendResult(interp, "wrong # args: should be \"",
    -      Tcl_GetStringFromObj(objv[0], 0), "    ", 0);
    +      Tcl_GetStringFromObj(objv[0], 0), "    ", NULL);
     #endif /* SQLITE_OMIT_UTF16 */
       return TCL_ERROR;
     }
    @@ -3750,7 +3750,7 @@ static int SQLITE_TCLAPI test_bind_zeroblob64(
       rc = sqlite3_bind_zeroblob64(pStmt, idx, n);
       if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
     
    @@ -3777,7 +3777,7 @@ static int SQLITE_TCLAPI test_bind_int(
     
       if( objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", NULL);
         return TCL_ERROR;
       }
     
    @@ -3954,7 +3954,7 @@ static int SQLITE_TCLAPI test_bind_int64(
     
       if( objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", NULL);
         return TCL_ERROR;
       }
     
    @@ -4010,7 +4010,7 @@ static int SQLITE_TCLAPI test_bind_double(
     
       if( objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", NULL);
         return TCL_ERROR;
       }
     
    @@ -4067,7 +4067,7 @@ static int SQLITE_TCLAPI test_bind_null(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " STMT N", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " STMT N", NULL);
         return TCL_ERROR;
       }
     
    @@ -4107,7 +4107,7 @@ static int SQLITE_TCLAPI test_bind_text(
     
       if( objc!=5 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", NULL);
         return TCL_ERROR;
       }
     
    @@ -4167,7 +4167,7 @@ static int SQLITE_TCLAPI test_bind_text16(
     
       if( objc!=5 && objc!=6){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", NULL);
         return TCL_ERROR;
       }
     
    @@ -4189,7 +4189,7 @@ static int SQLITE_TCLAPI test_bind_text16(
       free(toFree);
       if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
     
    @@ -4220,7 +4220,7 @@ static int SQLITE_TCLAPI test_bind_blob(
     
       if( objc!=5 && objc!=6 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", NULL);
         return TCL_ERROR;
       }
     
    @@ -4718,12 +4718,12 @@ static int SQLITE_TCLAPI test_ex_errcode(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB", 0);
    +       Tcl_GetString(objv[0]), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
       rc = sqlite3_extended_errcode(db);
    -  Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0);
    +  Tcl_AppendResult(interp, (char *)t1ErrorName(rc), NULL);
       return TCL_OK;
     }
     
    @@ -4745,12 +4745,12 @@ static int SQLITE_TCLAPI test_errcode(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB", 0);
    +       Tcl_GetString(objv[0]), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
       rc = sqlite3_errcode(db);
    -  Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0);
    +  Tcl_AppendResult(interp, (char *)t1ErrorName(rc), NULL);
       return TCL_OK;
     }
     
    @@ -4771,7 +4771,7 @@ static int SQLITE_TCLAPI test_errmsg(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB", 0);
    +       Tcl_GetString(objv[0]), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -4799,7 +4799,7 @@ static int SQLITE_TCLAPI test_error_offset(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB", 0);
    +       Tcl_GetString(objv[0]), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -4831,7 +4831,7 @@ static int SQLITE_TCLAPI test_errmsg16(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB", 0);
    +       Tcl_GetString(objv[0]), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -4870,7 +4870,7 @@ static int SQLITE_TCLAPI test_prepare(
     
       if( objc!=5 && objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    +       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -4892,13 +4892,13 @@ static int SQLITE_TCLAPI test_prepare(
       if( rc!=SQLITE_OK ){
         assert( pStmt==0 );
         sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
    -    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), NULL);
         return TCL_ERROR;
       }
     
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
       }
       return TCL_OK;
     }
    @@ -4929,7 +4929,7 @@ static int SQLITE_TCLAPI test_prepare_v2(
     
       if( objc!=5 && objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
    +       Tcl_GetString(objv[0]), " DB sql bytes tailvar", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -4966,13 +4966,13 @@ static int SQLITE_TCLAPI test_prepare_v2(
       if( rc!=SQLITE_OK ){
         assert( pStmt==0 );
         sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
    -    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), NULL);
         return TCL_ERROR;
       }
     
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
       }
       return TCL_OK;
     }
    @@ -5003,7 +5003,7 @@ static int SQLITE_TCLAPI test_prepare_v3(
     
       if( objc!=6 && objc!=5 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB sql bytes flags tailvar", 0);
    +       Tcl_GetString(objv[0]), " DB sql bytes flags tailvar", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -5039,13 +5039,13 @@ static int SQLITE_TCLAPI test_prepare_v3(
       if( rc!=SQLITE_OK ){
         assert( pStmt==0 );
         sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
    -    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), NULL);
         return TCL_ERROR;
       }
     
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
       }
       return TCL_OK;
     }
    @@ -5070,7 +5070,7 @@ static int SQLITE_TCLAPI test_prepare_tkt3134(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
    +       Tcl_GetString(objv[0]), " DB sql bytes tailvar", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -5080,13 +5080,13 @@ static int SQLITE_TCLAPI test_prepare_tkt3134(
       if( rc!=SQLITE_OK ){
         assert( pStmt==0 );
         sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
    -    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), NULL);
         return TCL_ERROR;
       }
     
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
       }
       return TCL_OK;
     }
    @@ -5118,7 +5118,7 @@ static int SQLITE_TCLAPI test_prepare16(
     
       if( objc!=5 && objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    +       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -5146,7 +5146,7 @@ static int SQLITE_TCLAPI test_prepare16(
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
       }
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
     #endif /* SQLITE_OMIT_UTF16 */
       return TCL_OK;
     }
    @@ -5178,7 +5178,7 @@ static int SQLITE_TCLAPI test_prepare16_v2(
     
       if( objc!=5 && objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    +       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -5206,7 +5206,7 @@ static int SQLITE_TCLAPI test_prepare16_v2(
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
       }
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
     #endif /* SQLITE_OMIT_UTF16 */
       return TCL_OK;
     }
    @@ -5226,7 +5226,7 @@ static int SQLITE_TCLAPI test_open(
     
       if( objc!=3 && objc!=2 && objc!=1 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " filename options-list", 0);
    +       Tcl_GetString(objv[0]), " filename options-list", NULL);
         return TCL_ERROR;
       }
     
    @@ -5234,7 +5234,7 @@ static int SQLITE_TCLAPI test_open(
       sqlite3_open(zFilename, &db);
       
       if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -5305,7 +5305,7 @@ static int SQLITE_TCLAPI test_open_v2(
     
       rc = sqlite3_open_v2(zFilename, &db, flags, zVfs);
       if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -5325,7 +5325,7 @@ static int SQLITE_TCLAPI test_open16(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " filename options-list", 0);
    +       Tcl_GetString(objv[0]), " filename options-list", NULL);
         return TCL_ERROR;
       }
     
    @@ -5333,7 +5333,7 @@ static int SQLITE_TCLAPI test_open16(
       sqlite3_open16(zFilename, &db);
       
       if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
     #endif /* SQLITE_OMIT_UTF16 */
       return TCL_OK;
     }
    @@ -5409,7 +5409,7 @@ static int SQLITE_TCLAPI test_step(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT", 0);
    +       Tcl_GetString(objv[0]), " STMT", NULL);
         return TCL_ERROR;
       }
     
    @@ -5493,7 +5493,7 @@ static int SQLITE_TCLAPI test_column_count(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5520,7 +5520,7 @@ static int SQLITE_TCLAPI test_column_type(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5569,7 +5569,7 @@ static int SQLITE_TCLAPI test_column_int64(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5598,7 +5598,7 @@ static int SQLITE_TCLAPI test_column_blob(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5628,7 +5628,7 @@ static int SQLITE_TCLAPI test_column_double(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5655,7 +5655,7 @@ static int SQLITE_TCLAPI test_data_count(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5688,7 +5688,7 @@ static int SQLITE_TCLAPI test_stmt_utf8(
       xFuncU = (const unsigned char*(*)(sqlite3_stmt*,int))xFunc;
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5746,7 +5746,7 @@ static int SQLITE_TCLAPI test_stmt_utf16(
       xFunc = (const void *(*)(sqlite3_stmt*, int))clientData;
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5787,7 +5787,7 @@ static int SQLITE_TCLAPI test_stmt_int(
       xFunc = (int (*)(sqlite3_stmt*, int))clientData;
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", 
    -       Tcl_GetString(objv[0]), " STMT column", 0);
    +       Tcl_GetString(objv[0]), " STMT column", NULL);
         return TCL_ERROR;
       }
     
    @@ -5811,7 +5811,7 @@ static int SQLITE_TCLAPI test_interrupt(
     ){
       sqlite3 *db;
       if( argc!=2 ){
    -    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0);
    +    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
    @@ -5833,7 +5833,7 @@ static int SQLITE_TCLAPI test_is_interrupted(
       sqlite3 *db;
       int rc;
       if( argc!=2 ){
    -    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0);
    +    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
    @@ -5915,7 +5915,7 @@ static int SQLITE_TCLAPI get_autocommit(
       }
       if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
       sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3_get_autocommit(db));
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -5936,13 +5936,13 @@ static int SQLITE_TCLAPI test_busy_timeout(
       sqlite3 *db;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
    -        " DB", 0);
    +        " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
       if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR;
       rc = sqlite3_busy_timeout(db, ms);
    -  Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +  Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
       return TCL_OK;
     }
     
    @@ -5963,14 +5963,14 @@ static int SQLITE_TCLAPI test_setlk_timeout(
     
       if( argc==4 ){
         const char *zArg = argv[1];
    -    int nArg = strlen(zArg);
    +    const size_t nArg = strlen(zArg);
         if( nArg>=2 && nArg<=15 && memcmp(zArg, "-blockonconnect", nArg)==0 ){
           bBlockOnConnect = 1;
         }
       }
       if( argc!=(3+bBlockOnConnect) ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
    -        " ?-blockonconnect? DB MS", 0);
    +        " ?-blockonconnect? DB MS", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, argv[argc-2], &db) ) return TCL_ERROR;
    @@ -5978,7 +5978,7 @@ static int SQLITE_TCLAPI test_setlk_timeout(
       rc = sqlite3_setlk_timeout(
           db, ms, (bBlockOnConnect ? SQLITE_SETLK_BLOCK_ON_CONNECT : 0)
       );
    -  Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +  Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
       return TCL_OK;
     }
     
    @@ -6390,7 +6390,7 @@ static int SQLITE_TCLAPI test_pager_refcounts(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -6632,7 +6632,7 @@ static int SQLITE_TCLAPI file_control_test(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -6667,7 +6667,7 @@ static int SQLITE_TCLAPI file_control_lasterrno_test(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -6680,7 +6680,7 @@ static int SQLITE_TCLAPI file_control_lasterrno_test(
       }
       if( iArg!=0 ) {
         Tcl_AppendResult(interp, "Unexpected non-zero errno: ",
    -                     Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0);
    +                     Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", NULL);
         return TCL_ERROR;
       }
       return TCL_OK;  
    @@ -6816,7 +6816,7 @@ static int SQLITE_TCLAPI file_control_lockproxy_test(
       
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -                     Tcl_GetStringFromObj(objv[0], 0), " DB PWD", 0);
    +                     Tcl_GetStringFromObj(objv[0], 0), " DB PWD", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -6852,7 +6852,7 @@ static int SQLITE_TCLAPI file_control_lockproxy_test(
         rc = sqlite3_file_control(db, NULL, SQLITE_GET_LOCKPROXYFILE, &testPath);
         if( strncmp(proxyPath,testPath,11) ){
           Tcl_AppendResult(interp, "Lock proxy file did not match the "
    -                               "previously assigned value", 0);
    +                               "previously assigned value", NULL);
           return TCL_ERROR;
         }
         if( rc ){
    @@ -6889,7 +6889,7 @@ static int SQLITE_TCLAPI file_control_win32_av_retry(
     
       if( objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -6922,7 +6922,7 @@ static int file_control_win32_get_handle(
     
       if( objc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -6954,7 +6954,7 @@ static int SQLITE_TCLAPI file_control_win32_set_handle(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -6990,7 +6990,7 @@ static int SQLITE_TCLAPI file_control_persist_wal(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -7022,7 +7022,7 @@ static int SQLITE_TCLAPI file_control_powersafe_overwrite(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -7053,7 +7053,7 @@ static int SQLITE_TCLAPI file_control_vfsname(
     
       if( objc!=2 && objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -7115,7 +7115,7 @@ static int SQLITE_TCLAPI file_control_tempfilename(
     
       if( objc!=2 && objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -7148,7 +7148,7 @@ static int SQLITE_TCLAPI file_control_external_reader(
     
       if( objc!=2 && objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    @@ -7232,7 +7232,7 @@ static int SQLITE_TCLAPI test_limit(
     
       if( objc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), " DB ID VALUE", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), " DB ID VALUE", NULL);
         return TCL_ERROR;
       }
       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
    @@ -7543,7 +7543,7 @@ static int SQLITE_TCLAPI test_wal_checkpoint_v2(
       if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
         const char *zErrCode = sqlite3ErrName(rc);
         Tcl_ResetResult(interp);
    -    Tcl_AppendResult(interp, zErrCode, " - ", (char *)sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, zErrCode, " - ", (char *)sqlite3_errmsg(db), NULL);
         return TCL_ERROR;
       }
     
    @@ -7984,7 +7984,7 @@ struct win32FileLocker {
     #endif
     
     
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
     #include 
     /*
     ** The background thread that does file locking.
    @@ -8017,7 +8017,7 @@ static void SQLITE_CDECL win32_file_locker(void *pAppData){
     }
     #endif
     
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
     /*
     **      lock_win32_file FILENAME DELAY1 DELAY2
     **
    @@ -8826,7 +8826,7 @@ static int SQLITE_TCLAPI guess_number_of_cores(
       Tcl_Obj *CONST objv[]
     ){
       unsigned int nCore = 1;
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       SYSTEM_INFO sysinfo;
       GetSystemInfo(&sysinfo);
       nCore = (unsigned int)sysinfo.dwNumberOfProcessors;
    @@ -9006,7 +9006,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
          { "database_never_corrupt",        database_never_corrupt, 0},
          { "database_may_be_corrupt",       database_may_be_corrupt, 0},
          { "optimization_control",          optimization_control,0},
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
          { "lock_win32_file",               win32_file_lock,    0 },
     #endif
          { "tcl_objproc",                   runAsObjProc,       0 },
    diff --git a/src/test2.c b/src/test2.c
    index a9549aa7f5..899728ead9 100644
    --- a/src/test2.c
    +++ b/src/test2.c
    @@ -51,7 +51,7 @@ static int SQLITE_TCLAPI pager_open(
       char zBuf[100];
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " FILENAME N-PAGE\"", 0);
    +       " FILENAME N-PAGE\"", NULL);
         return TCL_ERROR;
       }
       if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
    @@ -59,14 +59,14 @@ static int SQLITE_TCLAPI pager_open(
           SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
           pager_test_reiniter);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       sqlite3PagerSetCachesize(pPager, nPage);
       pageSize = test_pagesize;
       sqlite3PagerSetPagesize(pPager, &pageSize, -1);
       sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -85,13 +85,13 @@ static int SQLITE_TCLAPI pager_close(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3PagerClose(pPager, 0);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -112,13 +112,13 @@ static int SQLITE_TCLAPI pager_rollback(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3PagerRollback(pPager);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -139,18 +139,18 @@ static int SQLITE_TCLAPI pager_commit(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       rc = sqlite3PagerCommitPhaseTwo(pPager);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -171,13 +171,13 @@ static int SQLITE_TCLAPI pager_stmt_begin(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3PagerOpenSavepoint(pPager, 1);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -198,14 +198,14 @@ static int SQLITE_TCLAPI pager_stmt_rollback(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0);
       sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -226,13 +226,13 @@ static int SQLITE_TCLAPI pager_stmt_commit(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -253,7 +253,7 @@ static int SQLITE_TCLAPI pager_stats(
       int i, *a;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
    @@ -287,13 +287,13 @@ static int SQLITE_TCLAPI pager_pagecount(
       int nPage;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
       sqlite3PagerPagecount(pPager, &nPage);
       sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nPage);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -315,7 +315,7 @@ static int SQLITE_TCLAPI page_get(
       int rc;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID PGNO\"", 0);
    +       " ID PGNO\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
    @@ -325,11 +325,11 @@ static int SQLITE_TCLAPI page_get(
         rc = sqlite3PagerGet(pPager, pgno, &pPage, 0);
       }
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -351,7 +351,7 @@ static int SQLITE_TCLAPI page_lookup(
       int pgno;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID PGNO\"", 0);
    +       " ID PGNO\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
    @@ -359,7 +359,7 @@ static int SQLITE_TCLAPI page_lookup(
       pPage = sqlite3PagerLookup(pPager, pgno);
       if( pPage ){
         sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
       }
       return TCL_OK;
     }
    @@ -377,7 +377,7 @@ static int SQLITE_TCLAPI pager_truncate(
       int pgno;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID PGNO\"", 0);
    +       " ID PGNO\"", NULL);
         return TCL_ERROR;
       }
       pPager = sqlite3TestTextToPtr(argv[1]);
    @@ -401,7 +401,7 @@ static int SQLITE_TCLAPI page_unref(
       DbPage *pPage;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " PAGE\"", 0);
    +       " PAGE\"", NULL);
         return TCL_ERROR;
       }
       pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
    @@ -424,12 +424,12 @@ static int SQLITE_TCLAPI page_read(
       DbPage *pPage;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " PAGE\"", 0);
    +       " PAGE\"", NULL);
         return TCL_ERROR;
       }
       pPage = sqlite3TestTextToPtr(argv[1]);
       memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -448,12 +448,12 @@ static int SQLITE_TCLAPI page_number(
       DbPage *pPage;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " PAGE\"", 0);
    +       " PAGE\"", NULL);
         return TCL_ERROR;
       }
       pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
       sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage));
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -473,13 +473,13 @@ static int SQLITE_TCLAPI page_write(
       int rc;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " PAGE DATA\"", 0);
    +       " PAGE DATA\"", NULL);
         return TCL_ERROR;
       }
       pPage = (DbPage *)sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3PagerWrite(pPage);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       pData = sqlite3PagerGetData(pPage);
    @@ -513,7 +513,7 @@ static int SQLITE_TCLAPI fake_big_file(
       int nFile;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " N-MEGABYTES FILE\"", 0);
    +       " N-MEGABYTES FILE\"", NULL);
         return TCL_ERROR;
       }
       if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
    @@ -536,7 +536,7 @@ static int SQLITE_TCLAPI fake_big_file(
           (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
       );
       if( rc ){
    -    Tcl_AppendResult(interp, "open failed: ", sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, "open failed: ", sqlite3ErrName(rc), NULL);
         sqlite3_free(zFile);
         return TCL_ERROR;
       }
    @@ -546,7 +546,7 @@ static int SQLITE_TCLAPI fake_big_file(
       sqlite3OsCloseFree(fd);
       sqlite3_free(zFile);
       if( rc ){
    -    Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    diff --git a/src/test3.c b/src/test3.c
    index f1b2b01680..8fbb96a80d 100644
    --- a/src/test3.c
    +++ b/src/test3.c
    @@ -46,9 +46,10 @@ static int SQLITE_TCLAPI btree_open(
       char *zFilename;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " FILENAME NCACHE FLAGS\"", 0);
    +       " FILENAME NCACHE FLAGS\"", NULL);
         return TCL_ERROR;
       }
    +
       if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
       nRefSqlite3++;
       if( nRefSqlite3==1 ){
    @@ -65,12 +66,12 @@ static int SQLITE_TCLAPI btree_open(
          SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
       sqlite3_free(zFilename);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       sqlite3BtreeSetCacheSize(pBt, nCache);
       sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -89,13 +90,13 @@ static int SQLITE_TCLAPI btree_close(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pBt = sqlite3TestTextToPtr(argv[1]);
       rc = sqlite3BtreeClose(pBt);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       nRefSqlite3--;
    @@ -124,7 +125,7 @@ static int SQLITE_TCLAPI btree_begin_transaction(
       int rc;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pBt = sqlite3TestTextToPtr(argv[1]);
    @@ -132,7 +133,7 @@ static int SQLITE_TCLAPI btree_begin_transaction(
       rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
       sqlite3BtreeLeave(pBt);
       if( rc!=SQLITE_OK ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    @@ -155,7 +156,7 @@ static int SQLITE_TCLAPI btree_pager_stats(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pBt = sqlite3TestTextToPtr(argv[1]);
    @@ -208,7 +209,7 @@ static int SQLITE_TCLAPI btree_cursor(
     
       if( argc!=4 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID TABLENUM WRITEABLE\"", 0);
    +       " ID TABLENUM WRITEABLE\"", NULL);
         return TCL_ERROR;
       }
       pBt = sqlite3TestTextToPtr(argv[1]);
    @@ -229,11 +230,11 @@ static int SQLITE_TCLAPI btree_cursor(
       sqlite3_mutex_leave(pBt->db->mutex);
       if( rc ){
         ckfree((char *)pCur);
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return SQLITE_OK;
     }
     
    @@ -253,7 +254,7 @@ static int SQLITE_TCLAPI btree_close_cursor(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pCur = sqlite3TestTextToPtr(argv[1]);
    @@ -271,7 +272,7 @@ static int SQLITE_TCLAPI btree_close_cursor(
     #endif
       ckfree((char *)pCur);
       if( rc ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return SQLITE_OK;
    @@ -297,7 +298,7 @@ static int SQLITE_TCLAPI btree_next(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pCur = sqlite3TestTextToPtr(argv[1]);
    @@ -309,11 +310,11 @@ static int SQLITE_TCLAPI btree_next(
       }
       sqlite3BtreeLeave(pCur->pBtree);
       if( rc ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return SQLITE_OK;
     }
     
    @@ -336,7 +337,7 @@ static int SQLITE_TCLAPI btree_first(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pCur = sqlite3TestTextToPtr(argv[1]);
    @@ -344,11 +345,11 @@ static int SQLITE_TCLAPI btree_first(
       rc = sqlite3BtreeFirst(pCur, &res);
       sqlite3BtreeLeave(pCur->pBtree);
       if( rc ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return SQLITE_OK;
     }
     
    @@ -370,7 +371,7 @@ static int SQLITE_TCLAPI btree_eof(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pCur = sqlite3TestTextToPtr(argv[1]);
    @@ -378,7 +379,7 @@ static int SQLITE_TCLAPI btree_eof(
       rc = sqlite3BtreeEof(pCur);
       sqlite3BtreeLeave(pCur->pBtree);
       sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return SQLITE_OK;
     }
     
    @@ -399,7 +400,7 @@ static int SQLITE_TCLAPI btree_payload_size(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pCur = sqlite3TestTextToPtr(argv[1]);
    @@ -407,7 +408,7 @@ static int SQLITE_TCLAPI btree_payload_size(
       n = sqlite3BtreePayloadSize(pCur);
       sqlite3BtreeLeave(pCur->pBtree);
       sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return SQLITE_OK;
     }
     
    @@ -437,7 +438,7 @@ static int SQLITE_TCLAPI btree_varint_test(
       unsigned char zBuf[100];
       if( argc!=5 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " START MULTIPLIER COUNT INCREMENT\"", 0);
    +       " START MULTIPLIER COUNT INCREMENT\"", NULL);
         return TCL_ERROR;
       }
       if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
    @@ -452,20 +453,20 @@ static int SQLITE_TCLAPI btree_varint_test(
         if( n1>9 || n1<1 ){
           sqlite3_snprintf(sizeof(zErr), zErr,
              "putVarint returned %d - should be between 1 and 9", n1);
    -      Tcl_AppendResult(interp, zErr, 0);
    +      Tcl_AppendResult(interp, zErr, NULL);
           return TCL_ERROR;
         }
         n2 = getVarint(zBuf, &out);
         if( n1!=n2 ){
           sqlite3_snprintf(sizeof(zErr), zErr,
               "putVarint returned %d and getVarint returned %d", n1, n2);
    -      Tcl_AppendResult(interp, zErr, 0);
    +      Tcl_AppendResult(interp, zErr, NULL);
           return TCL_ERROR;
         }
         if( in!=out ){
           sqlite3_snprintf(sizeof(zErr), zErr,
               "Wrote 0x%016llx and got back 0x%016llx", in, out);
    -      Tcl_AppendResult(interp, zErr, 0);
    +      Tcl_AppendResult(interp, zErr, NULL);
           return TCL_ERROR;
         }
         if( (in & 0xffffffff)==in ){
    @@ -476,14 +477,14 @@ static int SQLITE_TCLAPI btree_varint_test(
             sqlite3_snprintf(sizeof(zErr), zErr,
               "putVarint returned %d and GetVarint32 returned %d", 
                       n1, n2);
    -        Tcl_AppendResult(interp, zErr, 0);
    +        Tcl_AppendResult(interp, zErr, NULL);
             return TCL_ERROR;
           }
           if( in!=out ){
             sqlite3_snprintf(sizeof(zErr), zErr,
               "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
                 in, out);
    -        Tcl_AppendResult(interp, zErr, 0);
    +        Tcl_AppendResult(interp, zErr, NULL);
             return TCL_ERROR;
           }
         }
    @@ -523,12 +524,12 @@ static int SQLITE_TCLAPI btree_from_db(
     
       if( argc!=2 && argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " DB-HANDLE ?N?\"", 0);
    +       " DB-HANDLE ?N?\"", NULL);
         return TCL_ERROR;
       }
     
       if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
    -    Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
    +    Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", NULL);
         return TCL_ERROR;
       }
       if( argc==3 ){
    @@ -561,7 +562,7 @@ static int SQLITE_TCLAPI btree_ismemdb(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID\"", 0);
    +       " ID\"", NULL);
         return TCL_ERROR;
       }
       pBt = sqlite3TestTextToPtr(argv[1]);
    @@ -591,7 +592,7 @@ static int SQLITE_TCLAPI btree_set_cache_size(
       
       if( argc!=3 ){
         Tcl_AppendResult(
    -        interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
    +        interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", NULL);
         return TCL_ERROR;
       }
       pBt = sqlite3TestTextToPtr(argv[1]);
    @@ -646,7 +647,7 @@ static int SQLITE_TCLAPI btree_insert(
     
       Tcl_ResetResult(interp);
       if( rc ){
    -    Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrName(rc), NULL);
         return TCL_ERROR;
       }
       return TCL_OK;
    diff --git a/src/test4.c b/src/test4.c
    index 8a68f7d3e4..07236b3e5d 100644
    --- a/src/test4.c
    +++ b/src/test4.c
    @@ -119,7 +119,7 @@ static void *test_thread_main(void *pArg){
     */
     static int parse_thread_id(Tcl_Interp *interp, const char *zArg){
       if( zArg==0 || zArg[0]==0 || zArg[1]!=0 || !isupper((unsigned char)zArg[0]) ){
    -    Tcl_AppendResult(interp, "thread ID must be an upper case letter", 0);
    +    Tcl_AppendResult(interp, "thread ID must be an upper case letter", NULL);
         return -1;
       }
       return zArg[0] - 'A';
    @@ -143,13 +143,13 @@ static int SQLITE_TCLAPI tcl_thread_create(
     
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID FILENAME", 0);
    +       " ID FILENAME", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( threadset[i].busy ){
    -    Tcl_AppendResult(interp, "thread ", argv[1], " is already running", 0);
    +    Tcl_AppendResult(interp, "thread ", argv[1], " is already running", NULL);
         return TCL_ERROR;
       }
       threadset[i].busy = 1;
    @@ -159,7 +159,7 @@ static int SQLITE_TCLAPI tcl_thread_create(
       threadset[i].completed = 0;
       rc = pthread_create(&x, 0, test_thread_main, &threadset[i]);
       if( rc ){
    -    Tcl_AppendResult(interp, "failed to create the thread", 0);
    +    Tcl_AppendResult(interp, "failed to create the thread", NULL);
         sqlite3_free(threadset[i].zFilename);
         threadset[i].busy = 0;
         return TCL_ERROR;
    @@ -192,13 +192,13 @@ static int SQLITE_TCLAPI tcl_thread_wait(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID", 0);
    +       " ID", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    @@ -236,7 +236,7 @@ static int SQLITE_TCLAPI tcl_thread_halt(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID", 0);
    +       " ID", NULL);
         return TCL_ERROR;
       }
       if( argv[1][0]=='*' && argv[1][1]==0 ){
    @@ -247,7 +247,7 @@ static int SQLITE_TCLAPI tcl_thread_halt(
         i = parse_thread_id(interp, argv[1]);
         if( i<0 ) return TCL_ERROR;
         if( !threadset[i].busy ){
    -      Tcl_AppendResult(interp, "no such thread", 0);
    +      Tcl_AppendResult(interp, "no such thread", NULL);
           return TCL_ERROR;
         }
         test_stop_thread(&threadset[i]);
    @@ -272,18 +272,18 @@ static int SQLITE_TCLAPI tcl_thread_argc(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID", 0);
    +       " ID", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
       sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       return TCL_OK;
     }
     
    @@ -304,22 +304,22 @@ static int SQLITE_TCLAPI tcl_thread_argv(
     
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID N", 0);
    +       " ID N", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
       test_thread_wait(&threadset[i]);
       if( n<0 || n>=threadset[i].argc ){
    -    Tcl_AppendResult(interp, "column number out of range", 0);
    +    Tcl_AppendResult(interp, "column number out of range", NULL);
         return TCL_ERROR;
       }
    -  Tcl_AppendResult(interp, threadset[i].argv[n], 0);
    +  Tcl_AppendResult(interp, threadset[i].argv[n], NULL);
       return TCL_OK;
     }
     
    @@ -340,22 +340,22 @@ static int SQLITE_TCLAPI tcl_thread_colname(
     
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID N", 0);
    +       " ID N", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
       test_thread_wait(&threadset[i]);
       if( n<0 || n>=threadset[i].argc ){
    -    Tcl_AppendResult(interp, "column number out of range", 0);
    +    Tcl_AppendResult(interp, "column number out of range", NULL);
         return TCL_ERROR;
       }
    -  Tcl_AppendResult(interp, threadset[i].colv[n], 0);
    +  Tcl_AppendResult(interp, threadset[i].colv[n], NULL);
       return TCL_OK;
     }
     
    @@ -376,18 +376,18 @@ static int SQLITE_TCLAPI tcl_thread_result(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID", 0);
    +       " ID", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
       zName = sqlite3ErrName(threadset[i].rc);
    -  Tcl_AppendResult(interp, zName, 0);
    +  Tcl_AppendResult(interp, zName, NULL);
       return TCL_OK;
     }
     
    @@ -407,17 +407,17 @@ static int SQLITE_TCLAPI tcl_thread_error(
     
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID", 0);
    +       " ID", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    -  Tcl_AppendResult(interp, threadset[i].zErr, 0);
    +  Tcl_AppendResult(interp, threadset[i].zErr, NULL);
       return TCL_OK;
     }
     
    @@ -451,13 +451,13 @@ static int SQLITE_TCLAPI tcl_thread_compile(
       int i;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID SQL", 0);
    +       " ID SQL", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    @@ -505,13 +505,13 @@ static int SQLITE_TCLAPI tcl_thread_step(
       int i;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " IDL", 0);
    +       " IDL", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    @@ -548,13 +548,13 @@ static int SQLITE_TCLAPI tcl_thread_finalize(
       int i;
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " IDL", 0);
    +       " IDL", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    @@ -581,20 +581,20 @@ static int SQLITE_TCLAPI tcl_thread_swap(
       sqlite3 *temp;
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID1 ID2", 0);
    +       " ID1 ID2", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
       j = parse_thread_id(interp, argv[2]);
       if( j<0 ) return TCL_ERROR;
       if( !threadset[j].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[j]);
    @@ -622,13 +622,13 @@ static int SQLITE_TCLAPI tcl_thread_db_get(
       extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*);
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID", 0);
    +       " ID", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    @@ -653,13 +653,13 @@ static int SQLITE_TCLAPI tcl_thread_db_put(
       extern void *sqlite3TestTextToPtr(const char *);
       if( argc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID DB", 0);
    +       " ID DB", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    @@ -685,13 +685,13 @@ static int SQLITE_TCLAPI tcl_thread_stmt_get(
       extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*);
       if( argc!=2 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    -       " ID", 0);
    +       " ID", NULL);
         return TCL_ERROR;
       }
       i = parse_thread_id(interp, argv[1]);
       if( i<0 ) return TCL_ERROR;
       if( !threadset[i].busy ){
    -    Tcl_AppendResult(interp, "no such thread", 0);
    +    Tcl_AppendResult(interp, "no such thread", NULL);
         return TCL_ERROR;
       }
       test_thread_wait(&threadset[i]);
    diff --git a/src/test5.c b/src/test5.c
    index 334b5d07fe..06d2de911d 100644
    --- a/src/test5.c
    +++ b/src/test5.c
    @@ -67,7 +67,7 @@ static int SQLITE_TCLAPI test_value_overhead(
     
       if( objc!=3 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
    -        Tcl_GetStringFromObj(objv[0], 0), "  ", 0);
    +        Tcl_GetStringFromObj(objv[0], 0), "  ", NULL);
         return TCL_ERROR;
       }
     
    @@ -106,7 +106,7 @@ static u8 name_to_enc(Tcl_Interp *interp, Tcl_Obj *pObj){
         }
       }
       if( !pEnc->enc ){
    -    Tcl_AppendResult(interp, "No such encoding: ", z, 0);
    +    Tcl_AppendResult(interp, "No such encoding: ", z, NULL);
       }
       if( pEnc->enc==SQLITE_UTF16 ){
         return SQLITE_UTF16NATIVE;
    @@ -135,7 +135,7 @@ static int SQLITE_TCLAPI test_translate(
       if( objc!=4 && objc!=5 ){
         Tcl_AppendResult(interp, "wrong # args: should be \"",
             Tcl_GetStringFromObj(objv[0], 0), 
    -        "   ", 0
    +        "   ", NULL
         );
         return TCL_ERROR;
       }
    diff --git a/src/test6.c b/src/test6.c
    index 76db640c4d..aee7bf12aa 100644
    --- a/src/test6.c
    +++ b/src/test6.c
    @@ -755,12 +755,12 @@ static int processDevSymArgs(
         ){
           Tcl_AppendResult(interp,
             "Bad option: \"", zOpt,
    -        "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
    +        "\" - must be \"-characteristics\" or \"-sectorsize\"", NULL
           );
           return TCL_ERROR;
         }
         if( i==objc-1 ){
    -      Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
    +      Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"", NULL);
           return TCL_ERROR;
         }
     
    @@ -934,7 +934,7 @@ static int SQLITE_TCLAPI crashParamsObjCmd(
     
       zCrashFile = Tcl_GetStringFromObj(objv[objc-1], &nCrashFile);
       if( nCrashFile>=sizeof(g.zCrashFile) ){
    -    Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
    +    Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", NULL);
         goto error;
       }
       if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
    @@ -1044,7 +1044,7 @@ static int SQLITE_TCLAPI jtObjCmd(
       if( objc==3 ){
         if( strcmp(zParent, "-default") ){
           Tcl_AppendResult(interp,
    -          "bad option \"", zParent, "\": must be -default", 0
    +          "bad option \"", zParent, "\": must be -default", NULL
           );
           return TCL_ERROR;
         }
    @@ -1055,7 +1055,7 @@ static int SQLITE_TCLAPI jtObjCmd(
         zParent = 0;
       }
       if( jt_register(zParent, objc==3) ){
    -    Tcl_AppendResult(interp, "Error in jt_register", 0);
    +    Tcl_AppendResult(interp, "Error in jt_register", NULL);
         return TCL_ERROR;
       }
     
    diff --git a/src/test9.c b/src/test9.c
    index b5362adb7f..62b16795e3 100644
    --- a/src/test9.c
    +++ b/src/test9.c
    @@ -56,7 +56,7 @@ static int SQLITE_TCLAPI c_collation_test(
     
     error_out:
       Tcl_ResetResult(interp);
    -  Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, 0);
    +  Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, NULL);
       return TCL_ERROR;
     }
     
    @@ -96,7 +96,7 @@ static int SQLITE_TCLAPI c_realloc_test(
     
     error_out:
       Tcl_ResetResult(interp);
    -  Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, 0);
    +  Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, NULL);
       return TCL_ERROR;
     }
     
    @@ -174,7 +174,7 @@ static int SQLITE_TCLAPI c_misuse_test(
     
     error_out:
       Tcl_ResetResult(interp);
    -  Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, 0);
    +  Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, NULL);
       return TCL_ERROR;
     }
     
    diff --git a/src/test_backup.c b/src/test_backup.c
    index 8051888ee6..ae2348ebc2 100644
    --- a/src/test_backup.c
    +++ b/src/test_backup.c
    @@ -135,7 +135,7 @@ static int SQLITE_TCLAPI backupTestInit(
     
       pBackup = sqlite3_backup_init(pDestDb, zDestName, pSrcDb, zSrcName);
       if( !pBackup ){
    -    Tcl_AppendResult(interp, "sqlite3_backup_init() failed", 0);
    +    Tcl_AppendResult(interp, "sqlite3_backup_init() failed", NULL);
         return TCL_ERROR;
       }
     
    diff --git a/src/test_blob.c b/src/test_blob.c
    index bddad240ce..ae5a734179 100644
    --- a/src/test_blob.c
    +++ b/src/test_blob.c
    @@ -237,7 +237,7 @@ static int SQLITE_TCLAPI test_blob_read(
       if( nByte>0 ){
         zBuf = (unsigned char *)Tcl_AttemptAlloc(nByte);
         if( zBuf==0 ){
    -      Tcl_AppendResult(interp, "out of memory in " __FILE__, 0);
    +      Tcl_AppendResult(interp, "out of memory in " __FILE__, NULL);
           return TCL_ERROR;
         }
       }
    diff --git a/src/test_delete.c b/src/test_delete.c
    index 68fdbc6a75..3f34a72c46 100644
    --- a/src/test_delete.c
    +++ b/src/test_delete.c
    @@ -63,7 +63,7 @@ static int sqlite3DeleteUnlinkIfExists(
       int *pbExists
     ){
       int rc = SQLITE_ERROR;
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       if( pVfs ){
         if( pbExists ) *pbExists = 1;
         rc = pVfs->xDelete(pVfs, zFile, 0);
    @@ -115,7 +115,7 @@ SQLITE_API int sqlite3_delete_database(
         { "%s-wal%03d",     SQLITE_MULTIPLEX_WAL_8_3_OFFSET, 1 },
       };
     
    -#ifdef SQLITE_OS_WIN
    +#ifdef _WIN32
       sqlite3_vfs *pVfs = sqlite3_vfs_find("win32");
     #else
       sqlite3_vfs *pVfs = 0;
    diff --git a/src/test_fs.c b/src/test_fs.c
    index d821a83b9d..1c47bbaacf 100644
    --- a/src/test_fs.c
    +++ b/src/test_fs.c
    @@ -69,18 +69,15 @@
     #include 
     #include 
     
    -#if SQLITE_OS_UNIX || defined(__MINGW_H)
    +#if !defined(_WIN32) || defined(__MSVCRT__)
     # include 
     # include 
     # ifndef DIRENT
     #  define DIRENT dirent
     # endif
    -#endif
    -#if SQLITE_OS_WIN
    +#else
     # include 
    -# if !defined(__MINGW_H)
    -#  include "test_windirent.h"
    -# endif
    +# include "test_windirent.h"
     # ifndef S_ISREG
     #  define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
     # endif
    @@ -485,7 +482,7 @@ static int fstreeFilter(
       int nDir;
       char aWild[2] = { '\0', '\0' };
     
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       const char *zDrive = windirent_getenv("fstreeDrive");
       if( zDrive==0 ){
         zDrive = windirent_getenv("SystemDrive");
    @@ -538,7 +535,7 @@ static int fstreeFilter(
       sqlite3_bind_text(pCsr->pStmt, 2, zRoot, nRoot, SQLITE_TRANSIENT);
       sqlite3_bind_text(pCsr->pStmt, 3, zPrefix, nPrefix, SQLITE_TRANSIENT);
     
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       sqlite3_free(zPrefix);
       sqlite3_free(zRoot);
     #endif
    diff --git a/src/test_hexio.c b/src/test_hexio.c
    index 1a21e89aa0..048ab13246 100644
    --- a/src/test_hexio.c
    +++ b/src/test_hexio.c
    @@ -122,7 +122,7 @@ static int SQLITE_TCLAPI hexio_read(
         in = fopen(zFile, "r");
       }
       if( in==0 ){
    -    Tcl_AppendResult(interp, "cannot open input file ", zFile, 0);
    +    Tcl_AppendResult(interp, "cannot open input file ", zFile, NULL);
         return TCL_ERROR;
       }
       fseek(in, offset, SEEK_SET);
    @@ -132,7 +132,7 @@ static int SQLITE_TCLAPI hexio_read(
         got = 0;
       }
       sqlite3TestBinToHex(zBuf, got);
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
       sqlite3_free(zBuf);
       return TCL_OK;
     }
    @@ -175,7 +175,7 @@ static int SQLITE_TCLAPI hexio_write(
         out = fopen(zFile, "r+");
       }
       if( out==0 ){
    -    Tcl_AppendResult(interp, "cannot open output file ", zFile, 0);
    +    Tcl_AppendResult(interp, "cannot open output file ", zFile, NULL);
         return TCL_ERROR;
       }
       fseek(out, offset, SEEK_SET);
    @@ -324,12 +324,12 @@ static int SQLITE_TCLAPI utf8_to_utf8(
       z[n] = 0;
       nOut = sqlite3Utf8To8(z);
       sqlite3TestBinToHex(z,nOut);
    -  Tcl_AppendResult(interp, (char*)z, 0);
    +  Tcl_AppendResult(interp, (char*)z, NULL);
       sqlite3_free(z);
       return TCL_OK;
     #else
       Tcl_AppendResult(interp, 
    -      "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", 0
    +      "[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", NULL
       );
       return TCL_ERROR;
     #endif
    diff --git a/src/test_init.c b/src/test_init.c
    index f7b85875b0..0c6ac8eb56 100644
    --- a/src/test_init.c
    +++ b/src/test_init.c
    @@ -201,7 +201,7 @@ static int SQLITE_TCLAPI init_wrapper_install(
         }else if( strcmp(z, "pcache")==0 ){
           wrapped.pcache_fail = 1;
         }else{
    -      Tcl_AppendResult(interp, "Unknown argument: \"", z, "\"");
    +      Tcl_AppendResult(interp, "Unknown argument: \"", z, "\"", NULL);
           return TCL_ERROR;
         }
       }
    diff --git a/src/test_malloc.c b/src/test_malloc.c
    index 8d6c4fa505..1c19d896f2 100644
    --- a/src/test_malloc.c
    +++ b/src/test_malloc.c
    @@ -646,7 +646,7 @@ static int SQLITE_TCLAPI test_memdebug_fail(
         }
     
         if( zErr ){
    -      Tcl_AppendResult(interp, zErr, zOption, 0);
    +      Tcl_AppendResult(interp, zErr, zOption, NULL);
           return TCL_ERROR;
         }
       }
    diff --git a/src/test_multiplex.c b/src/test_multiplex.c
    index e5b43f4cc1..82551200f2 100644
    --- a/src/test_multiplex.c
    +++ b/src/test_multiplex.c
    @@ -1315,8 +1315,8 @@ static int SQLITE_TCLAPI test_multiplex_control(
       }
     
       if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
    -    Tcl_AppendResult(interp, "expected database handle, got \"", 0);
    -    Tcl_AppendResult(interp, Tcl_GetString(objv[1]), "\"", 0);
    +    Tcl_AppendResult(interp, "expected database handle, got \"", NULL);
    +    Tcl_AppendResult(interp, Tcl_GetString(objv[1]), "\"", NULL);
         return TCL_ERROR;
       }else{
         db = *(sqlite3 **)cmdInfo.objClientData;
    diff --git a/src/test_mutex.c b/src/test_mutex.c
    index e60a06df32..de064de4c4 100644
    --- a/src/test_mutex.c
    +++ b/src/test_mutex.c
    @@ -225,8 +225,8 @@ static int SQLITE_TCLAPI test_install_mutex_counters(
       assert(isInstall==0 || isInstall==1);
       assert(g.isInstalled==0 || g.isInstalled==1);
       if( isInstall==g.isInstalled ){
    -    Tcl_AppendResult(interp, "mutex counters are ", 0);
    -    Tcl_AppendResult(interp, isInstall?"already installed":"not installed", 0);
    +    Tcl_AppendResult(interp, "mutex counters are ", NULL);
    +    Tcl_AppendResult(interp, isInstall?"already installed":"not installed", NULL);
         return TCL_ERROR;
       }
     
    diff --git a/src/test_osinst.c b/src/test_osinst.c
    index 2d03d2bbcd..e776d89e55 100644
    --- a/src/test_osinst.c
    +++ b/src/test_osinst.c
    @@ -71,9 +71,8 @@
     
     #include "sqlite3.h"
     
    -#include "os_setup.h"
    -#if SQLITE_OS_WIN
    -#  include "os_win.h"
    +#ifdef _WIN32
    +#include 
     #endif
     
     #include 
    @@ -219,14 +218,7 @@ static sqlite3_io_methods vfslog_io_methods = {
       vfslogShmUnmap                  /* xShmUnmap */
     };
     
    -#if SQLITE_OS_UNIX && !defined(NO_GETTOD)
    -#include 
    -static sqlite3_uint64 vfslog_time(){
    -  struct timeval sTime;
    -  gettimeofday(&sTime, 0);
    -  return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
    -}
    -#elif SQLITE_OS_WIN
    +#ifdef _WIN32
     #include 
     static sqlite3_uint64 vfslog_time(){
       FILETIME ft;
    @@ -241,6 +233,13 @@ static sqlite3_uint64 vfslog_time(){
       /* ft is 100-nanosecond intervals, we want microseconds */
       return u64time /(sqlite3_uint64)10;
     }
    +#elif !defined(NO_GETTOD)
    +#include 
    +static sqlite3_uint64 vfslog_time(){
    +  struct timeval sTime;
    +  gettimeofday(&sTime, 0);
    +  return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
    +}
     #else
     static sqlite3_uint64 vfslog_time(){
       return 0;
    @@ -1146,7 +1145,7 @@ static int SQLITE_TCLAPI test_vfslog(
           zMsg = Tcl_GetString(objv[3]);
           rc = sqlite3_vfslog_annotate(zVfs, zMsg);
           if( rc!=SQLITE_OK ){
    -        Tcl_AppendResult(interp, "failed", 0);
    +        Tcl_AppendResult(interp, "failed", (char*)0);
             return TCL_ERROR;
           }
           break;
    @@ -1160,7 +1159,7 @@ static int SQLITE_TCLAPI test_vfslog(
           zVfs = Tcl_GetString(objv[2]);
           rc = sqlite3_vfslog_finalize(zVfs);
           if( rc!=SQLITE_OK ){
    -        Tcl_AppendResult(interp, "failed", 0);
    +        Tcl_AppendResult(interp, "failed", (char*)0);
             return TCL_ERROR;
           }
           break;
    @@ -1180,7 +1179,7 @@ static int SQLITE_TCLAPI test_vfslog(
           if( *zParent=='\0' ) zParent = 0;
           rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
           if( rc!=SQLITE_OK ){
    -        Tcl_AppendResult(interp, "failed", 0);
    +        Tcl_AppendResult(interp, "failed", (char*)0);
             return TCL_ERROR;
           }
           break;
    diff --git a/src/test_quota.c b/src/test_quota.c
    index 62d808a22b..d2f9cddd11 100644
    --- a/src/test_quota.c
    +++ b/src/test_quota.c
    @@ -44,14 +44,12 @@
     #define sqlite3_mutex_notheld(X)  ((void)(X),1)
     #endif /* SQLITE_THREADSAFE==0 */
     
    -#include "os_setup.h"
     
    -#if SQLITE_OS_UNIX
    -# include 
    -#endif
    -#if SQLITE_OS_WIN
    -# include "os_win.h"
    +#ifdef _WIN32
    +# include 
     # include 
    +#else
    +# include 
     #endif
     
     
    @@ -130,7 +128,7 @@ struct quota_FILE {
       FILE *f;                /* Open stdio file pointer */
       sqlite3_int64 iOfst;    /* Current offset into the file */
       quotaFile *pFile;       /* The file record in the quota system */
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       char *zMbcsName;        /* Full MBCS pathname of the file */
     #endif
     };
    @@ -375,7 +373,7 @@ static quotaFile *quotaFindFile(
     ** used to store the returned pointer when done.
     */
     static char *quota_utf8_to_mbcs(const char *zUtf8){
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       size_t n;          /* Bytes in zUtf8 */
       int nWide;         /* number of UTF-16 characters */
       int nMbcs;         /* Bytes of MBCS */
    @@ -410,7 +408,7 @@ static char *quota_utf8_to_mbcs(const char *zUtf8){
     ** Deallocate any memory allocated by quota_utf8_to_mbcs().
     */
     static void quota_mbcs_free(char *zOld){
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       sqlite3_free(zOld);
     #else
       /* No-op on unix */
    @@ -970,7 +968,7 @@ quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
       }
       quotaLeave();
       sqlite3_free(zFull);
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       p->zMbcsName = zFullTranslated;
     #endif
       return p;
    @@ -1073,7 +1071,7 @@ int sqlite3_quota_fclose(quota_FILE *p){
         }
         quotaLeave();
       }
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       quota_mbcs_free(p->zMbcsName);
     #endif
       sqlite3_free(p);
    @@ -1087,11 +1085,10 @@ int sqlite3_quota_fflush(quota_FILE *p, int doFsync){
       int rc;
       rc = fflush(p->f);
       if( rc==0 && doFsync ){
    -#if SQLITE_OS_UNIX
    -    rc = fsync(fileno(p->f));
    -#endif
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
         rc = _commit(_fileno(p->f));
    +#else
    +    rc = fsync(fileno(p->f));
     #endif
       }
       return rc!=0;
    @@ -1143,17 +1140,16 @@ int sqlite3_quota_ftruncate(quota_FILE *p, sqlite3_int64 szNew){
         pGroup->iSize += szNew - pFile->iSize;
         quotaLeave();
       }
    -#if SQLITE_OS_UNIX
    -  rc = ftruncate(fileno(p->f), szNew);
    -#endif
    -#if SQLITE_OS_WIN
    -#  if defined(__MINGW32__) && defined(SQLITE_TEST)
    +#ifdef _WIN32
    +#  if defined(__MSVCRT__) && defined(SQLITE_TEST)
          /* _chsize_s() is missing from MingW (as of 2012-11-06).  Use
          ** _chsize() as a work-around for testing purposes. */
          rc = _chsize(_fileno(p->f), (long)szNew);
     #  else
          rc = _chsize_s(_fileno(p->f), szNew);
     #  endif
    +#else
    +  rc = ftruncate(fileno(p->f), szNew);
     #endif
       if( pFile && rc==0 ){
         quotaGroup *pGroup = pFile->pGroup;
    @@ -1172,13 +1168,12 @@ int sqlite3_quota_ftruncate(quota_FILE *p, sqlite3_int64 szNew){
     */
     int sqlite3_quota_file_mtime(quota_FILE *p, time_t *pTime){
       int rc;
    -#if SQLITE_OS_UNIX
    -  struct stat buf;
    -  rc = fstat(fileno(p->f), &buf);
    -#endif
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       struct _stati64 buf;
       rc = _stati64(p->zMbcsName, &buf);
    +#else
    +  struct stat buf;
    +  rc = fstat(fileno(p->f), &buf);
     #endif
       if( rc==0 ) *pTime = buf.st_mtime;
       return rc;
    @@ -1190,13 +1185,12 @@ int sqlite3_quota_file_mtime(quota_FILE *p, time_t *pTime){
     */
     sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE *p){
       int rc;
    -#if SQLITE_OS_UNIX
    -  struct stat buf;
    -  rc = fstat(fileno(p->f), &buf);
    -#endif
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       struct _stati64 buf;
       rc = _stati64(p->zMbcsName, &buf);
    +#else
    +  struct stat buf;
    +  rc = fstat(fileno(p->f), &buf);
     #endif
       return rc==0 ? buf.st_size : -1;
     }
    diff --git a/src/test_sqllog.c b/src/test_sqllog.c
    index 9ae0e50685..5abf59a8bf 100644
    --- a/src/test_sqllog.c
    +++ b/src/test_sqllog.c
    @@ -84,7 +84,7 @@
     #include 
     #include 
     static int getProcessId(void){
    -#if SQLITE_OS_WIN
    +#ifdef _WIN32
       return (int)_getpid();
     #else
       return (int)getpid();
    diff --git a/src/test_superlock.c b/src/test_superlock.c
    index 7f3bf163a5..82997927c4 100644
    --- a/src/test_superlock.c
    +++ b/src/test_superlock.c
    @@ -338,7 +338,7 @@ static int SQLITE_TCLAPI superlock_cmd(
       if( rc!=SQLITE_OK ){
         extern const char *sqlite3ErrStr(int);
         Tcl_ResetResult(interp);
    -    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
    +    Tcl_AppendResult(interp, sqlite3ErrStr(rc), NULL);
         return TCL_ERROR;
       }
     
    diff --git a/src/test_syscall.c b/src/test_syscall.c
    index af2ae10015..35c303f8ee 100644
    --- a/src/test_syscall.c
    +++ b/src/test_syscall.c
    @@ -686,7 +686,7 @@ static int SQLITE_TCLAPI test_syscall_pagesize(
         }
       }else{
         if( pgsz<512 || (pgsz & (pgsz-1)) ){
    -      Tcl_AppendResult(interp, "pgsz out of range", 0);
    +      Tcl_AppendResult(interp, "pgsz out of range", NULL);
           return TCL_ERROR;
         }
         gSyscall.orig_getpagesize = pVfs->xGetSystemCall(pVfs, "getpagesize");
    @@ -729,7 +729,7 @@ static int SQLITE_TCLAPI test_syscall(
         return TCL_ERROR;
       }
       if( pVfs->iVersion<3 || pVfs->xSetSystemCall==0 ){
    -    Tcl_AppendResult(interp, "VFS does not support xSetSystemCall", 0);
    +    Tcl_AppendResult(interp, "VFS does not support xSetSystemCall", NULL);
         rc = TCL_ERROR;
       }else{
         rc = Tcl_GetIndexFromObjStruct(interp, 
    diff --git a/src/test_thread.c b/src/test_thread.c
    index 7c06d110ac..98ef2c2468 100644
    --- a/src/test_thread.c
    +++ b/src/test_thread.c
    @@ -201,7 +201,7 @@ static int SQLITE_TCLAPI sqlthread_spawn(
     
       rc = Tcl_CreateThread(&x, tclScriptThread, (void *)pNew, nStack, flags);
       if( rc!=TCL_OK ){
    -    Tcl_AppendResult(interp, "Error in Tcl_CreateThread()", 0);
    +    Tcl_AppendResult(interp, "Error in Tcl_CreateThread()", NULL);
         ckfree((char *)pNew);
         return TCL_ERROR;
       }
    @@ -235,7 +235,7 @@ static int SQLITE_TCLAPI sqlthread_parent(
       UNUSED_PARAMETER(objc);
     
       if( p==0 ){
    -    Tcl_AppendResult(interp, "no parent thread", 0);
    +    Tcl_AppendResult(interp, "no parent thread", NULL);
         return TCL_ERROR;
       }
     
    @@ -287,7 +287,7 @@ static int SQLITE_TCLAPI sqlthread_open(
       sqlite3_busy_handler(db, xBusy, 0);
       
       if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
    -  Tcl_AppendResult(interp, zBuf, 0);
    +  Tcl_AppendResult(interp, zBuf, NULL);
     
       return TCL_OK;
     }
    @@ -614,13 +614,13 @@ static int SQLITE_TCLAPI blocking_prepare_v2_proc(
       if( rc!=SQLITE_OK ){
         assert( pStmt==0 );
         sqlite3_snprintf(sizeof(zBuf), zBuf, "%s ", (char *)sqlite3ErrName(rc));
    -    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
    +    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), NULL);
         return TCL_ERROR;
       }
     
       if( pStmt ){
         if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    -    Tcl_AppendResult(interp, zBuf, 0);
    +    Tcl_AppendResult(interp, zBuf, NULL);
       }
       return TCL_OK;
     }
    diff --git a/src/test_vfs.c b/src/test_vfs.c
    index f75ef956b6..0d90a53a53 100644
    --- a/src/test_vfs.c
    +++ b/src/test_vfs.c
    @@ -1138,7 +1138,7 @@ static int SQLITE_TCLAPI testvfs_obj_cmd(
           );
           if( rc!=SQLITE_OK ){
             Tcl_AppendResult(interp, "failed to get full path: ",
    -                         Tcl_GetString(objv[2]), 0);
    +                         Tcl_GetString(objv[2]), NULL);
             ckfree(zName);
             return TCL_ERROR;
           }
    @@ -1147,7 +1147,7 @@ static int SQLITE_TCLAPI testvfs_obj_cmd(
           }
           ckfree(zName);
           if( !pBuffer ){
    -        Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), 0);
    +        Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), NULL);
             return TCL_ERROR;
           }
           if( objc==4 ){
    @@ -1225,7 +1225,7 @@ static int SQLITE_TCLAPI testvfs_obj_cmd(
               }
             }
             if( iMethod==ArraySize(vfsmethod) ){
    -          Tcl_AppendResult(interp, "unknown method: ", zElem, 0);
    +          Tcl_AppendResult(interp, "unknown method: ", zElem, NULL);
               return TCL_ERROR;
             }
           }
    @@ -1353,7 +1353,7 @@ static int SQLITE_TCLAPI testvfs_obj_cmd(
                 return TCL_ERROR;
               }
               if( aFlag[idx].iValue<0 && nFlags>1 ){
    -            Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), 0);
    +            Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), NULL);
                 return TCL_ERROR;
               }
               iNew |= aFlag[idx].iValue;
    @@ -1673,7 +1673,7 @@ static int SQLITE_TCLAPI test_vfs_set_readmark(
         return TCL_ERROR;
       }
       if( pShm==0 ){
    -    Tcl_AppendResult(interp, "*-shm is not yet mapped", 0);
    +    Tcl_AppendResult(interp, "*-shm is not yet mapped", NULL);
         return TCL_ERROR;
       }
       aShm = (u32*)pShm;
    diff --git a/src/utf.c b/src/utf.c
    index 57700bf20d..e24e1586bb 100644
    --- a/src/utf.c
    +++ b/src/utf.c
    @@ -555,7 +555,7 @@ int sqlite3Utf16ByteLen(const void *zIn, int nByte, int nChar){
       int n = 0;
       
       if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
    -  while( n=0xd8 && c<0xdc && z<=zEnd && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
    diff --git a/src/vacuum.c b/src/vacuum.c
    index ae3af86b7a..96d77e5bc4 100644
    --- a/src/vacuum.c
    +++ b/src/vacuum.c
    @@ -116,7 +116,7 @@ void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
     #else
         /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
         ** to VACUUM are silently ignored.  This is a back-out of a bug fix that
    -    ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270).
    +    ** occurred on 2016-08-19 (https://sqlite.org/src/info/083f9e6270).
         ** The buggy behavior is required for binary compatibility with some
         ** legacy applications. */
         iDb = sqlite3FindDb(pParse->db, pNm);
    diff --git a/src/vdbe.c b/src/vdbe.c
    index 19bc670e3a..586b03edd0 100644
    --- a/src/vdbe.c
    +++ b/src/vdbe.c
    @@ -1318,7 +1318,7 @@ case OP_Halt: {
           sqlite3VdbeError(p, "%s", pOp->p4.z);
         }
         pcx = (int)(pOp - aOp);
    -    sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
    +    sqlite3_log(pOp->p1, "abort at %d: %s; [%s]", pcx, p->zErrMsg, p->zSql);
       }
       rc = sqlite3VdbeHalt(p);
       assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
    @@ -9166,8 +9166,8 @@ abort_due_to_error:
       p->rc = rc;
       sqlite3SystemError(db, rc);
       testcase( sqlite3GlobalConfig.xLog!=0 );
    -  sqlite3_log(rc, "statement aborts at %d: [%s] %s",
    -                   (int)(pOp - aOp), p->zSql, p->zErrMsg);
    +  sqlite3_log(rc, "statement aborts at %d: %s; [%s]",
    +                   (int)(pOp - aOp), p->zErrMsg, p->zSql);
       if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
       if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
       if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){
    diff --git a/src/vdbeapi.c b/src/vdbeapi.c
    index 523f80097d..ed95494628 100644
    --- a/src/vdbeapi.c
    +++ b/src/vdbeapi.c
    @@ -1808,7 +1808,7 @@ int sqlite3_bind_text64(
       assert( xDel!=SQLITE_DYNAMIC );
       if( enc!=SQLITE_UTF8 ){
         if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
    -    nData &= ~(u16)1;
    +    nData &= ~(u64)1;
       }
       return bindText(pStmt, i, zData, nData, xDel, enc);
     }
    diff --git a/src/vdbemem.c b/src/vdbemem.c
    index 8534849432..6db9e4b1a7 100644
    --- a/src/vdbemem.c
    +++ b/src/vdbemem.c
    @@ -141,7 +141,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
     ** corresponding string value, then it is important that the string be
     ** derived from the numeric value, not the other way around, to ensure
     ** that the index and table are consistent.  See ticket
    -** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for
    +** https://sqlite.org/src/info/343634942dd54ab (2018-01-31) for
     ** an example.
     **
     ** This routine looks at pMem to verify that if it has both a numeric
    diff --git a/src/wal.c b/src/wal.c
    index 7d33a54c90..69de588dbb 100644
    --- a/src/wal.c
    +++ b/src/wal.c
    @@ -1133,10 +1133,8 @@ static void walChecksumBytes(
         s1 = s2 = 0;
       }
     
    -  assert( nByte>=8 );
    -  assert( (nByte&0x00000007)==0 );
    -  assert( nByte<=65536 );
    -  assert( nByte%4==0 );
    +  /* nByte is a multiple of 8 between 8 and 65536 */
    +  assert( nByte>=8 && (nByte&7)==0 && nByte<=65536 );
     
       if( !nativeCksum ){
         do {
    diff --git a/src/where.c b/src/where.c
    index ed63203495..c51d1ba815 100644
    --- a/src/where.c
    +++ b/src/where.c
    @@ -3476,7 +3476,7 @@ static int whereLoopAddBtreeIndex(
         if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
          && pNew->u.btree.nEqnColumn
          && (pNew->u.btree.nEqnKeyCol ||
    -           pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY)
    +          (pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY && !pProbe->bIdxRowid))
         ){
           if( pNew->u.btree.nEq>3 ){
             sqlite3ProgressCheck(pParse);
    @@ -6934,7 +6934,8 @@ WhereInfo *sqlite3WhereBegin(
         }
     
         /* TUNING:  Assume that a DISTINCT clause on a subquery reduces
    -    ** the output size by a factor of 8 (LogEst -30).
    +    ** the output size by a factor of 8 (LogEst -30).  Search for
    +    ** tag-20250414a to see other cases.
         */
         if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){
           WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n",
    diff --git a/src/wherecode.c b/src/wherecode.c
    index 5fe2308137..014f697d97 100644
    --- a/src/wherecode.c
    +++ b/src/wherecode.c
    @@ -542,7 +542,7 @@ static void adjustOrderByCol(ExprList *pOrderBy, ExprList *pEList){
     /*
     ** pX is an expression of the form:  (vector) IN (SELECT ...)
     ** In other words, it is a vector IN operator with a SELECT clause on the
    -** LHS.  But not all terms in the vector are indexable and the terms might
    +** RHS.  But not all terms in the vector are indexable and the terms might
     ** not be in the correct order for indexing.
     **
     ** This routine makes a copy of the input pX expression and then adjusts
    @@ -2364,7 +2364,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
         **
         ** This optimization also only applies if the (x1 OR x2 OR ...) term
         ** is not contained in the ON clause of a LEFT JOIN.
    -    ** See ticket http://www.sqlite.org/src/info/f2369304e4
    +    ** See ticket http://sqlite.org/src/info/f2369304e4
         **
         ** 2022-02-04:  Do not push down slices of a row-value comparison.
         ** In other words, "w" or "y" may not be a slice of a vector.  Otherwise,
    diff --git a/test/affinity2.test b/test/affinity2.test
    index 6ad257ac36..59f9dada53 100644
    --- a/test/affinity2.test
    +++ b/test/affinity2.test
    @@ -116,7 +116,7 @@ do_execsql_test 507 {
       SELECT * FROM t0 WHERE +-+'ce' >= t0.c0;
     } {-1 {}}
      
    -# 2019-08-30 ticket https://www.sqlite.org/src/info/40812aea1fde9594
    +# 2019-08-30 ticket https://sqlite.org/src/info/40812aea1fde9594
     #
     # Due to some differences in floating point computations, these tests do not
     # work under valgrind.
    diff --git a/test/affinity3.test b/test/affinity3.test
    index 3695ea8479..be415de46c 100644
    --- a/test/affinity3.test
    +++ b/test/affinity3.test
    @@ -11,14 +11,14 @@
     #
     # Test cases for bugs:
     #
    -#    https://www.sqlite.org/src/info/91e2e8ba6ff2e2
    -#    https://www.sqlite.org/src/info/7ffd1ca1d2ad4ecf
    +#    https://sqlite.org/src/info/91e2e8ba6ff2e2
    +#    https://sqlite.org/src/info/7ffd1ca1d2ad4ecf
     #
     
     set testdir [file dirname $argv0]
     source $testdir/tester.tcl
     
    -# Ticket https://www.sqlite.org/src/info/91e2e8ba6ff2e2 (2011-09-19)
    +# Ticket https://sqlite.org/src/info/91e2e8ba6ff2e2 (2011-09-19)
     # Automatic index causes undesired type conversions
     #
     do_execsql_test affinity3-100 {
    @@ -87,7 +87,7 @@ do_execsql_test affinity3-142 {
       SELECT id, (apr / 100), typeof(apr) apr_type  FROM v2rjrj;
     } {1 0.12 real 2 0.1201 real}
     
    -# Ticket https://www.sqlite.org/src/info/7ffd1ca1d2ad4ecf  (2017-01-16)
    +# Ticket https://sqlite.org/src/info/7ffd1ca1d2ad4ecf  (2017-01-16)
     # Incorrect affinity when using automatic indexes 
     #
     do_execsql_test affinity3-200 {
    diff --git a/test/all.test b/test/all.test
    index 46e8115fba..22d7b8daed 100644
    --- a/test/all.test
    +++ b/test/all.test
    @@ -42,7 +42,7 @@ run_test_suite pcache100
     run_test_suite prepare
     run_test_suite mmap
     
    -if {$::tcl_platform(platform)=="unix"} {
    +if {$::tcl_platform(platform) eq "unix"} {
       ifcapable !default_autovacuum {
         run_test_suite autovacuum_crash
       }
    diff --git a/test/alter4.test b/test/alter4.test
    index f6ada8f3fb..7e2d7e66a8 100644
    --- a/test/alter4.test
    +++ b/test/alter4.test
    @@ -379,7 +379,7 @@ do_execsql_test alter4-9.3 {
     # Confirm that doing an ALTER TABLE on a legacy format database
     # does not corrupt DESC indexes.
     #
    -# Ticket https://www.sqlite.org/src/tktview/f68bf68513a1c
    +# Ticket https://sqlite.org/src/tktview/f68bf68513a1c
     #
     do_test alter4-10.1 {
       db close
    diff --git a/test/altercol.test b/test/altercol.test
    index f44aa2e065..5f7de57a4e 100644
    --- a/test/altercol.test
    +++ b/test/altercol.test
    @@ -796,7 +796,7 @@ do_execsql_test 19.1 {
       {CREATE VIEW v2(e) AS SELECT coalesce(t2.c,t1.f) FROM t1, t2 WHERE t1.b=t2.d}
     }
     
    -# 2019-01-08: https://www.sqlite.org/src/tktview/bc8d94f0fbd633fd9a051e3
    +# 2019-01-08: https://sqlite.org/src/tktview/bc8d94f0fbd633fd9a051e3
     #
     # ALTER TABLE RENAME COLUMN does not work for tables that have redundant
     # UNIQUE constraints.
    diff --git a/test/altertab2.test b/test/altertab2.test
    index 576dc49670..56e42f1a69 100644
    --- a/test/altertab2.test
    +++ b/test/altertab2.test
    @@ -351,7 +351,7 @@ do_execsql_test 8.5 {
       SELECT sql FROM sqlite_master WHERE name = 'v4'
     } {{CREATE VIEW v4 AS SELECT * FROM t4 WHERE (c=1 AND 0) OR b=2}}
     
    -# 2019-06-10 https://www.sqlite.org/src/info/533010b8cacebe82
    +# 2019-06-10 https://sqlite.org/src/info/533010b8cacebe82
     reset_db
     do_catchsql_test 8.6 {
       CREATE TABLE t0(c0);
    diff --git a/test/analyzeC.test b/test/analyzeC.test
    index 2f43d57a1e..f5bcaeb781 100644
    --- a/test/analyzeC.test
    +++ b/test/analyzeC.test
    @@ -133,7 +133,7 @@ do_execsql_test 4.3 {
     } {/.*INDEX t1ca.*/}
     
     # 2019-08-15.
    -# Ticket https://www.sqlite.org/src/tktview/e4598ecbdd18bd82945f602901
    +# Ticket https://sqlite.org/src/tktview/e4598ecbdd18bd82945f602901
     # The sz=N parameter in the sqlite_stat1 table needs to have a value of
     # 2 or more to avoid a division by zero in the query planner.
     #
    diff --git a/test/analyzer1.test b/test/analyzer1.test
    index 51b5f8b6af..1f0b0f6376 100644
    --- a/test/analyzer1.test
    +++ b/test/analyzer1.test
    @@ -19,7 +19,7 @@ ifcapable !vtab {
       return
     }
     
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       set PROG "sqlite3_analyzer.exe"
     } else {
       set PROG "./sqlite3_analyzer"
    diff --git a/test/attach.test b/test/attach.test
    index 557201d654..3445c43fa7 100644
    --- a/test/attach.test
    +++ b/test/attach.test
    @@ -759,7 +759,7 @@ do_test attach-6.1 {
         ATTACH DATABASE 'no-such-file' AS nosuch;
       }
     } {0 {}}
    -if {$tcl_platform(platform)=="unix"} {
    +if {$tcl_platform(platform) eq "unix"} {
       do_test attach-6.2 {
         sqlite3 dbx cannot-read
         dbx eval {CREATE TABLE t1(a,b,c)}
    diff --git a/test/autoinc.test b/test/autoinc.test
    index 2c7ee2a7e8..9f869f35ea 100644
    --- a/test/autoinc.test
    +++ b/test/autoinc.test
    @@ -669,7 +669,7 @@ ifcapable trigger {
       } {1 124 2 10123}
     }
     
    -# 2016-10-03 ticket https://www.sqlite.org/src/tktview/7b3328086a5c1
    +# 2016-10-03 ticket https://sqlite.org/src/tktview/7b3328086a5c1
     # Make sure autoincrement plays nicely with the xfer optimization
     #
     do_execsql_test autoinc-10.1 {
    diff --git a/test/autoindex5.test b/test/autoindex5.test
    index aa8dec27d9..adfc3e5f76 100644
    --- a/test/autoindex5.test
    +++ b/test/autoindex5.test
    @@ -142,7 +142,7 @@ do_catchsql_test 2.2 {
       );
     } {0 9}
     
    -# Ticket https://www.sqlite.org/src/info/787fa716be3a7f65
    +# Ticket https://sqlite.org/src/info/787fa716be3a7f65
     # Segfault due to multiple uses of the same subquery where the
     # subquery is implemented via coroutine.
     #
    diff --git a/test/avtrans.test b/test/avtrans.test
    index 6fc4a3e393..b483c71a44 100644
    --- a/test/avtrans.test
    +++ b/test/avtrans.test
    @@ -903,7 +903,7 @@ for {set i 2} {$i<=$limit} {incr i} {
              INSERT INTO t3 SELECT randstr(10,400) FROM t3 WHERE random()%10==0;
            }
         } {}
    -    if {$tcl_platform(platform)=="unix"} {
    +    if {$tcl_platform(platform) eq "unix"} {
           do_test avtrans-9.$i.4-$cnt {
              expr {$sqlite_sync_count>0}
           } 1
    diff --git a/test/backup2.test b/test/backup2.test
    index 1822e2dbf0..095ecc752d 100644
    --- a/test/backup2.test
    +++ b/test/backup2.test
    @@ -141,7 +141,7 @@ do_test backup2-9 {
     
     # Try to restore from an unreadable file.
     #
    -if {$tcl_platform(platform)=="windows"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       set msg {cannot open source database: unable to open database file}
     } elseif {[string match *BSD $tcl_platform(os)]} {
       set msg {}
    diff --git a/test/bc_common.tcl b/test/bc_common.tcl
    index c47f99681f..953ce62621 100644
    --- a/test/bc_common.tcl
    +++ b/test/bc_common.tcl
    @@ -9,7 +9,7 @@ proc bc_find_binaries {zCaption} {
       set binaries [list]
       set self [info nameofexec]
       set pattern "$self?*"
    -  if {$::tcl_platform(platform)=="windows"} {
    +  if {$::tcl_platform(platform) eq "windows"} {
         set pattern [string map {\.exe {}} $pattern]
       }
       foreach file [glob -nocomplain $pattern] {
    diff --git a/test/btree01.test b/test/btree01.test
    index 6e4717ae65..b1909a3adb 100644
    --- a/test/btree01.test
    +++ b/test/btree01.test
    @@ -17,7 +17,7 @@ source $testdir/tester.tcl
     set testprefix btree01
     
     # The refactoring on the b-tree balance() routine in check-in
    -# http://www.sqlite.org/src/info/face33bea1ba3a (2014-10-27)
    +# http://sqlite.org/src/info/face33bea1ba3a (2014-10-27)
     # caused the integrity_check on the following SQL to fail.
     #
     do_execsql_test btree01-1.1 {
    diff --git a/test/cast.test b/test/cast.test
    index 1c9071d775..c1b564328a 100644
    --- a/test/cast.test
    +++ b/test/cast.test
    @@ -385,7 +385,7 @@ do_execsql_test cast-6.1 {
     } {9000000000000000001 9000000000000000001 9000000000000000001 9000000000000000001}
     
     # 2019-06-07
    -# https://www.sqlite.org/src/info/4c2d7639f076aa7c
    +# https://sqlite.org/src/info/4c2d7639f076aa7c
     do_execsql_test cast-7.1 {
       SELECT CAST('-' AS NUMERIC);
     } {0}
    @@ -400,7 +400,7 @@ do_execsql_test cast-7.4 {
     } {0}
     
     # 2019-06-07
    -# https://www.sqlite.org/src/info/e8bedb2a184001bb
    +# https://sqlite.org/src/info/e8bedb2a184001bb
     do_execsql_test cast-7.10 {
       SELECT '' - 2851427734582196970;
     } {-2851427734582196970}
    @@ -412,7 +412,7 @@ do_execsql_test cast-7.12 {
     } {-1}
     
     # 2019-06-10
    -# https://www.sqlite.org/src/info/dd6bffbfb6e61db9
    +# https://sqlite.org/src/info/dd6bffbfb6e61db9
     #
     # EVIDENCE-OF: R-55084-10555 Casting a TEXT or BLOB value into NUMERIC
     # yields either an INTEGER or a REAL result.
    @@ -441,7 +441,7 @@ do_execsql_test cast-7.33 {
     } 0
     
     # 2019-06-12
    -# https://www.sqlite.org/src/info/674385aeba91c774
    +# https://sqlite.org/src/info/674385aeba91c774
     #
     do_execsql_test cast-7.40 {
       SELECT CAST('-0.0' AS numeric);
    diff --git a/test/chunksize.test b/test/chunksize.test
    index 47d118d841..be3795fc5c 100644
    --- a/test/chunksize.test
    +++ b/test/chunksize.test
    @@ -14,7 +14,7 @@ set testdir [file dirname $argv0]
     source $testdir/tester.tcl
     set testprefix chunksize
     
    -if {$::tcl_platform(platform)!="unix"} {
    +if {$::tcl_platform(platform) ne "unix"} {
       finish_test
       return
     }
    diff --git a/test/colname.test b/test/colname.test
    index 24fb51acfc..0907df641e 100644
    --- a/test/colname.test
    +++ b/test/colname.test
    @@ -378,7 +378,7 @@ do_test colname-9.210 {
       execsql2 {SELECT t1.a, v3.a AS n FROM t1 JOIN v3}
     } {a 1 n 3}
     
    -# 2017-12-23:  Ticket https://www.sqlite.org/src/info/3b4450072511e621
    +# 2017-12-23:  Ticket https://sqlite.org/src/info/3b4450072511e621
     # Inconsistent column names in CREATE TABLE AS
     #
     # Verify that the names of columns in the created table of a CREATE TABLE AS
    diff --git a/test/conflict.test b/test/conflict.test
    index ba3ad9b0dd..54c01d36de 100644
    --- a/test/conflict.test
    +++ b/test/conflict.test
    @@ -824,7 +824,7 @@ do_test conflict-13.2 {
     } {1 3}
     
     
    -# Ticket https://www.sqlite.org/src/tktview/e6f1f2e34dceeb1ed61531c7e9
    +# Ticket https://sqlite.org/src/tktview/e6f1f2e34dceeb1ed61531c7e9
     # Verify that it is not possible to sneak a NULL value into a NOT NULL
     # column using REPLACE.
     #
    diff --git a/test/crash8.test b/test/crash8.test
    index c07829979f..b2b01183fd 100644
    --- a/test/crash8.test
    +++ b/test/crash8.test
    @@ -356,7 +356,7 @@ ifcapable pragma {
     # is not created on F2FS file-systems that support atomic
     # write. So do not run these tests in that case either.
     #
    -if {$::tcl_platform(platform)=="unix" && [atomic_batch_write test.db]==0 } {
    +if {$::tcl_platform(os) ne "Windows NT" && [atomic_batch_write test.db]==0 } {
       for {set i 1} {$i < 10} {incr i} {
         catch { db close }
         forcedelete test.db test.db-journal
    diff --git a/test/date.test b/test/date.test
    index 2042880a92..8badccf3fb 100644
    --- a/test/date.test
    +++ b/test/date.test
    @@ -584,7 +584,7 @@ datetest 16.30 {datetime(5373484,'-14712 years')} {-4713-12-31 12:00:00}
     datetest 16.31 {datetime(5373484,'-14713 years')} NULL
     
     # 2017-03-02: Wrong 'start of day' computation.
    -# https://www.sqlite.org/src/info/6097cb92745327a1
    +# https://sqlite.org/src/info/6097cb92745327a1
     #
     datetest 17.1 {datetime(2457754, 'start of day')} {2016-12-31 00:00:00}
     datetest 17.2 {datetime(2457828)} {2017-03-15 12:00:00}
    diff --git a/test/delete4.test b/test/delete4.test
    index 8d6a1b8c7c..34151446b1 100644
    --- a/test/delete4.test
    +++ b/test/delete4.test
    @@ -170,7 +170,7 @@ do_execsql_test 5.0 {
     } {}
     
     # 2016-05-02
    -# Ticket https://www.sqlite.org/src/tktview/dc6ebeda93960877
    +# Ticket https://sqlite.org/src/tktview/dc6ebeda93960877
     # A subquery in the WHERE clause of a one-pass DELETE can cause an
     # incorrect answer.
     #
    diff --git a/test/expr.test b/test/expr.test
    index 55b1dc9502..71518df690 100644
    --- a/test/expr.test
    +++ b/test/expr.test
    @@ -1002,7 +1002,7 @@ do_execsql_test expr-13.9 {
       SELECT '' <= "";
     } {1}
     
    -# 2018-02-26. Ticket https://www.sqlite.org/src/tktview/36fae083b450e3af85
    +# 2018-02-26. Ticket https://sqlite.org/src/tktview/36fae083b450e3af85
     # 
     do_execsql_test expr-14.1 {
       DROP TABLE IF EXISTS t1;
    diff --git a/test/extension01.test b/test/extension01.test
    index 97b772680e..ba8a44edb5 100644
    --- a/test/extension01.test
    +++ b/test/extension01.test
    @@ -60,7 +60,7 @@ do_test 1.5 {
     } {0}
     
     do_test 1.6 {
    -  if {$::tcl_platform(platform)=="unix"} {
    +  if {$::tcl_platform(os) ne "Windows NT"} {
         file attributes ./file2.txt -permissions r--r--r--
       } else {
         file attributes ./file2.txt -readonly 1
    @@ -70,7 +70,7 @@ do_test 1.6 {
       }
     } {nil}
     do_test 1.7 {
    -  if {$::tcl_platform(platform)=="unix"} {
    +  if {$::tcl_platform(os) ne "Windows NT"} {
         file attributes ./file2.txt -permissions rw-r--r--
       } else {
         file attributes ./file2.txt -readonly 0
    diff --git a/test/external_reader.test b/test/external_reader.test
    index 5d293981c5..d56aa4e261 100644
    --- a/test/external_reader.test
    +++ b/test/external_reader.test
    @@ -19,7 +19,7 @@ ifcapable !wal {
       finish_test 
       return 
     }
    -if {$::tcl_platform(platform)!="unix"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       finish_test 
       return
     }
    diff --git a/test/filectrl.test b/test/filectrl.test
    index fee29e0442..9b1a1c7589 100644
    --- a/test/filectrl.test
    +++ b/test/filectrl.test
    @@ -47,7 +47,7 @@ db close
     forcedelete .test_control_lockproxy.db-conch test.proxy
     forcedelete test.db test2.db
     
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       do_test filectrl-2.1 {
         sqlite3 db test2.db
         set size [file size test2.db]
    diff --git a/test/func.test b/test/func.test
    index 85c9ada7eb..4e5f617e74 100644
    --- a/test/func.test
    +++ b/test/func.test
    @@ -1241,7 +1241,7 @@ do_test func-24.12 {
                               WHEN 'program' THEN null ELSE t1 END) FROM tbl1
       }
     } {,is,free,software}
    -# Tests to verify ticket http://www.sqlite.org/src/tktview/55746f9e65f8587c0
    +# Tests to verify ticket http://sqlite.org/src/tktview/55746f9e65f8587c0
     do_test func-24.13 {
       execsql {
         SELECT typeof(group_concat(x)) FROM (SELECT '' AS x);
    diff --git a/test/func3.test b/test/func3.test
    index 0221a0dfd6..518bd51c79 100644
    --- a/test/func3.test
    +++ b/test/func3.test
    @@ -154,7 +154,7 @@ do_test func3-5.39 {
     } [db eval {EXPLAIN SELECT min(1.0+'2.0',4*11)}]
     
     # Unlikely() does not preserve the affinity of X.
    -# ticket https://www.sqlite.org/src/tktview/0c620df60b
    +# ticket https://sqlite.org/src/tktview/0c620df60b
     #
     do_execsql_test func3-5.40 {
       SELECT likely(CAST(1 AS INT))=='1';
    diff --git a/test/gencol1.test b/test/gencol1.test
    index ed7ea567d4..a247a7148d 100644
    --- a/test/gencol1.test
    +++ b/test/gencol1.test
    @@ -211,9 +211,9 @@ do_catchsql_test gencol1-6.10 {
       REPLACE INTO t0(c1) VALUES(NULL);
     } {1 {NOT NULL constraint failed: t0.c0}}
     
    -# 2019-11-06 ticket https://www.sqlite.org/src/info/2399f5986134f79c
    -# 2019-12-27 ticket https://www.sqlite.org/src/info/5fbc159eeb092130
    -# 2019-12-27 ticket https://www.sqlite.org/src/info/37823501c68a09f9
    +# 2019-11-06 ticket https://sqlite.org/src/info/2399f5986134f79c
    +# 2019-12-27 ticket https://sqlite.org/src/info/5fbc159eeb092130
    +# 2019-12-27 ticket https://sqlite.org/src/info/37823501c68a09f9
     #
     # All of the above tickets deal with NOT NULL ON CONFLICT REPLACE
     # constraints on tables that have generated columns.
    diff --git a/test/in.test b/test/in.test
    index 601c7e3b4d..67fdd4f555 100644
    --- a/test/in.test
    +++ b/test/in.test
    @@ -652,7 +652,7 @@ do_execsql_test in-14.1 {
       SELECT * FROM c1 WHERE a IN (SELECT a FROM c1) ORDER BY 1
     } {1 2 3 4}
     
    -# 2019-02-20 Ticket https://www.sqlite.org/src/tktview/df46dfb631f75694fbb97033b69
    +# 2019-02-20 Ticket https://sqlite.org/src/tktview/df46dfb631f75694fbb97033b69
     #
     do_execsql_test in-15.0 {
       DROP TABLE IF EXISTS t1;
    @@ -736,7 +736,7 @@ do_execsql_test in-16.2 {
     } {}
     
     # 2019-06-11
    -# https://www.sqlite.org/src/info/57353f8243c637c0
    +# https://sqlite.org/src/info/57353f8243c637c0
     #
     do_execsql_test in-17.1 {
       SELECT 1 IN ('1');
    @@ -760,7 +760,7 @@ do_execsql_test in-18.1 {
       SELECT * FROM t0 WHERE '1' IN (t0.c0);
     } {}
     
    -# 2019-09-02 ticket https://www.sqlite.org/src/info/2841e99d104c6436
    +# 2019-09-02 ticket https://sqlite.org/src/info/2841e99d104c6436
     # For the IN_INDEX_NOOP optimization, apply REAL affinity to the LHS
     # values prior to comparison if the RHS has REAL affinity.
     #
    diff --git a/test/index.test b/test/index.test
    index 11d3d7191c..25ff41762d 100644
    --- a/test/index.test
    +++ b/test/index.test
    @@ -738,7 +738,7 @@ do_test index-21.2 {
       }
     } {0 {9 5 1}}
     
    -# 2019-05-01 ticket https://www.sqlite.org/src/info/3be1295b264be2fa
    +# 2019-05-01 ticket https://sqlite.org/src/info/3be1295b264be2fa
     do_execsql_test index-22.0 {
       DROP TABLE IF EXISTS t1;
       CREATE TABLE t1(a, b TEXT);
    @@ -748,7 +748,7 @@ do_execsql_test index-22.0 {
       SELECT a, b, '|' FROM t1;
     } {a 1 | a 0 |}
     
    -# 2019-05-10 ticket https://www.sqlite.org/src/info/ae0f637bddc5290b
    +# 2019-05-10 ticket https://sqlite.org/src/info/ae0f637bddc5290b
     do_execsql_test index-23.0 {
       DROP TABLE t1;
       CREATE TABLE t1(a TEXT, b REAL);
    diff --git a/test/index6.test b/test/index6.test
    index 16370f521d..007823a283 100644
    --- a/test/index6.test
    +++ b/test/index6.test
    @@ -391,7 +391,7 @@ do_execsql_test index6-11.2 {
     } {/USING INDEX t11x/}
     
     # 2018-12-08
    -# Ticket https://www.sqlite.org/src/info/1d958d90596593a7
    +# Ticket https://sqlite.org/src/info/1d958d90596593a7
     # NOT IN operator fails when using a partial index.
     #
     do_execsql_test index6-12.1 {
    @@ -412,7 +412,7 @@ do_execsql_test index6-12.2 {
     } {1 2}
     
     # 2019-05-04
    -# Ticket https://www.sqlite.org/src/tktview/5c6955204c392ae763a95
    +# Ticket https://sqlite.org/src/tktview/5c6955204c392ae763a95
     # Theorem prover error
     #
     do_execsql_test index6-13.1 {
    @@ -438,8 +438,8 @@ do_execsql_test index6-14.2 {
     } {{} row}
     
     # 2019-08-30
    -# Ticket https://www.sqlite.org/src/info/a6408d42b9f44462
    -# Ticket https://www.sqlite.org/src/info/fba33c8b1df6a915
    +# Ticket https://sqlite.org/src/info/a6408d42b9f44462
    +# Ticket https://sqlite.org/src/info/fba33c8b1df6a915
     # https://sqlite.org/src/info/bac716244fddac1fe841
     #
     do_execsql_test index6-15.1 {
    diff --git a/test/indexexpr1.test b/test/indexexpr1.test
    index d5c47e403e..ca6682cda7 100644
    --- a/test/indexexpr1.test
    +++ b/test/indexexpr1.test
    @@ -330,7 +330,7 @@ do_execsql_test indexexpr1-1010 {
     # 2016-10-10
     # Make sure indexes on expressions skip over initial NULL values in the
     # index as they are suppose to do.
    -# Ticket https://www.sqlite.org/src/tktview/4baa46491212947
    +# Ticket https://sqlite.org/src/tktview/4baa46491212947
     #
     do_execsql_test indexexpr1-1100 {
       DROP TABLE IF EXISTS t1;
    @@ -374,7 +374,7 @@ do_execsql_test indexexpr1-1200.4 {
       0 0 0 2 0 4 2 0 2 2 4 0
     }
     
    -# Ticket https://www.sqlite.org/src/tktview/eb703ba7b50c1a
    +# Ticket https://sqlite.org/src/tktview/eb703ba7b50c1a
     # Incorrect result using an index on an expression with a collating function
     #
     do_execsql_test indexexpr1-1300.1 {
    @@ -429,7 +429,7 @@ do_execsql_test indexexpr1-1510 {
       REPLACE INTO t1 SELECT a, randomblob(a) FROM t1
     } {}
     
    -# 2018-01-31 https://www.sqlite.org/src/tktview/343634942dd54ab57b702411
    +# 2018-01-31 https://sqlite.org/src/tktview/343634942dd54ab57b702411
     # When an index on an expression depends on the string representation of
     # a numeric table column, trouble can arise since there are multiple
     # string that can map to the same numeric value.  (Ex: 123, 0123, 000123).
    @@ -449,7 +449,7 @@ do_execsql_test indexexpr1-1620 {
       SELECT b FROM t1 WHERE lower(a)='01234' ORDER BY +b;
     } {}
     
    -# 2019-08-09 https://www.sqlite.org/src/info/9080b6227fabb466
    +# 2019-08-09 https://sqlite.org/src/info/9080b6227fabb466
     # ExprImpliesExpr theorem prover bug:
     # "(NULL IS FALSE) IS FALSE" does not imply "NULL IS NULL"
     #
    @@ -461,7 +461,7 @@ do_execsql_test indexexpr1-1700 {
       SELECT * FROM t0 WHERE ((NULL IS FALSE) IS FALSE);
     } {0}
     
    -# 2019-09-02 https://www.sqlite.org/src/tktview/57af00b6642ecd6848
    +# 2019-09-02 https://sqlite.org/src/tktview/57af00b6642ecd6848
     # When the expression of an an index-on-expression references a
     # table column of type REAL that is actually holding an MEM_IntReal
     # value, be sure to use the REAL value and not the INT value when
    diff --git a/test/insert.test b/test/insert.test
    index 51e62268db..fd08eb43b8 100644
    --- a/test/insert.test
    +++ b/test/insert.test
    @@ -413,7 +413,7 @@ do_execsql_test insert-11.1 {
     
     
     # More columns of input than there are columns in the table.
    -# Ticket http://www.sqlite.org/src/info/e9654505cfda9361
    +# Ticket http://sqlite.org/src/info/e9654505cfda9361
     #
     do_execsql_test insert-12.1 {
       CREATE TABLE t12a(a,b,c,d,e,f,g);
    @@ -437,7 +437,7 @@ do_execsql_test insert-12.3 {
     # 2018-06-11.  From OSSFuzz.  A column cache malfunction in
     # the constraint checking on an index of expressions causes
     # an assertion fault in a REPLACE.  Ticket
    -# https://www.sqlite.org/src/info/c2432ef9089ee73b
    +# https://sqlite.org/src/info/c2432ef9089ee73b
     #
     do_execsql_test insert-13.1 {
       DROP TABLE IF EXISTS t13;
    @@ -475,7 +475,7 @@ do_execsql_test insert-15.1 {
     } {4 33000}
     
     # 2019-10-16
    -# ticket https://www.sqlite.org/src/info/a8a4847a2d96f5de
    +# ticket https://sqlite.org/src/info/a8a4847a2d96f5de
     # On a REPLACE INTO, if an AFTER trigger adds back the conflicting
     # row, you can end up with the wrong number of rows in an index.
     #
    diff --git a/test/instr.test b/test/instr.test
    index d23d66c25c..326f8eb9ee 100644
    --- a/test/instr.test
    +++ b/test/instr.test
    @@ -257,7 +257,7 @@ do_execsql_test instr-1.64 {
       SELECT instr(a, b) FROM x1;
     } 0
     
    -# 2019-09-16 ticket https://www.sqlite.org/src/info/587791f92620090e
    +# 2019-09-16 ticket https://sqlite.org/src/info/587791f92620090e
     #
     do_execsql_test instr-2.0 {
       DROP TABLE IF EXISTS t0;
    diff --git a/test/intpkey.test b/test/intpkey.test
    index d6b8833a27..a8d2fb2ffb 100644
    --- a/test/intpkey.test
    +++ b/test/intpkey.test
    @@ -604,7 +604,7 @@ do_test intpkey-15.7 {
       }
     } {}
     
    -# 2016-04-18 ticket https://www.sqlite.org/src/tktview/7d7525cb01b68712495d3a
    +# 2016-04-18 ticket https://sqlite.org/src/tktview/7d7525cb01b68712495d3a
     # Be sure to escape quoted typenames.
     #
     do_execsql_test intpkey-16.0 {
    @@ -614,7 +614,7 @@ do_execsql_test intpkey-16.1 {
       PRAGMA table_info=t16a;
     } {0 id INTEGER 0 {} 1 1 b TEXT 0 {} 0 2 c INT 0 {} 0}
     
    -# 2016-05-06 ticket https://www.sqlite.org/src/tktview/16c9801ceba4923939085
    +# 2016-05-06 ticket https://sqlite.org/src/tktview/16c9801ceba4923939085
     # When the schema contains an index on the IPK and no other index
     # and a WHERE clause on a delete uses an OR where both sides referencing
     # the IPK, then it is possible that the OP_Delete will fail because there
    diff --git a/test/io.test b/test/io.test
    index dfadcd1362..1dc84bdee0 100644
    --- a/test/io.test
    +++ b/test/io.test
    @@ -443,7 +443,7 @@ sqlite3_simulate_device -char safe_append
     # on the journal file between steps (2) and (3) above.
     #
     set expected_sync_count 2
    -if {$::tcl_platform(platform)=="unix"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
       ifcapable dirsync {
         incr expected_sync_count
       }
    @@ -465,7 +465,7 @@ do_test io-4.2.1 {
       execsql { INSERT INTO abc VALUES('c', 'd') }
       file exists test.db-journal
     } {1}
    -if {$::tcl_platform(platform)=="unix"} {
    +if {$::tcl_platform(platform) eq "unix"} {
       do_test io-4.2.2 {
         hexio_read test.db-journal 8 4
       } {FFFFFFFF}
    diff --git a/test/ioerr.test b/test/ioerr.test
    index fb54d8b384..c76c9c1e6f 100644
    --- a/test/ioerr.test
    +++ b/test/ioerr.test
    @@ -172,7 +172,7 @@ ifcapable crashtest&&attach {
     # These tests can't be run on windows because the windows version of 
     # SQLite holds a mandatory exclusive lock on journal files it has open.
     #
    -if {$tcl_platform(platform)!="windows" && ![atomic_batch_write test.db]} {
    +if {$tcl_platform(platform) ne"windows" && ![atomic_batch_write test.db]} {
       do_ioerr_test ioerr-7 -tclprep {
         db close
         sqlite3 db2 test2.db
    @@ -211,7 +211,7 @@ do_ioerr_test ioerr-8 -ckrefcount true -tclprep {
     
     # For test coverage: Cause an IO error whilst reading the master-journal
     # name from a journal file.
    -if {$tcl_platform(platform)=="unix" && [atomic_batch_write test.db]==0} {
    +if {$tcl_platform(platform) eq "unix" && [atomic_batch_write test.db]==0} {
       do_ioerr_test ioerr-9 -ckrefcount true -tclprep {
         execsql {
           CREATE TABLE t1(a,b,c);
    diff --git a/test/join.test b/test/join.test
    index aa526aeb29..b34136f5dd 100644
    --- a/test/join.test
    +++ b/test/join.test
    @@ -799,7 +799,7 @@ do_execsql_test join-14.9 {
     } {111 {}}
     
     # Verify the fix to ticket 
    -# https://www.sqlite.org/src/tktview/7fde638e94287d2c948cd9389
    +# https://sqlite.org/src/tktview/7fde638e94287d2c948cd9389
     #
     db close
     sqlite3 db :memory:
    @@ -819,7 +819,7 @@ do_execsql_test join-14.12 {
     } {4 {} {} | 2 2 1 |}
     
     # Verify the fix for ticket
    -# https://www.sqlite.org/src/info/892fc34f173e99d8
    +# https://sqlite.org/src/info/892fc34f173e99d8
     #
     db close
     sqlite3 db :memory:
    @@ -904,7 +904,7 @@ do_execsql_test join-15.110 {
        ORDER BY a1, a2, a3, a4, a5;
     } {1 {} {} {} {} 1 11 {} {} {} 1 12 {} {} {} 1 12 121 {} {} 1 13 {} {} {}}
     
    -# 2019-02-05 Ticket https://www.sqlite.org/src/tktview/5948e09b8c415bc45da5c
    +# 2019-02-05 Ticket https://sqlite.org/src/tktview/5948e09b8c415bc45da5c
     # Error in join due to the LEFT JOIN strength reduction optimization.
     #
     do_execsql_test join-16.100 {
    diff --git a/test/join5.test b/test/join5.test
    index 703c256f86..eb8ba3c7b5 100644
    --- a/test/join5.test
    +++ b/test/join5.test
    @@ -106,7 +106,7 @@ do_test join5-2.12 {
       execsql {SELECT * FROM xy LEFT JOIN ab ON NULL WHERE NULL}
     } {}
     
    -# Ticket https://www.sqlite.org/src/tktview/6f2222d550f5b0ee7ed37601
    +# Ticket https://sqlite.org/src/tktview/6f2222d550f5b0ee7ed37601
     # Incorrect output on a LEFT JOIN.
     #
     do_execsql_test join5-3.1 {
    @@ -161,7 +161,7 @@ do_execsql_test join5-3.3 {
       SELECT * FROM x1 LEFT JOIN x2 JOIN x3 WHERE x3.d = x2.b;
     } {}
     
    -# Ticket https://www.sqlite.org/src/tktview/c2a19d81652f40568c770c43 on
    +# Ticket https://sqlite.org/src/tktview/c2a19d81652f40568c770c43 on
     # 2015-08-20.  LEFT JOIN and the push-down optimization.
     #
     do_execsql_test join5-4.1 {
    diff --git a/test/journal1.test b/test/journal1.test
    index bcbafe30f6..56c862f055 100644
    --- a/test/journal1.test
    +++ b/test/journal1.test
    @@ -25,7 +25,7 @@ source $testdir/tester.tcl
     # Or with atomic_batch_write systems, as journal files are
     # not created.
     #
    -if {$tcl_platform(platform)=="windows"
    +if {$tcl_platform(platform) eq "windows"
      || [atomic_batch_write test.db]
     } {
       finish_test
    diff --git a/test/journal3.test b/test/journal3.test
    index c3e3d12db6..a29b68d54a 100644
    --- a/test/journal3.test
    +++ b/test/journal3.test
    @@ -20,7 +20,7 @@ source $testdir/malloc_common.tcl
     # If a connection is required to create a journal file, it creates it with 
     # the same file-system permissions as the database file itself. Test this.
     #
    -if {$::tcl_platform(platform) == "unix"
    +if {$::tcl_platform(os) ne "Windows NT"
      && [atomic_batch_write test.db]==0
     } {
     
    diff --git a/test/json101.test b/test/json101.test
    index 3963ffbb6b..aec959acb2 100644
    --- a/test/json101.test
    +++ b/test/json101.test
    @@ -444,7 +444,7 @@ foreach {tn isvalid ws} {
       $isvalid
     }
     
    -# Ticket https://www.sqlite.org/src/info/ad2559db380abf8e
    +# Ticket https://sqlite.org/src/info/ad2559db380abf8e
     # Control characters must be escaped in JSON strings.
     #
     do_execsql_test json101-8.1 {
    @@ -807,7 +807,7 @@ do_execsql_test json101-10.95 {
     } {0}
     
     #--------------------------------------------------------------------------
    -# 2017-04-11.  https://www.sqlite.org/src/info/981329adeef51011
    +# 2017-04-11.  https://sqlite.org/src/info/981329adeef51011
     # Stack overflow on deeply nested JSON.
     #
     # The following tests confirm that deeply nested JSON is considered invalid.
    @@ -878,7 +878,7 @@ do_execsql_test json101-12.120b {
     } {0}
     
     # 2018-01-26
    -# ticket https://www.sqlite.org/src/tktview/80177f0c226ff54f6ddd41
    +# ticket https://sqlite.org/src/tktview/80177f0c226ff54f6ddd41
     # Make sure the query planner knows about the arguments to table-valued functions.
     #
     do_execsql_test json101-13.100 {
    diff --git a/test/json103.test b/test/json103.test
    index e7483073b6..f94217ac10 100644
    --- a/test/json103.test
    +++ b/test/json103.test
    @@ -55,7 +55,7 @@ do_execsql_test json103-220 {
        WHERE rowid<7 GROUP BY b ORDER BY b;
     } {0 {{"n3":3,"n6":6}} 1 {{"n1":1,"n4":4}} 2 {{"n2":2,"n5":5}}}
     
    -# ticket https://www.sqlite.org/src/info/f45ac567eaa9f93c 2016-01-30
    +# ticket https://sqlite.org/src/info/f45ac567eaa9f93c 2016-01-30
     # Invalid JSON generated by json_group_array() 
     #
     # The underlying problem is a failure to reset Mem.eSubtype
    diff --git a/test/like.test b/test/like.test
    index 0d732b569c..1f9a810e5d 100644
    --- a/test/like.test
    +++ b/test/like.test
    @@ -1013,7 +1013,7 @@ do_execsql_test like-12.16 {
       SELECT id FROM t12b WHERE x LIKE 'abc%' COLLATE binary ORDER BY +id;
     } {/SCAN/}
     
    -# Ticket [https://www.sqlite.org/src/tktview/80369eddd5c94d49f7fbbcf5]
    +# Ticket [https://sqlite.org/src/tktview/80369eddd5c94d49f7fbbcf5]
     # 2016-01-20
     #
     do_execsql_test like-13.1 {
    diff --git a/test/like3.test b/test/like3.test
    index 01d19a54f6..03681606c3 100644
    --- a/test/like3.test
    +++ b/test/like3.test
    @@ -112,7 +112,7 @@ do_execsql_test like3-4.2ck {
       SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY +x ASC;
     } {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'}
     
    -# 2018-09-10 ticket https://www.sqlite.org/src/tktview/c94369cae9b561b1f996
    +# 2018-09-10 ticket https://sqlite.org/src/tktview/c94369cae9b561b1f996
     # The like optimization fails for a column with numeric affinity if
     # the pattern '/%' or begins with the escape character.
     #
    @@ -199,7 +199,7 @@ do_execsql_test like3-5.400 {
     } {./}
     
     # 2019-06-14
    -# Ticket https://www.sqlite.org/src/info/ce8717f0885af975
    +# Ticket https://sqlite.org/src/info/ce8717f0885af975
     do_execsql_test like3-5.410 {
       DROP TABLE IF EXISTS t0;
       CREATE TABLE t0(c0 INT UNIQUE COLLATE NOCASE);
    @@ -208,7 +208,7 @@ do_execsql_test like3-5.410 {
     } {.1%}
     
     # 2019-09-03
    -# Ticket https://www.sqlite.org/src/info/0f0428096f
    +# Ticket https://sqlite.org/src/info/0f0428096f
     do_execsql_test like3-5.420 {
       DROP TABLE IF EXISTS t0;
       CREATE TABLE t0(c0 UNIQUE);
    diff --git a/test/limit2.test b/test/limit2.test
    index c03f39cd9c..2ecd8ab5f5 100644
    --- a/test/limit2.test
    +++ b/test/limit2.test
    @@ -98,7 +98,7 @@ do_execsql_test limit2-210 {
     } {1 1 {} {} | 3 3 {} {} | 4 4 {} {} |}
     
     # Bug in the ORDER BY LIMIT optimization reported on 2016-09-06.
    -# Ticket https://www.sqlite.org/src/info/559733b09e96
    +# Ticket https://sqlite.org/src/info/559733b09e96
     #
     do_execsql_test limit2-300 {
       CREATE TABLE t300(a,b,c);
    @@ -150,11 +150,11 @@ do_execsql_test 502 {
       SELECT j FROM t502 WHERE i IN (1,2,3,4,5) ORDER BY j LIMIT 3;
     } {1 3 4}
     
    -# Ticket https://www.sqlite.org/src/info/123c9ba32130a6c9 2017-12-13
    +# Ticket https://sqlite.org/src/info/123c9ba32130a6c9 2017-12-13
     # Incorrect result when an idnex is used for an ordered join.
     #
     # This test case is in the limit2.test module because the problem was first
    -# exposed by check-in https://www.sqlite.org/src/info/559733b09e which 
    +# exposed by check-in https://sqlite.org/src/info/559733b09e which 
     # implemented the ORDER BY LIMIT optimization that limit2.test strives to
     # test.
     #
    @@ -167,7 +167,7 @@ do_execsql_test 600 {
       SELECT y FROM t1, t2 WHERE a=x AND b<=y ORDER BY b DESC;
     } {3}
     
    -# Ticket https://www.sqlite.org/src/info/9936b2fa443fec03 2018-09-08
    +# Ticket https://sqlite.org/src/info/9936b2fa443fec03 2018-09-08
     # Infinite loop due to the ORDER BY LIMIT optimization.
     #
     do_execsql_test 700 {
    diff --git a/test/loadext.test b/test/loadext.test
    index 6da8a52894..e95d5f6eb8 100644
    --- a/test/loadext.test
    +++ b/test/loadext.test
    @@ -66,9 +66,13 @@ if {$::tcl_platform(os) eq "Darwin"} {
       set dlerror_nosymbol   {dlsym.XXX, %2$s.: symbol not found}
     }
     
    -if {$::tcl_platform(platform) eq "windows"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       set dlerror_nosuchfile {The specified module could not be found.*}
    -  set dlerror_notadll    {%%1 is not a valid Win32 application.*}
    +  if {$::tcl_platform(platform) eq "unix"} {
    +    set dlerror_notadll    $dlerror_nosuchfile
    +  } else {
    +    set dlerror_notadll    {%%1 is not a valid Win32 application.*}
    +  }
       set dlerror_nosymbol   {The specified procedure could not be found.*}
     }
     
    diff --git a/test/lock.test b/test/lock.test
    index cacb6d3ff1..3f4631a623 100644
    --- a/test/lock.test
    +++ b/test/lock.test
    @@ -145,7 +145,7 @@ do_test lock-1.21 {
     # connections, because UNIX supports reader/writer locks.  Under windows,
     # this is not possible.
     #
    -if {$::tcl_platform(platform)=="unix"} {
    +if {$::tcl_platform(platform) eq "unix"} {
       do_test lock-1.22 {
         db eval {SELECT * FROM t1} qv {
           set r [catch {db2 eval {SELECT a FROM t1}} msg]
    diff --git a/test/malloc.test b/test/malloc.test
    index 5e82e8028b..e53bfcd192 100644
    --- a/test/malloc.test
    +++ b/test/malloc.test
    @@ -329,7 +329,7 @@ ifcapable crashtest&&attach {
       }
     }
     
    -if {$tcl_platform(platform)!="windows" && [atomic_batch_write test.db]==0} {
    +if {$tcl_platform(platform) ne "windows" && [atomic_batch_write test.db]==0} {
       do_malloc_test 14 -tclprep {
         catch {db close}
         sqlite3 db2 test2.db
    diff --git a/test/minmax.test b/test/minmax.test
    index 81bd46dbe2..232ac14a05 100644
    --- a/test/minmax.test
    +++ b/test/minmax.test
    @@ -633,7 +633,7 @@ do_test_13_noopt 13.7 {
       SELECT min(c), count(c) FROM t1 WHERE a='a';
     } {1 5}
     
    -# 2016-07-26.  https://www.sqlite.org/src/info/a0bac8b3c3d1bb75
    +# 2016-07-26.  https://sqlite.org/src/info/a0bac8b3c3d1bb75
     # Incorrect result on a min() query after a CREATE INDEX.
     #
     do_execsql_test 14.1 {
    diff --git a/test/misc7.test b/test/misc7.test
    index add9014b08..f4ef2d2103 100644
    --- a/test/misc7.test
    +++ b/test/misc7.test
    @@ -100,7 +100,7 @@ proc do_fileopen_test {prefix sql} {
     execsql { CREATE TABLE abc(a PRIMARY KEY, b, c); }
     db close
     
    -if {$tcl_platform(platform)!="windows"} {
    +if {$tcl_platform(platform) ne "windows"} {
       do_fileopen_test misc7-6.1 {
         BEGIN;
         INSERT INTO abc VALUES(1, 2, 3);
    @@ -390,7 +390,7 @@ do_test misc7-16.X {
     # These tests do not work on windows due to restrictions in the
     # windows file system.
     #
    -if {$tcl_platform(platform)!="windows"} {
    +if {$tcl_platform(platform) ne "windows"} {
     
       # Some network filesystems (ex: AFP) do not support setting read-only
       # permissions.  Only run these tests if full unix permission setting
    @@ -534,7 +534,7 @@ do_test misc7-22.4 {
     catch { db close }
     forcedelete test.db
     
    -if {$::tcl_platform(platform)=="unix"
    +if {$::tcl_platform(platform) eq "unix"
      && [atomic_batch_write test.db]==0
     } {
       reset_db
    diff --git a/test/mmap2.test b/test/mmap2.test
    index 1f8346b915..df96671dfb 100644
    --- a/test/mmap2.test
    +++ b/test/mmap2.test
    @@ -21,10 +21,10 @@ set testdir [file dirname $argv0]
     source $testdir/tester.tcl
     set testprefix mmap2
     
    -if {$::tcl_platform(platform)!="unix" || [test_syscall defaultvfs] != "unix"} {
    +if {[llength [info commands test_syscall]]==0} {
       finish_test
       return
    -}
    +} 
     ifcapable !mmap {
       finish_test
       return
    diff --git a/test/nockpt.test b/test/nockpt.test
    index 4cc61d11e1..f5d11732be 100644
    --- a/test/nockpt.test
    +++ b/test/nockpt.test
    @@ -61,7 +61,7 @@ do_test 1.14 { sqlite3_db_config db NO_CKPT_ON_CLOSE 1 } {1}
     do_execsql_test 1.14 { PRAGMA main.journal_mode = delete } {delete}
     do_test 1.15 { file exists test.db-wal } {0}
     
    -if {$::tcl_platform(platform)!="windows"} {
    +if {$::tcl_platform(platform) ne "windows"} {
     #-------------------------------------------------------------------------
     # Test an unusual scenario:
     #
    @@ -102,7 +102,9 @@ sqlite3_close_v2 $::db1
     
     # Delete the database, wal and shm files.
     #
    -forcedelete test.db test.db-wal test.db-shm
    +catch {forcedelete test.db}
    +catch {forcedelete test.db-wal}
    +catch {forcedelete  test.db-shm}
     
     # Open and populate a new database file at the same file-system location
     # as the one just deleted. Contrive a partial checkpoint on it.
    diff --git a/test/orderby1.test b/test/orderby1.test
    index 41444a44c3..73eda83992 100644
    --- a/test/orderby1.test
    +++ b/test/orderby1.test
    @@ -536,7 +536,7 @@ do_test 8.3 {
     } 5000
     
     #---------------------------------------------------------------------------
    -# https://www.sqlite.org/src/tktview/cb3aa0641d9a413841c004293a4fc06cdc122029
    +# https://sqlite.org/src/tktview/cb3aa0641d9a413841c004293a4fc06cdc122029
     #
     # Adverse interaction between scalar subqueries and the partial-sorting
     # logic.
    diff --git a/test/orderby3.test b/test/orderby3.test
    index f005f0d2e8..09e9156d0f 100644
    --- a/test/orderby3.test
    +++ b/test/orderby3.test
    @@ -11,7 +11,7 @@
     # This file implements regression tests for SQLite library.  The
     # focus of this file is testing that the optimizations that disable
     # ORDER BY clauses work correctly on a 3-way join.  See ticket
    -# http://www.sqlite.org/src/956e4d7f89
    +# http://sqlite.org/src/956e4d7f89
     #
     
     
    diff --git a/test/orderby4.test b/test/orderby4.test
    index ec6eb041f6..944a91f37d 100644
    --- a/test/orderby4.test
    +++ b/test/orderby4.test
    @@ -12,7 +12,7 @@
     # focus of this file is testing that the optimizations that disable
     # ORDER BY clauses work correctly on multi-value primary keys and
     # unique indices when only some prefix of the terms in the key are
    -# used.  See ticket http://www.sqlite.org/src/info/a179fe74659
    +# used.  See ticket http://sqlite.org/src/info/a179fe74659
     #
     
     
    diff --git a/test/oserror.test b/test/oserror.test
    index a51301cc52..43d72569d9 100644
    --- a/test/oserror.test
    +++ b/test/oserror.test
    @@ -16,7 +16,10 @@
     
     set testdir [file dirname $argv0]
     source $testdir/tester.tcl
    -if {$::tcl_platform(platform)!="unix"} { finish_test ; return }
    +if {[llength [info commands test_syscall]]==0} {
    +  finish_test
    +  return
    +} 
     set ::testprefix oserror
     
     db close
    diff --git a/test/pager1.test b/test/pager1.test
    index 79598e2a70..9a39e6f374 100644
    --- a/test/pager1.test
    +++ b/test/pager1.test
    @@ -454,7 +454,7 @@ do_test pager1.4.2.1 {
       tstvfs delete
     } {}
     
    -if {$::tcl_platform(platform)!="windows"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
     do_test pager1.4.2.2 {
       faultsim_restore_and_reopen
       execsql {
    @@ -567,7 +567,7 @@ foreach {tn1 tcl} {
         # make sure SQLite doesn't get confused by this.
         #
         set nPadding [expr 511 - $::mj_filename_length]
    -    if {$tcl_platform(platform)=="windows"} {
    +    if {$tcl_platform(platform) eq "windows"} {
           # TBD need to figure out how to do this correctly for Windows!!!
           set nPadding [expr 255 - $::mj_filename_length]
         }
    @@ -1714,7 +1714,7 @@ do_execsql_test pager1-13.1.1 {
       UPDATE t1 SET b = a_string(400);
     } {persist}
     
    -if {$::tcl_platform(platform)!="windows"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
     # Run transactions of increasing sizes. Eventually, one (or more than one)
     # of these will write just enough content that one of the old headers created 
     # by the transaction in the block above lies immediately after the content
    @@ -1739,7 +1739,7 @@ for {set nUp 1} {$nUp<64} {incr nUp} {
     }
     }
     
    -if {$::tcl_platform(platform)!="windows"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
     # Same test as above. But this time with an index on the table.
     #
     do_execsql_test pager1-13.2.1 {
    @@ -2538,7 +2538,7 @@ do_test pager1-30.1 {
     # file can still be rolled back. This is required for backward compatibility -
     # versions of SQLite prior to 3.5.8 always set this field to zero.
     #
    -if {$tcl_platform(platform)=="unix"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
     do_test pager1-31.1 {
       faultsim_delete_and_reopen
       execsql {
    @@ -2612,7 +2612,7 @@ forcedelete test.db
     # and the call to unlink() returns an ENOENT error, the COMMIT does not
     # succeed.
     #
    -if {$::tcl_platform(platform)=="unix"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
       do_test pager1-33.1 {
         sqlite3 db test.db
         execsql {
    diff --git a/test/pager4.test b/test/pager4.test
    index 2cf73d1b17..537f529dd3 100644
    --- a/test/pager4.test
    +++ b/test/pager4.test
    @@ -13,7 +13,7 @@
     # is unlinked or renamed out from under SQLite.
     #
     
    -if {$tcl_platform(platform)!="unix"} return
    +if {$tcl_platform(os) eq "Windows NT"} return
     
     set testdir [file dirname $argv0]
     source $testdir/tester.tcl
    diff --git a/test/pagerfault.test b/test/pagerfault.test
    index 3006dad7cc..6e82b90090 100644
    --- a/test/pagerfault.test
    +++ b/test/pagerfault.test
    @@ -20,7 +20,7 @@ if {[permutation] == "inmemory_journal"} {
       return
     }
     
    -if {$::tcl_platform(platform)=="windows"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       finish_test
       return
     }
    diff --git a/test/permutations.test b/test/permutations.test
    index 18e423f94e..50c41770ad 100644
    --- a/test/permutations.test
    +++ b/test/permutations.test
    @@ -104,7 +104,7 @@ foreach f [glob -nocomplain $testdir/../ext/session/*.test] {
     }
     unset f
     
    -if {$::tcl_platform(platform)!="unix"} {
    +if {$::tcl_platform(platform) ne "unix"} {
       set alltests [test_set $alltests -exclude crash.test crash2.test]
     }
     set alltests [test_set $alltests -exclude {
    diff --git a/test/pragma.test b/test/pragma.test
    index e823a67630..5249cc7c41 100644
    --- a/test/pragma.test
    +++ b/test/pragma.test
    @@ -1823,7 +1823,7 @@ do_test pragma-19.5 {
       file tail [lindex [execsql {PRAGMA filename}] 0]
     } {test.db}
     
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
     # Test data_store_directory pragma
     #
     db close
    diff --git a/test/quota.test b/test/quota.test
    index 5d0bda3ad3..f49600043e 100644
    --- a/test/quota.test
    +++ b/test/quota.test
    @@ -216,7 +216,7 @@ do_test quota-3.2.9 {
     set ::quota [list]
     proc quota_callback {file limitvar size} {
       upvar $limitvar limit
    -  if {$::tcl_platform(platform)=="windows"} {
    +  if {$::tcl_platform(platform) eq "windows"} {
         set file [ lindex [string map {\\ \/} $file] 0 ]
       }
       lappend ::quota $file $size
    @@ -351,7 +351,7 @@ do_test quota-4.3.1 {
     } {}
     
     unset -nocomplain quotagroup
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       set quotagroup *\\quota-test-A?.db
     } else {
       set quotagroup */quota-test-A?.db
    @@ -402,7 +402,7 @@ do_test quota-4.4.7 {
     } [expr {[file size quota-test-A1.db]+[file size quota-test-A2.db]}]
     
     unset -nocomplain quotagroup
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       set quotagroup *\\quota-test-B*
     } else {
       set quotagroup */quota-test-B*
    diff --git a/test/readonly.test b/test/readonly.test
    index 303300e6f1..00392266eb 100644
    --- a/test/readonly.test
    +++ b/test/readonly.test
    @@ -15,7 +15,7 @@
     
     set testdir [file dirname $argv0]
     source $testdir/tester.tcl
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       finish_test
       return
     }
    diff --git a/test/rowvalue.test b/test/rowvalue.test
    index 59b44d9386..e2688e9030 100644
    --- a/test/rowvalue.test
    +++ b/test/rowvalue.test
    @@ -255,7 +255,7 @@ do_catchsql_test 11.8 {
       SELECT * FROM t11 WHERE (a,a) IS NOT 1;
     } {1 {row value misused}}
     
    -# 2016-10-27: https://www.sqlite.org/src/tktview/fef4bb4bd9185ec8f
    +# 2016-10-27: https://sqlite.org/src/tktview/fef4bb4bd9185ec8f
     # Incorrect result from a LEFT JOIN with a row-value constraint
     #
     do_execsql_test 12.1 {
    @@ -349,7 +349,7 @@ do_catchsql_test 15.5 {
     #-------------------------------------------------------------------------
     # Row-values used in UPDATE statements within TRIGGERs
     #
    -# Ticket https://www.sqlite.org/src/info/8c9458e703666e1a
    +# Ticket https://sqlite.org/src/info/8c9458e703666e1a
     #
     do_execsql_test 16.1 {
       CREATE TABLE t16a(a,b,c);
    @@ -449,7 +449,7 @@ do_execsql_test 18.6 {
     } {1 1 1 1 2 1}
     
      
    -# 2018-02-13 Ticket https://www.sqlite.org/src/tktview/f484b65f3d6230593c3
    +# 2018-02-13 Ticket https://sqlite.org/src/tktview/f484b65f3d6230593c3
     # Incorrect result from a row-value comparison in the WHERE clause.
     #
     do_execsql_test 19.1 {
    @@ -558,7 +558,7 @@ do_catchsql_test 20.1 {
       SELECT 1 WHERE (2,(2,0)) IS (2,(2,0));
     } {0 1}
     
    -# 2018-11-03: Ticket https://www.sqlite.org/src/info/1a84668dcfdebaf1
    +# 2018-11-03: Ticket https://sqlite.org/src/info/1a84668dcfdebaf1
     # Assertion fault when doing row-value operations on a primary key
     # containing duplicate columns.
     #
    @@ -782,4 +782,27 @@ do_execsql_test 33.3 {
       SELECT * FROM t1 WHERE (a,b) BETWEEN (2,99) AND (4,0);
     } {3 100}
     
    +# 2025-04-15 https://sqlite.org/forum/forumpost/b9647a113b465950
    +# Incorrect result when the schema includes a table with a UNIQUE
    +# constraint and one of the columns in the UNIQUE constraint is the
    +# INTEGER PRIMARY KEY, and the columns that UNIQUE constraint are
    +# used in a rowvalue-IN operator constraint.
    +#
    +reset_db
    +do_execsql_test 34.1 {
    +  CREATE TABLE items (
    +    Id INTEGER  /* rowid alias */,
    +    Item INTEGER  /* any type */,
    +    Test TEXT  /* TEXT or BLOB */,
    +    Filler,  /* any type */
    +    PRIMARY KEY(Id),
    +    UNIQUE(Item, Id)
    +  );
    +  INSERT INTO items (Id, Item)
    +    VALUES (1, 2), (2, 2), (3, 3), (4, 5);
    +  UPDATE items SET test='ok'
    +    WHERE (Id, Item) IN (SELECT Id, Item FROM items);
    +  SELECT Id, Item, test FROM items ORDER BY id;
    +} {1 2 ok 2 2 ok 3 3 ok 4 5 ok}
    +
     finish_test
    diff --git a/test/rowvalue3.test b/test/rowvalue3.test
    index 80ebeb7617..7d07976948 100644
    --- a/test/rowvalue3.test
    +++ b/test/rowvalue3.test
    @@ -203,7 +203,7 @@ foreach {tn idx} {
     #-------------------------------------------------------------------------
     
     # 2016-11-17.  Query flattening in a vector SELECT on the RHS of an IN
    -# operator.  Ticket https://www.sqlite.org/src/info/da7841375186386c
    +# operator.  Ticket https://sqlite.org/src/info/da7841375186386c
     #
     do_execsql_test 5.0 {
       DROP TABLE IF EXISTS t1;
    diff --git a/test/rowvalue7.test b/test/rowvalue7.test
    index 03591afaf4..2823667e73 100644
    --- a/test/rowvalue7.test
    +++ b/test/rowvalue7.test
    @@ -56,7 +56,7 @@ do_catchsql_test 2.2 {
     } {1 {3 columns assigned 2 values}}
     
     # 2019-08-26
    -# ticket https://www.sqlite.org/src/info/78acc9d40f0786e8
    +# ticket https://sqlite.org/src/info/78acc9d40f0786e8
     #
     do_catchsql_test 3.0 {
       DROP TABLE IF EXISTS t1;
    diff --git a/test/savepoint7.test b/test/savepoint7.test
    index 59c3cd6cdc..2652cc3972 100644
    --- a/test/savepoint7.test
    +++ b/test/savepoint7.test
    @@ -95,7 +95,7 @@ do_test savepoint7-2.2 {
       list $rc $msg [db eval {SELECT * FROM t2}]
     } {1 {abort due to ROLLBACK} {}}
     
    -# Ticket: https://www.sqlite.org/src/tktview/7f7f8026eda387d544b
    +# Ticket: https://sqlite.org/src/tktview/7f7f8026eda387d544b
     # Segfault in the in-memory journal logic triggered by a tricky
     # combination of SAVEPOINT operations.
     #
    diff --git a/test/select3.test b/test/select3.test
    index 4bbd70cc75..ab16ab9fd8 100644
    --- a/test/select3.test
    +++ b/test/select3.test
    @@ -268,7 +268,7 @@ do_test select3-8.2 {
       }
     } {real}
     
    -# 2019-05-09 ticket https://www.sqlite.org/src/tktview/6c1d3febc00b22d457c7
    +# 2019-05-09 ticket https://sqlite.org/src/tktview/6c1d3febc00b22d457c7
     #
     unset -nocomplain x
     foreach {id x} {
    diff --git a/test/select4.test b/test/select4.test
    index d49708ece8..890897f2a9 100644
    --- a/test/select4.test
    +++ b/test/select4.test
    @@ -915,7 +915,7 @@ do_execsql_test select4-14.17 {
       VALUES(1),(2),(3),(4) UNION ALL SELECT 5 LIMIT 3;
     } {1 2 3}
     
    -# Ticket https://www.sqlite.org/src/info/d06a25c84454a372
    +# Ticket https://sqlite.org/src/info/d06a25c84454a372
     # Incorrect answer due to two co-routines using the same registers and expecting
     # those register values to be preserved across a Yield.
     #
    @@ -968,7 +968,7 @@ do_execsql_test select4-16.3 {
       ORDER BY t3.a;
     } {95 96 97 98 99}
     
    -# Ticket https://www.sqlite.org/src/tktview/f7f8c97e975978d45  on 2016-04-25
    +# Ticket https://sqlite.org/src/tktview/f7f8c97e975978d45  on 2016-04-25
     #
     # The where push-down optimization from 2015-06-02 is suppose to disable
     # on aggregate subqueries.  But if the subquery is a compound where the
    diff --git a/test/select6.test b/test/select6.test
    index f748ab47a4..301ec11c36 100644
    --- a/test/select6.test
    +++ b/test/select6.test
    @@ -611,7 +611,7 @@ do_execsql_test 11.100 {
         FROM ( SELECT count(*) AS cnt FROM t1 );
     } {{}}
     
    -# 2019-05-29 ticket https://www.sqlite.org/src/info/c41afac34f15781f
    +# 2019-05-29 ticket https://sqlite.org/src/info/c41afac34f15781f
     # A LIMIT clause in a subquery is incorrectly applied to a subquery.
     #
     do_execsql_test 12.100 {
    diff --git a/test/shared.test b/test/shared.test
    index 146830e56a..42292ab40f 100644
    --- a/test/shared.test
    +++ b/test/shared.test
    @@ -161,7 +161,7 @@ do_test shared-$av.1.8 {
     
     do_test shared-$av.2.1 {
       # Open connection db3 to the database.
    -  if {$::tcl_platform(platform)=="unix"} {
    +  if {$::tcl_platform(platform) eq "unix"} {
         sqlite3 db3 "file:test.db?cache=private" -uri 1
       } else {
         sqlite3 db3 TEST.DB
    @@ -797,7 +797,7 @@ do_test shared-$av.10.2 {
     do_test shared-$av.10.3 {
       # An external connection should be able to read the database, but not
       # prepare a write operation.
    -  if {$::tcl_platform(platform)=="unix"} {
    +  if {$::tcl_platform(platform) eq "unix"} {
         sqlite3 db3 "file:test.db?cache=private" -uri 1
       } else {
         sqlite3 db3 TEST.DB
    diff --git a/test/shared3.test b/test/shared3.test
    index e313069990..2e32398cac 100644
    --- a/test/shared3.test
    +++ b/test/shared3.test
    @@ -70,7 +70,7 @@ do_test shared3-2.5 {
     # test case shared3-2.3 above). The goal of the following tests is to
     # ensure that the cache-size really is 10 pages.
     #
    -#if {$::tcl_platform(platform)=="unix"} {
    +#if {$::tcl_platform(platform) eq "unix"} {
     #  set alternative_name ./test.db
     #} else {
     #  set alternative_name TEST.DB
    diff --git a/test/shared6.test b/test/shared6.test
    index 499cbb0eb5..18f9f537b6 100644
    --- a/test/shared6.test
    +++ b/test/shared6.test
    @@ -139,7 +139,7 @@ do_test shared6-1.X {
     # that connect to the same file using different VFS implementations do
     # not share a cache.
     #
    -if {$::tcl_platform(platform) eq "unix"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
       do_test shared6-2.1 {
         sqlite3 db1 test.db -vfs unix
         sqlite3 db2 test.db -vfs unix
    diff --git a/test/shell1.test b/test/shell1.test
    index f89d34d536..8cf11b2409 100644
    --- a/test/shell1.test
    +++ b/test/shell1.test
    @@ -515,6 +515,7 @@ do_test shell1-3.15.3 {
     } {1 {ERROR: extra parameter: "BAD".  Usage:
     .output ?FILE?           Send output to FILE or stdout if FILE is omitted
        If FILE begins with '|' then open it as a pipe.
    +   If FILE is 'off' then output is disabled.
        Options:
          --bom                 Prefix output with a UTF8 byte-order mark
          -e                    Send output to the system text editor
    @@ -533,6 +534,7 @@ do_test shell1-3.16.2 {
     } {1 {ERROR: extra parameter: "BAD".  Usage:
     .output ?FILE?           Send output to FILE or stdout if FILE is omitted
        If FILE begins with '|' then open it as a pipe.
    +   If FILE is 'off' then output is disabled.
        Options:
          --bom                 Prefix output with a UTF8 byte-order mark
          -e                    Send output to the system text editor
    @@ -1064,20 +1066,20 @@ do_test shell1-5.0 {
         #       return character (and on Windows, the end-of-file character)
         #       cannot be used here.
         #
    -    if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} {
    +    if {$i==0x0D || ($tcl_platform(platform) eq "windows" && $i==0x1A)} {
           continue
         }
         # Tcl 8.7 maps 0x80 through 0x9f into valid UTF8.  So skip those tests.
         if {$i>=0x80} {
           if {$i<=0x9F || $tcl_version>=9.0} continue
    -      if {$tcl_platform(platform)=="windows"} continue
    +      if {$tcl_platform(platform) eq "windows"} continue
         }
    -    if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"}  continue
    -    if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"}  continue
    +    if {$i>=0xE0 && $tcl_platform(os) eq "OpenBSD"}  continue
    +    if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os) eq "Linux"}  continue
         set hex [format %02X $i]
         set char [subst \\x$hex]; set oldChar $char
         set escapes [list]
    -    if {$tcl_platform(platform)=="windows"} {
    +    if {$tcl_platform(platform) eq "windows"} {
           #
           # NOTE: On Windows, we need to escape all the whitespace characters,
           #       the alarm (\a) character, and those with special meaning to
    diff --git a/test/shell3.test b/test/shell3.test
    index ef3ea784ff..6bb49f5c3d 100644
    --- a/test/shell3.test
    +++ b/test/shell3.test
    @@ -36,7 +36,7 @@ sqlite3 db test.db
     # different.  This causes problems for the tests below.  To avoid
     # issues, these tests are disabled for windows.
     #
    -if {$::tcl_platform(platform)=="windows"} {
    +if {$::tcl_platform(platform) eq "windows"} {
       finish_test
       return
     }
    diff --git a/test/shell8.test b/test/shell8.test
    index ca37598e93..e555396365 100644
    --- a/test/shell8.test
    +++ b/test/shell8.test
    @@ -55,7 +55,7 @@ proc dir_to_list {dirname {n -1}} {
       set res [list]
       foreach f [glob -nocomplain $dirname/*] {
         set mtime [file mtime $f]
    -    if {$::tcl_platform(platform)!="windows"} {
    +    if {$::tcl_platform(platform) ne "windows"} {
           set perm [file attributes $f -perm]
         } else {
           set perm 0
    diff --git a/test/shmlock.test b/test/shmlock.test
    index 89b29fd7ac..fce0cf8f5e 100644
    --- a/test/shmlock.test
    +++ b/test/shmlock.test
    @@ -114,7 +114,7 @@ sqlite3 db0 test.db
     sqlite3 db1 test.db
     do_test 3.1 { execsql { SELECT * FROM t1 } db0 } {1 2}
     do_test 3.2 { execsql { SELECT * FROM t1 } db1 } {1 2}
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(os) eq "Windows NT"} {
       set isWindows 1
     } else {
       set isWindows 0
    diff --git a/test/speedtest1.c b/test/speedtest1.c
    index b49c70098f..10cd30f1c7 100644
    --- a/test/speedtest1.c
    +++ b/test/speedtest1.c
    @@ -35,6 +35,7 @@ static const char zHelp[] =
       "  --exclusive         Enable locking_mode=EXCLUSIVE\n"
       "  --explain           Like --sqlonly but with added EXPLAIN keywords\n"
       "  --fullfsync         Enable fullfsync=TRUE\n"
    +  "  --hard-heap-limit N The hard limit on the maximum heap size\n"
       "  --heap SZ MIN       Memory allocator uses SZ bytes & min allocation MIN\n"
       "  --incrvacuum        Enable incremenatal vacuum mode\n"
       "  --journal M         Set the journal_mode to M\n"
    @@ -60,6 +61,7 @@ static const char zHelp[] =
       "  --sqlonly           No-op.  Only show the SQL that would have been run.\n"
       "  --shrink-memory     Invoke sqlite3_db_release_memory() frequently.\n"
       "  --size N            Relative test size.  Default=100\n"
    +  "  --soft-heap-limit N The soft limit on the maximum heap size\n"
       "  --strict            Use STRICT table where appropriate\n"
       "  --stats             Show statistics at the end\n"
       "  --stmtscanstatus    Activate SQLITE_DBCONFIG_STMT_SCANSTATUS\n"
    @@ -542,6 +544,7 @@ char *speedtest1_once(const char *zFormat, ...){
       char *zSql;
       sqlite3_stmt *pStmt;
       char *zResult = 0;
    +  int rc;
       va_start(ap, zFormat);
       zSql = sqlite3_vmprintf(zFormat, ap);
       va_end(ap);
    @@ -561,6 +564,12 @@ char *speedtest1_once(const char *zFormat, ...){
           const char *z = (const char*)sqlite3_column_text(pStmt, 0);
           if( z ) zResult = sqlite3_mprintf("%s", z);
         }
    +    rc = sqlite3_reset(pStmt);
    +    if( rc!=SQLITE_OK ){
    +      fprintf(stderr, "%s\nError code %d: %s\n",
    +              sqlite3_sql(pStmt), rc, sqlite3_errmsg(g.db));
    +      exit(1);
    +    }
         sqlite3_finalize(pStmt);
       }
       sqlite3_free(zSql);
    @@ -590,7 +599,7 @@ void speedtest1_prepare(const char *zFormat, ...){
     
     /* Run an SQL statement previously prepared */
     void speedtest1_run(void){
    -  int i, n, len;
    +  int i, n, len, rc;
       if( g.bSqlOnly ) return;
       assert( g.pStmt );
       g.nResult = 0;
    @@ -649,12 +658,22 @@ void speedtest1_run(void){
       if( g.bReprepare ){
         sqlite3_stmt *pNew;
         sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0);
    -    sqlite3_finalize(g.pStmt);
    +    rc = sqlite3_finalize(g.pStmt);
    +    if( rc!=SQLITE_OK ){
    +      fprintf(stderr, "%s\nError code %d: %s\n",
    +                      sqlite3_sql(pNew), rc, sqlite3_errmsg(g.db));
    +      exit(1);
    +    }
         g.pStmt = pNew;
       }else
     #endif
       {
    -    sqlite3_reset(g.pStmt);
    +    rc = sqlite3_reset(g.pStmt);
    +    if( rc!=SQLITE_OK ){
    +      fprintf(stderr, "%s\nError code %d: %s\n",
    +                      sqlite3_sql(g.pStmt), rc, sqlite3_errmsg(g.db));
    +      exit(1);
    +    }
       }
       speedtest1_shrink_memory();
     }
    @@ -2949,6 +2968,8 @@ int main(int argc, char **argv){
       int doIncrvac = 0;            /* True for --incrvacuum */
       const char *zJMode = 0;       /* Journal mode */
       const char *zKey = 0;         /* Encryption key */
    +  int nHardHeapLmt = 0;         /* The hard heap limit */
    +  int nSoftHeapLmt = 0;         /* The soft heap limit */
       int nLook = -1, szLook = 0;   /* --lookaside configuration */
       int noSync = 0;               /* True for --nosync */
       int pageSize = 0;             /* Desired page size.  0 means default */
    @@ -3021,6 +3042,10 @@ int main(int argc, char **argv){
           }else if( strcmp(z,"explain")==0 ){
             g.bSqlOnly = 1;
             g.bExplain = 1;
    +      }else if( strcmp(z,"hard-heap-limit")==0 ){
    +        ARGC_VALUE_CHECK(1);
    +        nHardHeapLmt = integerValue(argv[i+1]);
    +        i += 1;
           }else if( strcmp(z,"heap")==0 ){
             ARGC_VALUE_CHECK(2);
             nHeap = integerValue(argv[i+1]);
    @@ -3110,6 +3135,10 @@ int main(int argc, char **argv){
           }else if( strcmp(z,"size")==0 ){
             ARGC_VALUE_CHECK(1);
             g.szTest = g.szBase = integerValue(argv[++i]);
    +      }else if( strcmp(z,"soft-heap-limit")==0 ){
    +        ARGC_VALUE_CHECK(1);
    +        nSoftHeapLmt = integerValue(argv[i+1]);
    +        i += 1;
           }else if( strcmp(z,"stats")==0 ){
             showStats = 1;
           }else if( strcmp(z,"temp")==0 ){
    @@ -3271,6 +3300,15 @@ int main(int argc, char **argv){
       if( zJMode ){
         speedtest1_exec("PRAGMA journal_mode=%s", zJMode);
       }
    +  if( nHardHeapLmt>0 ){
    +    speedtest1_exec("PRAGMA hard_heap_limit=%d", nHardHeapLmt);
    +  }
    +  if( nSoftHeapLmt>0 ){
    +    speedtest1_exec("PRAGMA soft_heap_limit=%d", nSoftHeapLmt);
    +  }
    +  if( zJMode ){
    +    speedtest1_exec("PRAGMA journal_mode=%s", zJMode);
    +  }
     
       if( g.bExplain ) printf(".explain\n.echo on\n");
       if( strcmp(zTSet,"mix1")==0 ) zTSet = zMix1Tests;
    diff --git a/test/subquery.test b/test/subquery.test
    index 17061d4b60..898c8f7560 100644
    --- a/test/subquery.test
    +++ b/test/subquery.test
    @@ -650,6 +650,44 @@ do_eqp_test subquery-10.2 {
     # |--SCAN v2
     # `--SEARCH t1 USING INDEX x12 (aa=?)
     #
    +#---------------------------------------------------------------------------
    +# Follow-up on 2025-04-14.  Performance issue found while working
    +# on Fossil (Fossil check-in 2025-04-13T19:54).
    +#
    +do_execsql_test 10.3 {
    +  CREATE TABLE blob(
    +    rid INTEGER PRIMARY KEY,
    +    size INT,
    +    uuid TEXT
    +  );
    +  CREATE TABLE delta(
    +    rid INTEGER PRIMARY KEY,
    +    srcid INT
    +  );
    +  CREATE INDEX delta_i1 ON delta(srcid);
    +}
    +do_eqp_test subquery-10.4 {
    +  WITH RECURSIVE deltasof(rid) AS (
    +    SELECT rid FROM delta WHERE srcid=125020
    +    UNION
    +    SELECT delta.rid FROM deltasof, delta
    +     WHERE delta.srcid=deltasof.rid)
    +  SELECT deltasof.rid, blob.uuid FROM deltasof, blob
    +   WHERE blob.rid=deltasof.rid;
    +} {
    +  QUERY PLAN
    +  |--CO-ROUTINE deltasof
    +  |  |--SETUP
    +  |  |  `--SEARCH delta USING COVERING INDEX delta_i1 (srcid=?)
    +  |  `--RECURSIVE STEP
    +  |     |--SCAN deltasof
    +  |     `--SEARCH delta USING COVERING INDEX delta_i1 (srcid=?)
    +  |--SCAN deltasof
    +  `--SEARCH blob USING INTEGER PRIMARY KEY (rowid=?)
    +}
    +# ^^^^^^^^^^^^^^^^^^
    +# deltasof should be the outer loop and blob the inner loop
    +# Prior to the fix, SQLite was doing it the other way around.
     
     #-----------------------------------------------------------------------------
     # 2024-04-25 Column affinities for columns of compound subqueries
    diff --git a/test/subquery2.test b/test/subquery2.test
    index 0c1bdc6697..8513dc75c8 100644
    --- a/test/subquery2.test
    +++ b/test/subquery2.test
    @@ -104,7 +104,7 @@ do_execsql_test 2.2 {
     } {2 3   3 6   4 10}
     
     ############################################################################
    -# Ticket http://www.sqlite.org/src/info/d11a6e908f (2014-09-20)
    +# Ticket http://sqlite.org/src/info/d11a6e908f (2014-09-20)
     # Query planner fault on three-way nested join with compound inner SELECT 
     #
     do_execsql_test 3.0 {
    diff --git a/test/symlink.test b/test/symlink.test
    index 685cae5a41..fc78a04720 100644
    --- a/test/symlink.test
    +++ b/test/symlink.test
    @@ -17,7 +17,7 @@ source $testdir/tester.tcl
     set testprefix symlink
     
     # This only runs on unix.
    -if {$::tcl_platform(platform)!="unix"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       finish_test
       return
     }
    diff --git a/test/symlink2.test b/test/symlink2.test
    index 9a2237e4c0..7305f6dd38 100644
    --- a/test/symlink2.test
    +++ b/test/symlink2.test
    @@ -17,7 +17,7 @@ source $testdir/tester.tcl
     set testprefix symlink2
     
     # This only runs on Windows.
    -if {$::tcl_platform(platform)!="windows"} {
    +if {$::tcl_platform(platform) ne "windows"} {
       finish_test
       return
     }
    diff --git a/test/sync.test b/test/sync.test
    index 023425e6b1..b24800d100 100644
    --- a/test/sync.test
    +++ b/test/sync.test
    @@ -34,7 +34,7 @@ if {[atomic_batch_write test.db]} {
     set sqlite_sync_count 0
     proc cond_incr_sync_count {adj} {
       global sqlite_sync_count
    -  if {$::tcl_platform(platform) == "windows"} {
    +  if {$::tcl_platform(os) eq "Windows NT"} {
         incr sqlite_sync_count $adj
       } else {
         ifcapable !dirsync {
    diff --git a/test/sync2.test b/test/sync2.test
    index 89e66c8455..ce8132c714 100644
    --- a/test/sync2.test
    +++ b/test/sync2.test
    @@ -26,7 +26,7 @@ ifcapable !pager_pragmas||!attach||!dirsync {
       finish_test
       return
     }
    -if {$::tcl_platform(platform)!="unix" 
    +if {$::tcl_platform(os) eq "Windows NT"
       || [permutation] == "journaltest"
       || [permutation] == "inmemory_journal"
       || [atomic_batch_write test.db] 
    diff --git a/test/tabfunc01.test b/test/tabfunc01.test
    index c16fb9bec2..0e29c35683 100644
    --- a/test/tabfunc01.test
    +++ b/test/tabfunc01.test
    @@ -194,6 +194,63 @@ do_execsql_test tabfunc01-5.2 {
        WHERE value=67;
     } 67
     
    +# 2025-03-22 forum post 0d5d63257e3ff4f6
    +#
    +do_execsql_test tabfunc01-6.1 {
    +  SELECT value FROM generate_series(1,10) WHERE value<5.5;
    +} {1 2 3 4 5}
    +do_execsql_test tabfunc01-6.2 {
    +  SELECT value FROM generate_series(1,10) WHERE value<5.0;
    +} {1 2 3 4}
    +do_execsql_test tabfunc01-6.3 {
    +  SELECT value FROM generate_series(1,10) WHERE value<=5.5;
    +} {1 2 3 4 5}
    +do_execsql_test tabfunc01-6.4 {
    +  SELECT value FROM generate_series(1,10) WHERE value<=5.0;
    +} {1 2 3 4 5}
    +do_execsql_test tabfunc01-6.5 {
    +  SELECT value FROM generate_series(1,10) WHERE value>5.5;
    +} {6 7 8 9 10}
    +do_execsql_test tabfunc01-6.6 {
    +  SELECT value FROM generate_series(1,10) WHERE value>5.0;
    +} {6 7 8 9 10}
    +do_execsql_test tabfunc01-6.7 {
    +  SELECT value FROM generate_series(1,10) WHERE value>=5.5;
    +} {6 7 8 9 10}
    +do_execsql_test tabfunc01-6.8 {
    +  SELECT value FROM generate_series(1,10) WHERE value>=5.0;
    +} {5 6 7 8 9 10}
    +do_execsql_test tabfunc01-6.9 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value<5.5;
    +} {5 4 3 2 1}
    +do_execsql_test tabfunc01-6.10 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value<5.0;
    +} {4 3 2 1}
    +do_execsql_test tabfunc01-6.11 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value<=5.5;
    +} {5 4 3 2 1}
    +do_execsql_test tabfunc01-6.12 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value<=5.0;
    +} {5 4 3 2 1}
    +do_execsql_test tabfunc01-6.13 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value>5.5;
    +} {10 9 8 7 6}
    +do_execsql_test tabfunc01-6.14 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value>5.0;
    +} {10 9 8 7 6}
    +do_execsql_test tabfunc01-6.15 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value>=5.5;
    +} {10 9 8 7 6}
    +do_execsql_test tabfunc01-6.16 {
    +  SELECT value FROM generate_series(10,1,-1) WHERE value>=5.0;
    +} {10 9 8 7 6 5}
    +do_execsql_test tabfunc01-6.17 {
    +  SELECT value FROM generate_series(1,10) WHERE value==5.5;
    +} {}
    +do_execsql_test tabfunc01-6.18 {
    +  SELECT value FROM generate_series(1,10) WHERE value==5.0;
    +} {5}
    +
     # The next series of tests is verifying that virtual table are able
     # to optimize the IN operator, even on terms that are not marked "omit".
     # When the generate_series virtual table is compiled for the testfixture,
    @@ -282,7 +339,7 @@ do_test tabfunc01-750 {
       }
     } {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |}
     
    -# ticket https://www.sqlite.org/src/info/2ae0c599b735d59e
    +# ticket https://sqlite.org/src/info/2ae0c599b735d59e
     # Verification of testtag-20230227a
     do_test tabfunc01-751 {
       db eval {
    diff --git a/test/table.test b/test/table.test
    index b961207f8b..46ecd7d23b 100644
    --- a/test/table.test
    +++ b/test/table.test
    @@ -792,7 +792,7 @@ do_catchsql_test table-16.7 {
       INSERT INTO t16 DEFAULT VALUES;
     } {1 {unknown function: string_agg()}}
     
    -# Ticket [https://www.sqlite.org/src/info/094d39a4c95ee4abbc417f04214617675ba15c63]
    +# Ticket [https://sqlite.org/src/info/094d39a4c95ee4abbc417f04214617675ba15c63]
     # describes a assertion fault that occurs on a CREATE TABLE .. AS SELECT statement.
     # the following test verifies that the problem has been fixed.
     #
    @@ -810,7 +810,7 @@ do_execsql_test table-17.1 {
     } {1 1 | 2 2 |}
     
     # 2015-06-16
    -# Ticket [https://www.sqlite.org/src/tktview/873cae2b6e25b1991ce5e9b782f9cd0409b96063]
    +# Ticket [https://sqlite.org/src/tktview/873cae2b6e25b1991ce5e9b782f9cd0409b96063]
     # Make sure a CREATE TABLE AS statement correctly rolls back partial changes to the
     # sqlite_master table when the SELECT on the right-hand side aborts.
     #
    @@ -825,7 +825,7 @@ do_execsql_test table-18.2 {
     } {ok}
     
     # 2015-09-09
    -# Ticket [https://www.sqlite.org/src/info/acd12990885d9276]
    +# Ticket [https://sqlite.org/src/info/acd12990885d9276]
     # "CREATE TABLE ... AS SELECT ... FROM sqlite_master" fails because the row
     # in the sqlite_master table for the next table is initially populated
     # with a NULL instead of a record created by OP_Record.
    diff --git a/test/tester.tcl b/test/tester.tcl
    index 8f1f83e65b..fc8feda253 100644
    --- a/test/tester.tcl
    +++ b/test/tester.tcl
    @@ -814,7 +814,7 @@ proc do_test {name cmd expected} {
     # on Windows because of issues with ANSI and UTF8 I/O on Win11.
     #
     proc do_test_with_ansi_output {name cmd expected} {
    -  if {![info exists ::SLAVE] || $::tcl_platform(platform)!="windows"} {
    +  if {![info exists ::SLAVE] || $::tcl_platform(platform) ne "windows"} {
         uplevel 1 [list do_test $name $cmd $expected]
       }
     }
    @@ -873,7 +873,7 @@ proc catchcmdex {db {cmd ""}} {
     
     proc filepath_normalize {p} {
       # test cases should be written to assume "unix"-like file paths
    -  if {$::tcl_platform(platform)!="unix"} {
    +  if {$::tcl_platform(platform) ne "unix"} {
         string map [list \\ / \{/ / .db\} .db] \
             [regsub -nocase -all {[a-z]:[/\\]+} $p {/}]
       } {
    @@ -1833,7 +1833,7 @@ proc crashsql {args} {
       # error message.  We map that to the expected message
       # so that we don't have to change all of the test
       # cases.
    -  if {$::tcl_platform(platform)=="windows"} {
    +  if {$::tcl_platform(platform) eq "windows"} {
         if {$msg=="child killed: unknown signal"} {
           set msg "child process exited abnormally"
         }
    @@ -1884,7 +1884,7 @@ proc crash_on_write {args} {
       # error message.  We map that to the expected message
       # so that we don't have to change all of the test
       # cases.
    -  if {$::tcl_platform(platform)=="windows"} {
    +  if {$::tcl_platform(platform) eq "windows"} {
         if {$msg=="child killed: unknown signal"} {
           set msg "child process exited abnormally"
         }
    @@ -2548,7 +2548,7 @@ proc test_restore_config_pagecache {} {
     }
     
     proc test_binary_name {nm} {
    -  if {$::tcl_platform(platform)=="windows"} {
    +  if {$::tcl_platform(platform) eq "windows"} {
         set ret "$nm.exe"
       } else {
         set ret $nm
    diff --git a/test/testrunner.tcl b/test/testrunner.tcl
    index 6ff414c4bd..60c4627f92 100755
    --- a/test/testrunner.tcl
    +++ b/test/testrunner.tcl
    @@ -38,7 +38,7 @@ proc find_interpreter {} {
       }
       if {$rc} {
         puts "Cannot find tcl package sqlite3: Trying to build it now..."
    -    if {$::tcl_platform(platform)=="windows"} {
    +    if {$::tcl_platform(platform) eq "windows"} {
           set bat [open make-tcl-extension.bat w]
           puts $bat "nmake /f Makefile.msc tclextension"
           close $bat
    @@ -170,7 +170,7 @@ proc guess_number_of_cores {} {
       if {[catch {number_of_cores} ret]} {
         set ret 4
       
    -    if {$::tcl_platform(platform)=="windows"} {
    +    if {$::tcl_platform(platform) eq "windows"} {
           catch { set ret $::env(NUMBER_OF_PROCESSORS) }
         } else {
           if {$::tcl_platform(os)=="Darwin"} {
    @@ -263,6 +263,19 @@ switch -nocase -glob -- $tcl_platform(os) {
         set TRG(shell)       sqlite3.exe
         set TRG(run)         run.bat
         set TRG(runcmd)      "run.bat"
    +    if {"unix" eq $tcl_platform(platform)} {
    +      # Presumably cygwin. This block gets testrunner.tcl started on
    +      # Cygwin but then downstream tests all fail, at least in part
    +      # because of the discrepancies in build target names which need
    +      # .exe on cygwin but not on other Unix-like platforms.
    +      set TRG(platform)  cygwin
    +      set TRG(make)      make.sh
    +      set TRG(makecmd)   "bash make.sh"
    +      set TRG(testfixture) testfixture
    +      set TRG(shell)       sqlite3
    +      set TRG(run)       run.sh
    +      set TRG(runcmd)    "bash run.sh"
    +    }
       }
       default {
         puts "tcl_platform(os)=$::tcl_platform(os)"
    @@ -804,7 +817,7 @@ for {set ii 0} {$ii < [llength $argv]} {incr ii} {
         } elseif {[string match "$a*" --stop-on-coredump]} {
           set TRG(stopOnCore) 1
         } elseif {[string match "$a*" --status]} {
    -      if {$tcl_platform(platform)=="windows"} {
    +      if {$tcl_platform(platform) eq "windows"} {
             puts stdout \
     "The --status option is not available on Windows. A suggested work-around"
             puts stdout \
    @@ -1487,7 +1500,7 @@ proc progress_report {} {
       global TRG
     
       if {$TRG(fullstatus)} {
    -    if {$::tcl_platform(platform)=="windows"} {
    +    if {$::tcl_platform(platform) eq "windows"} {
           exec [info nameofexe] $::argv0 status --cls
         } else {
           show_status trdb 1
    diff --git a/test/testrunner_data.tcl b/test/testrunner_data.tcl
    index 2597cbe478..ade126a64d 100644
    --- a/test/testrunner_data.tcl
    +++ b/test/testrunner_data.tcl
    @@ -455,7 +455,7 @@ proc trd_fuzztest_data {} {
       set lFuzzDb    [glob [file join $::testdir fuzzdata*.db]] 
       set lSessionDb [glob [file join $::testdir sessionfuzz-data*.db]]
     
    -  if {$::tcl_platform(platform)=="windows"} {
    +  if {$::tcl_platform(platform) eq "windows"} {
         return [list fuzzcheck.exe $lFuzzDb]
       }
     
    @@ -527,7 +527,7 @@ proc make_script {cfg srcdir bMsvc} {
       set configOpts [list]                         ;# Extra args for [configure]
     
       # Define either SQLITE_OS_WIN or SQLITE_OS_UNIX, as appropriate.
    -  if {$::tcl_platform(platform)=="windows"} {
    +  if {$::tcl_platform(os) eq "Windows NT"} {
         lappend opts -DSQLITE_OS_WIN=1
       } else {
         lappend opts -DSQLITE_OS_UNIX=1
    diff --git a/test/tkt3457.test b/test/tkt3457.test
    index 0273494639..17b6c72cd4 100644
    --- a/test/tkt3457.test
    +++ b/test/tkt3457.test
    @@ -15,10 +15,10 @@
     set testdir [file dirname $argv0]
     source $testdir/tester.tcl
     
    -if {$tcl_platform(platform) != "unix"} {
    +if {[llength [info commands test_syscall]]==0} {
       finish_test
       return
    -}
    +} 
     if {[atomic_batch_write test.db]} {
       finish_test
       return
    diff --git a/test/trigger1.test b/test/trigger1.test
    index afeb7ddccb..67943677f9 100644
    --- a/test/trigger1.test
    +++ b/test/trigger1.test
    @@ -751,7 +751,7 @@ do_execsql_test trigger1-18.1 {
       SELECT * FROM t18;
     } {1 3 2}     ;# Not: 1 1001 1000
     
    -# 2018-04-26 ticket [https://www.sqlite.org/src/tktview/d85fffd6ffe856092e]
    +# 2018-04-26 ticket [https://sqlite.org/src/tktview/d85fffd6ffe856092e]
     # VDBE Program uses an expired value.
     #
     do_execsql_test trigger1-19.0 {
    diff --git a/test/triggerG.test b/test/triggerG.test
    index 8cf20b5ec9..b078fffb2e 100644
    --- a/test/triggerG.test
    +++ b/test/triggerG.test
    @@ -19,7 +19,7 @@ ifcapable {!trigger} {
     }
     
     # Test cases for ticket 
    -# https://www.sqlite.org/src/tktview/06796225f59c057cd120f
    +# https://sqlite.org/src/tktview/06796225f59c057cd120f
     #
     # The OP_Once opcode was not working correctly for recursive triggers.
     #
    diff --git a/test/unixexcl.test b/test/unixexcl.test
    index 8e9c4644d1..c24945e5e3 100644
    --- a/test/unixexcl.test
    +++ b/test/unixexcl.test
    @@ -18,7 +18,7 @@ source $testdir/tester.tcl
     source $testdir/lock_common.tcl
     source $testdir/malloc_common.tcl
     
    -if {$::tcl_platform(platform)!="unix" || [info commands test_syscall]==""} {
    +if {[llength [info commands test_syscall]]==0} {
       finish_test
       return
     } 
    diff --git a/test/update.test b/test/update.test
    index bf7666662a..0a380fa030 100644
    --- a/test/update.test
    +++ b/test/update.test
    @@ -616,7 +616,7 @@ do_test update-14.4 {
     
     } ;# ifcapable {trigger}
     
    -# Ticket [https://www.sqlite.org/src/tktview/43107840f1c02] on 2014-10-29
    +# Ticket [https://sqlite.org/src/tktview/43107840f1c02] on 2014-10-29
     # An assertion fault on UPDATE
     #
     ifcapable altertable {
    @@ -703,7 +703,7 @@ do_execsql_test update-19.10 {
       SELECT * FROM t1;
     } {2 2}
     
    -# 2019-12-29 ticket https://www.sqlite.org/src/info/314cc133e5ada126
    +# 2019-12-29 ticket https://sqlite.org/src/info/314cc133e5ada126
     # REPLACE conflict resolution during an UPDATE causes a DELETE trigger 
     # to fire.  If that DELETE trigger subsequently modifies the row
     # being updated, bad things can happen.  Prevent this by prohibiting
    @@ -711,8 +711,8 @@ do_execsql_test update-19.10 {
     # REPLACE conflict resolution on the UPDATE.
     #
     # See also tickets:
    -#   https://www.sqlite.org/src/info/c1e19e12046d23fe 2019-10-25
    -#   https://www.sqlite.org/src/info/a8a4847a2d96f5de 2019-10-16 
    +#   https://sqlite.org/src/info/c1e19e12046d23fe 2019-10-25
    +#   https://sqlite.org/src/info/a8a4847a2d96f5de 2019-10-16 
     #
     reset_db
     do_execsql_test update-20.10 {
    diff --git a/test/upsert1.test b/test/upsert1.test
    index 8af273a89a..49168f840b 100644
    --- a/test/upsert1.test
    +++ b/test/upsert1.test
    @@ -129,7 +129,7 @@ do_execsql_test upsert1-610 {
     } {ok}
     
     # 2018-08-14
    -# Ticket https://www.sqlite.org/src/info/908f001483982c43
    +# Ticket https://sqlite.org/src/info/908f001483982c43
     # If there are multiple uniqueness contraints, the UPSERT should fire
     # if the one constraint it targets fails, regardless of whether or not
     # the other constraints pass or fail.  In other words, the UPSERT constraint
    diff --git a/test/uri.test b/test/uri.test
    index 863676f078..62090f46af 100644
    --- a/test/uri.test
    +++ b/test/uri.test
    @@ -59,7 +59,7 @@ foreach {tn uri file} {
         if {[string first %00 $uri]>=0} continue
       }
     
    -  if {$tcl_platform(platform)=="windows"} {
    +  if {$tcl_platform(platform) eq "windows"} {
         #
         # NOTE: Due to limits on legal characters for file names imposed by
         #       Windows, we must skip the final two tests here (i.e. the
    @@ -306,7 +306,7 @@ foreach {tn uri res} {
       6     "file://x/PWD/test.db"           {invalid uri authority: x}
     } {
     
    -  if {$tcl_platform(platform)=="windows"} {
    +  if {$tcl_platform(platform) eq "windows"} {
         set uri  [string map [list PWD [string range [get_pwd] 3 end]] $uri]
       } else {
         set uri  [string map [list PWD [string range [get_pwd] 1 end]] $uri]
    diff --git a/test/vacuum-into.test b/test/vacuum-into.test
    index d559b7fb39..c041ebe7a7 100644
    --- a/test/vacuum-into.test
    +++ b/test/vacuum-into.test
    @@ -111,7 +111,7 @@ do_catchsql_test vacuum-into-420 {
     
     # The ability to VACUUM INTO a read-only database
     db close
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       file attributes test.db -readonly 1
     } else {
       file attributes test.db -permissions 292  ;# 292 == 0444
    @@ -121,7 +121,7 @@ forcedelete test.db2
     do_execsql_test vacuum-into-500 {
       VACUUM INTO 'test.db2';
     }
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       file attributes test.db -readonly 0
     } else {
       file attributes test.db -permissions 420   ;# 420 = 0644
    diff --git a/test/vtabH.test b/test/vtabH.test
    index cf3dcafd9a..07704cefb1 100644
    --- a/test/vtabH.test
    +++ b/test/vtabH.test
    @@ -124,13 +124,13 @@ foreach ::tclvar_set_omit {0 1} {
     
     #-------------------------------------------------------------------------
     #
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       set drive [string range [pwd] 0 1]
       set ::env(fstreeDrive) $drive
     }
     reset_db
     register_fs_module db
    -if {$tcl_platform(platform)!="windows" || \
    +if {$tcl_platform(platform) ne "windows" || \
         [regexp -nocase -- {^[A-Z]:} $drive]} {
       do_execsql_test 3.0 {
         SELECT name FROM fsdir WHERE dir = '.' AND name = 'test.db';
    diff --git a/test/wal2.test b/test/wal2.test
    index 5ef303edc6..064bed0b20 100644
    --- a/test/wal2.test
    +++ b/test/wal2.test
    @@ -26,7 +26,7 @@ ifcapable !wal {finish_test ; return }
     set sqlite_sync_count 0
     proc cond_incr_sync_count {adj} {
       global sqlite_sync_count
    -  if {$::tcl_platform(platform) == "windows"} {
    +  if {$::tcl_platform(os) eq "Windows NT"} {
         incr sqlite_sync_count $adj
       } {
         ifcapable !dirsync {
    @@ -1038,7 +1038,7 @@ tvfs delete
     # the new files with the same file-system permissions as the database 
     # file itself. Test this.
     #
    -if {$::tcl_platform(platform) == "unix"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
       faultsim_delete_and_reopen
       # Changed on 2012-02-13: umask is deliberately ignored for -wal files.
       #set umask [exec /bin/sh -c umask]
    @@ -1094,7 +1094,7 @@ if {$::tcl_platform(platform) == "unix"} {
     # database, wal or shm files cannot be opened, or can only be opened
     # read-only.
     #
    -if {$::tcl_platform(platform) == "unix"} {
    +if {$::tcl_platform(os) ne "Windows NT"} {
       proc perm {} {
         set L [list]
         foreach f {test.db test.db-wal test.db-shm} {
    diff --git a/test/wal6.test b/test/wal6.test
    index 9bbc58409d..081608cd30 100644
    --- a/test/wal6.test
    +++ b/test/wal6.test
    @@ -46,7 +46,7 @@ foreach jmode $all_journal_modes {
     # Under Windows, you'll get an error trying to delete
     # a file this is already opened.  Close the first connection
     # so the other tests work.
    -if {$tcl_platform(platform)=="windows"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       if {$jmode=="persist" || $jmode=="truncate"} {
         db close
       }
    @@ -61,7 +61,7 @@ if {$tcl_platform(platform)=="windows"} {
         } db2
       } {wal 1 2 3 4}
     
    -if {$tcl_platform(platform)=="windows"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       if {$jmode=="persist" || $jmode=="truncate"} {
         sqlite3 db test.db
       }
    diff --git a/test/wal64k.test b/test/wal64k.test
    index 8ff8e4b77c..bacb14328a 100644
    --- a/test/wal64k.test
    +++ b/test/wal64k.test
    @@ -19,10 +19,10 @@ set testprefix wal64k
     
     ifcapable !wal {finish_test ; return }
     
    -if {$tcl_platform(platform) != "unix"} {
    +if {[llength [info commands test_syscall]]==0} {
       finish_test
       return
    -}
    +} 
     
     db close
     test_syscall pagesize 65536
    diff --git a/test/walblock.test b/test/walblock.test
    index 23167a8830..86a52b3f96 100644
    --- a/test/walblock.test
    +++ b/test/walblock.test
    @@ -17,7 +17,7 @@ source $testdir/wal_common.tcl
     
     finish_test; return;    #  Feature currently not implemented.
     ifcapable !wal {finish_test ; return }
    -if {$::tcl_platform(platform)!="unix"} { finish_test ; return }
    +if {$::tcl_platform(platform) ne "unix"} { finish_test ; return }
     set testprefix walblock
     
     catch { db close }
    diff --git a/test/walcrash4.test b/test/walcrash4.test
    index 80839b39e5..43292def42 100644
    --- a/test/walcrash4.test
    +++ b/test/walcrash4.test
    @@ -38,7 +38,7 @@ faultsim_save_and_close
     
     # The error message is different on unix and windows
     #
    -if {$::tcl_platform(platform)=="windows"} {
    +if {$::tcl_platform(platform) eq "windows"} {
      set msg "child killed: unknown signal"
     } else {
      set msg "child process exited abnormally"
    diff --git a/test/walmode.test b/test/walmode.test
    index f760823c8d..1c3325acf2 100644
    --- a/test/walmode.test
    +++ b/test/walmode.test
    @@ -47,7 +47,7 @@ do_test walmode-1.2 {
     
     if {[atomic_batch_write test.db]==0} {
       set expected_sync_count 3
    -  if {$::tcl_platform(platform)!="windows"} {
    +  if {$::tcl_platform(os) ne "Windows NT"} {
         ifcapable dirsync {
           incr expected_sync_count
         }
    diff --git a/test/walnoshm.test b/test/walnoshm.test
    index d4082178dd..f546c29b13 100644
    --- a/test/walnoshm.test
    +++ b/test/walnoshm.test
    @@ -104,6 +104,7 @@ do_test 2.1.5 {
     } {exclusive delete a b c d e f g h}
     
     do_test 2.2.1 {
    +  db2 close
       forcecopy test.db     test2.db
       forcecopy test.db-wal test2.db-wal
       sqlite3 db3 test2.db -vfs tvfsshm
    diff --git a/test/walro.test b/test/walro.test
    index cae52db6d3..a39b844d9d 100644
    --- a/test/walro.test
    +++ b/test/walro.test
    @@ -19,7 +19,7 @@ set ::testprefix walro
     
     # These tests are only going to work on unix.
     #
    -if {$::tcl_platform(platform) != "unix"} {
    +if {$::tcl_platform(os) eq "Windows NT"} {
       finish_test
       return
     }
    diff --git a/test/walsetlk.test b/test/walsetlk.test
    index b65eb9ab68..969bcaf465 100644
    --- a/test/walsetlk.test
    +++ b/test/walsetlk.test
    @@ -204,10 +204,10 @@ do_multiclient_test tn {
       #
       set bSleep 1
       if {$::sqlite_options(setlk_timeout)==1} {
    -    if {$::tcl_platform(platform)=="windows"} {
    +    if {$::tcl_platform(platform) eq "windows"} {
           set bSleep 0
         }
    -    if {$::tcl_platform(platform)=="unix"} {
    +    if {$::tcl_platform(platform) eq "unix"} {
           set bSleep [expr $tn==2]
         }
       }
    @@ -252,7 +252,7 @@ do_test 3.1b {
     # Set bExpect to true if calls to xSleep() are expected. Such calls are
     # expected unless this is an SQLITE_ENABLE_SETLK_TIMEOUT=1 build.
     set bExpect 1
    -if {$tcl_platform(platform)=="windows" && $::sqlite_options(setlk_timeout)==1} {
    +if {$tcl_platform(platform) eq "windows" && $::sqlite_options(setlk_timeout)==1} {
       set bExpect 0
     }
     do_test 3.2 {
    diff --git a/test/where.test b/test/where.test
    index 0a8cfd572b..c377006fb9 100644
    --- a/test/where.test
    +++ b/test/where.test
    @@ -1388,7 +1388,7 @@ do_execsql_test where-19.0 {
       SELECT t191.rowid FROM t192, t191 WHERE (a=y OR b=y) AND x=?1;
     } {/.* sqlite_autoindex_t191_1 .* sqlite_autoindex_t191_2 .*/}
     
    -# 2018-04-24 ticket [https://www.sqlite.org/src/info/4ba5abf65c5b0f9a]
    +# 2018-04-24 ticket [https://sqlite.org/src/info/4ba5abf65c5b0f9a]
     # Index on expressions leads to an incorrect answer for a LEFT JOIN
     #
     do_execsql_test where-20.0 {
    @@ -1422,7 +1422,7 @@ do_execsql_test where-21.1 {
       4 0 1
     }
     
    -# 2018-11-05: ticket [https://www.sqlite.org/src/tktview/65eb38f6e46de8c75e188a]
    +# 2018-11-05: ticket [https://sqlite.org/src/tktview/65eb38f6e46de8c75e188a]
     # Incorrect result in LEFT JOIN when STAT4 is enabled.
     #
     sqlite3 db :memory:
    @@ -1435,7 +1435,7 @@ do_execsql_test where-22.1 {
     } {5}
     
     # 20190-02-22:  A bug introduced by checkin
    -# https://www.sqlite.org/src/info/fa792714ae62fa98.
    +# https://sqlite.org/src/info/fa792714ae62fa98.
     #
     do_execsql_test where-23.0 {
       DROP TABLE IF EXISTS t1;
    @@ -1547,7 +1547,7 @@ do_catchsql_test where-25.5 {
         ON CONFLICT(c) DO UPDATE SET b=NULL
     } {1 {corrupt database}}
     
    -# 2019-08-21 Ticket https://www.sqlite.org/src/info/d9f584e936c7a8d0
    +# 2019-08-21 Ticket https://sqlite.org/src/info/d9f584e936c7a8d0
     #
     db close
     sqlite3 db :memory:
    diff --git a/test/where2.test b/test/where2.test
    index 7a7e9b92ed..a38f6e54ba 100644
    --- a/test/where2.test
    +++ b/test/where2.test
    @@ -767,7 +767,7 @@ do_execsql_test where2-13.1 {
       SELECT * FROM t13 WHERE (1=2 AND a=3) OR a=4;
     } {4 5}
     
    -# https://www.sqlite.org/src/info/5e3c886796e5512e  (2016-03-09)
    +# https://sqlite.org/src/info/5e3c886796e5512e  (2016-03-09)
     # Correlated subquery on the RHS of an IN operator 
     #
     do_execsql_test where2-14.1 {
    diff --git a/test/whereG.test b/test/whereG.test
    index c154058233..6ee8634817 100644
    --- a/test/whereG.test
    +++ b/test/whereG.test
    @@ -237,7 +237,7 @@ do_eqp_test 5.3.3 {
     } {SCAN t1}
     
     # 2015-06-18
    -# Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70]
    +# Ticket [https://sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70]
     #
     do_execsql_test 6.0 {
       DROP TABLE IF EXISTS t1;
    @@ -273,7 +273,7 @@ do_execsql_test 7.3 {
     } {1 3 1 4 9 3 9 4}
     
     # 2019-08-22
    -# Ticket https://www.sqlite.org/src/info/7e07a3dbf5a8cd26
    +# Ticket https://sqlite.org/src/info/7e07a3dbf5a8cd26
     #
     do_execsql_test 8.1 {
       DROP TABLE IF EXISTS t0;
    diff --git a/test/whereL.test b/test/whereL.test
    index 2e9ae219e1..ffbae02b8d 100644
    --- a/test/whereL.test
    +++ b/test/whereL.test
    @@ -254,4 +254,44 @@ do_execsql_test 810 {
       SELECT * FROM v0 LEFT JOIN t0 ON c31} {
         append LDFLAGS $OPTS
       }
    -  if {$TCLMAJOR>8} {
    -    set OUT libtcl9sqlite$VERSION.$SUFFIX
    +  if {$tcl_platform(os) eq "Windows NT"} {
    +    set OUT cyg
       } else {
    -    set OUT libsqlite$VERSION.$SUFFIX
    +    set OUT lib
    +  }
    +  if {$TCLMAJOR>8} {
    +    set OUT ${OUT}tcl9sqlite$VERSION.$SUFFIX
    +  } else {
    +    set OUT ${OUT}sqlite$VERSION.$SUFFIX
       }
       set @ $OUT; # Workaround for https://sqlite.org/forum/forumpost/0683a49cb02f31a1
                   # in which Gentoo edits their tclConfig.sh to include an soname
    @@ -295,7 +300,7 @@ package ifneeded sqlite3 $VERSION \\
     
       # Generate and execute the command with which to do the compilation.
       #
    -  set cmd "$CMD tclsqlite3.c -o $OUT $LIBS"
    +  set cmd "$CMD -DUSE_TCL_STUBS tclsqlite3.c -o $OUT $LIBS"
       puts $cmd
       file delete -force $OUT
       catch {exec {*}$cmd} errmsg
    diff --git a/tool/mkautoconfamal.sh b/tool/mkautoconfamal.sh
    index c26ac8c73c..35f8dbc8c6 100644
    --- a/tool/mkautoconfamal.sh
    +++ b/tool/mkautoconfamal.sh
    @@ -25,18 +25,6 @@ VERSION=`cat $TOP/VERSION`
     HASH=`cut -c1-10 $TOP/manifest.uuid`
     DATETIME=`grep '^D' $TOP/manifest | tr -c -d '[0-9]' | cut -c1-12`
     
    -# Inject the current version into the TEA autoconf file.
    -#
    -sed -e "s/@VERSION@/$VERSION/" \
    -    < $TOP/autoconf/tea/configure.ac.in \
    -    > $TOP/autoconf/tea/configure.ac
    -# And then verify that that worked...
    -#
    -if grep $VERSION $TOP/autoconf/tea/configure.ac > /dev/null
    -then echo "TEA version number ok"
    -else echo "TEA version number mismatch.  Should be $VERSION"; exit 1
    -fi
    -
     # If this script is given an argument of --snapshot, then generate a
     # snapshot tarball named for the current checkout SHA hash, rather than
     # the version number.
    @@ -85,6 +73,10 @@ rm -f ./*~
     #  find . -name '*~' -exec rm \{} \;
     #fi
     
    +mkdir -p autosetup/teaish
    +mv tea/autosetup/*.tcl autosetup/teaish/.
    +rm -fr tea/autosetup
    +
     mkdir -p tea/generic
     cat < tea/generic/tclsqlite3.c
     #ifdef USE_SYSTEM_SQLITE
    @@ -95,12 +87,9 @@ cat < tea/generic/tclsqlite3.c
     EOF
     cat  $TOP/src/tclsqlite.c           >> tea/generic/tclsqlite3.c
     
    -cd tea
    -rm -f configure.ac.in
    -autoconf
    -rm -rf autom4te.cache
    +find . -type f -name '*~' -exec rm -f \{} \;
    +find . -type f -name '#*#' -exec rm -f \{} \;
     
    -cd ../
     ./configure && make dist
     tar xzf sqlite-$VERSION.tar.gz
     mv sqlite-$VERSION $TARBALLNAME
    diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl
    index 1d0f892363..7b6f57e426 100644
    --- a/tool/mksqlite3c.tcl
    +++ b/tool/mksqlite3c.tcl
    @@ -111,7 +111,7 @@ puts $out [subst \
     ** separate file. This file contains only code for the core SQLite library.
     **}]
     set srcroot [file dirname [file dirname [info script]]]
    -if {$tcl_platform(platform)=="windows"} {
    +if {$tcl_platform(platform) eq "windows"} {
       set vsrcprog src-verify.exe
     } else {
       set vsrcprog ./src-verify
    diff --git a/tool/sqlite3_analyzer.c.in b/tool/sqlite3_analyzer.c.in
    index 945c3c5b90..9860c0b0fc 100644
    --- a/tool/sqlite3_analyzer.c.in
    +++ b/tool/sqlite3_analyzer.c.in
    @@ -55,7 +55,7 @@ static int subst_puts(
         }else if( strcmp(zArg, "-nonewline")==0 ){
           addNewLine = 0;
         }else{
    -      Tcl_AppendResult(interp, "bad argument: ", zArg, 0);
    +      Tcl_AppendResult(interp, "bad argument: ", zArg, NULL);
           return TCL_ERROR;
         }
       }
    diff --git a/tool/srcck1.c b/tool/srcck1.c
    index 20084ac47f..5a1158beb9 100644
    --- a/tool/srcck1.c
    +++ b/tool/srcck1.c
    @@ -13,7 +13,7 @@
     ** The aim of this utility is to prevent recurrences of errors such
     ** as the one fixed at:
     **
    -**   https://www.sqlite.org/src/info/a2952231ac7abe16
    +**   https://sqlite.org/src/info/a2952231ac7abe16
     **
     ** Note that another similar error was found by this utility when it was
     ** first written.  That other error was fixed by the same check-in that
    diff --git a/tool/tclConfigShToAutoDef.sh b/tool/tclConfigShToAutoDef.sh
    deleted file mode 100755
    index d12657063e..0000000000
    --- a/tool/tclConfigShToAutoDef.sh
    +++ /dev/null
    @@ -1,29 +0,0 @@
    -#!/bin/sh
    -#
    -# A level of indirection for use soley by the configure script
    -# (auto.def).
    -#
    -# Expects to be passed a full path to a tclConfig.sh. It sources it
    -# and emits TCL code which sets some vars which are exported by
    -# tclConfig.sh.
    -#
    -# This script expects that the caller has already validated that the
    -# file exists, is not a directory, and is readable.
    -#
    -# If passed no filename, or an empty one, then it emits config code
    -# suitable for the "config not found" case.
    -if test x = "x$1"; then
    -  TCL_INCLUDE_SPEC=
    -  TCL_LIB_SPEC=
    -  TCL_STUB_LIB_SPEC=
    -  TCL_EXEC_PREFIX=
    -  TCL_VERSION=
    -else
    -  . "$1"
    -fi
    -
    -echo "define TCL_INCLUDE_SPEC {$TCL_INCLUDE_SPEC} ;"
    -echo "define TCL_LIB_SPEC {$TCL_LIB_SPEC} ;"
    -echo "define TCL_STUB_LIB_SPEC {$TCL_STUB_LIB_SPEC} ;"
    -echo "define TCL_EXEC_PREFIX {$TCL_EXEC_PREFIX} ;"
    -echo "define TCL_VERSION {$TCL_VERSION} ;"