xref: /freebsd/contrib/sqlite3/autosetup/teaish/feature.tcl (revision df21a004be237a1dccd03c7b47254625eea62fa9)
1########################################################################
2# 2025 April 7
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 feature-tests.tcl -----
13# @section TEA-ish collection of feature tests.
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
20# @teaish-check-libz
21#
22# Checks for zlib.h and the function deflate in libz. If found,
23# prepends -lz to the extension's ldflags and returns 1, else returns
24# 0. It also defines LDFLAGS_LIBZ to the libs flag.
25#
26proc teaish-check-libz {} {
27  teaish-check-cached "Checking for libz" {
28    set rc 0
29    if {[msg-quiet cc-check-includes zlib.h] && [msg-quiet proj-check-function-in-lib deflate z]} {
30      teaish-ldflags-prepend [define LDFLAGS_LIBZ [get-define lib_deflate]]
31      undefine lib_deflate
32      incr rc
33    }
34    expr $rc
35  }
36}
37
38# @teaish-check-librt ?funclist?
39#
40# Checks whether -lrt is needed for any of the given functions.  If
41# so, appends -lrt via [teaish-ldflags-prepend] and returns 1, else
42# returns 0. It also defines LDFLAGS_LIBRT to the libs flag or an
43# empty string.
44#
45# Some systems (ex: SunOS) require -lrt in order to use nanosleep.
46#
47proc teaish-check-librt {{funclist {fdatasync nanosleep}}} {
48  teaish-check-cached -nostatus "Checking whether ($funclist) need librt" {
49    define LDFLAGS_LIBRT ""
50    foreach func $funclist {
51      if {[msg-quiet proj-check-function-in-lib $func rt]} {
52        set ldrt [get-define lib_${func}]
53        undefine lib_${func}
54        if {"" ne $ldrt} {
55          teaish-ldflags-prepend -r [define LDFLAGS_LIBRT $ldrt]
56          msg-result $ldrt
57          return 1
58        } else {
59          msg-result "no lib needed"
60          return 1
61        }
62      }
63    }
64    msg-result "not found"
65    return 0
66  }
67}
68
69# @teaish-check-stdint
70#
71# A thin proxy for [cc-with] which checks for <stdint.h> and the
72# various fixed-size int types it declares. It defines HAVE_STDINT_T
73# to 0 or 1 and (if it's 1) defines HAVE_XYZ_T for each XYZ int type
74# to 0 or 1, depending on whether its available.
75proc teaish-check-stdint {} {
76  teaish-check-cached "Checking for stdint.h" {
77    msg-quiet cc-with {-includes stdint.h} \
78      {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
79         uint8_t uint16_t uint32_t uint64_t uintptr_t}
80  }
81}
82
83# @teaish-is-mingw
84#
85# Returns 1 if building for mingw, else 0.
86proc teaish-is-mingw {} {
87  return [expr {
88    [string match *mingw* [get-define host]] &&
89    ![file exists /dev/null]
90  }]
91}
92
93# @teaish-check-libdl
94#
95# Checks for whether dlopen() can be found and whether it requires
96# -ldl for linking. If found, returns 1, defines LDFLAGS_DLOPEN to the
97# linker flags (if any), and passes those flags to
98# teaish-ldflags-prepend. It unconditionally defines HAVE_DLOPEN to 0
99# or 1 (the its return result value).
100proc teaish-check-dlopen {} {
101  teaish-check-cached -nostatus "Checking for dlopen()" {
102    set rc 0
103    set lfl ""
104    if {[cc-with {-includes dlfcn.h} {
105      cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} {
106      msg-result "-ldl not needed"
107      incr rc
108    } elseif {[cc-check-includes dlfcn.h]} {
109      incr rc
110      if {[cc-check-function-in-lib dlopen dl]} {
111        set lfl [get-define lib_dlopen]
112        undefine lib_dlopen
113        msg-result " dlopen() needs $lfl"
114      } else {
115        msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in."
116      }
117    } else {
118      msg-result "not found"
119    }
120    teaish-ldflags-prepend [define LDFLAGS_DLOPEN $lfl]
121    define HAVE_DLOPEN $rc
122  }
123}
124
125#
126# @teaish-check-libmath
127#
128# Handles the --enable-math flag. Returns 1 if found, else 0.
129# If found, it prepends -lm (if needed) to the linker flags.
130proc teaish-check-libmath {} {
131  teaish-check-cached "Checking for libc math library" {
132    set lfl ""
133    set rc 0
134    if {[msg-quiet proj-check-function-in-lib ceil m]} {
135      incr rc
136      set lfl [get-define lib_ceil]
137      undefine lib_ceil
138      teaish-ldflags-prepend $lfl
139      msg-checking "$lfl "
140    }
141    define LDFLAGS_LIBMATH $lfl
142    expr $rc
143  }
144}
145
146# @teaish-import-features ?-flags? feature-names...
147#
148# For each $name in feature-names... it invokes:
149#
150#   use teaish/feature/$name
151#
152# to load TEAISH_AUTOSETUP_DIR/feature/$name.tcl
153#
154# By default, if a proc named teaish-check-${name}-options is defined
155# after sourcing a file, it is called and its result is passed to
156# proj-append-options. This can be suppressed with the -no-options
157# flag.
158#
159# Flags:
160#
161#   -no-options: disables the automatic running of
162#    teaish-check-NAME-options,
163#
164#   -run: if the function teaish-check-NAME exists after importing
165#    then it is called. This flag must not be used when calling this
166#    function from teaish-options. This trumps both -pre and -post.
167#
168#   -pre: if the function teaish-check-NAME exists after importing
169#    then it is passed to [teaish-checks-queue -pre].
170#
171#   -post: works like -pre but instead uses[teaish-checks-queue -post].
172proc teaish-import-features {args} {
173  set pk ""
174  set doOpt 1
175  proj-parse-simple-flags args flags {
176    -no-options 0 {set doOpt 0}
177    -run        0 {expr 1}
178    -pre        0 {set pk -pre}
179    -post       0 {set pk -post}
180  }
181  #
182  # TODO: never import the same module more than once. The "use"
183  # command is smart enough to not do that but we would need to
184  # remember whether or not any teaish-check-${arg}* procs have been
185  # called before, and skip them.
186  #
187  if {$flags(-run) && "" ne $pk} {
188    proj-error "Cannot use both -run and $pk" \
189      " (called from [proj-scope 1])"
190  }
191
192  foreach arg $args {
193    uplevel "use teaish/feature/$arg"
194    if {$doOpt} {
195      set n "teaish-check-${arg}-options"
196      if {[llength [info proc $n]] > 0} {
197        if {"" ne [set x [$n]]} {
198          options-add $x
199        }
200      }
201    }
202    if {$flags(-run)} {
203      set n "teaish-check-${arg}"
204      if {[llength [info proc $n]] > 0} {
205        uplevel 1 $n
206      }
207    } elseif {"" ne $pk} {
208      set n "teaish-check-${arg}"
209      if {[llength [info proc $n]] > 0} {
210        teaish-checks-queue {*}$pk $n
211      }
212    }
213  }
214}
215