From 1e24694b593ac2bcd792e81125cd32bee1580b45 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 17 May 2025 07:02:06 +0000 Subject: Latest upstream teaish pieces for minor fixes. Restructure this copy of teaish to simplify maintenance and the autoconf bundle build. FossilOrigin-Name: 2b8d9b75ec5fe96cb5d06a3464fd4eb9a53018b7b548fedcd6cdbc46cdb55bdc --- autoconf/tea/Makefile.in | 73 +- autoconf/tea/_teaish.tester.tcl.in | 49 + autoconf/tea/autosetup/README.txt | 4 - autoconf/tea/autosetup/core.tcl | 2368 ---------------------------- autoconf/tea/autosetup/feature-tests.tcl | 214 --- autoconf/tea/autosetup/tester.tcl | 193 --- autoconf/tea/teaish.tcl | 2 +- autoconf/tea/teaish.tester.tcl.in | 43 - autosetup/proj.tcl | 94 +- autosetup/teaish/README.txt | 4 + autosetup/teaish/core.tcl | 2532 ++++++++++++++++++++++++++++++ autosetup/teaish/feature-tests.tcl | 214 +++ autosetup/teaish/tester.tcl | 228 +++ manifest | 33 +- manifest.uuid | 2 +- tool/mkautoconfamal.sh | 6 +- 16 files changed, 3158 insertions(+), 2901 deletions(-) create mode 100644 autoconf/tea/_teaish.tester.tcl.in delete mode 100644 autoconf/tea/autosetup/README.txt delete mode 100644 autoconf/tea/autosetup/core.tcl delete mode 100644 autoconf/tea/autosetup/feature-tests.tcl delete mode 100644 autoconf/tea/autosetup/tester.tcl delete mode 100644 autoconf/tea/teaish.tester.tcl.in create mode 100644 autosetup/teaish/README.txt create mode 100644 autosetup/teaish/core.tcl create mode 100644 autosetup/teaish/feature-tests.tcl create mode 100644 autosetup/teaish/tester.tcl diff --git a/autoconf/tea/Makefile.in b/autoconf/tea/Makefile.in index ad71c8b3e..5b2ad4c69 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@ @@ -157,23 +167,12 @@ 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 -# -teaish__cleanExtra = - # List of deps which may trigger an auto-reconfigure. # teaish__autogen.deps = \ $(tx.makefile.in) $(teaish.makefile.in) \ $(tx.tcl) \ - @TEAISH_PKGINDEX_TCL_IN@ \ + @TEAISH_PKGINDEX_TCL_IN@ @TEAISH_TM_TCL_IN@ \ @AUTODEPS@ @if TEAISH_MAKEFILE_IN @@ -271,10 +270,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 @@ -300,26 +299,59 @@ 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)]..."; \ @@ -344,10 +376,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) diff --git a/autoconf/tea/_teaish.tester.tcl.in b/autoconf/tea/_teaish.tester.tcl.in new file mode 100644 index 000000000..59d11f0a8 --- /dev/null +++ b/autoconf/tea/_teaish.tester.tcl.in @@ -0,0 +1,49 @@ +# -*- tcl -*- +# +# Unless this file is named _teaish.tester.tcl.in, you are probably +# looking at an automatically generated/filtered copy and should +# probably not edit it. +# +# This is the wrapper script invoked by teaish's "make test" recipe. +# It gets passed 3 args: +# +# $1 = the DLL name, or "" if the extension has no DLL +# +# $2 = the "load prefix" for Tcl's [load] or empty if $1 is empty +# +# $3 = the /path/to/teaish/tester.tcl (test utility code) +# +@if TEAISH_VSATISFIES_CODE +@TEAISH_VSATISFIES_CODE@ +@endif +if {[llength [lindex $::argv 0]] > 0} { + load [file normalize [lindex $::argv 0]] [lindex $::argv 1]; + # ----^^^^^^^ 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 +@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*] + array set ::teaish__BuildFlags @TEAISH__DEFINES_MAP@ + set dir [file normalize [file dirname $file]] + #test-fail "Just testing" + source -encoding utf-8 $file +}} [join {@TEAISH_TEST_TCL@}] +@else # TEAISH_TEST_TCL +# No $TEAISH_TEST_TCL provided, so here's a default test which simply +# loads the extension. +puts {Extension @TEAISH_NAME@ @TEAISH_VERSION@ successfully loaded from @TEAISH_TESTER_TCL@} +@endif diff --git a/autoconf/tea/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 /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 ""] - if {"" 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 - # 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 "" - 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 -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 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/teaish.tcl b/autoconf/tea/teaish.tcl index 87d059c32..9333495aa 100644 --- a/autoconf/tea/teaish.tcl +++ b/autoconf/tea/teaish.tcl @@ -117,7 +117,7 @@ proc teaish-options {} { # work needed for this extension. # proc teaish-configure {} { - use teaish/feature-tests + use teaish/feature teaish-src-add -dist -dir generic/tclsqlite3.c diff --git a/autoconf/tea/teaish.tester.tcl.in b/autoconf/tea/teaish.tester.tcl.in deleted file mode 100644 index 4e203cd78..000000000 --- a/autoconf/tea/teaish.tester.tcl.in +++ /dev/null @@ -1,43 +0,0 @@ -# -*- tcl -*- -# -# Unless this file is named teaish.tester.tcl.in, you are probably -# looking at an automatically generated/filtered copy and should -# probably not edit it. -# -# This is the wrapper script invoked by teaish's "make test" recipe. -# It gets passed 3 args: -# -# $1 = the DLL name, or "" if the extension has no DLL -# -# $2 = the "load prefix" for Tcl's [load] or empty if $1 is empty -# -# $3 = the /path/to/teaish/tester.tcl (test utility code) -# -@if TEAISH_VSATISFIES_CODE -@TEAISH_VSATISFIES_CODE@ -@endif -if {[llength [lindex $::argv 0]] > 0} { - load [file normalize [lindex $::argv 0]] [lindex $::argv 1]; - # ----^^^^^^^ 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 -@if TEAISH_PKGINIT_TCL -apply {{file} { - set dir [file dirname $::argv0] - source -encoding utf-8 $file -}} [join {@TEAISH_PKGINIT_TCL@}] -@endif -@if TEAISH_TEST_TCL -apply {{file} { - # Populate state for [tester.tcl::teaish-build-flag*] - array set ::teaish__BuildFlags @TEAISH__DEFINES_MAP@ - set dir [file normalize [file dirname $file]] - #test-fail "Just testing" - source -encoding utf-8 $file -}} [join {@TEAISH_TEST_TCL@}] -@else # TEAISH_TEST_TCL -# No $TEAISH_TEST_TCL provided, so here's a default test which simply -# loads the extension. -puts {Extension @TEAISH_NAME@ @TEAISH_VERSION@ successfully loaded from @TEAISH_TESTER_TCL@} -@endif diff --git a/autosetup/proj.tcl b/autosetup/proj.tcl index 4691cfe36..a4957ed61 100644 --- a/autosetup/proj.tcl +++ b/autosetup/proj.tcl @@ -60,8 +60,8 @@ # $proj__Config is an internal-use-only array for storing whatever generic # internal stuff we need stored. # -array set proj__Config { - self-tests 0 +array set ::proj__Config { + self-tests 1 } @@ -74,8 +74,8 @@ array set proj__Config { # # See: proj-dot-ins-append and proj-dot-ins-process # -set proj__Config(dot-in-files) [list] -set proj__Config(isatty) [isatty? stdout] +set ::proj__Config(dot-in-files) [list] +set ::proj__Config(isatty) [isatty? stdout] # # @proj-warn msg @@ -88,6 +88,25 @@ proc proj-warn {args} { puts stderr [join [list "WARNING: \[[proj-scope 1]\]: " {*}$args] " "] } + +# Internal impl of [proj-fatal] and [proj-error]. It must be called +# using tailcall. +proc proj__faterr {failMode argv} { + show-notices + set lvl 1 + while {"-up" eq [lindex $argv 0]} { + set argv [lassign $argv -] + incr lvl + } + if {$failMode} { + puts stderr [join [list "FATAL: \[[proj-scope $lvl]]: " {*}$argv]] + exit 1 + } else { + error [join [list "\[[proj-scope $lvl]]:" {*}$argv]] + } +} + + # # @proj-fatal ?-up...? msg... # @@ -99,31 +118,19 @@ proc proj-warn {args} { # additional level. # proc proj-fatal {args} { - show-notices - set lvl 1 - while {"-up" eq [lindex $args 0]} { - set args [lassign $args -] - incr lvl - } - puts stderr [join [list "FATAL: \[[proj-scope $lvl]]: " {*}$args]] - exit 1 + tailcall proj__faterr 1 $args } # # @proj-error ?-up...? msg... # -# Works like prop-fatal but uses [error] intead of [exit]. +# Works like proj-fatal but uses [error] intead of [exit]. # proc proj-error {args} { - show-notices - set lvl 1 - while {"-up" eq [lindex $args 0]} { - set args [lassign $args -] - incr lvl - } - error [join [list "\[[proj-scope $lvl]]:" {*}$args]] + tailcall proj__faterr 0 $args } +set ::proj__Config(verbose-assert) [get-env proj-assert-verbose 0] # # @proj-assert script ?message? # @@ -133,7 +140,7 @@ proc proj-error {args} { # used instead. # proc proj-assert {script {msg ""}} { - if {1 == [get-env proj-assert 0]} { + if {1 eq $::proj__Config(verbose-assert)} { msg-result [proj-bold "asserting: $script"] } if {![uplevel 1 [list expr $script]]} { @@ -162,7 +169,9 @@ proc proj-bold {args} { # @proj-indented-notice ?-error? ?-notice? msg # # Takes a multi-line message and emits it with consistent indentation. -# It does not perform any line-wrapping of its own. +# It does not perform any line-wrapping of its own. Which output +# routine it uses depends on its flags, defaulting to msg-result. +# For -error and -notice it uses user-notice. # # If the -notice flag it used then it emits using [user-notice], which # means its rendering will (A) go to stderr and (B) be delayed until @@ -176,7 +185,7 @@ proc proj-bold {args} { # proc proj-indented-notice {args} { set fErr "" - set outFunc "puts" + set outFunc "msg-result" while {[llength $args] > 1} { switch -exact -- [lindex $args 0] { -error { @@ -632,7 +641,7 @@ proc proj-no-check-module-loader {} { } # -# @proj-file-conent ?-trim? filename +# @proj-file-content ?-trim? filename # # Opens the given file, reads all of its content, and returns it. If # the first arg is -trim, the contents of the file named by the second @@ -701,10 +710,10 @@ proc proj-file-write {args} { # argument it is assumed to be the name of an autosetup boolean config # which controls whether to run/skip this check. # -# Returns 1 if supported, else 0. Defines MAKE_COMPILATION_DB to "yes" -# if supported, "no" if not. The use of MAKE_COMPILATION_DB is -# deprecated/discouraged. It also sets HAVE_COMPILE_COMMANDS to 0 or -# 1, and that's the preferred usage. +# Returns 1 if supported, else 0, and defines HAVE_COMPILE_COMMANDS to +# that value. Defines MAKE_COMPILATION_DB to "yes" if supported, "no" +# if not. The use of MAKE_COMPILATION_DB is deprecated/discouraged: +# HAVE_COMPILE_COMMANDS is preferred. # # ACHTUNG: this test has a long history of false positive results # because of compilers reacting differently to the -MJ flag. @@ -713,6 +722,7 @@ proc proj-check-compile-commands {{configFlag {}}} { msg-checking "compile_commands.json support... " if {"" ne $configFlag && ![proj-opt-truthy $configFlag]} { msg-result "explicitly disabled" + define HAVE_COMPILE_COMMANDS 0 define MAKE_COMPILATION_DB no return 0 } else { @@ -787,7 +797,12 @@ proc proj-make-from-dot-in {args} { catch { exec chmod u+w $fOut } } #puts "making template: $fIn ==> $fOut" - make-template $fIn $fOut + #define-push {top_srcdir} { + #puts "--- $fIn $fOut top_srcdir=[get-define top_srcdir]" + make-template $fIn $fOut + #puts "--- $fIn $fOut top_srcdir=[get-define top_srcdir]" + # make-template modifies top_srcdir + #} if {$touch} { proj-touch $fOut } @@ -1220,7 +1235,7 @@ proc proj-quote-str_ {value} { # the formatted value or the value $::proj__Config(defs-skip) if the caller # should skip emitting that value. # -set proj__Config(defs-skip) "-proj-defs-format_ sentinel" +set ::proj__Config(defs-skip) "-proj-defs-format_ sentinel" proc proj-defs-format_ {type value} { switch -exact -- $type { -bare { @@ -1258,6 +1273,8 @@ proc proj-defs-format_ {type value} { return $value } +# +# @proj-dump-defs-json outfile ...flags # # This function works almost identically to autosetup's # make-config-header but emits its output in JSON form. It is not a @@ -1965,12 +1982,10 @@ array set proj__Cache {} # then used to generate the key. i.e. the default of 0 uses the # calling scope's name as the key. # -# "-": same as 0 -# # Anything else: returned as-is # proc proj-cache-key {{addLevel 0} arg} { - if {"-" eq $arg} {set arg 0} + #if {"-" eq $arg} {set arg 0} if {[string is integer -strict $arg]} { return [proj-scope [expr {$arg + $addLevel + 1}]] } @@ -2046,8 +2061,6 @@ proc proj-coalesce {args} { # # @proj-parse-simple-flags ... # -# An experiment. Do not use. -# # A helper to parse flags from proc argument lists. # # Expects a list of arguments to parse, an array name to store any @@ -2097,19 +2110,20 @@ proc proj-coalesce {args} { # # Example: # -# set args [list -foo -bar {blah} 8 9 10] -# set args [proj-parse-simple-flags args flags { +# set args [list -foo -bar {blah} 8 9 10 -theEnd] +# proj-parse-simple-flags args flags { # -foo 0 {expr 1} # -bar => 0 # -no-baz 2 {return 0} # } # # After that $flags would contain {-foo 1 -bar {blah} -no-baz 2} -# and $args would be {8 9 10}. +# and $args would be {8 9 10 -theEnd}. # # Potential TODOs: consider using lappend instead of set so that any # given flag can be used more than once. Or add a syntax to indicate -# that. +# that multiples are allowed. Also consider searching the whole +# argv list, rather than stopping at the first non-flag # proc proj-parse-simple-flags {argvName tgtArrayName prototype} { upvar $argvName argv @@ -2187,7 +2201,7 @@ proc proj-parse-simple-flags {argvName tgtArrayName prototype} { if {$::proj__Config(self-tests)} { apply {{} { - proj-warn "Test code for proj-cache" + #proj-warn "Test code for proj-cache" proj-assert {![proj-cache-check here check]} proj-assert {"here" eq [proj-cache-key here]} proj-assert {"" eq $check} diff --git a/autosetup/teaish/README.txt b/autosetup/teaish/README.txt new file mode 100644 index 000000000..e11519b04 --- /dev/null +++ b/autosetup/teaish/README.txt @@ -0,0 +1,4 @@ +The *.tcl files in this directory are part of the SQLite's "autoconf" +bundle which are specific to the TEA(-ish) build. During the tarball +generation process, they are copied into /autoconf/autosetup/teaish +(which itself is created as part of that process). diff --git a/autosetup/teaish/core.tcl b/autosetup/teaish/core.tcl new file mode 100644 index 000000000..5476206ed --- /dev/null +++ b/autosetup/teaish/core.tcl @@ -0,0 +1,2532 @@ +######################################################################## +# 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 + # 0x100 = disabled by -tm.tcl.in + # 0x200 = disabled by -tm.tcl + # + # 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 + # + # 0 = no tm.tcl + # 0x01 = tm.tcl.in + # 0x10 = static tm.tcl + tm-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 after initialization. + # + 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 + -tm.tcl TEAISH_TM_TCL + -tm.tcl.in TEAISH_TM_TCL_IN + -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 + # Whether or not "make install" parts are enabled. By default + # they are, but we have a single use case where they're + # both unnecessary and unhelpful, so... + install-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} { + # We found an extension. Source it... + set ttcl $::teaish__Config(teaish.tcl) + proj-assert {"" ne [teaish-pkginfo-get -name]} + proj-assert {[file exists $ttcl]} \ + "Expecting to have found teaish.(tcl|config) by now" + if {[string match *.tcl $ttcl]} { + uplevel 1 {source $::teaish__Config(teaish.tcl)} + } else { + teaish-pkginfo-set {*}[proj-file-content -trim $ttcl] + } + unset ttcl + # 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_PKGINIT_TCL -v "" + - TEAISH_PKGINIT_TCL_IN -v "" + - TEAISH_PKGINIT_TCL_TAIL -v "" + - TEAISH_TEST_TCL -v "" + - TEAISH_TEST_TCL_IN -v "" + + -version - -v 0.0.0 + -name.pkg - -e {set ::teaish__PkgInfo(-name)} + -name.dist - -e {set ::teaish__PkgInfo(-name)} + -libDir - -e { + join [list \ + $::teaish__PkgInfo(-name.pkg) \ + $::teaish__PkgInfo(-version)] "" + } + -loadPrefix - -e { + string totitle $::teaish__PkgInfo(-name.pkg) + } + -vsatisfies - -v {{Tcl 8.5-}} + -pkgInit.tcl - -v "" + -pkgInit.tcl.in - -v "" + -url - -v "" + -tm.tcl - -v "" + -tm.tcl.in - -v "" + } { + set isPIFlag [expr {"-" ne $pflag}] + if {$isPIFlag} { + if {[info exists ::teaish__PkgInfo($pflag)]} { + # Was already set - skip it. + continue; + } + proj-assert {{-} eq $key} + set key $f2d($pflag) + } + proj-assert {"" ne $key} + set got [get-define $key ""] + if {"" 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 + # 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 + } + } + if {$::teaish__Config(vsatisfies-error)} { + set vunsat \ + [list error [list Package \ + $::teaish__PkgInfo(-name) $::teaish__PkgInfo(-version) \ + requires $pv]] + } else { + set vunsat return + } + lappend code \ + [string trim [subst -nocommands \ + {if { ![package vsatisfies [package provide $pkg] $vcheck] } {\n $vunsat\n}}]] + }; # 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" + } + if {0x300 & $::teaish__Config(pkgindex-policy)} { + teaish__verbose 1 msg-result "pkgIndex disabled by -tm.tcl(.in)" + } else { + 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] + } + if {0x0f & $::teaish__Config(tm-policy)} { + file delete -force -- [get-define TEAISH_TM_TCL] + proj-dot-ins-append [get-define TEAISH_TM_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_INSTALL $::teaish__Config(install-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]] + } + proj-remap-autoconf-dir-vars + set tdefs [teaish__defines_to_list] + define TEAISH__DEFINES_MAP $tdefs; # injected into _teaish.tester.tcl + + # + # NO [define]s after this point! + # + proj-dot-ins-process -validate + proj-if-opt-truthy teaish-dump-defines { + proj-file-write config.defines.txt $tdefs + } + +}; # 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 [teaish-pkginfo-get -libDir] + 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 + + set gotSh [file-isexec $withSh] + set tmdir ""; # first tcl::tm::list entry + if {$gotSh} { + catch { + set tmli [exec echo {puts [tcl::tm::list]} | $withSh] + # Reminder: this list contains many names of dirs which do not + # exist but are legitimate. If we rely only on an is-dir check, + # we can end up not finding any of the many candidates. + set firstDir "" + foreach d $tmli { + if {"" eq $firstDir && ![string match //*:* $d]} { + # First non-VFS entry, e.g. not //zipfs: + set firstDir $d + } + if {[file isdirectory $d]} { + set tmdir $d + break + } + } + if {"" eq $tmdir} { + set tmdir $firstDir + } + }; # find tcl::tm path + } + define TEAISH_TCL_TM_DIR $tmdir + + # Finally, let's wrap up... + if {$gotSh} { + teaish__verbose 1 msg-result "Using tclsh = $withSh" + if {$cfg ne ""} { + define HAVE_TCL 1 + } else { + proj-warn "Found tclsh but no tclConfig.sh." + } + if {"" eq $tmdir} { + proj-warn "Did not find tcl::tm directory." + } + } + 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 {!$gotSh} { + 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, with the caveat that a symlink to tclsh, or + wrapper script around it, e.g. ~/bin/tclsh -> + $HOME/tcl/9.0/bin/tclsh9.1, may not work because tclsh emits + different library paths for the former than the latter. + } + } + 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} { + set f [file join $dir $fid] + if {[file readable $f]} { + file-normalize $f + } elseif {$mustHave} { + proj-error "Missing required $dir/$fid" + } + }} + + # + # 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 0 teaish.config $extD] + if {"" eq $extT} { + 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 $dirBld/teaish.config $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@ ?flags? 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. The -nomsg flag suppresses the +# message for non-cache-hit checks. 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. The -msg-0 and -msg-1 flags can be used to change the ok/no +# text. +# +# 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. +# +# $script may be a command and its arguments, as opposed to a single +# script block. +# +# Flags: +# +# -nostatus = do not emit "ok" or "no" at the end. This presumes +# that either $script will emit at least one newline before +# returning or the caller will account for it. Because of how this +# function is typically used, -nostatus is not honored when the +# response includes a cached result. +# +# -quiet = disable output from Autosetup's msg-checking and +# msg-result for the duration of the $script check. Note that when +# -quiet is in effect, Autosetup's user-notice can be used to queue +# up output to appear after the check is done. Also note that +# -quiet has no effect on _this_ function, only the $script part. +# +# -nomsg = do not emit $msg for initial check. Like -nostatus, this +# flag is not honored when the response includes a cached result +# because it would otherwise produce no output (which is confusing +# in this context). This is useful when a check runs several other +# verbose checks and they emit all the necessary info. +# +# -msg-0 and -msg-1 MSG = strings to show when the check has failed +# resp. passed. Defaults are "no" and "ok". The 0 and 1 refer to the +# result value from teaish-feature-cache-check. +# +# -key cachekey = set the cache context key. Only needs to be +# explicit when using this function multiple times from a single +# scope. See proj-cache-check and friends for details on the key +# name. Its default is the name of the scope which calls this +# function. +# +proc teaish-check-cached {args} { + proj-parse-simple-flags args flags { + -nostatus 0 {expr 1} + -quiet 0 {expr 1} + -key => 1 + -nomsg 0 {expr 1} + -msg-0 => no + -msg-1 => ok + } + set args [lassign $args msg] + set script [join $args] + if {"" eq $msg} { + set msg [proj-scope 1] + } + if {[teaish-feature-cache-check $flags(-key) check]} { + #if {0 == $flags(-nomsg)} { + msg-checking "${msg} ... (cached) " + #} + #if {!$flags(-nostatus)} { + msg-result $flags(-msg-[expr {0 != ${check}}]) + #} + return $check + } else { + if {0 == $flags(-nomsg)} { + msg-checking "${msg} ... " + } + if {$flags(-quiet)} { + incr ::autosetup(msg-quiet) + } + set code [catch {uplevel 1 $script} rc xopt] + if {$flags(-quiet)} { + incr ::autosetup(msg-quiet) -1 + } + #puts "***** cached-check got code=$code rc=$rc" + if {$code in {0 2}} { + teaish-feature-cache-set 1 $rc + if {!$flags(-nostatus)} { + msg-result $flags(-msg-[expr {0 != ${rc}}]) + } else { + #show-notices; # causes a phantom newline because we're in a + #msg-checking scope, so... + if {[info exists ::autosetup(notices)]} { + show-notices + } + } + } 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 "{${value}}" + } + return \"[string map [list \\ \\\\ \" \\\"] $value]\" +} + +# +# Internal helper for teaish__defines_to_list. Expects to be passed +# a name and the variadic $args which are passed to +# teaish__defines_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 +# Autosetup's [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. +# +# -jsarray {...} 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] + } + -jsarray { + set ar {} + foreach v $value { + if {![string is integer -strict $v]} { + set v [teaish__quote_str 0 $v] + } + if {$::teaish__Config(defs-skip) ne $v} { + lappend ar $v + } + } + set value [concat \[ [join $ar {, }] \]] + } + "" { + # (Much later:) Why do we do this? + set value $::teaish__Config(defs-skip) + } + default { + proj-error \ + "Unknown [proj-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. Some +# defines are specifically filtered out of the result, either because +# their irrelevant to teaish or because they may be arbitrarily large +# (e.g. makefile content). +# +# The $args are explained in the docs for internal-use-only +# [teaish__defs_format]. The default mode is -autolist. +# +proc teaish__defines_to_list {args} { + set lines {} + lappend lines "\{" + set skipper $::teaish__Config(defs-skip) + set args [list \ + -none { + TEAISH__* + TEAISH_*_CODE + AM_* AS_* + } \ + {*}$args \ + -autolist *] + foreach d [lsort [dict keys [all-defines]]] { + set type [teaish__defs_type $d $args] + set value [teaish__defs_format $type [get-define $d]] + if {$skipper ne $value} { + lappend lines "$d $value" + } + } + lappend lines "\}" + tailcall 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 { + if {$::teaish__Config(tm-policy)} { + proj-fatal -up "Cannot use pragma $arg together with -tm.tcl or -tm.tcl.in." + } + 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 "pragma $arg: found no package-local pkgIndex.tcl\[.in]" + } + } + + no-dist { + set ::teaish__Config(dist-enabled) 0 + } + + no-install { + set ::teaish__Config(install-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 "" + 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 { + teaish__pragma {*}$v + } + + -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 - + -pkgInit.tcl.in { + if {0x22 & $::teaish__Config(pkginit-policy)} { + proj-fatal "Cannot use -pkgInit.tcl(.in) more than once." + } + set x [file join $::teaish__Config(extension-dir) $v] + set tTail [file tail $v] + if {"-pkgInit.tcl.in" eq $f} { + # Generate pkginit file X from X.in + set pI 0x02 + set tIn $x + set tOut [file rootname $tTail] + set other -pkgInit.tcl + } else { + # Static pkginit file X + set pI 0x20 + set tIn "" + set tOut $x + set other -pkgInit.tcl.in + } + set ::teaish__Config(pkginit-policy) $pI + set ::teaish__PkgInfo($other) {} + define TEAISH_PKGINIT_TCL_IN $tIn + define TEAISH_PKGINIT_TCL $tOut + define TEAISH_PKGINIT_TCL_TAIL $tTail + teaish-dist-add $v + set v $x + } + + -tm.tcl - + -tm.tcl.in { + if {0x30 & $::teaish__Config(pkgindex-policy)} { + proj-fatal "Cannot use $f together with a pkgIndex.tcl." + } elseif {$::teaish__Config(tm-policy)} { + proj-fatal "Cannot use -tm.tcl(.in) more than once." + } + set x [file join $::teaish__Config(extension-dir) $v] + if {"-tm.tcl.in" eq $f} { + # Generate tm file X from X.in + set pT 0x02 + set pI 0x100 + set tIn $x + set tOut [file rootname [file tail $v]] + set other -tm.tcl + } else { + # Static tm file X + set pT 0x20 + set pI 0x200 + set tIn "" + set tOut $x + set other -tm.tcl.in + } + set ::teaish__Config(pkgindex-policy) $pI + set ::teaish__Config(tm-policy) $pT + set ::teaish__PkgInfo($other) {} + define TEAISH_TM_TCL_IN $tIn + define TEAISH_TM_TCL $tOut + define TEAISH_PKGINDEX_TCL "" + define TEAISH_PKGINDEX_TCL_IN "" + define TEAISH_PKGINDEX_TCL_TAIL "" + teaish-dist-add $v + teaish__pragma no-dll + set v $x + } + + default { + proj-assert {"" ne $d} + 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 +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 \[$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/autosetup/teaish/feature-tests.tcl b/autosetup/teaish/feature-tests.tcl new file mode 100644 index 000000000..6c927d1a7 --- /dev/null +++ b/autosetup/teaish/feature-tests.tcl @@ -0,0 +1,214 @@ +######################################################################## +# 2025 April 7 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# * May you do good and not evil. +# * May you find forgiveness for yourself and forgive others. +# * May you share freely, never taking more than you give. +# +######################################################################## +# ----- @module feature-tests.tcl ----- +# @section TEA-ish collection of feature tests. +# +# Functions in this file with a prefix of teaish__ are +# private/internal APIs. Those with a prefix of teaish- are +# public APIs. + + +# @teaish-check-libz +# +# Checks for zlib.h and the function deflate in libz. If found, +# prepends -lz to the extension's ldflags and returns 1, else returns +# 0. It also defines LDFLAGS_LIBZ to the libs flag. +# +proc teaish-check-libz {} { + teaish-check-cached "Checking for libz" { + set rc 0 + if {[msg-quiet cc-check-includes zlib.h] && [msg-quiet proj-check-function-in-lib deflate z]} { + teaish-ldflags-prepend [define LDFLAGS_LIBZ [get-define lib_deflate]] + undefine lib_deflate + incr rc + } + expr $rc + } +} + +# @teaish-check-librt ?funclist? +# +# Checks whether -lrt is needed for any of the given functions. If +# so, appends -lrt via [teaish-ldflags-prepend] and returns 1, else +# returns 0. It also defines LDFLAGS_LIBRT to the libs flag or an +# empty string. +# +# Some systems (ex: SunOS) require -lrt in order to use nanosleep. +# +proc teaish-check-librt {{funclist {fdatasync nanosleep}}} { + teaish-check-cached -nostatus "Checking whether ($funclist) need librt" { + define LDFLAGS_LIBRT "" + foreach func $funclist { + if {[msg-quiet proj-check-function-in-lib $func rt]} { + set ldrt [get-define lib_${func}] + undefine lib_${func} + if {"" ne $ldrt} { + teaish-ldflags-prepend -r [define LDFLAGS_LIBRT $ldrt] + msg-result $ldrt + return 1 + } else { + msg-result "no lib needed" + return 1 + } + } + } + msg-result "not found" + return 0 + } +} + +# @teaish-check-stdint +# +# A thin proxy for [cc-with] which checks for and the +# various fixed-size int types it declares. It defines HAVE_STDINT_T +# to 0 or 1 and (if it's 1) defines HAVE_XYZ_T for each XYZ int type +# to 0 or 1, depending on whether its available. +proc teaish-check-stdint {} { + teaish-check-cached "Checking for stdint.h" { + msg-quiet cc-with {-includes stdint.h} \ + {cc-check-types int8_t int16_t int32_t int64_t intptr_t \ + uint8_t uint16_t uint32_t uint64_t uintptr_t} + } +} + +# @teaish-is-mingw +# +# Returns 1 if building for mingw, else 0. +proc teaish-is-mingw {} { + return [expr { + [string match *mingw* [get-define host]] && + ![file exists /dev/null] + }] +} + +# @teaish-check-libdl +# +# Checks for whether dlopen() can be found and whether it requires +# -ldl for linking. If found, returns 1, defines LDFLAGS_DLOPEN to the +# linker flags (if any), and passes those flags to +# teaish-ldflags-prepend. It unconditionally defines HAVE_DLOPEN to 0 +# or 1 (the its return result value). +proc teaish-check-dlopen {} { + teaish-check-cached -nostatus "Checking for dlopen()" { + set rc 0 + set lfl "" + if {[cc-with {-includes dlfcn.h} { + cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} { + msg-result "-ldl not needed" + incr rc + } elseif {[cc-check-includes dlfcn.h]} { + incr rc + if {[cc-check-function-in-lib dlopen dl]} { + set lfl [get-define lib_dlopen] + undefine lib_dlopen + msg-result " dlopen() needs $lfl" + } else { + msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in." + } + } else { + msg-result "not found" + } + teaish-ldflags-prepend [define LDFLAGS_DLOPEN $lfl] + define HAVE_DLOPEN $rc + } +} + +# +# @teaish-check-libmath +# +# Handles the --enable-math flag. Returns 1 if found, else 0. +# If found, it prepends -lm (if needed) to the linker flags. +proc teaish-check-libmath {} { + teaish-check-cached "Checking for libc math library" { + set lfl "" + set rc 0 + if {[msg-quiet proj-check-function-in-lib ceil m]} { + incr rc + set lfl [get-define lib_ceil] + undefine lib_ceil + teaish-ldflags-prepend $lfl + msg-checking "$lfl " + } + define LDFLAGS_LIBMATH $lfl + expr $rc + } +} + +# @teaish-import-features ?-flags? feature-names... +# +# For each $name in feature-names... it invokes: +# +# use teaish/feature/$name +# +# to load TEAISH_AUTOSETUP_DIR/feature/$name.tcl +# +# By default, if a proc named teaish-check-${name}-options is defined +# after sourcing a file, it is called and its result is passed to +# proj-append-options. This can be suppressed with the -no-options +# flag. +# +# Flags: +# +# -no-options: disables the automatic running of +# teaish-check-NAME-options, +# +# -run: if the function teaish-check-NAME exists after importing +# then it is called. This flag must not be used when calling this +# function from teaish-options. This trumps both -pre and -post. +# +# -pre: if the function teaish-check-NAME exists after importing +# then it is passed to [teaish-checks-queue -pre]. +# +# -post: works like -pre but instead uses[teaish-checks-queue -post]. +proc teaish-import-features {args} { + set pk "" + set doOpt 1 + proj-parse-simple-flags args flags { + -no-options 0 {set doOpt 0} + -run 0 {expr 1} + -pre 0 {set pk -pre} + -post 0 {set pk -post} + } + # + # TODO: never import the same module more than once. The "use" + # command is smart enough to not do that but we would need to + # remember whether or not any teaish-check-${arg}* procs have been + # called before, and skip them. + # + if {$flags(-run) && "" ne $pk} { + proj-error "Cannot use both -run and $pk" \ + " (called from [proj-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/autosetup/teaish/tester.tcl b/autosetup/teaish/tester.tcl new file mode 100644 index 000000000..d8b5f7a0e --- /dev/null +++ b/autosetup/teaish/tester.tcl @@ -0,0 +1,228 @@ +######################################################################## +# 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 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 and target canonical Tcl only, not JimTcl +# (which the autosetup pieces do target). + +# +# @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" +} + +array set ::test__Counters {} +array set ::test__Config { + verbose-assert 0 verbose-affirm 0 +} + +# Internal impl for affirm and assert. +# +# $args = ?-v? script {msg-on-fail ""} +proc test__affert {failMode args} { + if {$failMode} { + set what assert + } else { + set what affirm + } + set verbose $::test__Config(verbose-$what) + if {"-v" eq [lindex $args 0]} { + lassign $args - script msg + if {1 == [llength $args]} { + # If -v is the only arg, toggle default verbose mode + set ::test__Config(verbose-$what) [expr {!$::test__Config(verbose-$what)}] + return + } + incr verbose + } else { + lassign $args script msg + } + incr ::test__Counters($what) + if {![uplevel 1 [concat expr [list $script]]]} { + if {"" eq $msg} { + set msg $script + } + set txt [join [list $what # $::test__Counters($what) "failed:" $msg]] + if {$failMode} { + puts stderr $txt + exit 1 + } else { + error $txt + } + } elseif {$verbose} { + puts stderr [join [list $what # $::test__Counters($what) "passed:" $script]] + } +} + +# +# @affirm ?-v? script ?msg? +# +# Works like a conventional assert method does, but reports failures +# using [error] instead of [exit]. If -v is used, it reports passing +# assertions to stderr. $script is evaluated in the caller's scope as +# an argument to [expr]. +# +proc affirm {args} { + tailcall test__affert 0 {*}$args +} + +# +# @assert ?-v? script ?msg? +# +# Works like [affirm] but exits on error. +# +proc assert {args} { + tailcall test__affert 1 {*}$args +} + +# +# @test-assert testId script ?msg? +# +# Works like [assert] but emits $testId to stdout first. +# +proc test-assert {testId script {msg ""}} { + puts "test $testId" + tailcall test__affert 1 $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] + tailcall test__affert 0 [list $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/manifest b/manifest index c61a38545..299b14194 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sversion\sof\sthe\sprevious\scheck-in. -D 2025-05-16T18:19:11.764 +C Latest\supstream\steaish\spieces\sfor\sminor\sfixes.\sRestructure\sthis\scopy\sof\steaish\sto\ssimplify\smaintenance\sand\sthe\sautoconf\sbundle\sbuild. +D 2025-05-17T07:02:06.426 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -22,20 +22,16 @@ F autoconf/Makefile.msc f15ad424ca2820df8e39d9157965710af0a64d87773706706a12ea4f F autoconf/README.first f1d3876e9a7852c22f275a6f06814e64934cecbc0b5b9617d64849094c1fd136 F autoconf/README.txt b749816b8452b3af994dc6d607394bef3df1736d7e09359f1087de8439a52807 F autoconf/auto.def 3d994f3a9cc9b712dbce92a5708570ddcf3b988141b6eb738f2ed16127a9f0ac -F autoconf/tea/Makefile.in 8c00e2ed350754d6b45681318ed7e4578aed8ad732abcac0593c1b10dc29e5a6 +F autoconf/tea/Makefile.in 14c6a79ce87e10d8a35398f2d0e04e1d83a88eb52ee16ebf0eeaccf005ff84b3 F autoconf/tea/README.txt 656d4686c509d375f5988ff3deda94f65fe6cd8358cd55d1f1dcc7b6e2ff73aa +F autoconf/tea/_teaish.tester.tcl.in ed5445512e91c12afbbb99771efb68a23be4a046d52d61213fb5b6f010118129 w autoconf/tea/teaish.tester.tcl.in F autoconf/tea/auto.def ce95b9450e2fa4ba5dc857e208fe10f4e6f2d737796ac3278aee6079db417529 -F autoconf/tea/autosetup/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca -F autoconf/tea/autosetup/core.tcl 7d942639871111e2fcef571c9d5a6e2dc75972eb214cf814a6b99f1e2b25182f -F autoconf/tea/autosetup/feature-tests.tcl 18194fb79a24d30e5bbdeab40999616f39278b53a27525349ded033af2fd73be -F autoconf/tea/autosetup/tester.tcl c293695a0ab5d9e8d0ceeb0ee422f90e8a6aa9f0c7c51acd0b6d9f09d8edfed3 F autoconf/tea/configure d0b12b984edca6030d1976375b80157ac78b5b90a5b4f0dcee39357f63f4a80b x F autoconf/tea/doc/sqlite3.n 9a97f4f717ceab73004ea412af7960625c1cb24b5c25e4ae4c8b5d8fa4300f4e F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523 F autoconf/tea/pkgIndex.tcl.in e07da6b94561f4aa382bab65b1ccceb04701b97bf59d007c1d1f20a222b22d07 -F autoconf/tea/teaish.tcl 8e124f33cbaf9309f3e49be4e7018a03b8f3a52f8c8d9e1e5419f4f7b0eae59e +F autoconf/tea/teaish.tcl 81571a9f9ae5c70735595b05586cb2de9d2aea7e32aad10417c4982f2e2f01c8 F autoconf/tea/teaish.test.tcl cfe94e1fb79dd078f650295be59843d470125e0cc3a17a1414c1fb8d77f4aea6 -F autoconf/tea/teaish.tester.tcl.in 31ac5b7b1e226b7e1bfc6b578a6c1a51550306ef7afae5949eec046df006ca7d F autosetup/LICENSE 41a26aebdd2cd185d1e2b210f71b7ce234496979f6b35aef2cbf6b80cbed4ce4 F autosetup/README.autosetup a78ff8c4a3d2636a4268736672a74bf14a82f42687fcf0631a70c516075c031e F autosetup/README.md f324bb9f9bf1cc787122034df53fbfdfed28ee2657e6652b763d992ab0d04829 @@ -51,9 +47,13 @@ F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e F autosetup/jimsh0.c 563b966c137a4ce3c9333e5196723b7ac0919140a9d7989eb440463cd855c367 F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba -F autosetup/proj.tcl 0287234d817e800ab0e10d46bf98545ba5762edd69e5dd0e2902029a7e6c3555 +F autosetup/proj.tcl 2d3431d7b379a741d2b6727e34b6885e546066c1956e43757adbaf49db82945b F autosetup/sqlite-config.tcl 7ff986f6c3951f3aec5608522cbf772d8d04a0d26cc894289e2ca4836e018719 F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9 +F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca w autoconf/tea/autosetup/README.txt +F autosetup/teaish/core.tcl a96140a11141dc165e0e84f38e0bd0031611553303a40ab9df7f28646611292a w autoconf/tea/autosetup/core.tcl +F autosetup/teaish/feature-tests.tcl 18194fb79a24d30e5bbdeab40999616f39278b53a27525349ded033af2fd73be w autoconf/tea/autosetup/feature-tests.tcl +F autosetup/teaish/tester.tcl 091745984473faea6985254b9986c6dfd0cce06f68bc515ba4afc1e6b3742fa8 w autoconf/tea/autosetup/tester.tcl F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x F contrib/sqlitecon.tcl eb4c6578e08dd353263958da0dc620f8400b869a50d06e271ab0be85a51a08d3 F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd @@ -2151,7 +2151,7 @@ F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669 F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439 F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176 F tool/mkamalzip.tcl 8aa5ebe7973c8b8774062d34e15fea9815c4cc2ceea3a9b184695f005910876a -F tool/mkautoconfamal.sh 07b43da6ef5dfe4c8a119f813b997429e7237ccf537daa14e19af6e6d5a0947f +F tool/mkautoconfamal.sh 564378ae48cc8f4c8c68ef6d00228a0b2a70e2e3e4c67f26be1dd05d9730fefd F tool/mkccode.tcl c42a8f8cf78f92e83795d5447460dbce7aaf78a3bbf9082f1507dc71a3665f3c x F tool/mkctimec.tcl 11c9eda4a8d18c74b79280b30506d832849fd1855e6d9e95e1fd506f1d211c37 x F tool/mkkeywordhash.c 6b0be901c47f9ad42215fc995eb2f4384ac49213b1fba395102ec3e999acf559 @@ -2207,8 +2207,11 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 955a026996b93e530ca5b566689cc646b31d3b9b5a5837897a58452d70f6d942 -R 804d8a6678db1d3197b731d5b4dee948 -U drh -Z 439b5225de67a70c541dcd306ac1747e +P 036c97e36cb36a2ac765a8e8539433dcb63f69155d4c24857f84faa44eed6eb5 +R 84f69ea0a581f0671fbf90c83e33cd68 +T *branch * tea-cleanups +T *sym-tea-cleanups * +T -sym-trunk * Cancelled\sby\sbranch. +U stephan +Z ec5e72cf16174ce398433604a2e0a2ca # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0bb3bb984..77c3c6156 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -036c97e36cb36a2ac765a8e8539433dcb63f69155d4c24857f84faa44eed6eb5 +2b8d9b75ec5fe96cb5d06a3464fd4eb9a53018b7b548fedcd6cdbc46cdb55bdc diff --git a/tool/mkautoconfamal.sh b/tool/mkautoconfamal.sh index 35f8dbc8c..b750593c9 100644 --- a/tool/mkautoconfamal.sh +++ b/tool/mkautoconfamal.sh @@ -63,7 +63,7 @@ cp $TOP/main.mk $TMPSPACE cd $TMPSPACE # Clean up emacs-generated backup files from the target -rm -f ./autosetup/*~ +rm -f ./autosetup/*~ ./autosetup/teaish/*~ rm -f ./*~ #if true; then @@ -73,10 +73,6 @@ rm -f ./*~ # find . -name '*~' -exec rm \{} \; #fi -mkdir -p autosetup/teaish -mv tea/autosetup/*.tcl autosetup/teaish/. -rm -fr tea/autosetup - mkdir -p tea/generic cat < tea/generic/tclsqlite3.c #ifdef USE_SYSTEM_SQLITE -- cgit v1.2.3 From 9bb2548e3e8b5bae356f763c1f517c6b19a2eb46 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 17 May 2025 10:32:48 +0000 Subject: Rename feature-tests.tcl to feature.tcl. Haiku tcl portability fixes. FossilOrigin-Name: 15bd9e581a6d6ebe281b091adc04dca4d1c7fa9bbb582bcbab8c401b4f976753 --- autosetup/proj.tcl | 39 ++++--- autosetup/teaish/core.tcl | 19 ++-- autosetup/teaish/feature-tests.tcl | 214 ------------------------------------- autosetup/teaish/feature.tcl | 214 +++++++++++++++++++++++++++++++++++++ manifest | 25 ++--- manifest.uuid | 2 +- 6 files changed, 263 insertions(+), 250 deletions(-) delete mode 100644 autosetup/teaish/feature-tests.tcl create mode 100644 autosetup/teaish/feature.tcl diff --git a/autosetup/proj.tcl b/autosetup/proj.tcl index a4957ed61..2d921a927 100644 --- a/autosetup/proj.tcl +++ b/autosetup/proj.tcl @@ -1971,10 +1971,12 @@ if {0} { array set proj__Cache {} # -# @proj-cache-key ?addLevel? arg +# @proj-cache-key arg {addLevel 0} # # Helper to generate cache keys for [proj-cache-*]. # +# $addLevel should almost always be 0. +# # Returns a cache key for the given argument: # # integer: relative call stack levels to get the scope name of for @@ -1984,8 +1986,7 @@ array set proj__Cache {} # # Anything else: returned as-is # -proc proj-cache-key {{addLevel 0} arg} { - #if {"-" eq $arg} {set arg 0} +proc proj-cache-key {arg {addLevel 0}} { if {[string is integer -strict $arg]} { return [proj-scope [expr {$arg + $addLevel + 1}]] } @@ -1993,14 +1994,19 @@ proc proj-cache-key {{addLevel 0} arg} { } # -# @proj-cache-set ?key? ?addLevel? value +# @proj-cache-set ?-key KEY? ?-level 0? value # # Sets a feature-check cache entry with the given key. # # See proj-cache-key for $key's and $addLevel's semantics, noting that # this function adds one to $addLevel for purposes of that call. -proc proj-cache-set {{key 0} {addLevel 0} val} { - set key [proj-cache-key [expr {1 + $addLevel}] $key] +proc proj-cache-set {args} { + proj-parse-simple-flags args flags { + -key => 0 + -level => 0 + } + lassign $args val + set key [proj-cache-key $flags(-key) [expr {1 + $flags(-level)}]] #puts "** fcheck set $key = $val" set ::proj__Cache($key) $val } @@ -2010,7 +2016,7 @@ proc proj-cache-set {{key 0} {addLevel 0} val} { # # Removes an entry from the proj-cache. proc proj-cache-remove {{key 0} {addLevel 0}} { - set key [proj-cache-key [expr {1 + $addLevel}] $key] + set key [proj-cache-key $key [expr {1 + $addLevel}]] set rv "" if {[info exists ::proj__Cache($key)]} { set rv $::proj__Cache($key) @@ -2020,7 +2026,7 @@ proc proj-cache-remove {{key 0} {addLevel 0}} { } # -# @proj-cache-check ?$key? ?addLevel? tgtVarName +# @proj-cache-check ?-key KEY? ?-level LEVEL? tgtVarName # # Checks for a feature-check cache entry with the given key. # @@ -2030,10 +2036,15 @@ proc proj-cache-remove {{key 0} {addLevel 0}} { # # See proj-cache-key for $key's and $addLevel's semantics, noting that # this function adds one to $addLevel for purposes of that call. -proc proj-cache-check {{key 0} {addLevel 0} tgtVar} { +proc proj-cache-check {args} { + proj-parse-simple-flags args flags { + -key => 0 + -level => 0 + } + lassign $args tgtVar upvar $tgtVar tgt set rc 0 - set key [proj-cache-key [expr {1 + $addLevel}] $key] + set key [proj-cache-key $flags(-key) [expr {1 + $flags(-level)}]] #puts "** fcheck get key=$key" if {[info exists ::proj__Cache($key)]} { set tgt $::proj__Cache($key) @@ -2202,15 +2213,15 @@ proc proj-parse-simple-flags {argvName tgtArrayName prototype} { if {$::proj__Config(self-tests)} { apply {{} { #proj-warn "Test code for proj-cache" - proj-assert {![proj-cache-check here check]} + proj-assert {![proj-cache-check -key here check]} proj-assert {"here" eq [proj-cache-key here]} proj-assert {"" eq $check} - proj-cache-set here thevalue - proj-assert {[proj-cache-check here check]} + proj-cache-set -key here thevalue + proj-assert {[proj-cache-check -key here check]} proj-assert {"thevalue" eq $check} proj-assert {![proj-cache-check check]} - #puts "*** key = ([proj-cache-key -])" + #puts "*** key = ([proj-cache-key 0])" proj-assert {"" eq $check} proj-cache-set abc proj-assert {[proj-cache-check check]} diff --git a/autosetup/teaish/core.tcl b/autosetup/teaish/core.tcl index 5476206ed..381597ec5 100644 --- a/autosetup/teaish/core.tcl +++ b/autosetup/teaish/core.tcl @@ -1512,30 +1512,35 @@ proc teaish-make-config-header {filename} { } # -# @teaish-feature-cache-set ?$key? value +# @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. +# See proj-cache-set for the key's semantics. $key should +# normally be 0. # -proc teaish-feature-cache-set {{key 0} val} { - proj-cache-set $key 1 $val +proc teaish-feature-cache-set {key val} { + proj-cache-set -key $key -level 1 $val } # -# @teaish-feature-cache-check ?$key? tgtVarName +# @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. # +# $key should also almost always be 0 but, due to a tclsh +# incompatibility in 1 OS, it cannot have a default value unless it's +# the second argument (but it should be the first one). +# # 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} { +proc teaish-feature-cache-check {key tgtVar} { upvar $tgtVar tgt - proj-cache-check $key 1 tgt + proj-cache-check -key $key -level 1 tgt } # diff --git a/autosetup/teaish/feature-tests.tcl b/autosetup/teaish/feature-tests.tcl deleted file mode 100644 index 6c927d1a7..000000000 --- a/autosetup/teaish/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 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/autosetup/teaish/feature.tcl b/autosetup/teaish/feature.tcl new file mode 100644 index 000000000..6c927d1a7 --- /dev/null +++ b/autosetup/teaish/feature.tcl @@ -0,0 +1,214 @@ +######################################################################## +# 2025 April 7 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# * May you do good and not evil. +# * May you find forgiveness for yourself and forgive others. +# * May you share freely, never taking more than you give. +# +######################################################################## +# ----- @module feature-tests.tcl ----- +# @section TEA-ish collection of feature tests. +# +# Functions in this file with a prefix of teaish__ are +# private/internal APIs. Those with a prefix of teaish- are +# public APIs. + + +# @teaish-check-libz +# +# Checks for zlib.h and the function deflate in libz. If found, +# prepends -lz to the extension's ldflags and returns 1, else returns +# 0. It also defines LDFLAGS_LIBZ to the libs flag. +# +proc teaish-check-libz {} { + teaish-check-cached "Checking for libz" { + set rc 0 + if {[msg-quiet cc-check-includes zlib.h] && [msg-quiet proj-check-function-in-lib deflate z]} { + teaish-ldflags-prepend [define LDFLAGS_LIBZ [get-define lib_deflate]] + undefine lib_deflate + incr rc + } + expr $rc + } +} + +# @teaish-check-librt ?funclist? +# +# Checks whether -lrt is needed for any of the given functions. If +# so, appends -lrt via [teaish-ldflags-prepend] and returns 1, else +# returns 0. It also defines LDFLAGS_LIBRT to the libs flag or an +# empty string. +# +# Some systems (ex: SunOS) require -lrt in order to use nanosleep. +# +proc teaish-check-librt {{funclist {fdatasync nanosleep}}} { + teaish-check-cached -nostatus "Checking whether ($funclist) need librt" { + define LDFLAGS_LIBRT "" + foreach func $funclist { + if {[msg-quiet proj-check-function-in-lib $func rt]} { + set ldrt [get-define lib_${func}] + undefine lib_${func} + if {"" ne $ldrt} { + teaish-ldflags-prepend -r [define LDFLAGS_LIBRT $ldrt] + msg-result $ldrt + return 1 + } else { + msg-result "no lib needed" + return 1 + } + } + } + msg-result "not found" + return 0 + } +} + +# @teaish-check-stdint +# +# A thin proxy for [cc-with] which checks for and the +# various fixed-size int types it declares. It defines HAVE_STDINT_T +# to 0 or 1 and (if it's 1) defines HAVE_XYZ_T for each XYZ int type +# to 0 or 1, depending on whether its available. +proc teaish-check-stdint {} { + teaish-check-cached "Checking for stdint.h" { + msg-quiet cc-with {-includes stdint.h} \ + {cc-check-types int8_t int16_t int32_t int64_t intptr_t \ + uint8_t uint16_t uint32_t uint64_t uintptr_t} + } +} + +# @teaish-is-mingw +# +# Returns 1 if building for mingw, else 0. +proc teaish-is-mingw {} { + return [expr { + [string match *mingw* [get-define host]] && + ![file exists /dev/null] + }] +} + +# @teaish-check-libdl +# +# Checks for whether dlopen() can be found and whether it requires +# -ldl for linking. If found, returns 1, defines LDFLAGS_DLOPEN to the +# linker flags (if any), and passes those flags to +# teaish-ldflags-prepend. It unconditionally defines HAVE_DLOPEN to 0 +# or 1 (the its return result value). +proc teaish-check-dlopen {} { + teaish-check-cached -nostatus "Checking for dlopen()" { + set rc 0 + set lfl "" + if {[cc-with {-includes dlfcn.h} { + cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} { + msg-result "-ldl not needed" + incr rc + } elseif {[cc-check-includes dlfcn.h]} { + incr rc + if {[cc-check-function-in-lib dlopen dl]} { + set lfl [get-define lib_dlopen] + undefine lib_dlopen + msg-result " dlopen() needs $lfl" + } else { + msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in." + } + } else { + msg-result "not found" + } + teaish-ldflags-prepend [define LDFLAGS_DLOPEN $lfl] + define HAVE_DLOPEN $rc + } +} + +# +# @teaish-check-libmath +# +# Handles the --enable-math flag. Returns 1 if found, else 0. +# If found, it prepends -lm (if needed) to the linker flags. +proc teaish-check-libmath {} { + teaish-check-cached "Checking for libc math library" { + set lfl "" + set rc 0 + if {[msg-quiet proj-check-function-in-lib ceil m]} { + incr rc + set lfl [get-define lib_ceil] + undefine lib_ceil + teaish-ldflags-prepend $lfl + msg-checking "$lfl " + } + define LDFLAGS_LIBMATH $lfl + expr $rc + } +} + +# @teaish-import-features ?-flags? feature-names... +# +# For each $name in feature-names... it invokes: +# +# use teaish/feature/$name +# +# to load TEAISH_AUTOSETUP_DIR/feature/$name.tcl +# +# By default, if a proc named teaish-check-${name}-options is defined +# after sourcing a file, it is called and its result is passed to +# proj-append-options. This can be suppressed with the -no-options +# flag. +# +# Flags: +# +# -no-options: disables the automatic running of +# teaish-check-NAME-options, +# +# -run: if the function teaish-check-NAME exists after importing +# then it is called. This flag must not be used when calling this +# function from teaish-options. This trumps both -pre and -post. +# +# -pre: if the function teaish-check-NAME exists after importing +# then it is passed to [teaish-checks-queue -pre]. +# +# -post: works like -pre but instead uses[teaish-checks-queue -post]. +proc teaish-import-features {args} { + set pk "" + set doOpt 1 + proj-parse-simple-flags args flags { + -no-options 0 {set doOpt 0} + -run 0 {expr 1} + -pre 0 {set pk -pre} + -post 0 {set pk -post} + } + # + # TODO: never import the same module more than once. The "use" + # command is smart enough to not do that but we would need to + # remember whether or not any teaish-check-${arg}* procs have been + # called before, and skip them. + # + if {$flags(-run) && "" ne $pk} { + proj-error "Cannot use both -run and $pk" \ + " (called from [proj-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/manifest b/manifest index 299b14194..f942fdc26 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Latest\supstream\steaish\spieces\sfor\sminor\sfixes.\sRestructure\sthis\scopy\sof\steaish\sto\ssimplify\smaintenance\sand\sthe\sautoconf\sbundle\sbuild. -D 2025-05-17T07:02:06.426 +C Rename\sfeature-tests.tcl\sto\sfeature.tcl.\sHaiku\stcl\sportability\sfixes. +D 2025-05-17T10:32:48.060 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -24,7 +24,7 @@ F autoconf/README.txt b749816b8452b3af994dc6d607394bef3df1736d7e09359f1087de8439 F autoconf/auto.def 3d994f3a9cc9b712dbce92a5708570ddcf3b988141b6eb738f2ed16127a9f0ac F autoconf/tea/Makefile.in 14c6a79ce87e10d8a35398f2d0e04e1d83a88eb52ee16ebf0eeaccf005ff84b3 F autoconf/tea/README.txt 656d4686c509d375f5988ff3deda94f65fe6cd8358cd55d1f1dcc7b6e2ff73aa -F autoconf/tea/_teaish.tester.tcl.in ed5445512e91c12afbbb99771efb68a23be4a046d52d61213fb5b6f010118129 w autoconf/tea/teaish.tester.tcl.in +F autoconf/tea/_teaish.tester.tcl.in ed5445512e91c12afbbb99771efb68a23be4a046d52d61213fb5b6f010118129 F autoconf/tea/auto.def ce95b9450e2fa4ba5dc857e208fe10f4e6f2d737796ac3278aee6079db417529 F autoconf/tea/configure d0b12b984edca6030d1976375b80157ac78b5b90a5b4f0dcee39357f63f4a80b x F autoconf/tea/doc/sqlite3.n 9a97f4f717ceab73004ea412af7960625c1cb24b5c25e4ae4c8b5d8fa4300f4e @@ -47,13 +47,13 @@ F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e F autosetup/jimsh0.c 563b966c137a4ce3c9333e5196723b7ac0919140a9d7989eb440463cd855c367 F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba -F autosetup/proj.tcl 2d3431d7b379a741d2b6727e34b6885e546066c1956e43757adbaf49db82945b +F autosetup/proj.tcl 1518e5c5d9b444d3ce736affebc3f350ae72c2aa3879bd630770f3eb782a63a2 F autosetup/sqlite-config.tcl 7ff986f6c3951f3aec5608522cbf772d8d04a0d26cc894289e2ca4836e018719 F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9 -F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca w autoconf/tea/autosetup/README.txt -F autosetup/teaish/core.tcl a96140a11141dc165e0e84f38e0bd0031611553303a40ab9df7f28646611292a w autoconf/tea/autosetup/core.tcl -F autosetup/teaish/feature-tests.tcl 18194fb79a24d30e5bbdeab40999616f39278b53a27525349ded033af2fd73be w autoconf/tea/autosetup/feature-tests.tcl -F autosetup/teaish/tester.tcl 091745984473faea6985254b9986c6dfd0cce06f68bc515ba4afc1e6b3742fa8 w autoconf/tea/autosetup/tester.tcl +F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca +F autosetup/teaish/core.tcl 1ebbe849d8e716424a3ffe9384c7e8b352b3e1194d3d4a153b125cc5176b3715 +F autosetup/teaish/feature.tcl 18194fb79a24d30e5bbdeab40999616f39278b53a27525349ded033af2fd73be w autosetup/teaish/feature-tests.tcl +F autosetup/teaish/tester.tcl 091745984473faea6985254b9986c6dfd0cce06f68bc515ba4afc1e6b3742fa8 F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x F contrib/sqlitecon.tcl eb4c6578e08dd353263958da0dc620f8400b869a50d06e271ab0be85a51a08d3 F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd @@ -2207,11 +2207,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 036c97e36cb36a2ac765a8e8539433dcb63f69155d4c24857f84faa44eed6eb5 -R 84f69ea0a581f0671fbf90c83e33cd68 -T *branch * tea-cleanups -T *sym-tea-cleanups * -T -sym-trunk * Cancelled\sby\sbranch. +P 2b8d9b75ec5fe96cb5d06a3464fd4eb9a53018b7b548fedcd6cdbc46cdb55bdc +R 84fd07659c3e7d67a0460035bc41a4ec U stephan -Z ec5e72cf16174ce398433604a2e0a2ca +Z 4c4059c315c91efea7fdeb751250b5a0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 77c3c6156..74fd4d3d9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2b8d9b75ec5fe96cb5d06a3464fd4eb9a53018b7b548fedcd6cdbc46cdb55bdc +15bd9e581a6d6ebe281b091adc04dca4d1c7fa9bbb582bcbab8c401b4f976753 -- cgit v1.2.3 From c953cb6b3b779e6685de4da1b6a37e16bbbb2975 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 17 May 2025 10:35:11 +0000 Subject: Minor tcl doc update. FossilOrigin-Name: 43259e8c3fab13b4597cdd1c670df00ec756a6fefdeb7d4ba2e0644e4ad47113 --- autosetup/proj.tcl | 4 ++-- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/autosetup/proj.tcl b/autosetup/proj.tcl index 2d921a927..133556706 100644 --- a/autosetup/proj.tcl +++ b/autosetup/proj.tcl @@ -1998,8 +1998,8 @@ proc proj-cache-key {arg {addLevel 0}} { # # Sets a feature-check cache entry with the given key. # -# See proj-cache-key for $key's and $addLevel's semantics, noting that -# this function adds one to $addLevel for purposes of that call. +# See proj-cache-key for -key's and -level's semantics, noting that +# this function adds one to -level for purposes of that call. proc proj-cache-set {args} { proj-parse-simple-flags args flags { -key => 0 diff --git a/manifest b/manifest index f942fdc26..e417f50c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\sfeature-tests.tcl\sto\sfeature.tcl.\sHaiku\stcl\sportability\sfixes. -D 2025-05-17T10:32:48.060 +C Minor\stcl\sdoc\supdate. +D 2025-05-17T10:35:11.233 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -47,12 +47,12 @@ F autosetup/cc.tcl c0fcc50ca91deff8741e449ddad05bcd08268bc31177e613a6343bbd1fd3e F autosetup/find_tclconfig.tcl e64886ffe3b982d4df42cd28ed91fe0b5940c2c5785e126c1821baf61bc86a7e F autosetup/jimsh0.c 563b966c137a4ce3c9333e5196723b7ac0919140a9d7989eb440463cd855c367 F autosetup/pkg-config.tcl 4e635bf39022ff65e0d5434339dd41503ea48fc53822c9c5bde88b02d3d952ba -F autosetup/proj.tcl 1518e5c5d9b444d3ce736affebc3f350ae72c2aa3879bd630770f3eb782a63a2 +F autosetup/proj.tcl c4a77735b57f3c016a185bff048212a197b77723f9bea6cfafe396e4b542c666 F autosetup/sqlite-config.tcl 7ff986f6c3951f3aec5608522cbf772d8d04a0d26cc894289e2ca4836e018719 F autosetup/system.tcl 51d4be76cd9a9074704b584e5c9cbba616202c8468cf9ba8a4f8294a7ab1dba9 F autosetup/teaish/README.txt b40071e6f8506500a2f7f71d5fc69e0bf87b9d7678dd9da1e5b4d0acbf40b1ca F autosetup/teaish/core.tcl 1ebbe849d8e716424a3ffe9384c7e8b352b3e1194d3d4a153b125cc5176b3715 -F autosetup/teaish/feature.tcl 18194fb79a24d30e5bbdeab40999616f39278b53a27525349ded033af2fd73be w autosetup/teaish/feature-tests.tcl +F autosetup/teaish/feature.tcl 18194fb79a24d30e5bbdeab40999616f39278b53a27525349ded033af2fd73be F autosetup/teaish/tester.tcl 091745984473faea6985254b9986c6dfd0cce06f68bc515ba4afc1e6b3742fa8 F configure 9a00b21dfd13757bbfb8d89b30660a89ec1f8f3a79402b8f9f9b6fc475c3303a x F contrib/sqlitecon.tcl eb4c6578e08dd353263958da0dc620f8400b869a50d06e271ab0be85a51a08d3 @@ -2207,8 +2207,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 2b8d9b75ec5fe96cb5d06a3464fd4eb9a53018b7b548fedcd6cdbc46cdb55bdc -R 84fd07659c3e7d67a0460035bc41a4ec +P 15bd9e581a6d6ebe281b091adc04dca4d1c7fa9bbb582bcbab8c401b4f976753 +R 39ca8780111060790d2845d7852fde6d U stephan -Z 4c4059c315c91efea7fdeb751250b5a0 +Z f2bd0f683f4792863565410791d20518 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 74fd4d3d9..09a6068fd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -15bd9e581a6d6ebe281b091adc04dca4d1c7fa9bbb582bcbab8c401b4f976753 +43259e8c3fab13b4597cdd1c670df00ec756a6fefdeb7d4ba2e0644e4ad47113 -- cgit v1.2.3