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