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 } 2565