comparison third_party/sqlite3/autosetup/teaish/core.tcl @ 173:827c6ac504cd hg-web

Merged in default here.
author MrJuneJune <me@mrjunejune.com>
date Mon, 19 Jan 2026 18:59:10 -0800
parents 589bab390fb4
children
comparison
equal deleted inserted replaced
151:c033667da5f9 173:827c6ac504cd
1 ########################################################################
2 # 2025 April 5
3 #
4 # The author disclaims copyright to this source code. In place of
5 # a legal notice, here is a blessing:
6 #
7 # * May you do good and not evil.
8 # * May you find forgiveness for yourself and forgive others.
9 # * May you share freely, never taking more than you give.
10 #
11 ########################################################################
12 # ----- @module teaish.tcl -----
13 # @section TEA-ish ((TCL Extension Architecture)-ish)
14 #
15 # Functions in this file with a prefix of teaish__ are
16 # private/internal APIs. Those with a prefix of teaish- are
17 # public APIs.
18 #
19 # Teaish has a hard dependency on proj.tcl, and any public API members
20 # of that module are considered legal for use by teaish extensions.
21 #
22 # Project home page: https://fossil.wanderinghorse.net/r/teaish
23
24 use proj
25
26 #
27 # API-internal settings and shared state.
28 array set teaish__Config [proj-strip-hash-comments {
29 #
30 # Teaish's version number, not to be confused with
31 # teaish__PkgInfo(-version).
32 #
33 version 0.1-beta
34
35 # set to 1 to enable some internal debugging output
36 debug-enabled 0
37
38 #
39 # 0 = don't yet have extension's pkgindex
40 # 0x01 = found TEAISH_EXT_DIR/pkgIndex.tcl.in
41 # 0x02 = found srcdir/pkgIndex.tcl.in
42 # 0x10 = found TEAISH_EXT_DIR/pkgIndex.tcl (static file)
43 # 0x20 = static-pkgIndex.tcl pragma: behave as if 0x10
44 # 0x100 = disabled by -tm.tcl.in
45 # 0x200 = disabled by -tm.tcl
46 #
47 # Reminder: it's significant that the bottom 4 bits be
48 # cases where teaish manages ./pkgIndex.tcl.
49 #
50 pkgindex-policy 0
51
52 #
53 # The pkginit counterpart of pkgindex-policy:
54 #
55 # 0 = no pkginit
56 # 0x01 = found default X.in: generate X from X.in
57 # 0x10 = found static pkginit file X
58 # 0x02 = user-provided X.in generates ./X.
59 # 0x20 = user-provided static pkginit file X
60 #
61 # The 0x0f bits indicate that teaish is responsible for cleaning up
62 # the (generated) pkginit file.
63 #
64 pkginit-policy 0
65 #
66 # 0 = no tm.tcl
67 # 0x01 = tm.tcl.in
68 # 0x10 = static tm.tcl
69 tm-policy 0
70
71 #
72 # If 1+ then teaish__verbose will emit messages.
73 #
74 verbose 0
75
76 #
77 # Mapping of pkginfo -flags to their TEAISH_xxx define (if any).
78 # This must not be modified after initialization.
79 #
80 pkginfo-f2d {
81 -name TEAISH_NAME
82 -name.dist TEAISH_DIST_NAME
83 -name.pkg TEAISH_PKGNAME
84 -version TEAISH_VERSION
85 -libDir TEAISH_LIBDIR_NAME
86 -loadPrefix TEAISH_LOAD_PREFIX
87 -vsatisfies TEAISH_VSATISFIES
88 -pkgInit.tcl TEAISH_PKGINIT_TCL
89 -pkgInit.tcl.in TEAISH_PKGINIT_TCL_IN
90 -url TEAISH_URL
91 -tm.tcl TEAISH_TM_TCL
92 -tm.tcl.in TEAISH_TM_TCL_IN
93 -options {}
94 -pragmas {}
95 -src {}
96 }
97
98 #
99 # Queues for use with teaish-checks-queue and teaish-checks-run.
100 #
101 queued-checks-pre {}
102 queued-checks-post {}
103
104 # Whether or not "make dist" parts are enabled. They get enabled
105 # when building from an extension's dir, disabled when building
106 # elsewhere.
107 dist-enabled 1
108 # Whether or not "make install" parts are enabled. By default
109 # they are, but we have a single use case where they're
110 # both unnecessary and unhelpful, so...
111 install-enabled 1
112
113 # By default we enable compilation of a native extension but if the
114 # extension has no native code or the user wants to take that over
115 # via teaish.make.in or provide a script-only extension, we will
116 # elide the default compilation rules if this is 0.
117 dll-enabled 1
118
119 # Files to include in the "make dist" bundle.
120 dist-files {}
121
122 # List of source files for the extension.
123 extension-src {}
124
125 # Path to the teaish.tcl file.
126 teaish.tcl {}
127
128 # Dir where teaish.tcl is found.
129 extension-dir {}
130
131 # Whether the generates TEASH_VSATISFIES_CODE should error out on a
132 # satisfies error. If 0, it uses return instead of error.
133 vsatisfies-error 1
134
135 # Whether or not to allow a "full dist" - a "make dist" build which
136 # includes both the extension and teaish. By default this is only on
137 # if the extension dir is teaish's dir.
138 dist-full-enabled 0
139 }]
140 set teaish__Config(core-dir) $::autosetup(libdir)/teaish
141
142 #
143 # Array of info managed by teaish-pkginfo-get and friends. Has the
144 # same set of keys as $teaish__Config(pkginfo-f2d).
145 #
146 array set teaish__PkgInfo {}
147
148 #
149 # Runs {*}$args if $lvl is <= the current verbosity level, else it has
150 # no side effects.
151 #
152 proc teaish__verbose {lvl args} {
153 if {$lvl <= $::teaish__Config(verbose)} {
154 {*}$args
155 }
156 }
157
158 #
159 # @teaish-argv-has flags...
160 #
161 # Returns true if any arg in $::argv matches any of the given globs,
162 # else returns false.
163 #
164 proc teaish-argv-has {args} {
165 foreach glob $args {
166 foreach arg $::argv {
167 if {[string match $glob $arg]} {
168 return 1
169 }
170 }
171 }
172 return 0
173 }
174
175 if {[teaish-argv-has --teaish-verbose --t-v]} {
176 # Check this early so that we can use verbose-only messages in the
177 # pre-options-parsing steps.
178 set ::teaish__Config(verbose) 1
179 #teaish__verbose 1 msg-result "--teaish-verbose activated"
180 }
181
182 msg-quiet use system ; # Outputs "Host System" and "Build System" lines
183 if {"--help" ni $::argv} {
184 teaish__verbose 1 msg-result "TEA(ish) Version = $::teaish__Config(version)"
185 teaish__verbose 1 msg-result "Source dir = $::autosetup(srcdir)"
186 teaish__verbose 1 msg-result "Build dir = $::autosetup(builddir)"
187 }
188
189 #
190 # @teaish-configure-core
191 #
192 # Main entry point for the TEA-ish configure process. auto.def's primary
193 # (ideally only) job should be to call this.
194 #
195 proc teaish-configure-core {} {
196 proj-tweak-default-env-dirs
197
198 set ::teaish__Config(install-mode) [teaish-argv-has --teaish-install*]
199 set ::teaish__Config(create-ext-mode) \
200 [teaish-argv-has --teaish-create-extension=* --t-c-e=*]
201 set gotExt 0; # True if an extension config is found
202 if {!$::teaish__Config(create-ext-mode)
203 && !$::teaish__Config(install-mode)} {
204 # Don't look for an extension if we're in --t-c-e or --t-i mode
205 set gotExt [teaish__find_extension]
206 }
207
208 #
209 # Set up the core --flags. This needs to come before teaish.tcl is
210 # sourced so that that file can use teaish-pkginfo-set to append
211 # options.
212 #
213 options-add [proj-strip-hash-comments {
214 with-tcl:DIR
215 => {Directory containing tclConfig.sh or a directory one level up from
216 that, from which we can derive a directory containing tclConfig.sh.
217 Defaults to the $TCL_HOME environment variable.}
218
219 with-tclsh:PATH
220 => {Full pathname of tclsh to use. It is used for trying to find
221 tclConfig.sh. Warning: if its containing dir has multiple tclsh
222 versions, it may select the wrong tclConfig.sh!
223 Defaults to the $TCLSH environment variable.}
224
225 tcl-stubs=0 => {Enable use of Tcl stubs library.}
226
227 # TEA has --with-tclinclude but it appears to only be useful for
228 # building an extension against an uninstalled copy of TCL's own
229 # source tree. The policy here is that either we get that info
230 # from tclConfig.sh or we give up.
231 #
232 # with-tclinclude:DIR
233 # => {Specify the directory which contains the tcl.h. This should not
234 # normally be required, as that information comes from tclConfig.sh.}
235
236 # We _generally_ want to reduce the possibility of flag collisions with
237 # extensions, and thus use a teaish-... prefix on most flags. However,
238 # --teaish-extension-dir is frequently needed, so...
239 #
240 # As of this spontaneous moment, we'll settle on using --t-A-X to
241 # abbreviate --teaish-A...-X... flags when doing so is
242 # unambiguous...
243 ted: t-e-d:
244 teaish-extension-dir:DIR
245 => {Looks for an extension in the given directory instead of the current
246 dir.}
247
248 t-c-e:
249 teaish-create-extension:TARGET_DIRECTORY
250 => {Writes stub files for creating an extension. Will refuse to overwrite
251 existing files without --teaish-force.}
252
253 t-f
254 teaish-force
255 => {Has a context-dependent meaning (autosetup defines --force for its
256 own use).}
257
258 t-d-d
259 teaish-dump-defines
260 => {Dump all configure-defined vars to config.defines.txt}
261
262 t-v:=0
263 teaish-verbose:=0
264 => {Enable more (often extraneous) messages from the teaish core.}
265
266 t-d
267 teaish-debug=0 => {Enable teaish-specific debug output}
268
269 t-i
270 teaish-install:=auto
271 => {Installs a copy of teaish, including autosetup, to the target dir.
272 When used with --teaish-create-extension=DIR, a value of "auto"
273 (no no value) will inherit that directory.}
274
275 #TODO: --teaish-install-extension:=dir as short for
276 # --t-c-e=dir --t-i
277
278 t-e-p:
279 teaish-extension-pkginfo:pkginfo
280 => {For use with --teaish-create-extension. If used, it must be a
281 list of arguments for use with teaish-pkginfo-set, e.g.
282 --teaish-extension-pkginfo="-name Foo -version 2.3"}
283
284 t-v-c
285 teaish-vsatisfies-check=1
286 => {Disable the configure-time "vsatisfies" check on the target tclsh.}
287
288 }]; # main options.
289
290 if {$gotExt} {
291 # We found an extension. Source it...
292 set ttcl $::teaish__Config(teaish.tcl)
293 proj-assert {"" ne [teaish-pkginfo-get -name]}
294 proj-assert {[file exists $ttcl]} \
295 "Expecting to have found teaish.(tcl|config) by now"
296 if {[string match *.tcl $ttcl]} {
297 uplevel 1 {source $::teaish__Config(teaish.tcl)}
298 } else {
299 teaish-pkginfo-set {*}[proj-file-content -trim $ttcl]
300 }
301 unset ttcl
302 # Set up some default values if the extension did not set them.
303 # This must happen _after_ it's sourced but before
304 # teaish-configure is called.
305 array set f2d $::teaish__Config(pkginfo-f2d)
306 foreach {pflag key type val} {
307 - TEAISH_CFLAGS -v ""
308 - TEAISH_LDFLAGS -v ""
309 - TEAISH_MAKEFILE -v ""
310 - TEAISH_MAKEFILE_CODE -v ""
311 - TEAISH_MAKEFILE_IN -v ""
312 - TEAISH_PKGINDEX_TCL -v ""
313 - TEAISH_PKGINDEX_TCL_IN -v ""
314 - TEAISH_PKGINIT_TCL -v ""
315 - TEAISH_PKGINIT_TCL_IN -v ""
316 - TEAISH_PKGINIT_TCL_TAIL -v ""
317 - TEAISH_TEST_TCL -v ""
318 - TEAISH_TEST_TCL_IN -v ""
319
320 -version - -v 0.0.0
321 -name.pkg - -e {set ::teaish__PkgInfo(-name)}
322 -name.dist - -e {set ::teaish__PkgInfo(-name)}
323 -libDir - -e {
324 join [list \
325 $::teaish__PkgInfo(-name.pkg) \
326 $::teaish__PkgInfo(-version)] ""
327 }
328 -loadPrefix - -e {
329 string totitle $::teaish__PkgInfo(-name.pkg)
330 }
331 -vsatisfies - -v {{Tcl 8.5-}}
332 -pkgInit.tcl - -v ""
333 -pkgInit.tcl.in - -v ""
334 -url - -v ""
335 -tm.tcl - -v ""
336 -tm.tcl.in - -v ""
337 -src - -v ""
338 } {
339 #proj-assert 0 {Just testing}
340 set isPIFlag [expr {"-" ne $pflag}]
341 if {$isPIFlag} {
342 if {[info exists ::teaish__PkgInfo($pflag)]} {
343 # Was already set - skip it.
344 continue;
345 }
346 proj-assert {{-} eq $key};# "Unexpected pflag=$pflag key=$key type=$type val=$val"
347 set key $f2d($pflag)
348 }
349 if {"" ne $key} {
350 if {"<nope>" ne [get-define $key "<nope>"]} {
351 # Was already set - skip it.
352 continue
353 }
354 }
355 switch -exact -- $type {
356 -v {}
357 -e { set val [eval $val] }
358 default { proj-error "Invalid type flag: $type" }
359 }
360 #puts "***** defining default $pflag $key {$val} isPIFlag=$isPIFlag"
361 if {$key ne ""} {
362 define $key $val
363 }
364 if {$isPIFlag} {
365 set ::teaish__PkgInfo($pflag) $val
366 }
367 }
368 unset isPIFlag pflag key type val
369 array unset f2d
370 }; # sourcing extension's teaish.tcl
371
372 if {[llength [info proc teaish-options]] > 0} {
373 # Add options defined by teaish-options, which is assumed to be
374 # imported via [teaish-get -teaish-tcl].
375 set o [teaish-options]
376 if {"" ne $o} {
377 options-add $o
378 }
379 }
380 #set opts [proj-options-combine]
381 #lappend opts teaish-debug => {x}; #testing dupe entry handling
382 if {[catch {options {}} msg xopts]} {
383 # Workaround for <https://github.com/msteveb/autosetup/issues/73>
384 # where [options] behaves oddly on _some_ TCL builds when it's
385 # called from deeper than the global scope.
386 dict incr xopts -level
387 return {*}$xopts $msg
388 }
389
390 proj-xfer-options-aliases {
391 t-c-e => teaish-create-extension
392 t-d => teaish-debug
393 t-d-d => teaish-dump-defines
394 ted => teaish-extension-dir
395 t-e-d => teaish-extension-dir
396 t-e-p => teaish-extension-pkginfo
397 t-f => teaish-force
398 t-i => teaish-install
399 t-v => teaish-verbose
400 t-v-c => teaish-vsatisfies-check
401 }
402
403 scan [opt-val teaish-verbose 0] %d ::teaish__Config(verbose)
404 set ::teaish__Config(debug-enabled) [opt-bool teaish-debug]
405
406 set exitEarly 0
407 if {[proj-opt-was-provided teaish-create-extension]} {
408 teaish__create_extension [opt-val teaish-create-extension]
409 incr exitEarly
410 }
411 if {$::teaish__Config(install-mode)} {
412 teaish__install
413 incr exitEarly
414 }
415
416 if {$exitEarly} {
417 file delete -force config.log
418 return
419 }
420 proj-assert {1==$gotExt} "Else we cannot have gotten this far"
421
422 teaish__configure_phase1
423 }
424
425
426 #
427 # Internal config-time debugging output routine. It is not legal to
428 # call this from the global scope.
429 #
430 proc teaish-debug {msg} {
431 if {$::teaish__Config(debug-enabled)} {
432 puts stderr [proj-bold "** DEBUG: \[[proj-scope 1]\]: $msg"]
433 }
434 }
435
436 #
437 # Runs "phase 1" of the configuration, immediately after processing
438 # --flags. This is what will import the client-defined teaish.tcl.
439 #
440 proc teaish__configure_phase1 {} {
441 msg-result \
442 [join [list "Configuring build of Tcl extension" \
443 [proj-bold [teaish-pkginfo-get -name] \
444 [teaish-pkginfo-get -version]] "..."]]
445
446 uplevel 1 {
447 use cc cc-db cc-shared cc-lib; # pkg-config
448 }
449 teaish__check_tcl
450 apply {{} {
451 #
452 # If --prefix or --exec-prefix are _not_ provided, use their
453 # TCL_... counterpart from tclConfig.sh. Caveat: by the time we can
454 # reach this point, autosetup's system.tcl will have already done
455 # some non-trivial amount of work with these to create various
456 # derived values from them, so we temporarily end up with a mishmash
457 # of autotools-compatibility var values. That will be straightened
458 # out in the final stage of the configure script via
459 # [proj-remap-autoconf-dir-vars].
460 #
461 foreach {flag uflag tclVar} {
462 prefix prefix TCL_PREFIX
463 exec-prefix exec_prefix TCL_EXEC_PREFIX
464 } {
465 if {![proj-opt-was-provided $flag]} {
466 if {"exec-prefix" eq $flag} {
467 # If --exec-prefix was not used, ensure that --exec-prefix
468 # derives from the --prefix we may have just redefined.
469 set v {${prefix}}
470 } else {
471 set v [get-define $tclVar "???"]
472 teaish__verbose 1 msg-result "Using \$$tclVar for --$flag=$v"
473 }
474 proj-assert {"???" ne $v} "Expecting teaish__check_tcl to have defined $tclVar"
475 #puts "*** $flag $uflag $tclVar = $v"
476 proj-opt-set $flag $v
477 define $uflag $v
478
479 # ^^^ As of here, all autotools-compatibility vars which derive
480 # from --$flag, e.g. --libdir, still derive from the default
481 # --$flag value which was active when system.tcl was
482 # included. So long as those flags are not explicitly passed to
483 # the configure script, those will be straightened out via
484 # [proj-remap-autoconf-dir-vars].
485 }
486 }
487 }}; # --[exec-]prefix defaults
488 teaish__check_common_bins
489 #
490 # Set up library file names
491 #
492 proj-file-extensions
493 teaish__define_pkginfo_derived *
494
495 teaish-checks-run -pre
496 if {[llength [info proc teaish-configure]] > 0} {
497 # teaish-configure is assumed to be imported via
498 # teaish.tcl
499 teaish-configure
500 }
501 teaish-checks-run -post
502
503 define TEAISH_USE_STUBS [opt-bool tcl-stubs]
504
505 apply {{} {
506 # Set up "vsatisfies" code for pkgIndex.tcl.in,
507 # _teaish.tester.tcl.in, and for a configure-time check. We would
508 # like to put this before [teaish-checks-run -pre] but it's
509 # marginally conceivable that a client may need to dynamically
510 # calculate the vsatisfies and set it via [teaish-configure].
511 set vs [get-define TEAISH_VSATISFIES ""]
512 if {"" eq $vs} return
513 set code {}
514 set n 0
515 # Treat $vs as a list-of-lists {{Tcl 8.5-} {Foo 1.0- -3.0} ...}
516 # and generate Tcl which will run package vsatisfies tests with
517 # that info.
518 foreach pv $vs {
519 set n [llength $pv]
520 if {$n < 2} {
521 proj-error "-vsatisfies: {$pv} appears malformed. Whole list is: $vs"
522 }
523 set pkg [lindex $pv 0]
524 set vcheck {}
525 for {set i 1} {$i < $n} {incr i} {
526 lappend vcheck [lindex $pv $i]
527 }
528 if {[opt-bool teaish-vsatisfies-check]} {
529 set tclsh [get-define TCLSH_CMD]
530 set vsat "package vsatisfies \[ package provide $pkg \] $vcheck"
531 set vputs "puts \[ $vsat \]"
532 #puts "*** vputs = $vputs"
533 scan [exec echo $vputs | $tclsh] %d vvcheck
534 if {![info exists vvcheck] || 0 == $vvcheck} {
535 proj-fatal -up $tclsh "check failed:" $vsat
536 }
537 }
538 if {$::teaish__Config(vsatisfies-error)} {
539 set vunsat \
540 [list error [list Package \
541 $::teaish__PkgInfo(-name) $::teaish__PkgInfo(-version) \
542 requires $pv]]
543 } else {
544 set vunsat return
545 }
546 lappend code \
547 [string trim [subst -nocommands \
548 {if { ![package vsatisfies [package provide $pkg] $vcheck] } {\n $vunsat\n}}]]
549 }; # foreach pv
550 define TEAISH_VSATISFIES_CODE [join $code "\n"]
551 }}; # vsatisfies
552
553 if {[proj-looks-like-windows]} {
554 # Without this, linking of an extension will not work on Cygwin or
555 # Msys2.
556 msg-result "Using USE_TCL_STUBS for Unix(ish)-on-Windows environment"
557 teaish-cflags-add -DUSE_TCL_STUBS=1
558 }
559
560 #define AS_LIBDIR $::autosetup(libdir)
561 define TEAISH_TESTUTIL_TCL $::teaish__Config(core-dir)/tester.tcl
562
563 apply {{} {
564 #
565 # Ensure we have a pkgIndex.tcl and don't have a stale generated one
566 # when rebuilding for different --with-tcl=... values.
567 #
568 if {!$::teaish__Config(pkgindex-policy)} {
569 proj-error "Cannot determine which pkgIndex.tcl to use"
570 }
571 if {0x300 & $::teaish__Config(pkgindex-policy)} {
572 teaish__verbose 1 msg-result "pkgIndex disabled by -tm.tcl(.in)"
573 } else {
574 set tpi [proj-coalesce \
575 [get-define TEAISH_PKGINDEX_TCL_IN] \
576 [get-define TEAISH_PKGINDEX_TCL]]
577 proj-assert {$tpi ne ""} \
578 "TEAISH_PKGINDEX_TCL should have been set up by now"
579 teaish__verbose 1 msg-result "Using pkgIndex from $tpi"
580 if {0x0f & $::teaish__Config(pkgindex-policy)} {
581 # Don't leave stale pkgIndex.tcl laying around yet don't delete
582 # or overwrite a user-managed static pkgIndex.tcl.
583 file delete -force -- [get-define TEAISH_PKGINDEX_TCL]
584 proj-dot-ins-append [get-define TEAISH_PKGINDEX_TCL_IN]
585 } else {
586 teaish-dist-add [file tail $tpi]
587 }
588 }
589 }}; # $::teaish__Config(pkgindex-policy)
590
591 #
592 # Ensure we clean up TEAISH_PKGINIT_TCL if needed and @-process
593 # TEAISH_PKGINIT_TCL_IN if needed.
594 #
595 if {0x0f & $::teaish__Config(pkginit-policy)} {
596 file delete -force -- [get-define TEAISH_PKGINIT_TCL]
597 proj-dot-ins-append [get-define TEAISH_PKGINIT_TCL_IN] \
598 [get-define TEAISH_PKGINIT_TCL]
599 }
600 if {0x0f & $::teaish__Config(tm-policy)} {
601 file delete -force -- [get-define TEAISH_TM_TCL]
602 proj-dot-ins-append [get-define TEAISH_TM_TCL_IN]
603 }
604
605 apply {{} {
606 # Queue up any remaining dot-in files
607 set dotIns [list]
608 foreach {dIn => dOut} {
609 TEAISH_TESTER_TCL_IN => TEAISH_TESTER_TCL
610 TEAISH_TEST_TCL_IN => TEAISH_TEST_TCL
611 TEAISH_MAKEFILE_IN => TEAISH_MAKEFILE
612 } {
613 lappend dotIns [get-define $dIn ""] [get-define $dOut ""]
614 }
615 lappend dotIns $::autosetup(srcdir)/Makefile.in Makefile; # must be after TEAISH_MAKEFILE_IN.
616 # Much later: probably because of timestamps for deps purposes :-?
617 #puts "dotIns=$dotIns"
618 foreach {i o} $dotIns {
619 if {"" ne $i && "" ne $o} {
620 #puts " pre-dot-ins-append: \[$i\] -> \[$o\]"
621 proj-dot-ins-append $i $o
622 }
623 }
624 }}
625
626 define TEAISH_DIST_FULL \
627 [expr {
628 $::teaish__Config(dist-enabled)
629 && $::teaish__Config(dist-full-enabled)
630 }]
631
632 define TEAISH_AUTOSETUP_DIR $::teaish__Config(core-dir)
633 define TEAISH_ENABLE_DIST $::teaish__Config(dist-enabled)
634 define TEAISH_ENABLE_INSTALL $::teaish__Config(install-enabled)
635 define TEAISH_ENABLE_DLL $::teaish__Config(dll-enabled)
636 define TEAISH_TCL $::teaish__Config(teaish.tcl)
637
638 define TEAISH_DIST_FILES [join $::teaish__Config(dist-files)]
639 define TEAISH_EXT_DIR [join $::teaish__Config(extension-dir)]
640 define TEAISH_EXT_SRC [join $::teaish__Config(extension-src)]
641 proj-setup-autoreconfig TEAISH_AUTORECONFIG
642 foreach f {
643 TEAISH_CFLAGS
644 TEAISH_LDFLAGS
645 } {
646 # Ensure that any of these lists are flattened
647 define $f [join [get-define $f]]
648 }
649 proj-remap-autoconf-dir-vars
650 set tdefs [teaish__defines_to_list]
651 define TEAISH__DEFINES_MAP $tdefs; # injected into _teaish.tester.tcl
652
653 #
654 # NO [define]s after this point!
655 #
656 proj-if-opt-truthy teaish-dump-defines {
657 proj-file-write config.defines.txt $tdefs
658 }
659 proj-dot-ins-process -validate
660
661 }; # teaish__configure_phase1
662
663 #
664 # Run checks for required binaries.
665 #
666 proc teaish__check_common_bins {} {
667 if {"" eq [proj-bin-define install]} {
668 proj-warn "Cannot find install binary, so 'make install' will not work."
669 define BIN_INSTALL false
670 }
671 if {"" eq [proj-bin-define zip]} {
672 proj-warn "Cannot find zip, so 'make dist.zip' will not work."
673 }
674 if {"" eq [proj-bin-define tar]} {
675 proj-warn "Cannot find tar, so 'make dist.tgz' will not work."
676 }
677 }
678
679 #
680 # TCL...
681 #
682 # teaish__check_tcl performs most of the --with-tcl and --with-tclsh
683 # handling. Some related bits and pieces are performed before and
684 # after that function is called.
685 #
686 # Important [define]'d vars:
687 #
688 # - TCLSH_CMD is the path to the canonical tclsh or "".
689 #
690 # - TCL_CONFIG_SH is the path to tclConfig.sh or "".
691 #
692 # - TCLLIBDIR is the dir to which the extension library gets
693 # - installed.
694 #
695 proc teaish__check_tcl {} {
696 define TCLSH_CMD false ; # Significant is that it exits with non-0
697 define TCLLIBDIR "" ; # Installation dir for TCL extension lib
698 define TCL_CONFIG_SH ""; # full path to tclConfig.sh
699
700 # Clear out all vars which would harvest from tclConfig.sh so that
701 # the late-config validation of @VARS@ works even if --disable-tcl
702 # is used.
703 proj-tclConfig-sh-to-autosetup ""
704
705 # TODO: better document the steps this is taking.
706 set srcdir $::autosetup(srcdir)
707 msg-result "Checking for a suitable tcl... "
708 set use_tcl 1
709 set withSh [opt-val with-tclsh [proj-get-env TCLSH]]
710 set tclHome [opt-val with-tcl [proj-get-env TCL_HOME]]
711 if {[string match */lib $tclHome]} {
712 # TEA compatibility kludge: its --with-tcl wants the lib
713 # dir containing tclConfig.sh.
714 #proj-warn "Replacing --with-tcl=$tclHome for TEA compatibility"
715 regsub {/lib^} $tclHome "" tclHome
716 msg-result "NOTE: stripped /lib suffix from --with-tcl=$tclHome (a TEA-ism)"
717 }
718 if {0} {
719 # This misinteracts with the $TCL_PREFIX default: it will use the
720 # autosetup-defined --prefix default
721 if {"prefix" eq $tclHome} {
722 set tclHome [get-define prefix]
723 }
724 }
725 teaish-debug "use_tcl ${use_tcl}"
726 teaish-debug "withSh=${withSh}"
727 teaish-debug "tclHome=$tclHome"
728 if {"" eq $withSh && "" eq $tclHome} {
729 # If neither --with-tclsh nor --with-tcl are provided, try to find
730 # a workable tclsh.
731 set withSh [proj-first-bin-of tclsh9.1 tclsh9.0 tclsh8.6 tclsh]
732 teaish-debug "withSh=${withSh}"
733 }
734
735 set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
736 if {"" ne $withSh} {
737 # --with-tclsh was provided or found above. Validate it and use it
738 # to trump any value passed via --with-tcl=DIR.
739 if {![file-isexec $withSh]} {
740 proj-error "TCL shell $withSh is not executable"
741 } else {
742 define TCLSH_CMD $withSh
743 #msg-result "Using tclsh: $withSh"
744 }
745 if {$doConfigLookup &&
746 [catch {exec $withSh $::autosetup(libdir)/find_tclconfig.tcl} result] == 0} {
747 set tclHome $result
748 }
749 if {"" ne $tclHome && [file isdirectory $tclHome]} {
750 teaish__verbose 1 msg-result "$withSh recommends the tclConfig.sh from $tclHome"
751 } else {
752 proj-warn "$withSh is unable to recommend a tclConfig.sh"
753 set use_tcl 0
754 }
755 }
756 set cfg ""
757 set tclSubdirs {tcl9.1 tcl9.0 tcl8.6 tcl8.5 lib}
758 while {$use_tcl} {
759 if {"" ne $tclHome} {
760 # Ensure that we can find tclConfig.sh under ${tclHome}/...
761 if {$doConfigLookup} {
762 if {[file readable "${tclHome}/tclConfig.sh"]} {
763 set cfg "${tclHome}/tclConfig.sh"
764 } else {
765 foreach i $tclSubdirs {
766 if {[file readable "${tclHome}/$i/tclConfig.sh"]} {
767 set cfg "${tclHome}/$i/tclConfig.sh"
768 break
769 }
770 }
771 }
772 }
773 if {"" eq $cfg} {
774 proj-error "No tclConfig.sh found under ${tclHome}"
775 }
776 } else {
777 # If we have not yet found a tclConfig.sh file, look in $libdir
778 # which is set automatically by autosetup or via the --prefix
779 # command-line option. See
780 # https://sqlite.org/forum/forumpost/e04e693439a22457
781 set libdir [get-define libdir]
782 if {[file readable "${libdir}/tclConfig.sh"]} {
783 set cfg "${libdir}/tclConfig.sh"
784 } else {
785 foreach i $tclSubdirs {
786 if {[file readable "${libdir}/$i/tclConfig.sh"]} {
787 set cfg "${libdir}/$i/tclConfig.sh"
788 break
789 }
790 }
791 }
792 if {![file readable $cfg]} {
793 break
794 }
795 }
796 teaish__verbose 1 msg-result "Using tclConfig.sh = $cfg"
797 break
798 }; # while {$use_tcl}
799 define TCL_CONFIG_SH $cfg
800 # Export a subset of tclConfig.sh to the current TCL-space. If $cfg
801 # is an empty string, this emits empty-string entries for the
802 # various options we're interested in.
803 proj-tclConfig-sh-to-autosetup $cfg
804
805 if {"" eq $withSh && $cfg ne ""} {
806 # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
807 # based on info from tclConfig.sh.
808 set tclExecPrefix [get-define TCL_EXEC_PREFIX]
809 proj-assert {"" ne $tclExecPrefix}
810 set tryThese [list \
811 $tclExecPrefix/bin/tclsh[get-define TCL_VERSION] \
812 $tclExecPrefix/bin/tclsh ]
813 foreach trySh $tryThese {
814 if {[file-isexec $trySh]} {
815 set withSh $trySh
816 break
817 }
818 }
819 if {![file-isexec $withSh]} {
820 proj-warn "Cannot find a usable tclsh (tried: $tryThese)"
821 }
822 }
823 define TCLSH_CMD $withSh
824 if {$use_tcl} {
825 # Set up the TCLLIBDIR
826 set tcllibdir [get-env TCLLIBDIR ""]
827 set extDirName [teaish-pkginfo-get -libDir]
828 if {"" eq $tcllibdir} {
829 # Attempt to extract TCLLIBDIR from TCL's $auto_path
830 if {"" ne $withSh &&
831 [catch {exec echo "puts stdout \$auto_path" | "$withSh"} result] == 0} {
832 foreach i $result {
833 if {![string match //zip* $i] && [file isdirectory $i]} {
834 # isdirectory actually passes on //zipfs:/..., but those are
835 # useless for our purposes
836 set tcllibdir $i/$extDirName
837 break
838 }
839 }
840 } else {
841 proj-error "Cannot determine TCLLIBDIR."
842 }
843 }
844 define TCLLIBDIR $tcllibdir
845 }; # find TCLLIBDIR
846
847 set gotSh [file-isexec $withSh]
848 set tmdir ""; # first tcl::tm::list entry
849 if {$gotSh} {
850 catch {
851 set tmli [exec echo {puts [tcl::tm::list]} | $withSh]
852 # Reminder: this list contains many names of dirs which do not
853 # exist but are legitimate. If we rely only on an is-dir check,
854 # we can end up not finding any of the many candidates.
855 set firstDir ""
856 foreach d $tmli {
857 if {"" eq $firstDir && ![string match //*:* $d]} {
858 # First non-VFS entry, e.g. not //zipfs:
859 set firstDir $d
860 }
861 if {[file isdirectory $d]} {
862 set tmdir $d
863 break
864 }
865 }
866 if {"" eq $tmdir} {
867 set tmdir $firstDir
868 }
869 }; # find tcl::tm path
870 }
871 define TEAISH_TCL_TM_DIR $tmdir
872
873 # Finally, let's wrap up...
874 if {$gotSh} {
875 teaish__verbose 1 msg-result "Using tclsh = $withSh"
876 if {$cfg ne ""} {
877 define HAVE_TCL 1
878 } else {
879 proj-warn "Found tclsh but no tclConfig.sh."
880 }
881 if {"" eq $tmdir} {
882 proj-warn "Did not find tcl::tm directory."
883 }
884 }
885 show-notices
886 # If TCL is not found: if it was explicitly requested then fail
887 # fatally, else just emit a warning. If we can find the APIs needed
888 # to generate a working JimTCL then that will suffice for build-time
889 # TCL purposes (see: proc sqlite-determine-codegen-tcl).
890 if {!$gotSh} {
891 proj-error "Did not find tclsh"
892 } elseif {"" eq $cfg} {
893 proj-indented-notice -error {
894 Cannot find a usable tclConfig.sh file. Use --with-tcl=DIR to
895 specify a directory near which tclConfig.sh can be found, or
896 --with-tclsh=/path/to/tclsh to allow the tclsh binary to locate
897 its tclConfig.sh, with the caveat that a symlink to tclsh, or
898 wrapper script around it, e.g. ~/bin/tclsh ->
899 $HOME/tcl/9.0/bin/tclsh9.1, may not work because tclsh emits
900 different library paths for the former than the latter.
901 }
902 }
903 msg-result "Using Tcl [get-define TCL_VERSION] from [get-define TCL_PREFIX]."
904 teaish__tcl_platform_quirks
905 }; # teaish__check_tcl
906
907 #
908 # Perform last-minute platform-specific tweaks to account for quirks.
909 #
910 proc teaish__tcl_platform_quirks {} {
911 define TEAISH_POSTINST_PREREQUIRE ""
912 switch -glob -- [get-define host] {
913 *-haiku {
914 # Haiku's default TCLLIBDIR is "all wrong": it points to a
915 # read-only virtual filesystem mount-point. We bend it back to
916 # fit under $TCL_PACKAGE_PATH here.
917 foreach {k d} {
918 vj TCL_MAJOR_VERSION
919 vn TCL_MINOR_VERSION
920 pp TCL_PACKAGE_PATH
921 ld TCLLIBDIR
922 } {
923 set $k [get-define $d]
924 }
925 if {[string match /packages/* $ld]} {
926 set old $ld
927 set tail [file tail $ld]
928 if {8 == $vj} {
929 set ld "${pp}/tcl${vj}.${vn}/${tail}"
930 } else {
931 proj-assert {9 == $vj}
932 set ld "${pp}/${tail}"
933 }
934 define TCLLIBDIR $ld
935 # [load foo.so], without a directory part, does not work via
936 # automated tests on Haiku (but works when run
937 # manually). Similarly, the post-install [package require ...]
938 # test fails, presumably for a similar reason. We work around
939 # the former in _teaish.tester.tcl.in. We work around the
940 # latter by amending the post-install check's ::auto_path (in
941 # Makefile.in). This code MUST NOT contain any single-quotes.
942 define TEAISH_POSTINST_PREREQUIRE \
943 [join [list set ::auto_path \
944 \[ linsert \$::auto_path 0 $ld \] \; \
945 ]]
946 proj-indented-notice [subst -nocommands -nobackslashes {
947 Haiku users take note: patching target installation dir to match
948 Tcl's home because Haiku's is not writable.
949
950 Original : $old
951 Substitute: $ld
952 }]
953 }
954 }
955 }
956 }; # teaish__tcl_platform_quirks
957
958 #
959 # Searches $::argv and/or the build dir and/or the source dir for
960 # teaish.tcl and friends. Fails if it cannot find teaish.tcl or if
961 # there are other irreconcilable problems. If it returns 0 then it did
962 # not find an extension but the --help flag was seen, in which case
963 # that's not an error.
964 #
965 # This does not _load_ the extension, it primarily locates the files
966 # which make up an extension and fills out no small amount of teaish
967 # state related to that.
968 #
969 proc teaish__find_extension {} {
970 proj-assert {!$::teaish__Config(install-mode)}
971 teaish__verbose 1 msg-result "Looking for teaish extension..."
972
973 # Helper for the foreach loop below.
974 set checkTeaishTcl {{mustHave fid dir} {
975 set f [file join $dir $fid]
976 if {[file readable $f]} {
977 file-normalize $f
978 } elseif {$mustHave} {
979 proj-error "Missing required $dir/$fid"
980 }
981 }}
982
983 #
984 # We have to handle some flags manually because the extension must
985 # be loaded before [options] is run (so that the extension can
986 # inject its own options).
987 #
988 set dirBld $::autosetup(builddir); # dir we're configuring under
989 set dirSrc $::autosetup(srcdir); # where teaish's configure script lives
990 set extT ""; # teaish.tcl
991 set largv {}; # rewritten $::argv
992 set gotHelpArg 0; # got the --help
993 foreach arg $::argv {
994 #puts "*** arg=$arg"
995 switch -glob -- $arg {
996 --ted=* -
997 --t-e-d=* -
998 --teaish-extension-dir=* {
999 # Ensure that $extD refers to a directory and contains a
1000 # teaish.tcl.
1001 regexp -- {--[^=]+=(.+)} $arg - extD
1002 set extD [file-normalize $extD]
1003 if {![file isdirectory $extD]} {
1004 proj-error "--teaish-extension-dir value is not a directory: $extD"
1005 }
1006 set extT [apply $checkTeaishTcl 0 teaish.config $extD]
1007 if {"" eq $extT} {
1008 set extT [apply $checkTeaishTcl 1 teaish.tcl $extD]
1009 }
1010 set ::teaish__Config(extension-dir) $extD
1011 }
1012 --help {
1013 incr gotHelpArg
1014 lappend largv $arg
1015 }
1016 default {
1017 lappend largv $arg
1018 }
1019 }
1020 }
1021 set ::argv $largv
1022
1023 set dirExt $::teaish__Config(extension-dir); # dir with the extension
1024 #
1025 # teaish.tcl is a TCL script which implements various
1026 # interfaces described by this framework.
1027 #
1028 # We use the first one we find in the builddir or srcdir.
1029 #
1030 if {"" eq $extT} {
1031 set flist [list]
1032 proj-assert {$dirExt eq ""}
1033 lappend flist $dirBld/teaish.tcl $dirBld/teaish.config $dirSrc/teaish.tcl
1034 if {![proj-first-file-found extT $flist]} {
1035 if {$gotHelpArg} {
1036 # Tell teaish-configure-core that the lack of extension is not
1037 # an error when --help or --teaish-install is used.
1038 return 0;
1039 }
1040 proj-indented-notice -error "
1041 Did not find any of: $flist
1042
1043 If you are attempting an out-of-tree build, use
1044 --teaish-extension-dir=/path/to/extension"
1045 }
1046 }
1047 if {![file readable $extT]} {
1048 proj-error "extension tcl file is not readable: $extT"
1049 }
1050 set ::teaish__Config(teaish.tcl) $extT
1051 set dirExt [file dirname $extT]
1052
1053 set ::teaish__Config(extension-dir) $dirExt
1054 set ::teaish__Config(blddir-is-extdir) [expr {$dirBld eq $dirExt}]
1055 set ::teaish__Config(dist-enabled) $::teaish__Config(blddir-is-extdir); # may change later
1056 set ::teaish__Config(dist-full-enabled) \
1057 [expr {[file-normalize $::autosetup(srcdir)]
1058 eq [file-normalize $::teaish__Config(extension-dir)]}]
1059
1060 set addDist {{file} {
1061 teaish-dist-add [file tail $file]
1062 }}
1063 apply $addDist $extT
1064
1065 teaish__verbose 1 msg-result "Extension dir = [teaish-get -dir]"
1066 teaish__verbose 1 msg-result "Extension config = $extT"
1067
1068 teaish-pkginfo-set -name [file tail [file dirname $extT]]
1069
1070 #
1071 # teaish.make[.in] provides some of the info for the main makefile,
1072 # like which source(s) to build and their build flags.
1073 #
1074 # We use the first one of teaish.make.in or teaish.make we find in
1075 # $dirExt.
1076 #
1077 if {[proj-first-file-found extM \
1078 [list \
1079 $dirExt/teaish.make.in \
1080 $dirExt/teaish.make \
1081 ]]} {
1082 if {[string match *.in $extM]} {
1083 define TEAISH_MAKEFILE_IN $extM
1084 define TEAISH_MAKEFILE _[file rootname [file tail $extM]]
1085 } else {
1086 define TEAISH_MAKEFILE_IN ""
1087 define TEAISH_MAKEFILE $extM
1088 }
1089 apply $addDist $extM
1090 teaish__verbose 1 msg-result "Extension makefile = $extM"
1091 } else {
1092 define TEAISH_MAKEFILE_IN ""
1093 define TEAISH_MAKEFILE ""
1094 }
1095
1096 # Look for teaish.pkginit.tcl[.in]
1097 set piPolicy 0
1098 if {[proj-first-file-found extI \
1099 [list \
1100 $dirExt/teaish.pkginit.tcl.in \
1101 $dirExt/teaish.pkginit.tcl \
1102 ]]} {
1103 if {[string match *.in $extI]} {
1104 # Generate teaish.pkginit.tcl from $extI.
1105 define TEAISH_PKGINIT_TCL_IN $extI
1106 define TEAISH_PKGINIT_TCL [file rootname [file tail $extI]]
1107 set piPolicy 0x01
1108 } else {
1109 # Assume static $extI.
1110 define TEAISH_PKGINIT_TCL_IN ""
1111 define TEAISH_PKGINIT_TCL $extI
1112 set piPolicy 0x10
1113 }
1114 apply $addDist $extI
1115 teaish__verbose 1 msg-result "Extension post-load init = $extI"
1116 define TEAISH_PKGINIT_TCL_TAIL \
1117 [file tail [get-define TEAISH_PKGINIT_TCL]]; # for use in pkgIndex.tcl.in
1118 }
1119 set ::teaish__Config(pkginit-policy) $piPolicy
1120
1121 # Look for pkgIndex.tcl[.in]...
1122 set piPolicy 0
1123 if {[proj-first-file-found extPI $dirExt/pkgIndex.tcl.in]} {
1124 # Generate ./pkgIndex.tcl from $extPI.
1125 define TEAISH_PKGINDEX_TCL_IN $extPI
1126 define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]]
1127 apply $addDist $extPI
1128 set piPolicy 0x01
1129 } elseif {$dirExt ne $dirSrc
1130 && [proj-first-file-found extPI $dirSrc/pkgIndex.tcl.in]} {
1131 # Generate ./pkgIndex.tcl from $extPI.
1132 define TEAISH_PKGINDEX_TCL_IN $extPI
1133 define TEAISH_PKGINDEX_TCL [file rootname [file tail $extPI]]
1134 set piPolicy 0x02
1135 } elseif {[proj-first-file-found extPI $dirExt/pkgIndex.tcl]} {
1136 # Assume $extPI's a static file and use it.
1137 define TEAISH_PKGINDEX_TCL_IN ""
1138 define TEAISH_PKGINDEX_TCL $extPI
1139 apply $addDist $extPI
1140 set piPolicy 0x10
1141 }
1142 # Reminder: we have to delay removal of stale TEAISH_PKGINDEX_TCL
1143 # and the proj-dot-ins-append of TEAISH_PKGINDEX_TCL_IN until much
1144 # later in the process.
1145 set ::teaish__Config(pkgindex-policy) $piPolicy
1146
1147 # Look for teaish.test.tcl[.in]
1148 proj-assert {"" ne $dirExt}
1149 set flist [list $dirExt/teaish.test.tcl.in $dirExt/teaish.test.tcl]
1150 if {[proj-first-file-found ttt $flist]} {
1151 if {[string match *.in $ttt]} {
1152 # Generate _teaish.test.tcl from $ttt
1153 set xt _[file rootname [file tail $ttt]]
1154 file delete -force -- $xt; # ensure no stale copy is used
1155 define TEAISH_TEST_TCL $xt
1156 define TEAISH_TEST_TCL_IN $ttt
1157 } else {
1158 define TEAISH_TEST_TCL $ttt
1159 define TEAISH_TEST_TCL_IN ""
1160 }
1161 apply $addDist $ttt
1162 } else {
1163 define TEAISH_TEST_TCL ""
1164 define TEAISH_TEST_TCL_IN ""
1165 }
1166
1167 # Look for _teaish.tester.tcl[.in]
1168 set flist [list $dirExt/_teaish.tester.tcl.in $dirSrc/_teaish.tester.tcl.in]
1169 if {[proj-first-file-found ttt $flist]} {
1170 # Generate teaish.test.tcl from $ttt
1171 set xt [file rootname [file tail $ttt]]
1172 file delete -force -- $xt; # ensure no stale copy is used
1173 define TEAISH_TESTER_TCL $xt
1174 define TEAISH_TESTER_TCL_IN $ttt
1175 if {[lindex $flist 0] eq $ttt} {
1176 apply $addDist $ttt
1177 }
1178 unset ttt xt
1179 } else {
1180 if {[file exists [set ttt [file join $dirSrc _teaish.tester.tcl.in]]]} {
1181 set xt [file rootname [file tail $ttt]]
1182 define TEAISH_TESTER_TCL $xt
1183 define TEAISH_TESTER_TCL_IN $ttt
1184 } else {
1185 define TEAISH_TESTER_TCL ""
1186 define TEAISH_TESTER_TCL_IN ""
1187 }
1188 }
1189 unset flist
1190
1191 # TEAISH_OUT_OF_EXT_TREE = 1 if we're building from a dir other
1192 # than the extension's home dir.
1193 define TEAISH_OUT_OF_EXT_TREE \
1194 [expr {[file-normalize $::autosetup(builddir)] ne \
1195 [file-normalize $::teaish__Config(extension-dir)]}]
1196 return 1
1197 }; # teaish__find_extension
1198
1199 #
1200 # @teaish-cflags-add ?-p|prepend? ?-define? cflags...
1201 #
1202 # Equivalent to [proj-define-amend TEAISH_CFLAGS {*}$args].
1203 #
1204 proc teaish-cflags-add {args} {
1205 proj-define-amend TEAISH_CFLAGS {*}$args
1206 }
1207
1208 #
1209 # @teaish-define-to-cflag ?flags? defineName...|{defineName...}
1210 #
1211 # Uses [proj-define-to-cflag] to expand a list of [define] keys, each
1212 # one a separate argument, to CFLAGS-style -D... form then appends
1213 # that to the current TEAISH_CFLAGS.
1214 #
1215 # It accepts these flags from proj-define-to-cflag: -quote,
1216 # -zero-undef. It does _not_ support its -list flag.
1217 #
1218 # It accepts its non-flag argument(s) in 2 forms: (1) each arg is a
1219 # single [define] key or (2) its one arg is a list of such keys.
1220 #
1221 # TODO: document teaish's well-defined (as it were) defines for this
1222 # purpose. At a bare minimum:
1223 #
1224 # - TEAISH_NAME
1225 # - TEAISH_PKGNAME
1226 # - TEAISH_VERSION
1227 # - TEAISH_LIBDIR_NAME
1228 # - TEAISH_LOAD_PREFIX
1229 # - TEAISH_URL
1230 #
1231 proc teaish-define-to-cflag {args} {
1232 set flags {}
1233 while {[string match -* [lindex $args 0]]} {
1234 set arg [lindex $args 0]
1235 switch -exact -- $arg {
1236 -quote -
1237 -zero-undef {
1238 lappend flags $arg
1239 set args [lassign $args -]
1240 }
1241 default break
1242 }
1243 }
1244 if {1 == [llength $args]} {
1245 set args [list {*}[lindex $args 0]]
1246 }
1247 #puts "***** flags=$flags args=$args"
1248 teaish-cflags-add [proj-define-to-cflag {*}$flags {*}$args]
1249 }
1250
1251 #
1252 # @teaish-cflags-for-tea ?...CFLAGS?
1253 #
1254 # Adds several -DPACKAGE_... CFLAGS using the extension's metadata,
1255 # all as quoted strings. Those symbolic names are commonly used in
1256 # TEA-based builds, and this function is intended to simplify porting
1257 # of such builds. The -D... flags added are:
1258 #
1259 # -DPACKAGE_VERSION=...
1260 # -DPACKAGE_NAME=...
1261 # -DPACKAGE_URL=...
1262 # -DPACKAGE_STRING=...
1263 #
1264 # Any arguments are passed-on as-is to teaish-cflags-add.
1265 #
1266 proc teaish-cflags-for-tea {args} {
1267 set name $::teaish__PkgInfo(-name)
1268 set version $::teaish__PkgInfo(-version)
1269 set pstr [join [list $name $version]]
1270 teaish-cflags-add \
1271 {*}$args \
1272 '-DPACKAGE_VERSION="$version"' \
1273 '-DPACKAGE_NAME="$name"' \
1274 '-DPACKAGE_STRING="$pstr"' \
1275 '-DPACKAGE_URL="[teaish-get -url]"'
1276 }
1277
1278 #
1279 # @teaish-ldflags-add ?-p|-prepend? ?-define? ldflags...
1280 #
1281 # Equivalent to [proj-define-amend TEAISH_LDFLAGS {*}$args].
1282 #
1283 # Typically, -lXYZ flags need to be in "reverse" order, with each -lY
1284 # resolving symbols for -lX's to its left. This order is largely
1285 # historical, and not relevant on all environments, but it is
1286 # technically correct and still relevant on some environments.
1287 #
1288 # See: teaish-ldflags-prepend
1289 #
1290 proc teaish-ldflags-add {args} {
1291 proj-define-amend TEAISH_LDFLAGS {*}$args
1292 }
1293
1294 #
1295 # @teaish-ldflags-prepend args...
1296 #
1297 # Functionally equivalent to [teaish-ldflags-add -p {*}$args]
1298 #
1299 proc teaish-ldflags-prepend {args} {
1300 teaish-ldflags-add -p {*}$args
1301 }
1302
1303 #
1304 # @teaish-src-add ?-dist? ?-dir? src-files...
1305 #
1306 # Appends all non-empty $args to the project's list of C/C++ source or
1307 # (in some cases) object files.
1308 #
1309 # If passed -dist then it also passes each filename, as-is, to
1310 # [teaish-dist-add].
1311 #
1312 # If passed -dir then each src-file has [teaish-get -dir] prepended to
1313 # it before they're added to the list. As often as not, that will be
1314 # the desired behavior so that out-of-tree builds can find the
1315 # sources, but there are cases where it's not desired (e.g. when using
1316 # a source file from outside of the extension's dir, or when adding
1317 # object files (which are typically in the build tree)).
1318 #
1319 proc teaish-src-add {args} {
1320 proj-parse-simple-flags args flags {
1321 -dist 0 {expr 1}
1322 -dir 0 {expr 1}
1323 }
1324 if {$flags(-dist)} {
1325 teaish-dist-add {*}$args
1326 }
1327 if {$flags(-dir)} {
1328 set xargs {}
1329 foreach arg $args {
1330 if {"" ne $arg} {
1331 lappend xargs [file join $::teaish__Config(extension-dir) $arg]
1332 }
1333 }
1334 set args $xargs
1335 }
1336 lappend ::teaish__Config(extension-src) {*}$args
1337 }
1338
1339 #
1340 # @teaish-dist-add files-or-dirs...
1341 #
1342 # Adds the given files to the list of files to include with the "make
1343 # dist" rules.
1344 #
1345 # This is a no-op when the current build is not in the extension's
1346 # directory, as dist support is disabled in out-of-tree builds.
1347 #
1348 # It is not legal to call this until [teaish-get -dir] has been
1349 # reliably set (via teaish__find_extension).
1350 #
1351 proc teaish-dist-add {args} {
1352 if {$::teaish__Config(blddir-is-extdir)} {
1353 # ^^^ reminder: we ignore $::teaish__Config(dist-enabled) here
1354 # because the client might want to implement their own dist
1355 # rules.
1356 #proj-warn "**** args=$args"
1357 lappend ::teaish__Config(dist-files) {*}$args
1358 }
1359 }
1360
1361 # teaish-install-add files...
1362 # Equivalent to [proj-define-apend TEAISH_INSTALL_FILES ...].
1363 #proc teaish-install-add {args} {
1364 # proj-define-amend TEAISH_INSTALL_FILES {*}$args
1365 #}
1366
1367 #
1368 # @teash-make-add args...
1369 #
1370 # Appends makefile code to the TEAISH_MAKEFILE_CODE define. Each
1371 # arg may be any of:
1372 #
1373 # -tab: emit a literal tab
1374 # -nl: emit a literal newline
1375 # -nltab: short for -nl -tab
1376 # -bnl: emit a backslash-escaped end-of-line
1377 # -bnltab: short for -eol -tab
1378 #
1379 # Anything else is appended verbatim. This function adds no additional
1380 # spacing between each argument nor between subsequent invocations.
1381 # Generally speaking, a series of calls to this function need to
1382 # be sure to end the series with a newline.
1383 proc teaish-make-add {args} {
1384 set out [get-define TEAISH_MAKEFILE_CODE ""]
1385 foreach a $args {
1386 switch -exact -- $a {
1387 -bnl { set a " \\\n" }
1388 -bnltab { set a " \\\n\t" }
1389 -tab { set a "\t" }
1390 -nl { set a "\n" }
1391 -nltab { set a "\n\t" }
1392 }
1393 append out $a
1394 }
1395 define TEAISH_MAKEFILE_CODE $out
1396 }
1397
1398 # Internal helper to generate a clean/distclean rule name
1399 proc teaish__cleanup_rule {{tgt clean}} {
1400 set x [incr ::teaish__Config(teaish__cleanup_rule-counter-${tgt})]
1401 return ${tgt}-_${x}_
1402 }
1403
1404 # @teaish-make-obj ?flags? ?...args?
1405 #
1406 # Uses teaish-make-add to inject makefile rules for $objfile from
1407 # $srcfile, which is assumed to be C code which uses libtcl. Unless
1408 # -recipe is used (see below) it invokes the compiler using the
1409 # makefile-defined $(CC.tcl) which, in the default Makefile.in
1410 # template, includes any flags needed for building against the
1411 # configured Tcl.
1412 #
1413 # This always terminates the resulting code with a newline.
1414 #
1415 # Any arguments after the 2nd may be flags described below or, if no
1416 # -recipe is provided, flags for the compiler call.
1417 #
1418 # -obj obj-filename.o
1419 #
1420 # -src src-filename.c
1421 #
1422 # -recipe {...}
1423 # Uses the trimmed value of {...} as the recipe, prefixing it with
1424 # a single hard-tab character.
1425 #
1426 # -deps {...}
1427 # List of extra files to list as dependencies of $o.
1428 #
1429 # -clean
1430 # Generate cleanup rules as well.
1431 proc teaish-make-obj {args} {
1432 proj-parse-simple-flags args flags {
1433 -clean 0 {expr 1}
1434 -recipe => {}
1435 -deps => {}
1436 -obj => {}
1437 -src => {}
1438 }
1439 #parray flags
1440 if {"" eq $flags(-obj)} {
1441 set args [lassign $args flags(-obj)]
1442 if {"" eq $flags(-obj)} {
1443 proj-error "Missing -obj flag."
1444 }
1445 }
1446 foreach f {-deps -src} {
1447 set flags($f) [string trim [string map {\n " "} $flags($f)]]
1448 }
1449 foreach f {-deps -src} {
1450 set flags($f) [string trim $flags($f)]
1451 }
1452 #parray flags
1453 #puts "-- args=$args"
1454 teaish-make-add \
1455 "# [proj-scope 1] -> [proj-scope] $flags(-obj) $flags(-src)" -nl \
1456 "$flags(-obj): $flags(-src) $::teaish__Config(teaish.tcl)"
1457 if {[info exists flags(-deps)]} {
1458 teaish-make-add " " [join $flags(-deps)]
1459 }
1460 teaish-make-add -nltab
1461 if {[info exists flags(-recipe)]} {
1462 teaish-make-add [string trim $flags(-recipe)] -nl
1463 } else {
1464 teaish-make-add [join [list \$(CC.tcl) -c $flags(-src) {*}$args]] -nl
1465 }
1466 if {$flags(-clean)} {
1467 set rule [teaish__cleanup_rule]
1468 teaish-make-add \
1469 "clean: $rule\n$rule:\n\trm -f \"$flags(-obj)\"\n"
1470 }
1471 }
1472
1473 #
1474 # @teaish-make-clean ?-r? ?-dist? ...files|{...files}
1475 #
1476 # Adds makefile rules for cleaning up the given files via the "make
1477 # clean" or (if -dist is used) "make distclean" makefile rules. The -r
1478 # flag uses "rm -fr" instead of "rm -f", so be careful with that.
1479 #
1480 # The file names are taken literally as arguments to "rm", so they may
1481 # be shell wildcards to be resolved at cleanup-time. To clean up whole
1482 # directories, pass the -r flag. Each name gets quoted in
1483 # double-quotes, so spaces in names should not be a problem (but
1484 # double-quotes in names will be).
1485 #
1486 proc teaish-make-clean {args} {
1487 if {1 == [llength $args]} {
1488 set args [list {*}[lindex $args 0]]
1489 }
1490
1491 set tgt clean
1492 set rmflags "-f"
1493 proj-parse-simple-flags args flags {
1494 -dist 0 {
1495 set tgt distclean
1496 }
1497 -r 0 {
1498 set rmflags "-fr"
1499 }
1500 }
1501 set rule [teaish__cleanup_rule $tgt]
1502 teaish-make-add "# [proj-scope 1] -> [proj-scope]: [join $args]\n"
1503 teaish-make-add "${rule}:\n\trm ${rmflags}"
1504 foreach a $args {
1505 teaish-make-add " \"$a\""
1506 }
1507 teaish-make-add "\n${tgt}: ${rule}\n"
1508 }
1509
1510 #
1511 # @teaish-make-config-header filename
1512 #
1513 # Invokes autosetup's [make-config-header] and passes it $filename and
1514 # a relatively generic list of options for controlling which defined
1515 # symbols get exported. Clients which need more control over the
1516 # exports can copy/paste/customize this.
1517 #
1518 # The exported file is then passed to [proj-touch] because, in
1519 # practice, that's sometimes necessary to avoid build dependency
1520 # issues.
1521 #
1522 proc teaish-make-config-header {filename} {
1523 make-config-header $filename \
1524 -none {HAVE_CFLAG_* LDFLAGS_* SH_* TEAISH__* TEAISH_*_CODE} \
1525 -auto {SIZEOF_* HAVE_* TEAISH_* TCL_*} \
1526 -none *
1527 proj-touch $filename; # help avoid frequent unnecessary auto-reconfig
1528 }
1529
1530 #
1531 # @teaish-feature-cache-set $key value
1532 #
1533 # Sets a feature-check cache entry with the given key.
1534 # See proj-cache-set for the key's semantics. $key should
1535 # normally be 0.
1536 #
1537 proc teaish-feature-cache-set {key val} {
1538 proj-cache-set -key $key -level 1 $val
1539 }
1540
1541 #
1542 # @teaish-feature-cache-check key tgtVarName
1543 #
1544 # Checks for a feature-check cache entry with the given key.
1545 # See proj-cache-set for the key's semantics.
1546 #
1547 # $key should also almost always be 0 but, due to a tclsh
1548 # incompatibility in 1 OS, it cannot have a default value unless it's
1549 # the second argument (but it should be the first one).
1550 #
1551 # If the feature-check cache has a matching entry then this function
1552 # assigns its value to tgtVar and returns 1, else it assigns tgtVar to
1553 # "" and returns 0.
1554 #
1555 # See proj-cache-check for $key's semantics.
1556 #
1557 proc teaish-feature-cache-check {key tgtVar} {
1558 upvar $tgtVar tgt
1559 proj-cache-check -key $key -level 1 tgt
1560 }
1561
1562 #
1563 # @teaish-check-cached@ ?flags? msg script...
1564 #
1565 # A proxy for feature-test impls which handles caching of a feature
1566 # flag check on per-function basis, using the calling scope's name as
1567 # the cache key.
1568 #
1569 # It emits [msg-checking $msg]. If $msg is empty then it defaults to
1570 # the name of the caller's scope. The -nomsg flag suppresses the
1571 # message for non-cache-hit checks. At the end, it will [msg-result
1572 # "ok"] [msg-result "no"] unless -nostatus is used, in which case the
1573 # caller is responsible for emitting at least a newline when it's
1574 # done. The -msg-0 and -msg-1 flags can be used to change the ok/no
1575 # text.
1576 #
1577 # This function checks for a cache hit before running $script and
1578 # caching the result. If no hit is found then $script is run in the
1579 # calling scope and its result value is stored in the cache. This
1580 # routine will intercept a 'return' from $script.
1581 #
1582 # $script may be a command and its arguments, as opposed to a single
1583 # script block.
1584 #
1585 # Flags:
1586 #
1587 # -nostatus = do not emit "ok" or "no" at the end. This presumes
1588 # that either $script will emit at least one newline before
1589 # returning or the caller will account for it. Because of how this
1590 # function is typically used, -nostatus is not honored when the
1591 # response includes a cached result.
1592 #
1593 # -quiet = disable output from Autosetup's msg-checking and
1594 # msg-result for the duration of the $script check. Note that when
1595 # -quiet is in effect, Autosetup's user-notice can be used to queue
1596 # up output to appear after the check is done. Also note that
1597 # -quiet has no effect on _this_ function, only the $script part.
1598 #
1599 # -nomsg = do not emit $msg for initial check. Like -nostatus, this
1600 # flag is not honored when the response includes a cached result
1601 # because it would otherwise produce no output (which is confusing
1602 # in this context). This is useful when a check runs several other
1603 # verbose checks and they emit all the necessary info.
1604 #
1605 # -msg-0 and -msg-1 MSG = strings to show when the check has failed
1606 # resp. passed. Defaults are "no" and "ok". The 0 and 1 refer to the
1607 # result value from teaish-feature-cache-check.
1608 #
1609 # -key cachekey = set the cache context key. Only needs to be
1610 # explicit when using this function multiple times from a single
1611 # scope. See proj-cache-check and friends for details on the key
1612 # name. Its default is the name of the scope which calls this
1613 # function.
1614 #
1615 proc teaish-check-cached {args} {
1616 proj-parse-simple-flags args flags {
1617 -nostatus 0 {expr 1}
1618 -quiet 0 {expr 1}
1619 -key => 1
1620 -nomsg 0 {expr 1}
1621 -msg-0 => no
1622 -msg-1 => ok
1623 }
1624 set args [lassign $args msg]
1625 set script [join $args]
1626 if {"" eq $msg} {
1627 set msg [proj-scope 1]
1628 }
1629 if {[teaish-feature-cache-check $flags(-key) check]} {
1630 #if {0 == $flags(-nomsg)} {
1631 msg-checking "${msg} ... (cached) "
1632 #}
1633 #if {!$flags(-nostatus)} {
1634 msg-result $flags(-msg-[expr {0 != ${check}}])
1635 #}
1636 return $check
1637 } else {
1638 if {0 == $flags(-nomsg)} {
1639 msg-checking "${msg} ... "
1640 }
1641 if {$flags(-quiet)} {
1642 incr ::autosetup(msg-quiet)
1643 }
1644 set code [catch {uplevel 1 $script} rc xopt]
1645 if {$flags(-quiet)} {
1646 incr ::autosetup(msg-quiet) -1
1647 }
1648 #puts "***** cached-check got code=$code rc=$rc"
1649 if {$code in {0 2}} {
1650 teaish-feature-cache-set 1 $rc
1651 if {!$flags(-nostatus)} {
1652 msg-result $flags(-msg-[expr {0 != ${rc}}])
1653 } else {
1654 #show-notices; # causes a phantom newline because we're in a
1655 #msg-checking scope, so...
1656 if {[info exists ::autosetup(notices)]} {
1657 show-notices
1658 }
1659 }
1660 } else {
1661 #puts "**** code=$code rc=$rc xopt=$xopt"
1662 teaish-feature-cache-set 1 0
1663 }
1664 #puts "**** code=$code rc=$rc"
1665 return {*}$xopt $rc
1666 }
1667 }
1668
1669 #
1670 # Internal helper for teaish__defs_format_: returns a JSON-ish quoted
1671 # form of the given string-type values.
1672 #
1673 # If $asList is true then the return value is in {$value} form. If
1674 # $asList is false it only performs the most basic of escaping and
1675 # the input must not contain any control characters.
1676 #
1677 proc teaish__quote_str {asList value} {
1678 if {$asList} {
1679 return "{${value}}"
1680 }
1681 return \"[string map [list \\ \\\\ \" \\\"] $value]\"
1682 }
1683
1684 #
1685 # Internal helper for teaish__defines_to_list. Expects to be passed
1686 # a name and the variadic $args which are passed to
1687 # teaish__defines_to_list.. If it finds a pattern match for the
1688 # given $name in the various $args, it returns the type flag for that
1689 # $name, e.g. "-str" or "-bare", else returns an empty string.
1690 #
1691 proc teaish__defs_type {name spec} {
1692 foreach {type patterns} $spec {
1693 foreach pattern $patterns {
1694 if {[string match $pattern $name]} {
1695 return $type
1696 }
1697 }
1698 }
1699 return ""
1700 }
1701
1702 #
1703 # An internal impl detail. Requires a data type specifier, as used by
1704 # Autosetup's [make-config-header], and a value. Returns the formatted
1705 # value or the value $::teaish__Config(defs-skip) if the caller should
1706 # skip emitting that value.
1707 #
1708 # In addition to -str, -auto, etc., as defined by make-config-header,
1709 # it supports:
1710 #
1711 # -list {...} will cause non-integer values to be quoted in {...}
1712 # instead of quotes.
1713 #
1714 # -autolist {...} works like -auto {...} except that it falls back to
1715 # -list {...} type instead of -str {...} style for non-integers.
1716 #
1717 # -jsarray {...} emits the output in something which, for
1718 # conservative inputs, will be a valid JSON array. It can only
1719 # handle relatively simple values with no control characters in
1720 # them.
1721 #
1722 set teaish__Config(defs-skip) "-teaish__defs_format sentinel"
1723 proc teaish__defs_format {type value} {
1724 switch -exact -- $type {
1725 -bare {
1726 # Just output the value unchanged
1727 }
1728 -none {
1729 set value $::teaish__Config(defs-skip)
1730 }
1731 -str {
1732 set value [teaish__quote_str 0 $value]
1733 }
1734 -auto {
1735 # Automatically determine the type
1736 if {![string is integer -strict $value]} {
1737 set value [teaish__quote_str 0 $value]
1738 }
1739 }
1740 -autolist {
1741 if {![string is integer -strict $value]} {
1742 set value [teaish__quote_str 1 $value]
1743 }
1744 }
1745 -list {
1746 set value [teaish__quote_str 1 $value]
1747 }
1748 -jsarray {
1749 set ar {}
1750 foreach v $value {
1751 if {![string is integer -strict $v]} {
1752 set v [teaish__quote_str 0 $v]
1753 }
1754 if {$::teaish__Config(defs-skip) ne $v} {
1755 lappend ar $v
1756 }
1757 }
1758 set value [concat \[ [join $ar {, }] \]]
1759 }
1760 "" {
1761 # (Much later:) Why do we do this?
1762 set value $::teaish__Config(defs-skip)
1763 }
1764 default {
1765 proj-error \
1766 "Unknown [proj-scope] -type ($type) called from" \
1767 [proj-scope 1]
1768 }
1769 }
1770 return $value
1771 }
1772
1773 #
1774 # Returns Tcl code in the form of code which evaluates to a list of
1775 # configure-time DEFINEs in the form {key val key2 val...}. It may
1776 # misbehave for values which are not numeric or simple strings. Some
1777 # defines are specifically filtered out of the result, either because
1778 # their irrelevant to teaish or because they may be arbitrarily large
1779 # (e.g. makefile content).
1780 #
1781 # The $args are explained in the docs for internal-use-only
1782 # [teaish__defs_format]. The default mode is -autolist.
1783 #
1784 proc teaish__defines_to_list {args} {
1785 set lines {}
1786 lappend lines "\{"
1787 set skipper $::teaish__Config(defs-skip)
1788 set args [list \
1789 -none {
1790 TEAISH__*
1791 TEAISH_*_CODE
1792 AM_* AS_*
1793 } \
1794 {*}$args \
1795 -autolist *]
1796 foreach d [lsort [dict keys [all-defines]]] {
1797 set type [teaish__defs_type $d $args]
1798 set value [teaish__defs_format $type [get-define $d]]
1799 if {$skipper ne $value} {
1800 lappend lines "$d $value"
1801 }
1802 }
1803 lappend lines "\}"
1804 tailcall join $lines "\n"
1805 }
1806
1807 #
1808 # teaish__pragma ...flags
1809 #
1810 # Offers a way to tweak how teaish's core behaves in some cases, in
1811 # particular those which require changing how the core looks for an
1812 # extension and its files.
1813 #
1814 # Accepts the following flags. Those marked with [L] are safe to use
1815 # during initial loading of tclish.tcl (recall that most teaish APIs
1816 # cannot be used until [teaish-configure] is called).
1817 #
1818 # static-pkgIndex.tcl [L]: Tells teaish that ./pkgIndex.tcl is not
1819 # a generated file, so it will not try to overwrite or delete
1820 # it. Errors out if it does not find pkgIndex.tcl in the
1821 # extension's dir.
1822 #
1823 # no-dist [L]: tells teaish to elide the 'make dist' recipe
1824 # from the generated Makefile.
1825 #
1826 # no-dll [L]: tells teaish to elide the DLL-building recipe
1827 # from the generated Makefile.
1828 #
1829 # no-vsatisfies-error [L]: tells teaish that failure to match the
1830 # -vsatisfies value should simply "return" instead of "error".
1831 #
1832 # no-tester [L]: disables automatic generation of teaish.test.tcl
1833 # even if a copy of _teaish.tester.tcl.in is found.
1834 #
1835 # no-full-dist [L]: changes the "make dist" rules to never include
1836 # a copy of teaish itself. By default it will include itself only
1837 # if the extension lives in the same directory as teaish.
1838 #
1839 # full-dist [L]: changes the "make dist" rules to always include
1840 # a copy of teaish itself.
1841 #
1842 # Emits a warning message for unknown arguments.
1843 #
1844 proc teaish__pragma {args} {
1845 foreach arg $args {
1846 switch -exact -- $arg {
1847
1848 static-pkgIndex.tcl {
1849 if {$::teaish__Config(tm-policy)} {
1850 proj-fatal -up "Cannot use pragma $arg together with -tm.tcl or -tm.tcl.in."
1851 }
1852 set tpi [file join $::teaish__Config(extension-dir) pkgIndex.tcl]
1853 if {[file exists $tpi]} {
1854 define TEAISH_PKGINDEX_TCL_IN ""
1855 define TEAISH_PKGINDEX_TCL $tpi
1856 set ::teaish__Config(pkgindex-policy) 0x20
1857 } else {
1858 proj-error "pragma $arg: found no package-local pkgIndex.tcl\[.in]"
1859 }
1860 }
1861
1862 no-dist {
1863 set ::teaish__Config(dist-enabled) 0
1864 }
1865
1866 no-install {
1867 set ::teaish__Config(install-enabled) 0
1868 }
1869
1870 full-dist {
1871 set ::teaish__Config(dist-full-enabled) 1
1872 }
1873
1874 no-full-dist {
1875 set ::teaish__Config(dist-full-enabled) 0
1876 }
1877
1878 no-dll {
1879 set ::teaish__Config(dll-enabled) 0
1880 }
1881
1882 no-vsatisfies-error {
1883 set ::teaish__Config(vsatisfies-error) 0
1884 }
1885
1886 no-tester {
1887 define TEAISH_TESTER_TCL_IN ""
1888 define TEAISH_TESTER_TCL ""
1889 }
1890
1891 default {
1892 proj-error "Unknown flag: $arg"
1893 }
1894 }
1895 }
1896 }
1897
1898 #
1899 # @teaish-pkginfo-set ...flags
1900 #
1901 # The way to set up the initial package state. Used like:
1902 #
1903 # teaish-pkginfo-set -name foo -version 0.1.2
1904 #
1905 # Or:
1906 #
1907 # teaish-pkginfo-set ?-vars|-subst? {-name foo -version 0.1.2}
1908 #
1909 # The latter may be easier to write for a multi-line invocation.
1910 #
1911 # For the second call form, passing the -vars flag tells it to perform
1912 # a [subst] of (only) variables in the {...} part from the calling
1913 # scope. The -subst flag will cause it to [subst] the {...} with
1914 # command substitution as well (but no backslash substitution). When
1915 # using -subst for string concatenation, e.g. with -libDir
1916 # foo[get-version-number], be sure to wrap the value in braces:
1917 # -libDir {foo[get-version-number]}.
1918 #
1919 # Each pkginfo flag corresponds to one piece of extension package
1920 # info. Teaish provides usable default values for all of these flags,
1921 # but at least the -name and -version should be set by clients.
1922 # e.g. the default -name is the directory name the extension lives in,
1923 # which may change (e.g. when building it from a "make dist" bundle).
1924 #
1925 # The flags:
1926 #
1927 # -name theName: The extension's name. It defaults to the name of the
1928 # directory containing the extension. (In TEA this would be the
1929 # PACKAGE_NAME, not to be confused with...)
1930 #
1931 # -name.pkg pkg-provide-name: The extension's name for purposes of
1932 # Tcl_PkgProvide(), [package require], and friends. It defaults to
1933 # the `-name`, and is normally the same, but some projects (like
1934 # SQLite) have a different name here than they do in their
1935 # historical TEA PACKAGE_NAME.
1936 #
1937 # -version version: The extension's package version. Defaults to
1938 # 0.0.0.
1939 #
1940 # -libDir dirName: The base name of the directory into which this
1941 # extension should be installed. It defaults to a concatenation of
1942 # `-name.pkg` and `-version`.
1943 #
1944 # -loadPrefix prefix: For use as the second argument passed to
1945 # Tcl's `load` command in the package-loading process. It defaults
1946 # to title-cased `-name.pkg` because Tcl's `load` plugin system
1947 # expects it in that form.
1948 #
1949 # -options {...}: If provided, it must be a list compatible with
1950 # Autosetup's `options-add` function. These can also be set up via
1951 # `teaish-options`.
1952 #
1953 # -vsatisfies {{...} ...}: Expects a list-of-lists of conditions
1954 # for Tcl's `package vsatisfies` command: each list entry is a
1955 # sub-list of `{PkgName Condition...}`. Teaish inserts those
1956 # checks via its default pkgIndex.tcl.in and _teaish.tester.tcl.in
1957 # templates to verify that the system's package dependencies meet
1958 # these requirements. The default value is `{{Tcl 8.5-}}` (recall
1959 # that it's a list-of-lists), as 8.5 is the minimum Tcl version
1960 # teaish will run on, but some extensions may require newer
1961 # versions or dependencies on other packages. As a special case,
1962 # if `-vsatisfies` is given a single token, e.g. `8.6-`, then it
1963 # is transformed into `{Tcl $thatToken}`, i.e. it checks the Tcl
1964 # version which the package is being run with. If given multiple
1965 # lists, each `package provides` check is run in the given
1966 # order. Failure to meet a `vsatisfies` condition triggers an
1967 # error.
1968 #
1969 # -url {...}: an optional URL for the extension.
1970 #
1971 # -pragmas {...} A list of infrequently-needed lower-level
1972 # directives which can influence teaish, including:
1973 #
1974 # static-pkgIndex.tcl: tells teaish that the client manages their
1975 # own pkgIndex.tcl, so that teaish won't try to overwrite it
1976 # using a template.
1977 #
1978 # no-dist: tells teaish to elide the "make dist" recipe from the
1979 # makefile so that the client can implement it.
1980 #
1981 # no-dll: tells teaish to elide the makefile rules which build
1982 # the DLL, as well as any templated test script and pkgIndex.tcl
1983 # references to them. The intent here is to (A) support
1984 # client-defined build rules for the DLL and (B) eventually
1985 # support script-only extensions.
1986 #
1987 # Unsupported flags or pragmas will trigger an error.
1988 #
1989 # Potential pothole: setting certain state, e.g. -version, after the
1990 # initial call requires recalculating of some [define]s. Any such
1991 # changes should be made as early as possible in teaish-configure so
1992 # that any later use of those [define]s gets recorded properly (not
1993 # with the old value). This is particularly relevant when it is not
1994 # possible to determine the -version or -name until teaish-configure
1995 # has been called, and it's updated dynamically from
1996 # teaish-configure. Notably:
1997 #
1998 # - If -version or -name are updated, -libDir will almost certainly
1999 # need to be explicitly set along with them.
2000 #
2001 # - If -name is updated, -loadPrefix probably needs to be as well.
2002 #
2003 proc teaish-pkginfo-set {args} {
2004 set doVars 0
2005 set doCommands 0
2006 set xargs $args
2007 set recalc {}
2008 foreach arg $args {
2009 switch -exact -- $arg {
2010 -vars {
2011 incr doVars
2012 set xargs [lassign $xargs -]
2013 }
2014 -subst {
2015 incr doVars
2016 incr doCommands
2017 set xargs [lassign $xargs -]
2018 }
2019 default {
2020 break
2021 }
2022 }
2023 }
2024 set args $xargs
2025 unset xargs
2026 if {1 == [llength $args] && [llength [lindex $args 0]] > 1} {
2027 # Transform a single {...} arg into the canonical call form
2028 set a [list {*}[lindex $args 0]]
2029 if {$doVars || $doCommands} {
2030 set sflags -nobackslashes
2031 if {!$doCommands} {
2032 lappend sflags -nocommands
2033 }
2034 set a [uplevel 1 [list subst {*}$sflags $a]]
2035 }
2036 set args $a
2037 }
2038 set sentinel "<nope>"
2039 set flagDefs [list]
2040 foreach {f d} $::teaish__Config(pkginfo-f2d) {
2041 lappend flagDefs $f => $sentinel
2042 }
2043 proj-parse-simple-flags args flags $flagDefs
2044 if {[llength $args]} {
2045 proj-error -up "Too many (or unknown) arguments to [proj-scope]: $args"
2046 }
2047 foreach {f d} $::teaish__Config(pkginfo-f2d) {
2048 if {$sentinel eq [set v $flags($f)]} continue
2049 switch -exact -- $f {
2050
2051 -options {
2052 proj-assert {"" eq $d}
2053 options-add $v
2054 }
2055
2056 -pragmas {
2057 teaish__pragma {*}$v
2058 }
2059
2060 -vsatisfies {
2061 if {1 == [llength $v] && 1 == [llength [lindex $v 0]]} {
2062 # Transform X to {Tcl $X}
2063 set v [list [join [list Tcl $v]]]
2064 }
2065 define $d $v
2066 }
2067
2068 -pkgInit.tcl -
2069 -pkgInit.tcl.in {
2070 if {0x22 & $::teaish__Config(pkginit-policy)} {
2071 proj-fatal "Cannot use -pkgInit.tcl(.in) more than once."
2072 }
2073 set x [file join $::teaish__Config(extension-dir) $v]
2074 set tTail [file tail $v]
2075 if {"-pkgInit.tcl.in" eq $f} {
2076 # Generate pkginit file X from X.in
2077 set pI 0x02
2078 set tIn $x
2079 set tOut [file rootname $tTail]
2080 set other -pkgInit.tcl
2081 } else {
2082 # Static pkginit file X
2083 set pI 0x20
2084 set tIn ""
2085 set tOut $x
2086 set other -pkgInit.tcl.in
2087 }
2088 set ::teaish__Config(pkginit-policy) $pI
2089 set ::teaish__PkgInfo($other) {}
2090 define TEAISH_PKGINIT_TCL_IN $tIn
2091 define TEAISH_PKGINIT_TCL $tOut
2092 define TEAISH_PKGINIT_TCL_TAIL $tTail
2093 teaish-dist-add $v
2094 set v $x
2095 }
2096
2097 -src {
2098 set d $::teaish__Config(extension-dir)
2099 foreach f $v {
2100 lappend ::teaish__Config(dist-files) $f
2101 lappend ::teaish__Config(extension-src) $d/$f
2102 lappend ::teaish__PkgInfo(-src) $f
2103 # ^^^ so that default-value initialization in
2104 # teaish-configure-core recognizes that it's been set.
2105 }
2106 }
2107
2108 -tm.tcl -
2109 -tm.tcl.in {
2110 if {0x30 & $::teaish__Config(pkgindex-policy)} {
2111 proj-fatal "Cannot use $f together with a pkgIndex.tcl."
2112 } elseif {$::teaish__Config(tm-policy)} {
2113 proj-fatal "Cannot use -tm.tcl(.in) more than once."
2114 }
2115 set x [file join $::teaish__Config(extension-dir) $v]
2116 if {"-tm.tcl.in" eq $f} {
2117 # Generate tm file X from X.in
2118 set pT 0x02
2119 set pI 0x100
2120 set tIn $x
2121 set tOut [file rootname [file tail $v]]
2122 set other -tm.tcl
2123 } else {
2124 # Static tm file X
2125 set pT 0x20
2126 set pI 0x200
2127 set tIn ""
2128 set tOut $x
2129 set other -tm.tcl.in
2130 }
2131 set ::teaish__Config(pkgindex-policy) $pI
2132 set ::teaish__Config(tm-policy) $pT
2133 set ::teaish__PkgInfo($other) {}
2134 define TEAISH_TM_TCL_IN $tIn
2135 define TEAISH_TM_TCL $tOut
2136 define TEAISH_PKGINDEX_TCL ""
2137 define TEAISH_PKGINDEX_TCL_IN ""
2138 define TEAISH_PKGINDEX_TCL_TAIL ""
2139 teaish-dist-add $v
2140 teaish__pragma no-dll
2141 set v $x
2142 }
2143
2144 default {
2145 proj-assert {"" ne $d}
2146 define $d $v
2147 }
2148 }
2149 set ::teaish__PkgInfo($f) $v
2150 if {$f in {-name -version -libDir -loadPrefix}} {
2151 lappend recalc $f
2152 }
2153 }
2154 if {"" ne $recalc} {
2155 teaish__define_pkginfo_derived $recalc
2156 }
2157 }
2158
2159 #
2160 # @teaish-pkginfo-get ?arg?
2161 #
2162 # If passed no arguments, it returns the extension config info in the
2163 # same form accepted by teaish-pkginfo-set.
2164 #
2165 # If passed one -flagname arg then it returns the value of that config
2166 # option.
2167 #
2168 # Else it treats arg as the name of caller-scoped variable to
2169 # which this function assigns an array containing the configuration
2170 # state of this extension, in the same structure accepted by
2171 # teaish-pkginfo-set. In this case it returns an empty string.
2172 #
2173 proc teaish-pkginfo-get {args} {
2174 set cases {}
2175 set argc [llength $args]
2176 set rv {}
2177 switch -exact $argc {
2178 0 {
2179 # Return a list of (-flag value) pairs
2180 lappend cases default {{
2181 if {[info exists ::teaish__PkgInfo($flag)]} {
2182 lappend rv $flag $::teaish__PkgInfo($flag)
2183 } else {
2184 lappend rv $flag [get-define $defName]
2185 }
2186 }}
2187 }
2188
2189 1 {
2190 set arg $args
2191 if {[string match -* $arg]} {
2192 # Return the corresponding -flag's value
2193 lappend cases $arg {{
2194 if {[info exists ::teaish__PkgInfo($flag)]} {
2195 return $::teaish__PkgInfo($flag)
2196 } else {
2197 return [get-define $defName]
2198 }
2199 }}
2200 } else {
2201 # Populate target with an array of (-flag value).
2202 upvar $arg tgt
2203 array set tgt {}
2204 lappend cases default {{
2205 if {[info exists ::teaish__PkgInfo($flag)]} {
2206 set tgt($flag) $::teaish__PkgInfo($flag)
2207 } else {
2208 set tgt($flag) [get-define $defName]
2209 }
2210 }}
2211 }
2212 }
2213
2214 default {
2215 proj-error "invalid arg count from [proj-scope 1]"
2216 }
2217 }
2218
2219 foreach {flag defName} $::teaish__Config(pkginfo-f2d) {
2220 switch -exact -- $flag [join $cases]
2221 }
2222 if {0 == $argc} { return $rv }
2223 }
2224
2225 # (Re)set some defines based on pkginfo state. $flags is the list of
2226 # pkginfo -flags which triggered this, or "*" for the initial call.
2227 proc teaish__define_pkginfo_derived {flags} {
2228 set all [expr {{*} in $flags}]
2229 if {$all || "-version" in $flags || "-name" in $flags} {
2230 set name $::teaish__PkgInfo(-name) ; # _not_ -name.pkg
2231 if {[info exists ::teaish__PkgInfo(-version)]} {
2232 set pkgver $::teaish__PkgInfo(-version)
2233 set libname "lib"
2234 if {[string match *-cygwin [get-define host]]} {
2235 set libname cyg
2236 }
2237 define TEAISH_DLL8_BASENAME $libname$name$pkgver
2238 define TEAISH_DLL9_BASENAME ${libname}tcl9$name$pkgver
2239 set ext [get-define TARGET_DLLEXT]
2240 define TEAISH_DLL8 [get-define TEAISH_DLL8_BASENAME]$ext
2241 define TEAISH_DLL9 [get-define TEAISH_DLL9_BASENAME]$ext
2242 }
2243 }
2244 if {$all || "-libDir" in $flags} {
2245 if {[info exists ::teaish__PkgInfo(-libDir)]} {
2246 define TCLLIBDIR \
2247 [file dirname [get-define TCLLIBDIR]]/$::teaish__PkgInfo(-libDir)
2248 }
2249 }
2250 }
2251
2252 #
2253 # @teaish-checks-queue -pre|-post args...
2254 #
2255 # Queues one or more arbitrary "feature test" functions to be run when
2256 # teaish-checks-run is called. $flag must be one of -pre or -post to
2257 # specify whether the tests should be run before or after
2258 # teaish-configure is run. Each additional arg is the name of a
2259 # feature-test proc.
2260 #
2261 proc teaish-checks-queue {flag args} {
2262 if {$flag ni {-pre -post}} {
2263 proj-error "illegal flag: $flag"
2264 }
2265 lappend ::teaish__Config(queued-checks${flag}) {*}$args
2266 }
2267
2268 #
2269 # @teaish-checks-run -pre|-post
2270 #
2271 # Runs all feature checks queued using teaish-checks-queue
2272 # then cleares the queue.
2273 #
2274 proc teaish-checks-run {flag} {
2275 if {$flag ni {-pre -post}} {
2276 proj-error "illegal flag: $flag"
2277 }
2278 #puts "*** running $flag: $::teaish__Config(queued-checks${flag})"
2279 set foo 0
2280 foreach f $::teaish__Config(queued-checks${flag}) {
2281 if {![teaish-feature-cache-check $f foo]} {
2282 set v [$f]
2283 teaish-feature-cache-set $f $v
2284 }
2285 }
2286 set ::teaish__Config(queued-checks${flag}) {}
2287 }
2288
2289 #
2290 # A general-purpose getter for various teaish state. Requires one
2291 # flag, which determines its result value. Flags marked with [L] below
2292 # are safe for using at load-time, before teaish-pkginfo-set is called
2293 #
2294 # -dir [L]: returns the extension's directory, which may differ from
2295 # the teaish core dir or the build dir.
2296 #
2297 # -teaish-home [L]: the "home" dir of teaish itself, which may
2298 # differ from the extension dir or build dir.
2299 #
2300 # -build-dir [L]: the build directory (typically the current working
2301 # -dir).
2302 #
2303 # Any of the teaish-pkginfo-get/get flags: returns the same as
2304 # teaish-pkginfo-get. Not safe for use until teaish-pkginfo-set has
2305 # been called.
2306 #
2307 # Triggers an error if passed an unknown flag.
2308 #
2309 proc teaish-get {flag} {
2310 #-teaish.tcl {return $::teaish__Config(teaish.tcl)}
2311 switch -exact -- $flag {
2312 -dir {
2313 return $::teaish__Config(extension-dir)
2314 }
2315 -teaish-home {
2316 return $::autosetup(srcdir)
2317 }
2318 -build-dir {
2319 return $::autosetup(builddir)
2320 }
2321 default {
2322 if {[info exists ::teaish__PkgInfo($flag)]} {
2323 return $::teaish__PkgInfo($flag)
2324 }
2325 }
2326 }
2327 proj-error "Unhandled flag: $flag"
2328 }
2329
2330 #
2331 # Handles --teaish-create-extension=TARGET-DIR
2332 #
2333 proc teaish__create_extension {dir} {
2334 set force [opt-bool teaish-force]
2335 if {"" eq $dir} {
2336 proj-error "--teaish-create-extension=X requires a directory name."
2337 }
2338 file mkdir $dir/generic
2339 set cwd [pwd]
2340 #set dir [file-normalize [file join $cwd $dir]]
2341 teaish__verbose 1 msg-result "Created dir $dir"
2342 cd $dir
2343 if {!$force} {
2344 # Ensure that we don't blindly overwrite anything
2345 foreach f {
2346 generic/teaish.c
2347 teaish.tcl
2348 teaish.make.in
2349 teaish.test.tcl
2350 } {
2351 if {[file exists $f]} {
2352 error "Cowardly refusing to overwrite $dir/$f. Use --teaish-force to overwrite."
2353 }
2354 }
2355 }
2356
2357 set name [file tail $dir]
2358 set pkgName $name
2359 set version 0.0.1
2360 set loadPrefix [string totitle $pkgName]
2361 set content {teaish-pkginfo-set }
2362 #puts "0 content=$content"
2363 if {[opt-str teaish-extension-pkginfo epi]} {
2364 set epi [string trim $epi]
2365 if {[string match "*\n*" $epi]} {
2366 set epi "{$epi}"
2367 } elseif {![string match "{*}" $epi]} {
2368 append content "\{" $epi "\}"
2369 } else {
2370 append content $epi
2371 }
2372 #puts "2 content=$content\nepi=$epi"
2373 } else {
2374 append content [subst -nocommands -nobackslashes {{
2375 -name ${name}
2376 -name.pkg ${pkgName}
2377 -name.dist ${pkgName}
2378 -version ${version}
2379 -loadPrefix $loadPrefix
2380 -libDir ${name}${version}
2381 -vsatisfies {{Tcl 8.5-}}
2382 -url {}
2383 -options {}
2384 -pragmas {full-dist}
2385 }}]
2386 #puts "3 content=$content"
2387 }
2388 #puts "1 content=$content"
2389 append content "\n" {
2390 #proc teaish-options {} {
2391 # Return a list and/or use \[options-add\] to add new
2392 # configure flags. This is called before teaish's
2393 # bootstrapping is finished, so only teaish-*
2394 # APIs which are explicitly noted as being safe
2395 # early on may be used here. Any autosetup-related
2396 # APIs may be used here.
2397 #
2398 # Return an empty string if there are no options to
2399 # add or if they are added using \[options-add\].
2400 #
2401 # If there are no options to add, this proc need
2402 # not be defined.
2403 #}
2404
2405 # Called by teaish once bootstrapping is complete.
2406 # This function is responsible for the client-specific
2407 # parts of the configuration process.
2408 proc teaish-configure {} {
2409 teaish-src-add -dir -dist generic/teaish.c
2410 teaish-define-to-cflag -quote TEAISH_PKGNAME TEAISH_VERSION
2411
2412 # TODO: your code goes here..
2413 }
2414 }; # $content
2415 proj-file-write teaish.tcl $content
2416 teaish__verbose 1 msg-result "Created teaish.tcl"
2417
2418 set content "# Teaish test script.
2419 # When this tcl script is invoked via 'make test' it will have loaded
2420 # the package, run any teaish.pkginit.tcl code, and loaded
2421 # autosetup/teaish/tester.tcl.
2422 "
2423 proj-file-write teaish.test.tcl $content
2424 teaish__verbose 1 msg-result "Created teaish.test.tcl"
2425
2426 set content [subst -nocommands -nobackslashes {
2427 #include <tcl.h>
2428 static int
2429 ${loadPrefix}_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]){
2430 Tcl_SetObjResult(interp, Tcl_NewStringObj("this is the ${name} extension", -1));
2431 return TCL_OK;
2432 }
2433
2434 extern int DLLEXPORT ${loadPrefix}_Init(Tcl_Interp *interp){
2435 if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
2436 return TCL_ERROR;
2437 }
2438 if (Tcl_PkgProvide(interp, TEAISH_PKGNAME, TEAISH_VERSION) == TCL_ERROR) {
2439 return TCL_ERROR;
2440 }
2441 Tcl_CreateObjCommand(interp, TEAISH_PKGNAME, ${loadPrefix}_Cmd, NULL, NULL);
2442 return TCL_OK;
2443 }
2444 }]
2445 proj-file-write generic/teaish.c $content
2446 teaish__verbose 1 msg-result "Created generic/teaish.c"
2447
2448 set content "# teaish makefile for the ${name} extension
2449 # tx.src = \$(tx.dir)/generic/teaish.c
2450 # tx.LDFLAGS =
2451 # tx.CFLAGS =
2452 "
2453 proj-file-write teaish.make.in $content
2454 teaish__verbose 1 msg-result "Created teaish.make.in"
2455
2456 msg-result "Created new extension \[$dir\]."
2457
2458 cd $cwd
2459 set ::teaish__Config(install-ext-dir) $dir
2460 }
2461
2462 #
2463 # Internal helper for teaish__install
2464 #
2465 proc teaish__install_file {f destDir force} {
2466 set dest $destDir/[file tail $f]
2467 if {[file isdirectory $f]} {
2468 file mkdir $dest
2469 } elseif {!$force && [file exists $dest]} {
2470 array set st1 [file stat $f]
2471 array set st2 [file stat $dest]
2472 if {($st1(mtime) == $st2(mtime))
2473 && ($st1(size) == $st2(size))} {
2474 if {[file tail $f] in {
2475 pkgIndex.tcl.in
2476 _teaish.tester.tcl.in
2477 }} {
2478 # Assume they're the same. In the scope of the "make dist"
2479 # rules, this happens legitimately when an extension with a
2480 # copy of teaish installed in the same dir assumes that the
2481 # pkgIndex.tcl.in and _teaish.tester.tcl.in belong to the
2482 # extension, whereas teaish believes they belong to teaish.
2483 # So we end up with dupes of those.
2484 return
2485 }
2486 }
2487 proj-error -up "Cowardly refusing to overwrite \[$dest\]." \
2488 "Use --teaish-force to enable overwriting."
2489 } else {
2490 # file copy -force $f $destDir; # loses +x bit
2491 #
2492 # JimTcl doesn't have [file attribute], so we can't use that here
2493 # (in the context of an autosetup configure script).
2494 exec cp -p $f $dest
2495 }
2496 }
2497
2498 #
2499 # Installs a copy of teaish, with autosetup, to $dDest, which defaults
2500 # to the --teaish-install=X or --teash-create-extension=X dir. Won't
2501 # overwrite files unless --teaish-force is used.
2502 #
2503 proc teaish__install {{dDest ""}} {
2504 if {$dDest in {auto ""}} {
2505 set dDest [opt-val teaish-install]
2506 if {$dDest in {auto ""}} {
2507 if {[info exists ::teaish__Config(install-ext-dir)]} {
2508 set dDest $::teaish__Config(install-ext-dir)
2509 }
2510 }
2511 }
2512 set force [opt-bool teaish-force]
2513 if {$dDest in {auto ""}} {
2514 proj-error "Cannot determine installation directory."
2515 } elseif {!$force && [file exists $dDest/auto.def]} {
2516 proj-error \
2517 "Target dir looks like it already contains teaish and/or autosetup: $dDest" \
2518 "\nUse --teaish-force to overwrite it."
2519 }
2520
2521 set dSrc $::autosetup(srcdir)
2522 set dAS $::autosetup(libdir)
2523 set dAST $::teaish__Config(core-dir)
2524 set dASTF $dAST/feature
2525 teaish__verbose 1 msg-result "Installing teaish to \[$dDest\]..."
2526 if {$::teaish__Config(verbose)>1} {
2527 msg-result "dSrc = $dSrc"
2528 msg-result "dAS = $dAS"
2529 msg-result "dAST = $dAST"
2530 msg-result "dASTF = $dASTF"
2531 msg-result "dDest = $dDest"
2532 }
2533
2534 # Dest subdirs...
2535 set ddAS $dDest/autosetup
2536 set ddAST $ddAS/teaish
2537 set ddASTF $ddAST/feature
2538 foreach {srcDir destDir} [list \
2539 $dAS $ddAS \
2540 $dAST $ddAST \
2541 $dASTF $ddASTF \
2542 ] {
2543 teaish__verbose 1 msg-result "Copying files to $destDir..."
2544 file mkdir $destDir
2545 foreach f [glob -nocomplain -directory $srcDir *] {
2546 if {[string match {*~} $f] || [string match "#*#" [file tail $f]]} {
2547 # Editor-generated backups and emacs lock files
2548 continue
2549 }
2550 teaish__verbose 2 msg-result "\t$f"
2551 teaish__install_file $f $destDir $force
2552 }
2553 }
2554 teaish__verbose 1 msg-result "Copying files to $dDest..."
2555 foreach f {
2556 auto.def configure Makefile.in pkgIndex.tcl.in
2557 _teaish.tester.tcl.in
2558 } {
2559 teaish__verbose 2 msg-result "\t$f"
2560 teaish__install_file $dSrc/$f $dDest $force
2561 }
2562 set ::teaish__Config(install-self-dir) $dDest
2563 msg-result "Teaish $::teaish__Config(version) installed in \[$dDest\]."
2564 }