teaish.tcl revision 1.1 1 # Teaish configure script for the SQLite Tcl extension
2
3 #
4 # State for disparate config-time pieces.
5 #
6 array set sqlite__Config [proj-strip-hash-comments {
7 #
8 # The list of feature --flags which the --all flag implies. This
9 # requires special handling in a few places.
10 #
11 all-flag-enables {fts3 fts4 fts5 rtree geopoly}
12
13 # >0 if building in the canonical tree. -1=undetermined
14 is-canonical -1
15 }]
16
17 #
18 # Set up the package info for teaish...
19 #
20 apply {{dir} {
21 # Figure out the version number...
22 set version ""
23 if {[file exists $dir/../VERSION]} {
24 # The canonical SQLite TEA(ish) build
25 set version [proj-file-content -trim $dir/../VERSION]
26 set ::sqlite__Config(is-canonical) 1
27 set distname sqlite-tcl
28 } elseif {[file exists $dir/generic/tclsqlite3.c]} {
29 # The copy from the teaish tree, used as a dev/test bed before
30 # updating SQLite's tree.
31 set ::sqlite__Config(is-canonical) 0
32 set fd [open $dir/generic/tclsqlite3.c rb]
33 while {[gets $fd line] >=0} {
34 if {[regexp {^#define[ ]+SQLITE_VERSION[ ]+"(3.+)"} \
35 $line - version]} {
36 set distname sqlite-teaish
37 break
38 }
39 }
40 close $fd
41 }
42
43 if {"" eq $version} {
44 proj-fatal "Cannot determine the SQLite version number"
45 }
46
47 proj-assert {$::sqlite__Config(is-canonical) > -1}
48 proj-assert {[string match 3.*.* $version]} \
49 "Unexpected SQLite version: $version"
50
51 set pragmas {}
52 if {$::sqlite__Config(is-canonical)} {
53 # Disable "make dist" in the canonical tree. That tree is
54 # generated from several pieces and creating/testing working
55 # "dist" rules for that sub-build currently feels unnecessary. The
56 # copy in the teaish tree, though, should be able to "make dist".
57 lappend pragmas no-dist
58 } else {
59 lappend pragmas full-dist
60 }
61
62 teaish-pkginfo-set -vars {
63 -name sqlite
64 -name.pkg sqlite3
65 -version $version
66 -name.dist $distname
67 -libDir sqlite$version
68 -pragmas $pragmas
69 -src generic/tclsqlite3.c
70 }
71 # We should also have:
72 # -vsatisfies 8.6-
73 # But at least one platform is failing this vsatisfies check
74 # for no apparent reason:
75 # https://sqlite.org/forum/forumpost/fde857fb8101a4be
76 }} [teaish-get -dir]
77
78
79 #
80 # Must return either an empty string or a list in the form accepted by
81 # autosetup's [options] function.
82 #
83 proc teaish-options {} {
84 # These flags and defaults mostly derive from the historical TEA
85 # build. Some, like ICU, are taken from the canonical SQLite tree.
86 return [subst -nocommands -nobackslashes {
87 with-system-sqlite=0
88 => {Use the system-level SQLite instead of the copy in this tree.
89 Also requires use of --override-sqlite-version so that the build
90 knows what version number to associate with the system-level SQLite.}
91 override-sqlite-version:VERSION
92 => {For use with --with-system-sqlite to set the version number.}
93 threadsafe=1 => {Disable mutexing}
94 with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always}
95 load-extension=0 => {Enable loading of external extensions}
96 math=1 => {Disable math functions}
97 json=1 => {Disable JSON functions}
98 fts3 => {Enable the FTS3 extension}
99 fts4 => {Enable the FTS4 extension}
100 fts5 => {Enable the FTS5 extension}
101 update-limit => {Enable the UPDATE/DELETE LIMIT clause}
102 geopoly => {Enable the GEOPOLY extension}
103 rtree => {Enable the RTREE extension}
104 session => {Enable the SESSION extension}
105 all=1 => {Disable $::sqlite__Config(all-flag-enables)}
106 with-icu-ldflags:LDFLAGS
107 => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the
108 ICU libraries. e.g. on Ubuntu systems, try '-licui18n -licuuc -licudata'.}
109 with-icu-cflags:CFLAGS
110 => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU.
111 e.g. -I/usr/local/include}
112 with-icu-config:=auto
113 => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config,
114 /path/to/icu-config}
115 icu-collations=0
116 => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=...
117 or --with-icu-config}
118 }]
119 }
120
121 #
122 # Gets called by tea-configure-core. Must perform any configuration
123 # work needed for this extension.
124 #
125 proc teaish-configure {} {
126 use teaish/feature
127
128 if {[proj-opt-was-provided override-sqlite-version]} {
129 teaish-pkginfo-set -version [opt-val override-sqlite-version]
130 proj-warn "overriding sqlite version number:" [teaish-pkginfo-get -version]
131 } elseif {[proj-opt-was-provided with-system-sqlite]
132 && [opt-val with-system-sqlite] ne "0"} {
133 proj-fatal "when using --with-system-sqlite also use" \
134 "--override-sqlite-version to specify a library version number."
135 }
136
137 define CFLAGS [proj-get-env CFLAGS {-O2}]
138 sqlite-munge-cflags
139
140 #
141 # Add feature flags from legacy configure.ac which are not covered by
142 # --flags.
143 #
144 sqlite-add-feature-flag {
145 -DSQLITE_3_SUFFIX_ONLY=1
146 -DSQLITE_ENABLE_DESERIALIZE=1
147 -DSQLITE_ENABLE_DBPAGE_VTAB=1
148 -DSQLITE_ENABLE_BYTECODE_VTAB=1
149 -DSQLITE_ENABLE_DBSTAT_VTAB=1
150 }
151
152 if {[opt-bool with-system-sqlite]} {
153 msg-result "Using system-level sqlite3."
154 teaish-cflags-add -DUSE_SYSTEM_SQLITE
155 teaish-ldflags-add -lsqlite3
156 } elseif {$::sqlite__Config(is-canonical)} {
157 teaish-cflags-add -I[teaish-get -dir]/..
158 }
159
160 teaish-check-librt
161 teaish-check-libz
162 sqlite-handle-threadsafe
163 sqlite-handle-tempstore
164 sqlite-handle-load-extension
165 sqlite-handle-math
166 sqlite-handle-icu
167
168 sqlite-handle-common-feature-flags; # must be late in the process
169 }; # teaish-configure
170
171 define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
172 #
173 # Adds $args, if not empty, to OPT_FEATURE_FLAGS. This is intended only for holding
174 # -DSQLITE_ENABLE/OMIT/... flags, but that is not enforced here.
175 proc sqlite-add-feature-flag {args} {
176 if {"" ne $args} {
177 define-append OPT_FEATURE_FLAGS {*}$args
178 }
179 }
180
181 #
182 # Check for log(3) in libm and die with an error if it is not
183 # found. $featureName should be the feature name which requires that
184 # function (it's used only in error messages). defines LDFLAGS_MATH to
185 # the required linker flags (which may be empty even if the math APIs
186 # are found, depending on the OS).
187 proc sqlite-affirm-have-math {featureName} {
188 if {"" eq [get-define LDFLAGS_MATH ""]} {
189 if {![msg-quiet proj-check-function-in-lib log m]} {
190 user-error "Missing math APIs for $featureName"
191 }
192 set lfl [get-define lib_log ""]
193 undefine lib_log
194 if {"" ne $lfl} {
195 user-notice "Forcing requirement of $lfl for $featureName"
196 }
197 define LDFLAGS_MATH $lfl
198 teaish-ldflags-prepend $lfl
199 }
200 }
201
202 #
203 # Handle various SQLITE_ENABLE/OMIT_... feature flags.
204 proc sqlite-handle-common-feature-flags {} {
205 msg-result "Feature flags..."
206 if {![opt-bool all]} {
207 # Special handling for --disable-all
208 foreach flag $::sqlite__Config(all-flag-enables) {
209 if {![proj-opt-was-provided $flag]} {
210 proj-opt-set $flag 0
211 }
212 }
213 }
214 foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments {
215 all {} {
216 # The 'all' option must be first in this list. This impl makes
217 # an effort to only apply flags which the user did not already
218 # apply, so that combinations like (--all --disable-geopoly)
219 # will indeed disable geopoly. There are corner cases where
220 # flags which depend on each other will behave in non-intuitive
221 # ways:
222 #
223 # --all --disable-rtree
224 #
225 # Will NOT disable geopoly, though geopoly depends on rtree.
226 # The --geopoly flag, though, will automatically re-enable
227 # --rtree, so --disable-rtree won't actually disable anything in
228 # that case.
229 foreach k $::sqlite__Config(all-flag-enables) {
230 if {![proj-opt-was-provided $k]} {
231 proj-opt-set $k 1
232 }
233 }
234 }
235 fts3 -DSQLITE_ENABLE_FTS3 {sqlite-affirm-have-math fts3}
236 fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4}
237 fts5 -DSQLITE_ENABLE_FTS5 {sqlite-affirm-have-math fts5}
238 geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
239 rtree -DSQLITE_ENABLE_RTREE {}
240 session {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
241 update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
242 scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
243 }] {
244 if {$boolFlag ni $::autosetup(options)} {
245 # Skip flags which are in the canonical build but not
246 # the autoconf bundle.
247 continue
248 }
249 proj-if-opt-truthy $boolFlag {
250 sqlite-add-feature-flag $featureFlag
251 if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
252 msg-result " + $boolFlag"
253 }
254 } {
255 if {"all" ne $boolFlag} {
256 msg-result " - $boolFlag"
257 }
258 }
259 }
260 #
261 # Invert the above loop's logic for some SQLITE_OMIT_... cases. If
262 # config option $boolFlag is false, [sqlite-add-feature-flag
263 # $featureFlag], where $featureFlag is intended to be
264 # -DSQLITE_OMIT_...
265 foreach {boolFlag featureFlag} {
266 json -DSQLITE_OMIT_JSON
267 } {
268 if {[proj-opt-truthy $boolFlag]} {
269 msg-result " + $boolFlag"
270 } else {
271 sqlite-add-feature-flag $featureFlag
272 msg-result " - $boolFlag"
273 }
274 }
275
276 ##
277 # Remove duplicates from the final feature flag sets and show them
278 # to the user.
279 set oFF [get-define OPT_FEATURE_FLAGS]
280 if {"" ne $oFF} {
281 define OPT_FEATURE_FLAGS [lsort -unique $oFF]
282 msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
283 }
284 if {[lsearch [get-define TARGET_DEBUG ""] -DSQLITE_DEBUG=1] > -1} {
285 msg-result "Note: this is a debug build, so performance will suffer."
286 }
287 teaish-cflags-add -define OPT_FEATURE_FLAGS
288 }; # sqlite-handle-common-feature-flags
289
290 #
291 # If --enable-threadsafe is set, this adds -DSQLITE_THREADSAFE=1 to
292 # OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags
293 # needed for linking pthread (possibly an empty string). If
294 # --enable-threadsafe is not set, adds -DSQLITE_THREADSAFE=0 to
295 # OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to an empty string.
296 #
297 # It prepends the flags to the global LDFLAGS.
298 proc sqlite-handle-threadsafe {} {
299 msg-checking "Support threadsafe operation? "
300 define LDFLAGS_PTHREAD ""
301 set enable 0
302 if {[proj-opt-was-provided threadsafe]} {
303 proj-if-opt-truthy threadsafe {
304 if {[proj-check-function-in-lib pthread_create pthread]
305 && [proj-check-function-in-lib pthread_mutexattr_init pthread]} {
306 incr enable
307 set ldf [get-define lib_pthread_create]
308 define LDFLAGS_PTHREAD $ldf
309 teaish-ldflags-prepend $ldf
310 undefine lib_pthread_create
311 undefine lib_pthread_mutexattr_init
312 } else {
313 user-error "Missing required pthread libraries. Use --disable-threadsafe to disable this check."
314 }
315 # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
316 # found because it's in -lc on some platforms.
317 } {
318 msg-result "Disabled using --disable-threadsafe"
319 }
320 } else {
321 #
322 # If user does not specify --[disable-]threadsafe then select a
323 # default based on whether it looks like Tcl has threading
324 # support.
325 #
326 catch {
327 scan [exec echo {puts [tcl::pkgconfig get threaded]} | [get-define TCLSH_CMD]] \
328 %d enable
329 }
330 if {$enable} {
331 set flagName "--threadsafe"
332 set lblAbled "enabled"
333 msg-result yes
334 } else {
335 set flagName "--disable-threadsafe"
336 set lblAbled "disabled"
337 msg-result no
338 }
339 msg-result "Defaulting to ${flagName} because Tcl has threading ${lblAbled}."
340 # ^^^ We (probably) don't need to link against -lpthread in the
341 # is-enabled case. We might in the case of static linking. Unsure.
342 }
343 sqlite-add-feature-flag -DSQLITE_THREADSAFE=${enable}
344 return $enable
345 }
346
347 #
348 # Handles the --enable-load-extension flag. Returns 1 if the support
349 # is enabled, else 0. If support for that feature is not found, a
350 # fatal error is triggered if --enable-load-extension is explicitly
351 # provided, else a loud warning is instead emitted. If
352 # --disable-load-extension is used, no check is performed.
353 #
354 # Makes the following environment changes:
355 #
356 # - defines LDFLAGS_DLOPEN to any linker flags needed for this
357 # feature. It may legally be empty on some systems where dlopen()
358 # is in libc.
359 #
360 # - If the feature is not available, adds
361 # -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list.
362 proc sqlite-handle-load-extension {} {
363 define LDFLAGS_DLOPEN ""
364 set found 0
365 proj-if-opt-truthy load-extension {
366 set found [proj-check-function-in-lib dlopen dl]
367 if {$found} {
368 set ldf [get-define lib_dlopen]
369 define LDFLAGS_DLOPEN $ldf
370 teaish-ldflags-prepend $ldf
371 undefine lib_dlopen
372 } else {
373 if {[proj-opt-was-provided load-extension]} {
374 # Explicit --enable-load-extension: fail if not found
375 proj-indented-notice -error {
376 --enable-load-extension was provided but dlopen()
377 not found. Use --disable-load-extension to bypass this
378 check.
379 }
380 } else {
381 # It was implicitly enabled: warn if not found
382 proj-indented-notice {
383 WARNING: dlopen() not found, so loadable module support will
384 be disabled. Use --disable-load-extension to bypass this
385 check.
386 }
387 }
388 }
389 }
390 if {$found} {
391 msg-result "Loadable extension support enabled."
392 } else {
393 msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them."
394 sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1
395 }
396 return $found
397 }
398
399 #
400 # ICU - International Components for Unicode
401 #
402 # Handles these flags:
403 #
404 # --with-icu-ldflags=LDFLAGS
405 # --with-icu-cflags=CFLAGS
406 # --with-icu-config[=auto | pkg-config | /path/to/icu-config]
407 # --enable-icu-collations
408 #
409 # --with-icu-config values:
410 #
411 # - auto: use the first one of (pkg-config, icu-config) found on the
412 # system.
413 # - pkg-config: use only pkg-config to determine flags
414 # - /path/to/icu-config: use that to determine flags
415 #
416 # If --with-icu-config is used as neither pkg-config nor icu-config
417 # are found, fail fatally.
418 #
419 # If both --with-icu-ldflags and --with-icu-config are provided, they
420 # are cumulative. If neither are provided, icu-collations is not
421 # honored and a warning is emitted if it is provided.
422 #
423 # Design note: though we could automatically enable ICU if the
424 # icu-config binary or (pkg-config icu-io) are found, we specifically
425 # do not. ICU is always an opt-in feature.
426 proc sqlite-handle-icu {} {
427 define LDFLAGS_LIBICU [join [opt-val with-icu-ldflags ""]]
428 define CFLAGS_LIBICU [join [opt-val with-icu-cflags ""]]
429 if {[proj-opt-was-provided with-icu-config]} {
430 msg-result "Checking for ICU support..."
431 set icuConfigBin [opt-val with-icu-config]
432 set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
433 if {$icuConfigBin in {auto pkg-config}} {
434 uplevel 3 { use pkg-config }
435 if {[pkg-config-init 0] && [pkg-config icu-io]} {
436 # Maintenance reminder: historical docs say to use both of
437 # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
438 # all of them on tested OSes.
439 set tryIcuConfigBin 0
440 define LDFLAGS_LIBICU [get-define PKG_ICU_IO_LDFLAGS]
441 define-append LDFLAGS_LIBICU [get-define PKG_ICU_IO_LIBS]
442 define CFLAGS_LIBICU [get-define PKG_ICU_IO_CFLAGS]
443 } elseif {"pkg-config" eq $icuConfigBin} {
444 proj-fatal "pkg-config cannot find package icu-io"
445 } else {
446 proj-assert {"auto" eq $icuConfigBin}
447 }
448 }
449 if {$tryIcuConfigBin} {
450 if {"auto" eq $icuConfigBin} {
451 set icuConfigBin [proj-first-bin-of \
452 /usr/local/bin/icu-config \
453 /usr/bin/icu-config]
454 if {"" eq $icuConfigBin} {
455 proj-indented-notice -error {
456 --with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary.
457 On Ubuntu-like systems try:
458 --with-icu-ldflags='-licui18n -licuuc -licudata'
459 }
460 }
461 }
462 if {[file-isexec $icuConfigBin]} {
463 set x [exec $icuConfigBin --ldflags]
464 if {"" eq $x} {
465 proj-indented-notice -error \
466 [subst {
467 $icuConfigBin --ldflags returned no data.
468 On Ubuntu-like systems try:
469 --with-icu-ldflags='-licui18n -licuuc -licudata'
470 }]
471 }
472 define-append LDFLAGS_LIBICU $x
473 set x [exec $icuConfigBin --cppflags]
474 define-append CFLAGS_LIBICU $x
475 } else {
476 proj-fatal "--with-icu-config=$icuConfigBin does not refer to an executable"
477 }
478 }
479 }
480 set ldflags [define LDFLAGS_LIBICU [string trim [get-define LDFLAGS_LIBICU]]]
481 set cflags [define CFLAGS_LIBICU [string trim [get-define CFLAGS_LIBICU]]]
482 if {"" ne $ldflags} {
483 sqlite-add-feature-flag -DSQLITE_ENABLE_ICU
484 msg-result "Enabling ICU support with flags: $ldflags $cflags"
485 if {[opt-bool icu-collations]} {
486 msg-result "Enabling ICU collations."
487 sqlite-add-feature-flag -DSQLITE_ENABLE_ICU_COLLATIONS
488 }
489 teaish-ldflags-prepend $ldflags
490 teaish-cflags-add $cflags
491 } elseif {[opt-bool icu-collations]} {
492 proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
493 } else {
494 msg-result "ICU support is disabled."
495 }
496 }; # sqlite-handle-icu
497
498
499 #
500 # Handles the --with-tempstore flag.
501 #
502 # The test fixture likes to set SQLITE_TEMP_STORE on its own, so do
503 # not set that feature flag unless it was explicitly provided to the
504 # configure script.
505 proc sqlite-handle-tempstore {} {
506 if {[proj-opt-was-provided with-tempstore]} {
507 set ts [opt-val with-tempstore no]
508 set tsn 1
509 msg-checking "Use an in-RAM database for temporary tables? "
510 switch -exact -- $ts {
511 never { set tsn 0 }
512 no { set tsn 1 }
513 yes { set tsn 2 }
514 always { set tsn 3 }
515 default {
516 user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
517 }
518 }
519 msg-result $ts
520 sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
521 }
522 }
523
524 #
525 # Handles the --enable-math flag.
526 proc sqlite-handle-math {} {
527 proj-if-opt-truthy math {
528 if {![proj-check-function-in-lib ceil m]} {
529 user-error "Cannot find libm functions. Use --disable-math to bypass this."
530 }
531 set lfl [get-define lib_ceil]
532 undefine lib_ceil
533 define LDFLAGS_MATH $lfl
534 teaish-ldflags-prepend $lfl
535 sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS
536 msg-result "Enabling math SQL functions"
537 } {
538 define LDFLAGS_MATH ""
539 msg-result "Disabling math SQL functions"
540 }
541 }
542
543 #
544 # Move -DSQLITE_OMIT... and -DSQLITE_ENABLE... flags from CFLAGS and
545 # CPPFLAGS to OPT_FEATURE_FLAGS and remove them from BUILD_CFLAGS.
546 proc sqlite-munge-cflags {} {
547 # Move CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and
548 # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
549 # from the pre-3.48 build.
550 #
551 # If any configure flags for features are in conflict with
552 # CFLAGS/CPPFLAGS-specified feature flags, all bets are off. There
553 # are no guarantees about which one will take precedence.
554 foreach flagDef {CFLAGS CPPFLAGS} {
555 set tmp ""
556 foreach cf [get-define $flagDef ""] {
557 switch -glob -- $cf {
558 -DSQLITE_OMIT* -
559 -DSQLITE_ENABLE* {
560 sqlite-add-feature-flag $cf
561 }
562 default {
563 lappend tmp $cf
564 }
565 }
566 }
567 define $flagDef $tmp
568 }
569 }
570