# Teaish configure script for the SQLite Tcl extension # # State for disparate config-time pieces. # array set sqlite__Config [proj-strip-hash-comments { # # The list of feature --flags which the --all flag implies. This # requires special handling in a few places. # all-flag-enables {fts3 fts4 fts5 rtree geopoly} # >0 if building in the canonical tree. -1=undetermined is-canonical -1 }] # # Set up the package info for teaish... # apply {{dir} { # Figure out the version number... set version "" if {[file exists $dir/../VERSION]} { # The canonical SQLite TEA(ish) build set version [proj-file-content -trim $dir/../VERSION] set ::sqlite__Config(is-canonical) 1 set distname sqlite-tcl } elseif {[file exists $dir/generic/tclsqlite3.c]} { # The copy from the teaish tree, used as a dev/test bed before # updating SQLite's tree. set ::sqlite__Config(is-canonical) 0 set fd [open $dir/generic/tclsqlite3.c rb] while {[gets $fd line] >=0} { if {[regexp {^#define[ ]+SQLITE_VERSION[ ]+"(3.+)"} \ $line - version]} { set distname sqlite-teaish break } } close $fd } if {"" eq $version} { proj-fatal "Cannot determine the SQLite version number" } proj-assert {$::sqlite__Config(is-canonical) > -1} proj-assert {[string match 3.*.* $version]} \ "Unexpected SQLite version: $version" set pragmas {} if {$::sqlite__Config(is-canonical)} { # Disable "make dist" in the canonical tree. That tree is # generated from several pieces and creating/testing working # "dist" rules for that sub-build currently feels unnecessary. The # copy in the teaish tree, though, should be able to "make dist". lappend pragmas no-dist } else { lappend pragmas full-dist } teaish-pkginfo-set -vars { -name sqlite -name.pkg sqlite3 -version $version -name.dist $distname -libDir sqlite$version -pragmas $pragmas -src generic/tclsqlite3.c } # We should also have: # -vsatisfies 8.6- # But at least one platform is failing this vsatisfies check # for no apparent reason: # https://sqlite.org/forum/forumpost/fde857fb8101a4be }} [teaish-get -dir] # # Must return either an empty string or a list in the form accepted by # autosetup's [options] function. # proc teaish-options {} { # These flags and defaults mostly derive from the historical TEA # build. Some, like ICU, are taken from the canonical SQLite tree. return [subst -nocommands -nobackslashes { with-system-sqlite=0 => {Use the system-level SQLite instead of the copy in this tree. Also requires use of --override-sqlite-version so that the build knows what version number to associate with the system-level SQLite.} override-sqlite-version:VERSION => {For use with --with-system-sqlite to set the version number.} threadsafe=1 => {Disable mutexing} with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always} load-extension=0 => {Enable loading of external extensions} math=1 => {Disable math functions} json=1 => {Disable JSON functions} fts3 => {Enable the FTS3 extension} fts4 => {Enable the FTS4 extension} fts5 => {Enable the FTS5 extension} update-limit => {Enable the UPDATE/DELETE LIMIT clause} geopoly => {Enable the GEOPOLY extension} rtree => {Enable the RTREE extension} session => {Enable the SESSION extension} all=1 => {Disable $::sqlite__Config(all-flag-enables)} with-icu-ldflags:LDFLAGS => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the ICU libraries. e.g. on Ubuntu systems, try '-licui18n -licuuc -licudata'.} with-icu-cflags:CFLAGS => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU. e.g. -I/usr/local/include} with-icu-config:=auto => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config, /path/to/icu-config} icu-collations=0 => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=... or --with-icu-config} }] } # # Gets called by tea-configure-core. Must perform any configuration # work needed for this extension. # proc teaish-configure {} { use teaish/feature if {[proj-opt-was-provided override-sqlite-version]} { teaish-pkginfo-set -version [opt-val override-sqlite-version] proj-warn "overriding sqlite version number:" [teaish-pkginfo-get -version] } elseif {[proj-opt-was-provided with-system-sqlite] && [opt-val with-system-sqlite] ne "0"} { proj-fatal "when using --with-system-sqlite also use" \ "--override-sqlite-version to specify a library version number." } define CFLAGS [proj-get-env CFLAGS {-O2}] sqlite-munge-cflags # # Add feature flags from legacy configure.ac which are not covered by # --flags. # sqlite-add-feature-flag { -DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_DESERIALIZE=1 -DSQLITE_ENABLE_DBPAGE_VTAB=1 -DSQLITE_ENABLE_BYTECODE_VTAB=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 } if {[opt-bool with-system-sqlite]} { msg-result "Using system-level sqlite3." teaish-cflags-add -DUSE_SYSTEM_SQLITE teaish-ldflags-add -lsqlite3 } elseif {$::sqlite__Config(is-canonical)} { teaish-cflags-add -I[teaish-get -dir]/.. } teaish-check-librt teaish-check-libz sqlite-handle-threadsafe sqlite-handle-tempstore sqlite-handle-load-extension sqlite-handle-math sqlite-handle-icu sqlite-handle-common-feature-flags; # must be late in the process }; # teaish-configure define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags. # # Adds $args, if not empty, to OPT_FEATURE_FLAGS. This is intended only for holding # -DSQLITE_ENABLE/OMIT/... flags, but that is not enforced here. proc sqlite-add-feature-flag {args} { if {"" ne $args} { define-append OPT_FEATURE_FLAGS {*}$args } } # # Check for log(3) in libm and die with an error if it is not # found. $featureName should be the feature name which requires that # function (it's used only in error messages). defines LDFLAGS_MATH to # the required linker flags (which may be empty even if the math APIs # are found, depending on the OS). proc sqlite-affirm-have-math {featureName} { if {"" eq [get-define LDFLAGS_MATH ""]} { if {![msg-quiet proj-check-function-in-lib log m]} { user-error "Missing math APIs for $featureName" } set lfl [get-define lib_log ""] undefine lib_log if {"" ne $lfl} { user-notice "Forcing requirement of $lfl for $featureName" } define LDFLAGS_MATH $lfl teaish-ldflags-prepend $lfl } } # # Handle various SQLITE_ENABLE/OMIT_... feature flags. proc sqlite-handle-common-feature-flags {} { msg-result "Feature flags..." if {![opt-bool all]} { # Special handling for --disable-all foreach flag $::sqlite__Config(all-flag-enables) { if {![proj-opt-was-provided $flag]} { proj-opt-set $flag 0 } } } foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments { all {} { # The 'all' option must be first in this list. This impl makes # an effort to only apply flags which the user did not already # apply, so that combinations like (--all --disable-geopoly) # will indeed disable geopoly. There are corner cases where # flags which depend on each other will behave in non-intuitive # ways: # # --all --disable-rtree # # Will NOT disable geopoly, though geopoly depends on rtree. # The --geopoly flag, though, will automatically re-enable # --rtree, so --disable-rtree won't actually disable anything in # that case. foreach k $::sqlite__Config(all-flag-enables) { if {![proj-opt-was-provided $k]} { proj-opt-set $k 1 } } } fts3 -DSQLITE_ENABLE_FTS3 {sqlite-affirm-have-math fts3} fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4} fts5 -DSQLITE_ENABLE_FTS5 {sqlite-affirm-have-math fts5} geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree} rtree -DSQLITE_ENABLE_RTREE {} session {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {} update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {} scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {} }] { if {$boolFlag ni $::autosetup(options)} { # Skip flags which are in the canonical build but not # the autoconf bundle. continue } proj-if-opt-truthy $boolFlag { sqlite-add-feature-flag $featureFlag if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} { msg-result " + $boolFlag" } } { if {"all" ne $boolFlag} { msg-result " - $boolFlag" } } } # # Invert the above loop's logic for some SQLITE_OMIT_... cases. If # config option $boolFlag is false, [sqlite-add-feature-flag # $featureFlag], where $featureFlag is intended to be # -DSQLITE_OMIT_... foreach {boolFlag featureFlag} { json -DSQLITE_OMIT_JSON } { if {[proj-opt-truthy $boolFlag]} { msg-result " + $boolFlag" } else { sqlite-add-feature-flag $featureFlag msg-result " - $boolFlag" } } ## # Remove duplicates from the final feature flag sets and show them # to the user. set oFF [get-define OPT_FEATURE_FLAGS] if {"" ne $oFF} { define OPT_FEATURE_FLAGS [lsort -unique $oFF] msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]" } if {[lsearch [get-define TARGET_DEBUG ""] -DSQLITE_DEBUG=1] > -1} { msg-result "Note: this is a debug build, so performance will suffer." } teaish-cflags-add -define OPT_FEATURE_FLAGS }; # sqlite-handle-common-feature-flags # # If --enable-threadsafe is set, this adds -DSQLITE_THREADSAFE=1 to # OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags # needed for linking pthread (possibly an empty string). If # --enable-threadsafe is not set, adds -DSQLITE_THREADSAFE=0 to # OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to an empty string. # # It prepends the flags to the global LDFLAGS. proc sqlite-handle-threadsafe {} { msg-checking "Support threadsafe operation? " define LDFLAGS_PTHREAD "" set enable 0 if {[proj-opt-was-provided threadsafe]} { proj-if-opt-truthy threadsafe { if {[proj-check-function-in-lib pthread_create pthread] && [proj-check-function-in-lib pthread_mutexattr_init pthread]} { incr enable set ldf [get-define lib_pthread_create] define LDFLAGS_PTHREAD $ldf teaish-ldflags-prepend $ldf undefine lib_pthread_create undefine lib_pthread_mutexattr_init } else { user-error "Missing required pthread libraries. Use --disable-threadsafe to disable this check." } # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if # found because it's in -lc on some platforms. } { msg-result "Disabled using --disable-threadsafe" } } else { # # If user does not specify --[disable-]threadsafe then select a # default based on whether it looks like Tcl has threading # support. # catch { scan [exec echo {puts [tcl::pkgconfig get threaded]} | [get-define TCLSH_CMD]] \ %d enable } if {$enable} { set flagName "--threadsafe" set lblAbled "enabled" msg-result yes } else { set flagName "--disable-threadsafe" set lblAbled "disabled" msg-result no } msg-result "Defaulting to ${flagName} because Tcl has threading ${lblAbled}." # ^^^ We (probably) don't need to link against -lpthread in the # is-enabled case. We might in the case of static linking. Unsure. } sqlite-add-feature-flag -DSQLITE_THREADSAFE=${enable} return $enable } # # Handles the --enable-load-extension flag. Returns 1 if the support # is enabled, else 0. If support for that feature is not found, a # fatal error is triggered if --enable-load-extension is explicitly # provided, else a loud warning is instead emitted. If # --disable-load-extension is used, no check is performed. # # Makes the following environment changes: # # - defines LDFLAGS_DLOPEN to any linker flags needed for this # feature. It may legally be empty on some systems where dlopen() # is in libc. # # - If the feature is not available, adds # -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list. proc sqlite-handle-load-extension {} { define LDFLAGS_DLOPEN "" set found 0 proj-if-opt-truthy load-extension { set found [proj-check-function-in-lib dlopen dl] if {$found} { set ldf [get-define lib_dlopen] define LDFLAGS_DLOPEN $ldf teaish-ldflags-prepend $ldf undefine lib_dlopen } else { if {[proj-opt-was-provided load-extension]} { # Explicit --enable-load-extension: fail if not found proj-indented-notice -error { --enable-load-extension was provided but dlopen() not found. Use --disable-load-extension to bypass this check. } } else { # It was implicitly enabled: warn if not found proj-indented-notice { WARNING: dlopen() not found, so loadable module support will be disabled. Use --disable-load-extension to bypass this check. } } } } if {$found} { msg-result "Loadable extension support enabled." } else { msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them." sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1 } return $found } # # ICU - International Components for Unicode # # Handles these flags: # # --with-icu-ldflags=LDFLAGS # --with-icu-cflags=CFLAGS # --with-icu-config[=auto | pkg-config | /path/to/icu-config] # --enable-icu-collations # # --with-icu-config values: # # - auto: use the first one of (pkg-config, icu-config) found on the # system. # - pkg-config: use only pkg-config to determine flags # - /path/to/icu-config: use that to determine flags # # If --with-icu-config is used as neither pkg-config nor icu-config # are found, fail fatally. # # If both --with-icu-ldflags and --with-icu-config are provided, they # are cumulative. If neither are provided, icu-collations is not # honored and a warning is emitted if it is provided. # # Design note: though we could automatically enable ICU if the # icu-config binary or (pkg-config icu-io) are found, we specifically # do not. ICU is always an opt-in feature. proc sqlite-handle-icu {} { define LDFLAGS_LIBICU [join [opt-val with-icu-ldflags ""]] define CFLAGS_LIBICU [join [opt-val with-icu-cflags ""]] if {[proj-opt-was-provided with-icu-config]} { msg-result "Checking for ICU support..." set icuConfigBin [opt-val with-icu-config] set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config if {$icuConfigBin in {auto pkg-config}} { uplevel 3 { use pkg-config } if {[pkg-config-init 0] && [pkg-config icu-io]} { # Maintenance reminder: historical docs say to use both of # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has # all of them on tested OSes. set tryIcuConfigBin 0 define LDFLAGS_LIBICU [get-define PKG_ICU_IO_LDFLAGS] define-append LDFLAGS_LIBICU [get-define PKG_ICU_IO_LIBS] define CFLAGS_LIBICU [get-define PKG_ICU_IO_CFLAGS] } elseif {"pkg-config" eq $icuConfigBin} { proj-fatal "pkg-config cannot find package icu-io" } else { proj-assert {"auto" eq $icuConfigBin} } } if {$tryIcuConfigBin} { if {"auto" eq $icuConfigBin} { set icuConfigBin [proj-first-bin-of \ /usr/local/bin/icu-config \ /usr/bin/icu-config] if {"" eq $icuConfigBin} { proj-indented-notice -error { --with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary. On Ubuntu-like systems try: --with-icu-ldflags='-licui18n -licuuc -licudata' } } } if {[file-isexec $icuConfigBin]} { set x [exec $icuConfigBin --ldflags] if {"" eq $x} { proj-indented-notice -error \ [subst { $icuConfigBin --ldflags returned no data. On Ubuntu-like systems try: --with-icu-ldflags='-licui18n -licuuc -licudata' }] } define-append LDFLAGS_LIBICU $x set x [exec $icuConfigBin --cppflags] define-append CFLAGS_LIBICU $x } else { proj-fatal "--with-icu-config=$icuConfigBin does not refer to an executable" } } } set ldflags [define LDFLAGS_LIBICU [string trim [get-define LDFLAGS_LIBICU]]] set cflags [define CFLAGS_LIBICU [string trim [get-define CFLAGS_LIBICU]]] if {"" ne $ldflags} { sqlite-add-feature-flag -DSQLITE_ENABLE_ICU msg-result "Enabling ICU support with flags: $ldflags $cflags" if {[opt-bool icu-collations]} { msg-result "Enabling ICU collations." sqlite-add-feature-flag -DSQLITE_ENABLE_ICU_COLLATIONS } teaish-ldflags-prepend $ldflags teaish-cflags-add $cflags } elseif {[opt-bool icu-collations]} { proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags" } else { msg-result "ICU support is disabled." } }; # sqlite-handle-icu # # Handles the --with-tempstore flag. # # The test fixture likes to set SQLITE_TEMP_STORE on its own, so do # not set that feature flag unless it was explicitly provided to the # configure script. proc sqlite-handle-tempstore {} { if {[proj-opt-was-provided with-tempstore]} { set ts [opt-val with-tempstore no] set tsn 1 msg-checking "Use an in-RAM database for temporary tables? " switch -exact -- $ts { never { set tsn 0 } no { set tsn 1 } yes { set tsn 2 } always { set tsn 3 } default { user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always" } } msg-result $ts sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn } } # # Handles the --enable-math flag. proc sqlite-handle-math {} { proj-if-opt-truthy math { if {![proj-check-function-in-lib ceil m]} { user-error "Cannot find libm functions. Use --disable-math to bypass this." } set lfl [get-define lib_ceil] undefine lib_ceil define LDFLAGS_MATH $lfl teaish-ldflags-prepend $lfl sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS msg-result "Enabling math SQL functions" } { define LDFLAGS_MATH "" msg-result "Disabling math SQL functions" } } # # Move -DSQLITE_OMIT... and -DSQLITE_ENABLE... flags from CFLAGS and # CPPFLAGS to OPT_FEATURE_FLAGS and remove them from BUILD_CFLAGS. proc sqlite-munge-cflags {} { # Move CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived # from the pre-3.48 build. # # If any configure flags for features are in conflict with # CFLAGS/CPPFLAGS-specified feature flags, all bets are off. There # are no guarantees about which one will take precedence. foreach flagDef {CFLAGS CPPFLAGS} { set tmp "" foreach cf [get-define $flagDef ""] { switch -glob -- $cf { -DSQLITE_OMIT* - -DSQLITE_ENABLE* { sqlite-add-feature-flag $cf } default { lappend tmp $cf } } } define $flagDef $tmp } }