diff options
Diffstat (limited to 'autoconf')
-rw-r--r-- | autoconf/Makefile.in | 2 | ||||
-rw-r--r-- | autoconf/tea/Makefile.in | 146 | ||||
-rw-r--r-- | autoconf/tea/README.txt | 61 | ||||
-rw-r--r-- | autoconf/tea/_teaish.tester.tcl.in (renamed from autoconf/tea/teaish.tester.tcl.in) | 11 | ||||
-rw-r--r-- | autoconf/tea/autosetup/README.txt | 4 | ||||
-rw-r--r-- | autoconf/tea/autosetup/core.tcl | 2368 | ||||
-rw-r--r-- | autoconf/tea/autosetup/feature-tests.tcl | 214 | ||||
-rw-r--r-- | autoconf/tea/autosetup/tester.tcl | 193 | ||||
-rw-r--r-- | autoconf/tea/doc/sqlite3.n | 15 | ||||
-rw-r--r-- | autoconf/tea/teaish.tcl | 12 |
10 files changed, 150 insertions, 2876 deletions
diff --git a/autoconf/Makefile.in b/autoconf/Makefile.in index aaa23b7de..a77386fae 100644 --- a/autoconf/Makefile.in +++ b/autoconf/Makefile.in @@ -224,7 +224,7 @@ install: install-lib # ENABLE_STATIC_SHELL = @ENABLE_STATIC_SHELL@ sqlite3-shell-link-flags.1 = $(TOP)/sqlite3.c $(LDFLAGS.libsqlite3) -sqlite3-shell-link-flags.0 = -L. -lsqlite3 $(LDFLAGS.zlib) +sqlite3-shell-link-flags.0 = -L. -lsqlite3 $(LDFLAGS.zlib) $(LDFLAGS.math) sqlite3-shell-deps.1 = $(TOP)/sqlite3.c sqlite3-shell-deps.0 = $(libsqlite3.DLL) # diff --git a/autoconf/tea/Makefile.in b/autoconf/tea/Makefile.in index ad71c8b3e..ccf9a7b94 100644 --- a/autoconf/tea/Makefile.in +++ b/autoconf/tea/Makefile.in @@ -1,5 +1,9 @@ all: # +# Unless this file is named Makefile.in, you are probably looking +# at an automatically generated/filtered copy and should probably not +# edit it. +# # 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. @@ -47,6 +51,12 @@ tx.dll8 = @TEAISH_DLL8@ tx.dll9 = @TEAISH_DLL9@ tx.dll = $(tx.dll$(TCL_MAJOR_VERSION)) tx.dir = @TEAISH_EXT_DIR@ +@if TEAISH_TM_TCL +# Input filename for tcl::tm-style module +tx.tm = @TEAISH_TM_TCL@ +# Target filename for tcl::tm-style installation +tx.tm.tgt = $(tx.name.pkg)-$(tx.version).tm +@endif @if TEAISH_DIST_NAME tx.name.dist = @TEAISH_DIST_NAME@ @@ -136,7 +146,7 @@ LDFLAGS.shlib = @SH_LDFLAGS@ # sources passed to [teaish-src-add], but may also be appended to by # teaish.make. # -tx.src =@TEAISH_EXT_SRC@ +tx.src = @TEAISH_EXT_SRC@ # # tx.CFLAGS is typically set by teaish.make, whereas TEAISH_CFLAGS @@ -158,22 +168,16 @@ tx.LDFLAGS = 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 +# The base name for a distribution tar/zip file. # -teaish__cleanExtra = +tx.dist.basename = $(tx.name.dist)-$(tx.version) # 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_PKGINDEX_TCL_IN@ @TEAISH_TM_TCL_IN@ \ @AUTODEPS@ @if TEAISH_MAKEFILE_IN @@ -200,9 +204,14 @@ $(teaish.makefile): $(teaish__auto.def) $(teaish.makefile.in) \ @AUTODEPS@ @if TEAISH_TESTER_TCL_IN -@TEAISH_TESTER_TCL_IN@: -@TEAISH_TESTER_TCL@: @TEAISH_TESTER_TCL_IN@ -config.log: @TEAISH_TESTER_TCL@ +@TEAISH_TESTER_TCL_IN@: $(teaish__autogen.deps) +config.log: @TEAISH_TESTER_TCL_IN@ +@TEAISH_TESTER_TCL@: @TEAISH_TESTER_TCL_IN@ +@endif +@if TEAISH_TEST_TCL_IN +@TEAISH_TEST_TCL_IN@: $(teaish__autogen.deps) +config.log: @TEAISH_TEST_TCL_IN@ +@TEAISH_TEST_TCL@: @TEAISH_TEST_TCL_IN@ @endif # @@ -218,7 +227,7 @@ CC.tcl = \ # CC.dll = \ $(CC.tcl) $(tx.src) $(LDFLAGS.shlib) \ - $(LDFLAGS.configure) $(LDFLAGS) $(tx.LDFLAGS) $(TCL_STUB_LIB_SPEC) + $(tx.LDFLAGS) $(LDFLAGS.configure) $(LDFLAGS) $(TCL_STUB_LIB_SPEC) @if TEAISH_ENABLE_DLL # @@ -249,16 +258,25 @@ test-extension: # this name is reserved for use by teaish.make[.in] test-prepre: $(tx.dll) @endif @if TEAISH_TESTER_TCL -test-core.args = @TEAISH_TESTER_TCL@ +teaish.tester.tcl = @TEAISH_TESTER_TCL@ +test-core.args = $(teaish.tester.tcl) @if TEAISH_ENABLE_DLL test-core.args += '$(tx.dll)' '$(tx.loadPrefix)' @else test-core.args += '' '' @endif test-core.args += @TEAISH_TESTUTIL_TCL@ +# Clients may pass additional args via test.args=... +# and ::argv will be rewritten before the test script loads, to +# remove $(test-core.args) +test.args ?= test-core: test-pre - $(TCLSH) $(test-core.args) -test-prepre: @TEAISH_TESTER_TCL@ + $(TCLSH) $(test-core.args) $(test.args) +test-gdb: $(teaish.tester.tcl) + gdb --args $(TCLSH) $(test-core.args) $(test.args) +test-vg.flags ?= --leak-check=full -v --show-reachable=yes --track-origins=yes +test-vg: $(teaish.tester.tcl) + valgrind $(test-vg.flags) $(TCLSH) $(test-core.args) $(test.args) @else # !TEAISH_TESTER_TCL test-prepre: @endif # TEAISH_TESTER_TCL @@ -271,10 +289,10 @@ 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) + rm -f $(tx.dll8) $(tx.dll9) tclsh clean-post: clean-core clean: clean-post @@ -289,7 +307,7 @@ distclean-core: distclean-pre @endif @endif @if TEAISH_TESTER_TCL_IN - rm -f @TEAISH_TESTER_TCL@ + rm -f $(teaish.tester.tcl) @endif @if TEAISH_PKGINDEX_TCL_IN rm -f @TEAISH_PKGINDEX_TCL@ @@ -300,33 +318,71 @@ distclean-core: distclean-pre @if TEAISH_TEST_TCL_IN rm -f @TEAISH_TEST_TCL@ @endif -distclean-extension: # this name is reserved for use by teaish.make distclean-post: distclean-core distclean: distclean-post +# +# The (dist)clean-extension targets are reserved for use by +# client-side teaish.make. +# +# 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 +# +distclean-extension: +clean-extension: # # Installation rules... # +@if TEAISH_ENABLE_INSTALL .PHONY: install-pre install-core install-post install-test install-prepre install-extension install-extension: # this name is reserved for use by teaish.make + +@if TEAISH_ENABLE_DLL install-prepre: $(tx.dll) +@else +install-prepre: +@endif + +@if TEAISH_TM_TCL +install-core.tmdir = $(DESTDIR)@TEAISH_TCL_TM_DIR@ +@endif + 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. +@if TEAISH_ENABLE_DLL $(INSTALL) $(tx.dll) "$(DESTDIR)$(TCLLIBDIR)" - $(INSTALL.noexec) pkgIndex.tcl "$(DESTDIR)$(TCLLIBDIR)" +@endif +@if TEAISH_PKGINDEX_TCL + $(INSTALL.noexec) "@TEAISH_PKGINDEX_TCL@" "$(DESTDIR)$(TCLLIBDIR)" +@endif @if TEAISH_PKGINIT_TCL - $(INSTALL.noexec) @TEAISH_PKGINIT_TCL@ "$(DESTDIR)$(TCLLIBDIR)" + $(INSTALL.noexec) "@TEAISH_PKGINIT_TCL@" "$(DESTDIR)$(TCLLIBDIR)" +@endif +@if TEAISH_TM_TCL + @if [ ! -d "$(install-core.tmdir)" ]; then \ + set -x; $(INSTALL) -d "$(install-core.tmdir)"; \ + fi + $(INSTALL.noexec) "@TEAISH_TM_TCL@" "$(install-core.tmdir)/$(tx.tm.tgt)" @endif install-test: install-core @echo "Post-install test of [package require $(tx.name.pkg) $(tx.version)]..."; \ + set xtra=""; \ + if [ x != "x$(DESTDIR)" ]; then \ + xtra='set ::auto_path [linsert $$::auto_path 0 [file normalize $(DESTDIR)$(TCLLIBDIR)/..]];'; \ + fi; \ if echo \ - 'set c 0; ' \ + 'set c 0; ' $$xtra \ '@TEAISH_POSTINST_PREREQUIRE@' \ - 'if {[catch {package require $(tx.name.pkg) $(tx.version)}]} {incr c};' \ + 'if {[catch {package require $(tx.name.pkg) $(tx.version)} xc]} {incr c};' \ + 'if {$$c && "" ne $$xc} {puts $$xc; puts "auto_path=$$::auto_path"};' \ 'exit $$c' \ | $(TCLSH) ; then \ echo "passed"; \ @@ -344,10 +400,17 @@ install: install-post uninstall-extension: # this name is reserved for use by teaish.make uninstall-pre: uninstall-core: uninstall-pre +@if TEAISH_ENABLE_DLL rm -fr "$(DESTDIR)$(TCLLIBDIR)" +@endif +@if TEAISH_TM_TCL + rm -f "$(DESTDIR)$(install-core.tmdir)/$(tx.tm.tgt)" +@endif + uninstall-post: uninstall-core @echo "Uninstalled Tcl extension $(tx.name) $(tx.version)" uninstall: uninstall-post +@endif # TEAISH_ENABLE_INSTALL @if TEAISH_MAKEFILE_IN Makefile: $(tx.makefile.in) @@ -367,7 +430,7 @@ config.log: $(teaish.makefile.in) # recognized when running in --teaish-install mode, causing # the sub-configure to fail. dist.flags = --with-tclsh=$(TCLSH) -dist.reconfig = $(teaish.dir)/configure $(dist.flags) +dist.reconfig = $(teaish.dir)/configure $(tx.dist.reconfig-flags) $(dist.flags) # Temp dir for dist.zip. Must be different than dist.tgz or else # parallel builds may hose the dist. @@ -375,24 +438,23 @@ teaish__dist.tmp.zip = teaish__dist_zip # # Make a distribution zip file... # -dist.basename = $(tx.name.dist)-$(tx.version) -dist.zip = $(dist.basename).zip +dist.zip = $(tx.dist.basename).zip .PHONY: dist.zip dist.zip-core dist.zip-post #dist.zip-pre: # We apparently can't add a pre-hook here, 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.basename) + @mkdir -p $(teaish__dist.tmp.zip)/$(tx.dist.basename) @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.basename) + @tar xf $(teaish__dist.tmp.zip)/tmp.tar -C $(teaish__dist.tmp.zip)/$(tx.dist.basename) @if TEAISH_DIST_FULL @$(dist.reconfig) \ - --teaish-install=$(teaish__dist.tmp.zip)/$(dist.basename) \ - --t-e-d=$(teaish__dist.tmp.zip)/$(dist.basename) >/dev/null + --teaish-install=$(teaish__dist.tmp.zip)/$(tx.dist.basename) \ + --t-e-d=$(teaish__dist.tmp.zip)/$(tx.dist.basename) >/dev/null @endif - @rm -f $(dist.basename)/tmp.tar $(dist.zip) - @cd $(teaish__dist.tmp.zip) && zip -q -r ../$(dist.zip) $(dist.basename) + @rm -f $(tx.dist.basename)/tmp.tar $(dist.zip) + @cd $(teaish__dist.tmp.zip) && zip -q -r ../$(dist.zip) $(tx.dist.basename) @rm -fr $(teaish__dist.tmp.zip) @ls -la $(dist.zip) dist.zip-core: $(dist.zip) @@ -408,23 +470,23 @@ undist: undist-zip # Make a distribution tarball... # teaish__dist.tmp.tgz = teaish__dist_tgz -dist.tgz = $(dist.basename).tar.gz +dist.tgz = $(tx.dist.basename).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.basename) + @mkdir -p $(teaish__dist.tmp.tgz)/$(tx.dist.basename) @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.basename) + @tar xf $(teaish__dist.tmp.tgz)/tmp.tar -C $(teaish__dist.tmp.tgz)/$(tx.dist.basename) @if TEAISH_DIST_FULL - @rm -f $(teaish__dist.tmp.tgz)/$(dist.basename)/pkgIndex.tcl.in; # kludge + @rm -f $(teaish__dist.tmp.tgz)/$(tx.dist.basename)/pkgIndex.tcl.in; # kludge @$(dist.reconfig) \ - --teaish-install=$(teaish__dist.tmp.tgz)/$(dist.basename) \ - --t-e-d=$(teaish__dist.tmp.zip)/$(dist.basename) >/dev/null + --teaish-install=$(teaish__dist.tmp.tgz)/$(tx.dist.basename) \ + --t-e-d=$(teaish__dist.tmp.zip)/$(tx.dist.basename) >/dev/null @endif - @rm -f $(dist.basename)/tmp.tar $(dist.tgz) - @cd $(teaish__dist.tmp.tgz) && tar czf ../$(dist.tgz) $(dist.basename) + @rm -f $(tx.dist.basename)/tmp.tar $(dist.tgz) + @cd $(teaish__dist.tmp.tgz) && tar czf ../$(dist.tgz) $(tx.dist.basename) @rm -fr $(teaish__dist.tmp.tgz) @ls -la $(dist.tgz) dist.tgz-core: $(dist.tgz) diff --git a/autoconf/tea/README.txt b/autoconf/tea/README.txt index 28f23a88d..122b08d32 100644 --- a/autoconf/tea/README.txt +++ b/autoconf/tea/README.txt @@ -41,24 +41,32 @@ step-by-step instructions at the links below for more information: https://sqlite.org/src/doc/trunk/doc/compile-for-unix.md https://sqlite.org/src/doc/trunk/doc/compile-for-windows.md +And info about the extension's Tcl interface can be found at: + + https://sqlite.org/tclsqlite.html + The whole point of the amalgamation-autoconf tarball (in which this -README.txt file is embedded) is to provide a means of compiling -SQLite that does not require first installing TCL and/or "tclsh". -The canonical Makefile in the SQLite source tree provides more -capabilities (such as the the ability to run test cases to ensure -that the build worked) and is better maintained. The only -downside of the canonical Makefile is that it requires a TCL -installation. But if you are wanting to build the TCL extension for -SQLite, then presumably you already have a TCL installation. So why -not just use the more-capable and better-maintained canoncal Makefile? - -This TEA builder is derived from code found at +README.txt file is embedded) is to provide a means of compiling SQLite +that does not require first installing TCL and/or "tclsh". The +canonical Makefile in the SQLite source tree provides more +capabilities (such as the the ability to run test cases to ensure that +the build worked) and is better maintained. The only downside of the +canonical Makefile is that it requires a TCL installation. But if you +are wanting to build the TCL extension for SQLite, then presumably you +already have a TCL installation. So why not just use the more-capable +and better-maintained canoncal Makefile? + +As of version 3.50.0, this build process uses "teaish": + + https://fossil.wanderinghorse.net/r/teaish + +which is conceptually derived from the pre-3.50 toolchain, TEA: http://core.tcl-lang.org/tclconfig http://core.tcl-lang.org/sampleextension -The SQLite developers do not understand how it works. It seems to -work for us. It might also work for you. But we cannot promise that. +It to works for us. It might also work for you. But we cannot +promise that. If you want to use this TEA builder and it works for you, that's fine. But if you have trouble, the first thing you should do is go back @@ -70,30 +78,17 @@ to using the canonical Makefile in the SQLite source tree. UNIX BUILD ========== -Building under most UNIX systems is easy, just run the configure script -and then run make. For more information about the build process, see -the tcl/unix/README file in the Tcl src dist. The following minimal -example will install the extension in the /opt/tcl directory. +Building under most UNIX systems is easy, just run the configure +script and then run make. For example: $ cd sqlite-*-tea - $ ./configure --prefix=/opt/tcl - $ make + $ ./configure --with-tcl=/path/to/tcl/install/root + $ make test $ make install WINDOWS BUILD ============= -The recommended method to build extensions under windows is to use the -Msys + Mingw build process. This provides a Unix-style build while -generating native Windows binaries. Using the Msys + Mingw build tools -means that you can use the same configure script as per the Unix build -to create a Makefile. See the tcl/win/README file for the URL of -the Msys + Mingw download. - -If you have VC++ then you may wish to use the files in the win -subdirectory and build the extension using just VC++. These files have -been designed to be as generic as possible but will require some -additional maintenance by the project developer to synchronise with -the TEA configure.in and Makefile.in files. Instructions for using the -VC++ makefile are written in the first part of the Makefile.vc -file. +On Windows this build is known to work on Cygwin and some Msys2 +environments. We do not currently support Microsoft makefiles for +native Windows builds. diff --git a/autoconf/tea/teaish.tester.tcl.in b/autoconf/tea/_teaish.tester.tcl.in index 4e203cd78..e04d8e63e 100644 --- a/autoconf/tea/teaish.tester.tcl.in +++ b/autoconf/tea/_teaish.tester.tcl.in @@ -1,6 +1,6 @@ # -*- tcl -*- # -# Unless this file is named teaish.tester.tcl.in, you are probably +# 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. # @@ -21,13 +21,20 @@ if {[llength [lindex $::argv 0]] > 0} { # ----^^^^^^^ needed on Haiku when argv 0 is just a filename, else # load cannot find the file. } -source -encoding utf-8 [lindex $::argv 2]; # teaish/tester.tcl +set ::argv [lassign $argv - -] +source -encoding utf-8 [lindex $::argv 0]; # teaish/tester.tcl @if TEAISH_PKGINIT_TCL apply {{file} { set dir [file dirname $::argv0] source -encoding utf-8 $file }} [join {@TEAISH_PKGINIT_TCL@}] @endif +@if TEAISH_TM_TCL +apply {{file} { + set dir [file dirname $::argv0] + source -encoding utf-8 $file +}} [join {@TEAISH_TM_TCL@}] +@endif @if TEAISH_TEST_TCL apply {{file} { # Populate state for [tester.tcl::teaish-build-flag*] diff --git a/autoconf/tea/autosetup/README.txt b/autoconf/tea/autosetup/README.txt deleted file mode 100644 index e11519b04..000000000 --- a/autoconf/tea/autosetup/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -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 <TOP>/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 deleted file mode 100644 index 4b3eb9a82..000000000 --- a/autoconf/tea/autosetup/core.tcl +++ /dev/null @@ -1,2368 +0,0 @@ -######################################################################## -# 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 - -# -# API-internal settings and shared state. -array set teaish__Config [proj-strip-hash-comments { - # - # Teaish's version number, not to be confused with - # teaish__PkgInfo(-version). - # - version 0.1-beta - - # set to 1 to enable some internal debugging output - debug-enabled 0 - - # - # 0 = don't yet have extension's pkgindex - # 0x01 = found TEAISH_EXT_DIR/pkgIndex.tcl.in - # 0x02 = found srcdir/pkgIndex.tcl.in - # 0x10 = found TEAISH_EXT_DIR/pkgIndex.tcl (static file) - # 0x20 = static-pkgIndex.tcl pragma: behave as if 0x10 - # - # Reminder: it's significant that the bottom 4 bits be - # cases where teaish manages ./pkgIndex.tcl. - # - pkgindex-policy 0 - - # - # The pkginit counterpart of pkgindex-policy: - # - # 0 = no pkginit - # 0x01 = found default X.in: generate X from X.in - # 0x10 = found static pkginit file X - # 0x02 = user-provided X.in generates ./X. - # 0x20 = user-provided static pkginit file X - # - # The 0x0f bits indicate that teaish is responsible for cleaning up - # the (generated) pkginit file. - # - pkginit-policy 0 - - # - # If 1+ then teaish__verbose will emit messages. - # - verbose 0 - - # - # Mapping of pkginfo -flags to their TEAISH_xxx define (if any). - # This must not be modified. - # - pkginfo-f2d { - -name TEAISH_NAME - -name.dist TEAISH_DIST_NAME - -name.pkg TEAISH_PKGNAME - -version TEAISH_VERSION - -libDir TEAISH_LIBDIR_NAME - -loadPrefix TEAISH_LOAD_PREFIX - -vsatisfies TEAISH_VSATISFIES - -pkgInit.tcl TEAISH_PKGINIT_TCL - -pkgInit.tcl.in TEAISH_PKGINIT_TCL_IN - -url TEAISH_URL - -options {} - -pragmas {} - } - - # - # Queues for use with teaish-checks-queue and teaish-checks-run. - # - queued-checks-pre {} - queued-checks-post {} - - # Whether or not "make dist" parts are enabled. They get enabled - # when building from an extension's dir, disabled when building - # elsewhere. - dist-enabled 1 - - # By default we enable compilation of a native extension but if the - # extension has no native code or the user wants to take that over - # via teaish.make.in or provide a script-only extension, we will - # elide the default compilation rules if this is 0. - dll-enabled 1 - - # Files to include in the "make dist" bundle. - dist-files {} - - # List of source files for the extension. - extension-src {} - - # Path to the teaish.tcl file. - teaish.tcl {} - - # Dir where teaish.tcl is found. - extension-dir {} - - # Whether the generates TEASH_VSATISFIES_CODE should error out on a - # satisfies error. If 0, it uses return instead of error. - vsatisfies-error 1 - - # Whether or not to allow a "full dist" - a "make dist" build which - # includes both the extension and teaish. By default this is only on - # if the extension dir is teaish's dir. - dist-full-enabled 0 -}] -set teaish__Config(core-dir) $::autosetup(libdir)/teaish - -# -# Array of info managed by teaish-pkginfo-get and friends. Has the -# same set of keys as $teaish__Config(pkginfo-f2d). -# -array set teaish__PkgInfo {} - -# -# 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 = $::teaish__Config(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 ::teaish__Config(install-mode) [teaish-argv-has --teaish-install*] - set ::teaish__Config(create-ext-mode) \ - [teaish-argv-has --teaish-create-extension=* --t-c-e=*] - set gotExt 0; # True if an extension config is found - if {!$::teaish__Config(create-ext-mode) - && !$::teaish__Config(install-mode)} { - # Don't look for an extension if we're in --t-c-e or --t-i 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. The policy here is that 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 settle on using --t-A-X to - # abbreviate --teaish-A...-X... 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 --teaish-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:=0 - teaish-verbose:=0 - => {Enable more (often extraneous) messages from the teaish core.} - - t-d - teaish-debug=0 => {Enable teaish-specific debug output} - - t-i - teaish-install:=auto - => {Installs a copy of teaish, including autosetup, to the target dir. - When used with --teaish-create-extension=DIR, a value of "auto" - (no no value) will inherit that directory.} - - #TODO: --teaish-install-extension:=dir as short for - # --t-c-e=dir --t-i - - t-e-p: - teaish-extension-pkginfo:pkginfo - => {For use with --teaish-create-extension. If used, it must be a - list of arguments for use with teaish-pkginfo-set, e.g. - --teaish-extension-pkginfo="-name Foo -version 2.3"} - - t-v-c - teaish-vsatisfies-check=1 - => {Disable the configure-time "vsatisfies" check on the target tclsh.} - - }]; # main options. - - if {$gotExt} { - proj-assert {"" ne [teaish-pkginfo-get -name]} - proj-assert {[file exists $::teaish__Config(teaish.tcl)]} \ - "Expecting to have found teaish.tcl by now" - uplevel 1 {source $::teaish__Config(teaish.tcl)} - # Set up some default values if the extension did not set them. - # This must happen _after_ it's sourced but before - # teaish-configure is called. - array set f2d $::teaish__Config(pkginfo-f2d) - foreach {pflag key type val} { - - TEAISH_CFLAGS -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_TEST_TCL -v "" - - TEAISH_TEST_TCL_IN -v "" - - -version :f2d: -v 0.0.0 - -name.pkg :f2d: -e {teaish-pkginfo-get -name} - -name.dist :f2d: -e {teaish-pkginfo-get -name} - -libDir :f2d: -e { - join [list \ - [teaish-pkginfo-get -name.pkg] \ - [teaish-pkginfo-get -version]] "" - } - -loadPrefix :f2d: -e { - string totitle [teaish-get -name.pkg] - } - -vsatisfies :f2d: -v {{Tcl 8.5-}} - -pkgInit.tcl :f2d: -v "" - -pkgInit.tcl.in :f2d: -v "" - -url :f2d: -v "" - } { - set isPIFlag [expr {"-" ne $pflag}] - if {$isPIFlag} { - if {[info exists ::teaish__PkgInfo($pflag)]} { - # Was already set - skip it. - continue; - } - proj-assert {{:f2d:} eq $key} - set key $f2d($pflag) - } - proj-assert {"" ne $key} - set got [get-define $key "<nope>"] - if {"<nope>" ne $got} { - # Was already set - skip it. - continue - } - switch -exact -- $type { - -v {} - -e { set val [eval $val] } - default { proj-error "Invalid type flag: $type" } - } - #puts "***** defining default $pflag $key {$val} isPIFlag=$isPIFlag got=$got" - define $key $val - if {$isPIFlag} { - set ::teaish__PkgInfo($pflag) $val - } - } - unset isPIFlag pflag key type val - array unset f2d - }; # 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-get -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 <https://github.com/msteveb/autosetup/issues/73> - # 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-e-p => teaish-extension-pkginfo - t-f => teaish-force - t-i => teaish-install - t-v => teaish-verbose - t-v-c => teaish-vsatisfies-check - } - - scan [opt-val teaish-verbose 0] %d ::teaish__Config(verbose) - set ::teaish__Config(debug-enabled) [opt-bool teaish-debug] - - set exitEarly 0 - if {[proj-opt-was-provided teaish-create-extension]} { - teaish__create_extension [opt-val teaish-create-extension] - incr exitEarly - } - if {$::teaish__Config(install-mode)} { - teaish__install - incr exitEarly - } - - if {$exitEarly} { - file delete -force config.log - 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-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 - teaish__define_pkginfo_derived * - - 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 - - apply {{} { - # Set up "vsatisfies" code for pkgIndex.tcl.in, - # teaish.tester.tcl.in, and for a configure-time check. We would - # like to put this before [teaish-checks-run -pre] but it's - # marginally conceivable that a client may need to dynamically - # calculate the vsatisfies and set it via [teaish-configure]. - set vs [get-define TEAISH_VSATISFIES ""] - if {"" eq $vs} return - set code {} - set n 0 - # Treat $vs as a list-of-lists {{Tcl 8.5-} {Foo 1.0- -3.0} ...} - # and generate Tcl which will run package vsatisfies tests with - # that info. - foreach pv $vs { - set n [llength $pv] - if {$n < 2} { - proj-error "-vsatisfies: {$pv} appears malformed. Whole list is: $vs" - } - set pkg [lindex $pv 0] - set vcheck {} - for {set i 1} {$i < $n} {incr i} { - lappend vcheck [lindex $pv $i] - } - if {[opt-bool teaish-vsatisfies-check]} { - set tclsh [get-define TCLSH_CMD] - set vsat "package vsatisfies \[ package provide $pkg \] $vcheck" - set vputs "puts \[ $vsat \]" - #puts "*** vputs = $vputs" - scan [exec echo $vputs | $tclsh] %d vvcheck - if {0 == $vvcheck} { - proj-fatal -up $tclsh "check failed:" $vsat - } - } - lappend code [string trim [subst -nocommands -nobackslashes { -if { ![package vsatisfies [package provide $pkg] $vcheck] } { - if {$::teaish__Config(vsatisfies-error)} { - error {Package $::teaish__PkgInfo(-name) $::teaish__PkgInfo(-version) requires $pv} - } else { - return - } -}}]] - }; # foreach pv - define TEAISH_VSATISFIES_CODE [join $code "\n"] - }}; # vsatisfies - - 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_TESTUTIL_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" - if {0x0f & $::teaish__Config(pkgindex-policy)} { - # Don't leave stale pkgIndex.tcl laying around yet don't delete - # or overwrite a user-managed static pkgIndex.tcl. - file delete -force -- [get-define TEAISH_PKGINDEX_TCL] - proj-dot-ins-append [get-define TEAISH_PKGINDEX_TCL_IN] - } else { - teaish-dist-add [file tail $tpi] - } - }}; # $::teaish__Config(pkgindex-policy) - - # - # Ensure we clean up TEAISH_PKGINIT_TCL if needed and @-process - # TEAISH_PKGINIT_TCL_IN if needed. - # - if {0x0f & $::teaish__Config(pkginit-policy)} { - file delete -force -- [get-define TEAISH_PKGINIT_TCL] - proj-dot-ins-append [get-define TEAISH_PKGINIT_TCL_IN] - } - - apply {{} { - # Queue up any remaining dot-in files - set dotIns [list] - foreach d { - TEAISH_TESTER_TCL_IN - TEAISH_TEST_TCL_IN - TEAISH_MAKEFILE_IN - } { - lappend dotIns [get-define $d ""] - } - lappend dotIns $::autosetup(srcdir)/Makefile.in; # must be after TEAISH_MAKEFILE_IN - foreach f $dotIns { - if {"" ne $f} { - proj-dot-ins-append $f - } - } - }} - - define TEAISH_DIST_FULL \ - [expr { - $::teaish__Config(dist-enabled) - && $::teaish__Config(dist-full-enabled) - }] - - define TEAISH_AUTOSETUP_DIR $::teaish__Config(core-dir) - define TEAISH_ENABLE_DIST $::teaish__Config(dist-enabled) - define TEAISH_ENABLE_DLL $::teaish__Config(dll-enabled) - define TEAISH_TCL $::teaish__Config(teaish.tcl) - - define TEAISH_DIST_FILES [join $::teaish__Config(dist-files)] - define TEAISH_EXT_DIR [join $::teaish__Config(extension-dir)] - define TEAISH_EXT_SRC [join $::teaish__Config(extension-src)] - proj-setup-autoreconfig TEAISH_AUTORECONFIG - foreach f { - TEAISH_CFLAGS - TEAISH_LDFLAGS - } { - # Ensure that any of these lists are flattened - define $f [join [get-define $f]] - } - define TEAISH__DEFINES_MAP \ - [teaish__dump_defs_to_list]; # injected into teaish.tester.tcl - proj-remap-autoconf-dir-vars - 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_*_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 "" -}; # teaish__configure_phase1 - -# -# 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 withSh [opt-val with-tclsh [proj-get-env TCLSH]] - set tclHome [opt-val with-tcl [proj-get-env TCL_HOME]] - if {[string match */lib $tclHome]} { - # TEA compatibility kludge: its --with-tcl wants the lib - # dir containing tclConfig.sh. - #proj-warn "Replacing --with-tcl=$tclHome for TEA compatibility" - regsub {/lib^} $tclHome "" tclHome - msg-result "NOTE: stripped /lib suffix from --with-tcl=$tclHome (a TEA-ism)" - } - if {0} { - # This misinteracts with the $TCL_PREFIX default: it will use the - # autosetup-defined --prefix default - if {"prefix" eq $tclHome} { - set tclHome [get-define prefix] - } - } - teaish-debug "use_tcl ${use_tcl}" - teaish-debug "withSh=${withSh}" - teaish-debug "tclHome=$tclHome" - if {"" eq $withSh && "" eq $tclHome} { - # If neither --with-tclsh nor --with-tcl are provided, try to find - # a workable tclsh. - set withSh [proj-first-bin-of tclsh9.1 tclsh9.0 tclsh8.6 tclsh] - teaish-debug "withSh=${withSh}" - } - - set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases - if {"" ne $withSh} { - # --with-tclsh was provided or found above. Validate it and use it - # to trump any value passed via --with-tcl=DIR. - if {![file-isexec $withSh]} { - proj-error "TCL shell $withSh is not executable" - } else { - define TCLSH_CMD $withSh - #msg-result "Using tclsh: $withSh" - } - if {$doConfigLookup && - [catch {exec $withSh $::autosetup(libdir)/find_tclconfig.tcl} result] == 0} { - set tclHome $result - } - if {"" ne $tclHome && [file isdirectory $tclHome]} { - teaish__verbose 1 msg-result "$withSh recommends the tclConfig.sh from $tclHome" - } else { - proj-warn "$withSh is unable to recommend a tclConfig.sh" - set use_tcl 0 - } - } - set cfg "" - set tclSubdirs {tcl9.1 tcl9.0 tcl8.6 tcl8.5 lib} - while {$use_tcl} { - if {"" ne $tclHome} { - # Ensure that we can find tclConfig.sh under ${tclHome}/... - if {$doConfigLookup} { - if {[file readable "${tclHome}/tclConfig.sh"]} { - set cfg "${tclHome}/tclConfig.sh" - } else { - foreach i $tclSubdirs { - if {[file readable "${tclHome}/$i/tclConfig.sh"]} { - set cfg "${tclHome}/$i/tclConfig.sh" - break - } - } - } - } - if {"" eq $cfg} { - proj-error "No tclConfig.sh found under ${tclHome}" - } - } 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 - }; # while {$use_tcl} - 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 $withSh && $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 withSh $trySh - break - } - } - if {![file-isexec $withSh]} { - proj-warn "Cannot find a usable tclsh (tried: $tryThese)" - } - } - define TCLSH_CMD $withSh - 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 $withSh && - [catch {exec echo "puts stdout \$auto_path" | "$withSh"} 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 $withSh]} { - teaish__verbose 1 msg-result "Using tclsh = $withSh" - 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 $withSh]} { - 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 near which 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] from [get-define TCL_PREFIX]." - teaish__tcl_platform_quirks -}; # teaish__check_tcl - -# -# Perform last-minute platform-specific tweaks to account for quirks. -# -proc teaish__tcl_platform_quirks {} { - define TEAISH_POSTINST_PREREQUIRE "" - switch -glob -- [get-define host] { - *-haiku { - # Haiku's default TCLLIBDIR is "all wrong": it points to a - # read-only virtual filesystem mount-point. We bend it back to - # fit under $TCL_PACKAGE_PATH here. - foreach {k d} { - vj TCL_MAJOR_VERSION - vn TCL_MINOR_VERSION - pp TCL_PACKAGE_PATH - ld TCLLIBDIR - } { - set $k [get-define $d] - } - if {[string match /packages/* $ld]} { - set old $ld - set tail [file tail $ld] - if {8 == $vj} { - set ld "${pp}/tcl${vj}.${vn}/${tail}" - } else { - proj-assert {9 == $vj} - set ld "${pp}/${tail}" - } - define TCLLIBDIR $ld - # [load foo.so], without a directory part, does not work via - # automated tests on Haiku (but works when run - # manually). Similarly, the post-install [package require ...] - # test fails, presumably for a similar reason. We work around - # the former in teaish.tester.tcl.in. We work around the - # latter by amending the post-install check's ::auto_path (in - # Makefile.in). This code MUST NOT contain any single-quotes. - define TEAISH_POSTINST_PREREQUIRE \ - [join [list set ::auto_path \ - \[ linsert \$::auto_path 0 $ld \] \; \ - ]] - proj-indented-notice [subst -nocommands -nobackslashes { - Haiku users take note: patching target installation dir to match - Tcl's home because Haiku's is not writable. - - Original : $old - Substitute: $ld - }] - } - } - } -}; # teaish__tcl_platform_quirks - -# -# 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 primarily locates the files -# which make up an extension and fills out no small amount of teaish -# state related to that. -# -proc teaish__find_extension {} { - proj-assert {!$::teaish__Config(install-mode)} - teaish__verbose 1 msg-result "Looking for teaish extension..." - - # Helper for the foreach loop below. - set checkTeaishTcl {{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 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 $checkTeaishTcl 1 teaish.tcl $extD] - set ::teaish__Config(extension-dir) $extD - } - --help { - incr gotHelpArg - lappend largv $arg - } - default { - lappend largv $arg - } - } - } - set ::argv $largv - - set dirExt $::teaish__Config(extension-dir); # 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] - proj-assert {$dirExt eq ""} - lappend flist $dirBld/teaish.tcl $dirSrc/teaish.tcl - if {![proj-first-file-found extT $flist]} { - if {$gotHelpArg} { - # Tell teaish-configure-core that the lack of extension is not - # an error when --help or --teaish-install 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" - } - set ::teaish__Config(teaish.tcl) $extT - set dirExt [file dirname $extT] - - set ::teaish__Config(extension-dir) $dirExt - set ::teaish__Config(blddir-is-extdir) [expr {$dirBld eq $dirExt}] - set ::teaish__Config(dist-enabled) $::teaish__Config(blddir-is-extdir); # may change later - set ::teaish__Config(dist-full-enabled) \ - [expr {[file-normalize $::autosetup(srcdir)] - eq [file-normalize $::teaish__Config(extension-dir)]}] - - set addDist {{file} { - teaish-dist-add [file tail $file] - }} - apply $addDist $extT - - teaish__verbose 1 msg-result "Extension dir = [teaish-get -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 extM \ - [list \ - $dirExt/teaish.make.in \ - $dirExt/teaish.make \ - ]]} { - if {[string match *.in $extM]} { - define TEAISH_MAKEFILE_IN $extM - define TEAISH_MAKEFILE [file rootname [file tail $extM]] - } 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] - set piPolicy 0 - if {[proj-first-file-found extI \ - [list \ - $dirExt/teaish.pkginit.tcl.in \ - $dirExt/teaish.pkginit.tcl \ - ]]} { - if {[string match *.in $extI]} { - # Generate teaish.pkginit.tcl from $extI. - define TEAISH_PKGINIT_TCL_IN $extI - define TEAISH_PKGINIT_TCL [file rootname [file tail $extI]] - set piPolicy 0x01 - } else { - # Assume static $extI. - define TEAISH_PKGINIT_TCL_IN "" - define TEAISH_PKGINIT_TCL $extI - set piPolicy 0x10 - } - 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 - } - set ::teaish__Config(pkginit-policy) $piPolicy - - # Look for pkgIndex.tcl[.in]... - set piPolicy 0 - if {[proj-first-file-found extPI $dirExt/pkgIndex.tcl.in]} { - # Generate ./pkgIndex.tcl from $extPI. - define TEAISH_PKGINDEX_TCL_IN $extPI - define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]] - apply $addDist $extPI - set piPolicy 0x01 - } elseif {$dirExt ne $dirSrc - && [proj-first-file-found extPI $dirSrc/pkgIndex.tcl.in]} { - # Generate ./pkgIndex.tcl from $extPI. - define TEAISH_PKGINDEX_TCL_IN $extPI - define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]] - set piPolicy 0x02 - } elseif {[proj-first-file-found extPI $dirExt/pkgIndex.tcl]} { - # Assume $extPI's a static file and use it. - define TEAISH_PKGINDEX_TCL_IN "" - define TEAISH_PKGINDEX_TCL $extPI - apply $addDist $extPI - set piPolicy 0x10 - } - # Reminder: we have to delay removal of stale TEAISH_PKGINDEX_TCL - # and the proj-dot-ins-append of TEAISH_PKGINDEX_TCL_IN until much - # later in the process. - 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 ttt $flist]} { - 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 - } 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 ttt $flist]} { - # 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 - if {[lindex $flist 0] eq $ttt} { - apply $addDist $ttt - } - unset ttt xt - } else { - if {[file exists [set ttt [file join $dirSrc teaish.tester.tcl.in]]]} { - set xt [file rootname [file tail $ttt]] - define TEAISH_TESTER_TCL $xt - define TEAISH_TESTER_TCL_IN $ttt - } else { - define TEAISH_TESTER_TCL "" - define TEAISH_TESTER_TCL_IN "" - } - } - unset flist - - # TEAISH_OUT_OF_EXT_TREE = 1 if we're building from a dir other - # than the extension's home dir. - define TEAISH_OUT_OF_EXT_TREE \ - [expr {[file-normalize $::autosetup(builddir)] ne \ - [file-normalize $::teaish__Config(extension-dir)]}] - 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 ?flags? defineName...|{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. -# -# It accepts these flags from proj-define-to-cflag: -quote, -# -zero-undef. It does _not_ support its -list flag. -# -# It accepts its non-flag argument(s) in 2 forms: (1) each arg is a -# single [define] key or (2) its one arg is a list of such keys. -# -# TODO: document teaish's well-defined (as it were) defines for this -# purpose. At a bare minimum: -# -# - TEAISH_NAME -# - TEAISH_PKGNAME -# - TEAISH_VERSION -# - TEAISH_LIBDIR_NAME -# - TEAISH_LOAD_PREFIX -# - TEAISH_URL -# -proc teaish-define-to-cflag {args} { - set flags {} - while {[string match -* [lindex $args 0]]} { - set arg [lindex $args 0] - switch -exact -- $arg { - -quote - - -zero-undef { - lappend flags $arg - set args [lassign $args -] - } - default break - } - } - if {1 == [llength $args]} { - set args [list {*}[lindex $args 0]] - } - #puts "***** flags=$flags args=$args" - teaish-cflags-add [proj-define-to-cflag {*}$flags {*}$args] -} - -# -# @teaish-cflags-for-tea ?...CFLAGS? -# -# Adds several -DPACKAGE_... CFLAGS using the extension's metadata, -# all as quoted strings. Those symbolic names are commonly used in -# TEA-based builds, and this function is intended to simplify porting -# of such builds. The -D... flags added are: -# -# -DPACKAGE_VERSION=... -# -DPACKAGE_NAME=... -# -DPACKAGE_URL=... -# -DPACKAGE_STRING=... -# -# Any arguments are passed-on as-is to teaish-cflags-add. -# -proc teaish-cflags-for-tea {args} { - set name $::teaish__PkgInfo(-name) - set version $::teaish__PkgInfo(-version) - set pstr [join [list $name $version]] - teaish-cflags-add \ - {*}$args \ - '-DPACKAGE_VERSION="$version"' \ - '-DPACKAGE_NAME="$name"' \ - '-DPACKAGE_STRING="$pstr"' \ - '-DPACKAGE_URL="[teaish-get -url]"' -} - -# -# @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 the project's list of C/C++ source or -# (in some cases) object files. -# -# If passed -dist then it also passes each filename, as-is, to -# [teaish-dist-add]. -# -# If passed -dir then each src-file has [teaish-get -dir] prepended to -# it before they're added to the list. 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, or when adding -# object files (which are typically in the build tree)). -# -proc teaish-src-add {args} { - set i 0 - proj-parse-simple-flags args flags { - -dist 0 {expr 1} - -dir 0 {expr 1} - } - if {$flags(-dist)} { - teaish-dist-add {*}$args - } - if {$flags(-dir)} { - set xargs {} - foreach arg $args { - if {"" ne $arg} { - lappend xargs [file join $::teaish__Config(extension-dir) $arg] - } - } - set args $xargs - } - lappend ::teaish__Config(extension-src) {*}$args -} - -# -# @teaish-dist-add files-or-dirs... -# -# Adds the given files to the list of files to include with the "make -# dist" rules. -# -# 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-get -dir] has been -# reliably set (via teaish__find_extension). -# -proc teaish-dist-add {args} { - if {$::teaish__Config(blddir-is-extdir)} { - # ^^^ reminder: we ignore $::teaish__Config(dist-enabled) here - # because the client might want to implement their own dist - # rules. - #proj-warn "**** args=$args" - lappend ::teaish__Config(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-make-add 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 -# -bnl: emit a backslash-escaped end-of-line -# -bnltab: short for -eol -tab -# -# Anything else is appended verbatim. This function adds no additional -# spacing between each argument nor between subsequent invocations. -# Generally speaking, a series of calls to this function need to -# be sure to end the series with a newline. -proc teaish-make-add {args} { - set out [get-define TEAISH_MAKEFILE_CODE ""] - foreach a $args { - switch -exact -- $a { - -bnl { set a " \\\n" } - -bnltab { 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 -} - -# Internal helper to generate a clean/distclean rule name -proc teaish__cleanup_rule {{tgt clean}} { - set x [incr ::teaish__Config(teaish__cleanup_rule-counter-${tgt})] - return ${tgt}-_${x}_ -} - -# @teaish-make-obj objfile srcfile ?...args? -# -# Uses teaish-make-add to inject makefile rules for $objfile from -# $srcfile, which is assumed to be C code which uses libtcl. Unless -# -recipe is used (see below) it invokes the compiler using the -# makefile-defined $(CC.tcl) which, in the default Makefile.in -# template, includes any flags needed for building against the -# configured Tcl. -# -# This always terminates the resulting code with a newline. -# -# Any arguments after the 2nd may be flags described below or, if no -# -recipe is provided, flags for the compiler call. -# -# -recipe {...} -# Uses the trimmed value of {...} as the recipe, prefixing it with -# a single hard-tab character. -# -# -deps {...} -# List of extra files to list as dependencies of $o. Good luck -# escaping non-trivial cases properly. -# -# -clean -# Generate cleanup rules as well. -proc teaish-make-obj {o src args} { - set consume 0 - set clean 0 - set flag "" - array set flags {} - set xargs {} - foreach arg $args { - if {$consume} { - set consume 0 - set flags($flag) $arg - continue - } - switch -exact -- $arg { - -clean {incr clean} - -recipe - - -deps { - set flag $arg - incr consume - } - default { - lappend xargs $arg - } - } - } - teaish-make-add \ - "# [proj-scope 1] -> [proj-scope] $o $src" -nl \ - "$o: $src $::teaish__Config(teaish.tcl)" - if {[info exists flags(-deps)]} { - teaish-make-add " " [join $flags(-deps)] - } - teaish-make-add -nltab - if {[info exists flags(-recipe)]} { - teaish-make-add [string trim $flags(-recipe)] -nl - } else { - teaish-make-add [join [list \$(CC.tcl) -c $src {*}$xargs]] -nl - } - if {$clean} { - set rule [teaish__cleanup_rule] - teaish-make-add \ - "clean: $rule\n$rule:\n\trm -f \"$o\"\n" - } -} - -# -# @teaish-make-clean ?-r? ?-dist? ...files|{...files} -# -# Adds makefile rules for cleaning up the given files via the "make -# clean" or (if -dist is used) "make distclean" makefile rules. The -r -# flag uses "rm -fr" instead of "rm -f", so be careful with that. -# -# The file names are taken literally as arguments to "rm", so they may -# be shell wildcards to be resolved at cleanup-time. To clean up whole -# directories, pass the -r flag. Each name gets quoted in -# double-quotes, so spaces in names should not be a problem (but -# double-quotes in names will be). -# -proc teaish-make-clean {args} { - if {1 == [llength $args]} { - set args [list {*}[lindex $args 0]] - } - - set tgt clean - set rmflags "-f" - proj-parse-simple-flags args flags { - -dist 0 { - set tgt distclean - } - -r 0 { - set rmflags "-fr" - } - } - set rule [teaish__cleanup_rule $tgt] - teaish-make-add "# [proj-scope 1] -> [proj-scope]: [join $args]\n" - teaish-make-add "${rule}:\n\trm ${rmflags}" - foreach a $args { - teaish-make-add " \"$a\"" - } - teaish-make-add "\n${tgt}: ${rule}\n" -} - -# -# @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 \ - -none {HAVE_CFLAG_* LDFLAGS_* SH_* TEAISH__* TEAISH_*_CODE} \ - -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-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-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). -# -# static-pkgIndex.tcl [L]: Tells teaish that ./pkgIndex.tcl is not -# a generated file, so it will not try to overwrite or delete -# it. Errors out if it does not find pkgIndex.tcl in the -# extension's dir. -# -# no-dist [L]: tells teaish to elide the 'make dist' recipe -# from the generated Makefile. -# -# no-dll [L]: tells teaish to elide the DLL-building recipe -# from the generated Makefile. -# -# no-vsatisfies-error [L]: tells teaish that failure to match the -# -vsatisfies value should simply "return" instead of "error". -# -# no-tester [L]: disables automatic generation of teaish.test.tcl -# even if a copy of teaish.tester.tcl.in is found. -# -# no-full-dist [L]: changes the "make dist" rules to never include -# a copy of teaish itself. By default it will include itself only -# if the extension lives in the same directory as teaish. -# -# full-dist [L]: changes the "make dist" rules to always include -# a copy of teaish itself. -# -# Emits a warning message for unknown arguments. -# -proc teaish__pragma {args} { - foreach arg $args { - switch -exact -- $arg { - - static-pkgIndex.tcl { - set tpi [file join $::teaish__Config(extension-dir) pkgIndex.tcl] - if {[file exists $tpi]} { - define TEAISH_PKGINDEX_TCL_IN "" - define TEAISH_PKGINDEX_TCL $tpi - set ::teaish__Config(pkgindex-policy) 0x20 - } else { - proj-error "$arg: found no package-local pkgIndex.tcl\[.in]" - } - } - - no-dist { - set ::teaish__Config(dist-enabled) 0 - } - - full-dist { - set ::teaish__Config(dist-full-enabled) 1 - } - - no-full-dist { - set ::teaish__Config(dist-full-enabled) 0 - } - - no-dll { - set ::teaish__Config(dll-enabled) 0 - } - - no-vsatisfies-error { - set ::teaish__Config(vsatisfies-error) 0 - } - - no-tester { - define TEAISH_TESTER_TCL_IN "" - define TEAISH_TESTER_TCL "" - } - - default { - proj-error "Unknown flag: $arg" - } - } - } -} - -# -# @teaish-pkginfo-set ...flags -# -# The way to set up the initial package state. Used like: -# -# teaish-pkginfo-set -name foo -version 0.1.2 -# -# Or: -# -# teaish-pkginfo-set ?-vars|-subst? {-name foo -version 0.1.2} -# -# The latter may be easier to write for a multi-line invocation. -# -# For the second call form, passing the -vars flag tells it to perform -# a [subst] of (only) variables in the {...} part from the calling -# scope. The -subst flag will cause it to [subst] the {...} with -# command substitution as well (but no backslash substitution). When -# using -subst for string concatenation, e.g. with -libDir -# foo[get-version-number], be sure to wrap the value in braces: -# -libDir {foo[get-version-number]}. -# -# Each pkginfo flag corresponds to one piece of extension package -# info. Teaish provides usable default values for all of these flags, -# but at least the -name and -version should be set by clients. -# e.g. the default -name is the directory name the extension lives in, -# which may change (e.g. when building it from a "make dist" bundle). -# -# The flags: -# -# -name theName: The extension's name. It defaults to the name of the -# directory containing the extension. (In TEA this would be the -# PACKAGE_NAME, not to be confused with...) -# -# -name.pkg pkg-provide-name: The extension's name for purposes of -# Tcl_PkgProvide(), [package require], and friends. It defaults to -# the `-name`, and is normally the same, but some projects (like -# SQLite) have a different name here than they do in their -# historical TEA PACKAGE_NAME. -# -# -version version: The extension's package version. Defaults to -# 0.0.0. -# -# -libDir dirName: The base name of the directory into which this -# extension should be installed. It defaults to a concatenation of -# `-name.pkg` and `-version`. -# -# -loadPrefix prefix: For use as the second argument passed to -# Tcl's `load` command in the package-loading process. It defaults -# to title-cased `-name.pkg` because Tcl's `load` plugin system -# expects it in that form. -# -# -options {...}: If provided, it must be a list compatible with -# Autosetup's `options-add` function. These can also be set up via -# `teaish-options`. -# -# -vsatisfies {{...} ...}: Expects a list-of-lists of conditions -# for Tcl's `package vsatisfies` command: each list entry is a -# sub-list of `{PkgName Condition...}`. Teaish inserts those -# checks via its default pkgIndex.tcl.in and teaish.tester.tcl.in -# templates to verify that the system's package dependencies meet -# these requirements. The default value is `{{Tcl 8.5-}}` (recall -# that it's a list-of-lists), as 8.5 is the minimum Tcl version -# teaish will run on, but some extensions may require newer -# versions or dependencies on other packages. As a special case, -# if `-vsatisfies` is given a single token, e.g. `8.6-`, then it -# is transformed into `{Tcl $thatToken}`, i.e. it checks the Tcl -# version which the package is being run with. If given multiple -# lists, each `package provides` check is run in the given -# order. Failure to meet a `vsatisfies` condition triggers an -# error. -# -# -url {...}: an optional URL for the extension. -# -# -pragmas {...} A list of infrequently-needed lower-level -# directives which can influence teaish, including: -# -# static-pkgIndex.tcl: tells teaish that the client manages their -# own pkgIndex.tcl, so that teaish won't try to overwrite it -# using a template. -# -# no-dist: tells teaish to elide the "make dist" recipe from the -# makefile so that the client can implement it. -# -# no-dll: tells teaish to elide the makefile rules which build -# the DLL, as well as any templated test script and pkgIndex.tcl -# references to them. The intent here is to (A) support -# client-defined build rules for the DLL and (B) eventually -# support script-only extensions. -# -# Unsupported flags or pragmas will trigger an error. -# -# Potential pothole: setting certain state, e.g. -version, after the -# initial call requires recalculating of some [define]s. Any such -# changes should be made as early as possible in teaish-configure so -# that any later use of those [define]s gets recorded properly (not -# with the old value). This is particularly relevant when it is not -# possible to determine the -version or -name until teaish-configure -# has been called, and it's updated dynamically from -# teaish-configure. Notably: -# -# - If -version or -name are updated, -libDir will almost certainly -# need to be explicitly set along with them. -# -# - If -name is updated, -loadPrefix probably needs to be as well. -# -proc teaish-pkginfo-set {args} { - set doVars 0 - set doCommands 0 - set xargs $args - set recalc {} - foreach arg $args { - switch -exact -- $arg { - -vars { - incr doVars - set xargs [lassign $xargs -] - } - -subst { - incr doVars - incr doCommands - set xargs [lassign $xargs -] - } - default { - break - } - } - } - set args $xargs - unset xargs - if {1 == [llength $args] && [llength [lindex $args 0]] > 1} { - # Transform a single {...} arg into the canonical call form - set a [list {*}[lindex $args 0]] - if {$doVars || $doCommands} { - set sflags -nobackslashes - if {!$doCommands} { - lappend sflags -nocommands - } - set a [uplevel 1 [list subst {*}$sflags $a]] - } - set args $a - } - set sentinel "<nope>" - set flagDefs [list] - foreach {f d} $::teaish__Config(pkginfo-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-scope]: $args" - } - foreach {f d} $::teaish__Config(pkginfo-f2d) { - if {$sentinel eq [set v $flags($f)]} continue - switch -exact -- $f { - -options { - proj-assert {"" eq $d} - options-add $v - } - -pragmas { - foreach p $v { - teaish__pragma $p - } - } - -vsatisfies { - if {1 == [llength $v] && 1 == [llength [lindex $v 0]]} { - # Transform X to {Tcl $X} - set v [list [join [list Tcl $v]]] - } - define $d $v - } - -pkgInit.tcl.in { - # Generate pkginit file X from X.in - set ::teaish__Config(pkginit-policy) 0x02 - set x [file join $::teaish__Config(extension-dir) $v] - define TEAISH_PKGINIT_TCL_IN $x - set fout [file rootname [file tail $v]] - define TEAISH_PKGINIT_TCL $fout - define TEAISH_PKGINIT_TCL_TAIL $fout - set ::teaish__PkgInfo(-pkgInit.tcl) {} - teaish-dist-add $v - set v $x - } - -pkgInit.tcl { - # Static pkginit file X - set ::teaish__Config(pkginit-policy) 0x20 - set x [file join $::teaish__Config(extension-dir) $v] - define TEAISH_PKGINIT_TCL $x - define TEAISH_PKGINIT_TCL_IN "" - define TEAISH_PKGINIT_TCL_TAIL [file tail $v] - set ::teaish__PkgInfo(-pkgInit.tcl.in) {} - teaish-dist-add $v - set v $x - } - default { - define $d $v - } - } - set ::teaish__PkgInfo($f) $v - if {$f in {-name -version -libDir -loadPrefix}} { - lappend recalc $f - } - } - if {"" ne $recalc} { - teaish__define_pkginfo_derived $recalc - } -} - -# -# @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__PkgInfo($flag)]} { - lappend rv $flag $::teaish__PkgInfo($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__PkgInfo($flag)]} { - return $::teaish__PkgInfo($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__PkgInfo($flag)]} { - set tgt($flag) $::teaish__PkgInfo($flag) - } else { - set tgt($flag) [get-define $defName] - } - }} - } - } - - default { - proj-error "invalid arg count from [proj-scope 1]" - } - } - - foreach {flag defName} $::teaish__Config(pkginfo-f2d) { - switch -exact -- $flag [join $cases] - } - if {0 == $argc} { return $rv } -} - -# (Re)set some defines based on pkginfo state. $flags is the list of -# pkginfo -flags which triggered this, or "*" for the initial call. -proc teaish__define_pkginfo_derived {flags} { - set all [expr {{*} in $flags}] - if {$all || "-version" in $flags || "-name" in $flags} { - set name $::teaish__PkgInfo(-name) ; # _not_ -name.pkg - if {[info exists ::teaish__PkgInfo(-version)]} { - set pkgver $::teaish__PkgInfo(-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 - } - } - if {$all || "-libDir" in $flags} { - if {[info exists ::teaish__PkgInfo(-libDir)]} { - define TCLLIBDIR \ - [file dirname [get-define TCLLIBDIR]]/$::teaish__PkgInfo(-libDir) - } - } -} - -# -# @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}) {} -} - -# -# A general-purpose getter for various teaish state. Requires one -# flag, which determines its result value. Flags marked with [L] below -# are safe for using at load-time, before teaish-pkginfo-set is called -# -# -dir [L]: returns the extension's directory, which may differ from -# the teaish core dir or the build dir. -# -# -teaish-home [L]: the "home" dir of teaish itself, which may -# differ from the extension dir or build dir. -# -# -build-dir [L]: the build directory (typically the current working -# -dir). -# -# Any of the teaish-pkginfo-get/get flags: returns the same as -# teaish-pkginfo-get. Not safe for use until teaish-pkginfo-set has -# been called. -# -# Triggers an error if passed an unknown flag. -# -proc teaish-get {flag} { - #-teaish.tcl {return $::teaish__Config(teaish.tcl)} - switch -exact -- $flag { - -dir { - return $::teaish__Config(extension-dir) - } - -teaish-home { - return $::autosetup(srcdir) - } - -build-dir { - return $::autosetup(builddir) - } - default { - if {[info exists ::teaish__PkgInfo($flag)]} { - return $::teaish__PkgInfo($flag) - } - } - } - proj-error "Unhandled flag: $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/generic - set cwd [pwd] - #set dir [file-normalize [file join $cwd $dir]] - teaish__verbose 1 msg-result "Created dir $dir" - cd $dir - if {!$force} { - # Ensure that we don't blindly overwrite anything - foreach f { - generic/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 } - #puts "0 content=$content" - if {[opt-str teaish-extension-pkginfo epi]} { - set epi [string trim $epi] - if {[string match "*\n*" $epi]} { - set epi "{$epi}" - } elseif {![string match "{*}" $epi]} { - append content "\{" $epi "\}" - } else { - append content $epi - } - #puts "2 content=$content\nepi=$epi" - } else { - append content [subst -nocommands -nobackslashes {{ - -name ${name} - -name.pkg ${pkgName} - -name.dist ${pkgName} - -version ${version} - -loadPrefix $loadPrefix - -libDir ${name}${version} - -vsatisfies {{Tcl 8.5-}} - -url {} - -options {} - -pragmas {full-dist} - }}] - #puts "3 content=$content" - } - #puts "1 content=$content" - append content "\n" { -#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\]. - # - # If there are no options to add, this proc need - # not be defined. -#} - -# Called by teaish once bootstrapping is complete. -# This function is responsible for the client-specific -# parts of the configuration process. -proc teaish-configure {} { - teaish-src-add -dir -dist generic/teaish.c - teaish-define-to-cflag -quote TEAISH_PKGNAME TEAISH_VERSION - - # TODO: your code goes here.. -} -}; # $content - proj-file-write teaish.tcl $content - teaish__verbose 1 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 - teaish__verbose 1 msg-result "Created teaish.test.tcl" - - set content [subst -nocommands -nobackslashes { -#include <tcl.h> -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, TEAISH_PKGNAME, TEAISH_VERSION) == TCL_ERROR) { - return TCL_ERROR; - } - Tcl_CreateObjCommand(interp, TEAISH_PKGNAME, ${loadPrefix}_Cmd, NULL, NULL); - return TCL_OK; -} -}] - proj-file-write generic/teaish.c $content - teaish__verbose 1 msg-result "Created generic/teaish.c" - - set content "# teaish makefile for the ${name} extension -# tx.src = \$(tx.dir)/generic/teaish.c -# tx.LDFLAGS = -# tx.CFLAGS = -" - proj-file-write teaish.make.in $content - teaish__verbose 1 msg-result "Created teaish.make.in" - - msg-result "Created new extension $name in \[$dir]." - - cd $cwd - set ::teaish__Config(install-ext-dir) $dir -} - -# -# Internal helper for teaish__install -# -proc teaish__install_file {f destDir force} { - set dest $destDir/[file tail $f] - if {[file isdirectory $f]} { - file mkdir $dest - } elseif {!$force && [file exists $dest]} { - array set st1 [file stat $f] - array set st2 [file stat $dest] - if {($st1(mtime) == $st2(mtime)) - && ($st1(size) == $st2(size))} { - if {[file tail $f] in { - pkgIndex.tcl.in - teaish.tester.tcl.in - }} { - # Assume they're the same. In the scope of the "make dist" - # rules, this happens legitimately when an extension with a - # copy of teaish installed in the same dir assumes that the - # pkgIndex.tcl.in and teaish.tester.tcl.in belong to the - # extension, whereas teaish believes they belong to teaish. - # So we end up with dupes of those. - return - } - } - proj-error -up "Cowardly refusing to overwrite \[$dest\]." \ - "Use --teaish-force to enable overwriting." - } else { - # file copy -force $f $destDir; # loses +x bit - # - # JimTcl doesn't have [file attribute], so we can't use that here - # (in the context of an autosetup configure script). - exec cp -p $f $dest - } -} - -# -# Installs a copy of teaish, with autosetup, to $dDest, which defaults -# to the --teaish-install=X or --teash-create-extension=X dir. Won't -# overwrite files unless --teaish-force is used. -# -proc teaish__install {{dDest ""}} { - if {$dDest in {auto ""}} { - set dDest [opt-val teaish-install] - if {$dDest in {auto ""}} { - if {[info exists ::teaish__Config(install-ext-dir)]} { - set dDest $::teaish__Config(install-ext-dir) - } - } - } - set force [opt-bool teaish-force] - if {$dDest in {auto ""}} { - proj-error "Cannot determine installation directory." - } elseif {!$force && [file exists $dDest/auto.def]} { - proj-error \ - "Target dir looks like it already contains teaish and/or autosetup: $dDest" \ - "\nUse --teaish-force to overwrite it." - } - - set dSrc $::autosetup(srcdir) - set dAS $::autosetup(libdir) - set dAST $::teaish__Config(core-dir) - set dASTF $dAST/feature - teaish__verbose 1 msg-result "Installing teaish to \[$dDest\]..." - if {$::teaish__Config(verbose)>1} { - msg-result "dSrc = $dSrc" - msg-result "dAS = $dAS" - msg-result "dAST = $dAST" - msg-result "dASTF = $dASTF" - msg-result "dDest = $dDest" - } - - # Dest subdirs... - set ddAS $dDest/autosetup - set ddAST $ddAS/teaish - set ddASTF $ddAST/feature - foreach {srcDir destDir} [list \ - $dAS $ddAS \ - $dAST $ddAST \ - $dASTF $ddASTF \ - ] { - teaish__verbose 1 msg-result "Copying files to $destDir..." - file mkdir $destDir - foreach f [glob -directory $srcDir *] { - if {[string match {*~} $f] || [string match "#*#" [file tail $f]]} { - # Editor-generated backups and emacs lock files - continue - } - teaish__verbose 2 msg-result "\t$f" - teaish__install_file $f $destDir $force - } - } - teaish__verbose 1 msg-result "Copying files to $dDest..." - foreach f { - auto.def configure Makefile.in pkgIndex.tcl.in - teaish.tester.tcl.in - } { - teaish__verbose 2 msg-result "\t$f" - teaish__install_file $dSrc/$f $dDest $force - } - set ::teaish__Config(install-self-dir) $dDest - msg-result "Teaish $::teaish__Config(version) installed in \[$dDest\]." -} diff --git a/autoconf/tea/autosetup/feature-tests.tcl b/autoconf/tea/autosetup/feature-tests.tcl deleted file mode 100644 index 6c927d1a7..000000000 --- a/autoconf/tea/autosetup/feature-tests.tcl +++ /dev/null @@ -1,214 +0,0 @@ -######################################################################## -# 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 <stdint.h> 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-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 deleted file mode 100644 index 5c546e841..000000000 --- a/autoconf/tea/autosetup/tester.tcl +++ /dev/null @@ -1,193 +0,0 @@ -######################################################################## -# 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, minus any leading or trailing whitespace. If they differ, -# it triggers an [assert]. -# -proc test-expect {testId script result} { - puts "test $testId" - set x [string trim [uplevel 1 $script]] - set result [string trim $result] - 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-flag3 flag tgtVar ?dflt? -# -# 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 #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. -# -# 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-flag3 {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-flag3 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-flag3 $flag tgt $dflt - return $tgt -} diff --git a/autoconf/tea/doc/sqlite3.n b/autoconf/tea/doc/sqlite3.n deleted file mode 100644 index 351404634..000000000 --- a/autoconf/tea/doc/sqlite3.n +++ /dev/null @@ -1,15 +0,0 @@ -.TH sqlite3 n 4.1 "Tcl-Extensions" -.HS sqlite3 tcl -.BS -.SH NAME -sqlite3 \- an interface to the SQLite3 database engine -.SH SYNOPSIS -\fBsqlite3\fI command_name ?filename?\fR -.br -.SH DESCRIPTION -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 \fIhttps://sqlite.org/\fR and -in particular \fIhttps://sqlite.org/tclsqlite.html\fR. diff --git a/autoconf/tea/teaish.tcl b/autoconf/tea/teaish.tcl index 87d059c32..47e0ea701 100644 --- a/autoconf/tea/teaish.tcl +++ b/autoconf/tea/teaish.tcl @@ -64,12 +64,18 @@ apply {{dir} { -name.pkg sqlite3 -version $version -name.dist $distname - -vsatisfies 8.6- -libDir sqlite$version -pragmas $pragmas + -src generic/tclsqlite3.c } + # We should also have: + # -vsatisfies 8.6- + # But at least one platform is failing this vsatisfies check + # for no apparent reason: + # https://sqlite.org/forum/forumpost/fde857fb8101a4be }} [teaish-get -dir] + # # Must return either an empty string or a list in the form accepted by # autosetup's [options] function. @@ -117,9 +123,7 @@ proc teaish-options {} { # work needed for this extension. # proc teaish-configure {} { - use teaish/feature-tests - - teaish-src-add -dist -dir generic/tclsqlite3.c + use teaish/feature if {[proj-opt-was-provided override-sqlite-version]} { teaish-pkginfo-set -version [opt-val override-sqlite-version] |