| ######################################################################## |
| # 2025 April 7 |
| # |
| # The author disclaims copyright to this source code. In place of |
| # a legal notice, here is a blessing: |
| # |
| # * May you do good and not evil. |
| # * May you find forgiveness for yourself and forgive others. |
| # * May you share freely, never taking more than you give. |
| # |
| ######################################################################## |
| # ----- @module feature-tests.tcl ----- |
| # @section TEA-ish collection of feature tests. |
| # |
| # Functions in this file with a prefix of teaish__ are |
| # private/internal APIs. Those with a prefix of teaish- are |
| # public APIs. |
| |
| |
| # @teaish-check-libz |
| # |
| # Checks for zlib.h and the function deflate in libz. If found, |
| # prepends -lz to the extension's ldflags and returns 1, else returns |
| # 0. It also defines LDFLAGS_LIBZ to the libs flag. |
| # |
| proc teaish-check-libz {} { |
| teaish-check-cached "Checking for libz" { |
| set rc 0 |
| if {[msg-quiet cc-check-includes zlib.h] && [msg-quiet proj-check-function-in-lib deflate z]} { |
| teaish-ldflags-prepend [define LDFLAGS_LIBZ [get-define lib_deflate]] |
| undefine lib_deflate |
| incr rc |
| } |
| expr $rc |
| } |
| } |
| |
| # @teaish-check-librt ?funclist? |
| # |
| # Checks whether -lrt is needed for any of the given functions. If |
| # so, appends -lrt via [teaish-ldflags-prepend] and returns 1, else |
| # returns 0. It also defines LDFLAGS_LIBRT to the libs flag or an |
| # empty string. |
| # |
| # Some systems (ex: SunOS) require -lrt in order to use nanosleep. |
| # |
| proc teaish-check-librt {{funclist {fdatasync nanosleep}}} { |
| teaish-check-cached -nostatus "Checking whether ($funclist) need librt" { |
| define LDFLAGS_LIBRT "" |
| foreach func $funclist { |
| if {[msg-quiet proj-check-function-in-lib $func rt]} { |
| set ldrt [get-define lib_${func}] |
| undefine lib_${func} |
| if {"" ne $ldrt} { |
| teaish-ldflags-prepend -r [define LDFLAGS_LIBRT $ldrt] |
| msg-result $ldrt |
| return 1 |
| } else { |
| msg-result "no lib needed" |
| return 1 |
| } |
| } |
| } |
| msg-result "not found" |
| return 0 |
| } |
| } |
| |
| # @teaish-check-stdint |
| # |
| # A thin proxy for [cc-with] which checks for <stdint.h> and the |
| # various fixed-size int types it declares. It defines HAVE_STDINT_T |
| # to 0 or 1 and (if it's 1) defines HAVE_XYZ_T for each XYZ int type |
| # to 0 or 1, depending on whether its available. |
| proc teaish-check-stdint {} { |
| teaish-check-cached "Checking for stdint.h" { |
| msg-quiet cc-with {-includes stdint.h} \ |
| {cc-check-types int8_t int16_t int32_t int64_t intptr_t \ |
| uint8_t uint16_t uint32_t uint64_t uintptr_t} |
| } |
| } |
| |
| # @teaish-is-mingw |
| # |
| # Returns 1 if building for mingw, else 0. |
| proc teaish-is-mingw {} { |
| return [expr { |
| [string match *mingw* [get-define host]] && |
| ![file exists /dev/null] |
| }] |
| } |
| |
| # @teaish-check-libdl |
| # |
| # Checks for whether dlopen() can be found and whether it requires |
| # -ldl for linking. If found, returns 1, defines LDFLAGS_DLOPEN to the |
| # linker flags (if any), and passes those flags to |
| # teaish-ldflags-prepend. It unconditionally defines HAVE_DLOPEN to 0 |
| # or 1 (the its return result value). |
| proc teaish-check-dlopen {} { |
| teaish-check-cached -nostatus "Checking for dlopen()" { |
| set rc 0 |
| set lfl "" |
| if {[cc-with {-includes dlfcn.h} { |
| cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} { |
| msg-result "-ldl not needed" |
| incr rc |
| } elseif {[cc-check-includes dlfcn.h]} { |
| incr rc |
| if {[cc-check-function-in-lib dlopen dl]} { |
| set lfl [get-define lib_dlopen] |
| undefine lib_dlopen |
| msg-result " dlopen() needs $lfl" |
| } else { |
| msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in." |
| } |
| } else { |
| msg-result "not found" |
| } |
| teaish-ldflags-prepend [define LDFLAGS_DLOPEN $lfl] |
| define HAVE_DLOPEN $rc |
| } |
| } |
| |
| # |
| # @teaish-check-libmath |
| # |
| # Handles the --enable-math flag. Returns 1 if found, else 0. |
| # If found, it prepends -lm (if needed) to the linker flags. |
| proc teaish-check-libmath {} { |
| teaish-check-cached "Checking for libc math library" { |
| set lfl "" |
| set rc 0 |
| if {[msg-quiet proj-check-function-in-lib ceil m]} { |
| incr rc |
| set lfl [get-define lib_ceil] |
| undefine lib_ceil |
| teaish-ldflags-prepend $lfl |
| msg-checking "$lfl " |
| } |
| define LDFLAGS_LIBMATH $lfl |
| expr $rc |
| } |
| } |
| |
| # @teaish-import-features ?-flags? feature-names... |
| # |
| # For each $name in feature-names... it invokes: |
| # |
| # use teaish/feature/$name |
| # |
| # to load TEAISH_AUTOSETUP_DIR/feature/$name.tcl |
| # |
| # By default, if a proc named teaish-check-${name}-options is defined |
| # after sourcing a file, it is called and its result is passed to |
| # proj-append-options. This can be suppressed with the -no-options |
| # flag. |
| # |
| # Flags: |
| # |
| # -no-options: disables the automatic running of |
| # teaish-check-NAME-options, |
| # |
| # -run: if the function teaish-check-NAME exists after importing |
| # then it is called. This flag must not be used when calling this |
| # function from teaish-options. This trumps both -pre and -post. |
| # |
| # -pre: if the function teaish-check-NAME exists after importing |
| # then it is passed to [teaish-checks-queue -pre]. |
| # |
| # -post: works like -pre but instead uses[teaish-checks-queue -post]. |
| proc teaish-import-features {args} { |
| set pk "" |
| set doOpt 1 |
| proj-parse-simple-flags args flags { |
| -no-options 0 {set doOpt 0} |
| -run 0 {expr 1} |
| -pre 0 {set pk -pre} |
| -post 0 {set pk -post} |
| } |
| # |
| # TODO: never import the same module more than once. The "use" |
| # command is smart enough to not do that but we would need to |
| # remember whether or not any teaish-check-${arg}* procs have been |
| # called before, and skip them. |
| # |
| if {$flags(-run) && "" ne $pk} { |
| proj-error "Cannot use both -run and $pk" \ |
| " (called from [proj-scope 1])" |
| } |
| |
| foreach arg $args { |
| uplevel "use teaish/feature/$arg" |
| if {$doOpt} { |
| set n "teaish-check-${arg}-options" |
| if {[llength [info proc $n]] > 0} { |
| if {"" ne [set x [$n]]} { |
| options-add $x |
| } |
| } |
| } |
| if {$flags(-run)} { |
| set n "teaish-check-${arg}" |
| if {[llength [info proc $n]] > 0} { |
| uplevel 1 $n |
| } |
| } elseif {"" ne $pk} { |
| set n "teaish-check-${arg}" |
| if {[llength [info proc $n]] > 0} { |
| teaish-checks-queue {*}$pk $n |
| } |
| } |
| } |
| } |