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