# vim:se syn=tcl: # define JIM_VERSION 80 options-defaults { silent-rules 1 } # Note: modules which support options *must* be included before 'options' use cc cc-shared cc-db cc-lib pkg-config util use local options { utf8 => "Include support for utf8-encoded strings" lineedit=1 => "Disable line editing" references=1 => "Disable support for references" math => "Include support for math functions" ssl => "Include ssl/tls support in the aio extension" ipv6 => "Include ipv6 support in the aio extension" maintainer => {Enable the [debug] command and JimPanic} full => "Enable some optional features: ipv6, ssl, math, utf8, and some extensions (see --extinfo)" allextmod => "Enable all non-default extensions as modules if prerequisites are found" compat => "Enable some backward compatibility behaviour" extinfo => "Show information about available extensions" with-jim-shared shared => "Build a shared library instead of a static library" jim-regexp=1 => "Prefer POSIX regex if over the the built-in (Tcl-compatible) regex" docs=1 => "Don't build or install the documentation" docdir:path => "Path to install docs (if built)" random-hash => "Randomise hash tables. more secure but hash table results are not predicable" coverage => "Build with code coverage support" with-jim-ext: {with-ext:"ext1,ext2,..."} => { Specify additional Jim extensions to include. Use --extinfo to show information about available extensions. } with-out-jim-ext: {without-ext:"default|ext1,ext2,..."} => { Specify Jim extensions to exclude. If 'default' is given, the default extensions will not be added. } with-jim-extmod: {with-mod:"ext1,ext2,..."} => { Specify Jim extensions to build as separate modules (either C or Tcl). Note that not all extensions can be built as loadable modules. } # To help out openocd with automake install-jim=1 } # Attributes and help for each supportted extensions # tcl=Pure Tcl extension # static=Can't be built as a module # off=Off unless explicitly enabled or required by an enabled extension # optional=Off by default, but selected by --full # cpp=Is a C++ extension global extdb foreach {mod attrs help} { aio { static } {File and socket (networking) I/O} array {} {Tcl-compatible array command} binary { tcl optional } {Tcl-compatible binary command} clock {} {Tcl-compatible clock command} eventloop { static } {after, vwait, update} exec { static } {Tcl-compatible exec command} file {} {Tcl-compatible file command} glob { tcl } {Tcl-compatible glob command} history {} {Tcl access to interactive history} interp {} {Support for child interpreters} json { optional } {JSON decoder} jsonencode { tcl off } {JSON encoder} load { static } {Load binary extensions at runtime with load or package} mk { cpp off } {Interface to metakit} namespace { static } {Tcl compatible namespace support} nshelper { tcl off } {} oo { tcl } {Object Oriented class support} pack {} {Low level binary pack and unpack} package { static } {Package management with the package command} posix {} {Posix APIs including os.fork, os.uptime} readdir {} {Read the contents of a directory (used by glob)} readline { off } {Interface to libreadline} redis { off } {Client interface to redis database} regexp {} {Tcl-compatible regexp, regsub commands} rlprompt { tcl off } {readline-based REPL} sdl { off } {SDL graphics interface} signal { static } {Signal handling} sqlite3 { off } {Interface to sqlite3 database} stdlib { tcl static } {Built-in commands including lambda, stacktrace and some dict subcommands} syslog {} {System logging with syslog} tclcompat { tcl static } {Tcl compatible read, gets, puts, parray, case, ...} tclprefix { optional } {Support for the tcl::prefix command} tree { tcl } {OO tree structure, similar to tcllib ::struct::tree} win32 { off } {Interface to win32} zlib { optional } {zlib compression interface} } { dict set extdb attrs $mod $attrs dict set extdb help $mod $help } if {[opt-bool extinfo]} { use text-formatting use help use_pager nl p { Jim Tcl is very modular and many extensions can be selectively enabled (--with-ext) or disabled (--without-ext). Many extensions may be statically compiled into Jim Tcl or built as loadable modules (--with-mod). This includes both C extensions and Tcl extensions. } # collect extension info set attrs [dict get $extdb attrs] set info {} foreach mod [dict keys $attrs] { set help [dict get $extdb help $mod] if {$help ne ""} { if {"off" in [dict get $attrs $mod]} { set a off } elseif {"optional" in [dict get $attrs $mod]} { set a optional } else { set a default } dict set info $mod [list $a $help] } } proc showmods {heading info type} { p $heading foreach mod [dict keys $info] { lassign [dict get $info $mod] a help if {$a eq $type} { puts "[format %10s $mod] - $help" } } } showmods "These extensions are enabled by default:" $info default nl showmods "These are disabled by default, but enabled by --full:" $info optional nl showmods { These are disabled unless explicitly enabled or --allextmod is selected and the prerequisites are met: } $info off exit 0 } # Additional information about certain extensions # dep=list of extensions which are required for this extension # check=[expr] expression to evaluate to determine if the extension can be used # libdep=list of 'define' symbols for dependent libraries # pkg-config=name1 ?args?, name2* ?args? | name3 ?args? # Any set of packages from the alternates is acceptable (e.g. name1 and name2, or name3) # If the pkgname has a * appended, it is optional (so name1 without name2 is OK) # The optional args are pkg-config specifications (e.g. name1 >= 1.3.4) dict set extdb info { binary { dep pack } exec { check {([have-feature vfork] && [have-feature waitpid]) || [have-feature system]} } glob { dep readdir } load { check {[have-feature dlopen-compat] || [cc-check-function-in-lib dlopen dl]} libdep lib_dlopen } mk { check {[check-metakit]} libdep lib_mk } namespace { dep nshelper } json { dep jsonencode extrasrcs jsmn/jsmn.c } posix { check {[have-feature waitpid]} } readdir { check {[have-feature opendir]} } readline { pkg-config readline check {[cc-check-function-in-lib readline readline]} libdep lib_readline} rlprompt { dep readline } tree { dep oo } sdl { pkg-config {SDL2_gfx, SDL2_ttf* | SDL_gfx} check false } signal { check {[have-feature sigaction]} } sqlite3 { pkg-config sqlite3 check {[cc-check-function-in-lib sqlite3_prepare_v2 sqlite3]} libdep lib_sqlite3_prepare_v2 } redis { pkg-config hiredis check {[cc-check-function-in-lib redisConnect hiredis]} libdep lib_redisConnect } zlib { pkg-config zlib check {[cc-check-function-in-lib deflate z]} libdep lib_deflate } syslog { check {[have-feature syslog]} } tree { dep oo } win32 { check {[have-feature windows]} } } set warnings {} # Save the user-specified LIBS # We add detected libs to LDLIBS explicitly set LIBS [get-define LIBS] # In case -Werror is passed in CFLAGS, set -Wno-error when doing checks # to prevent warnings from becoming errors if {"-Werror" in [get-define CFLAGS] && [cctest -cflags -Wno-error]} { cc-with {-cflags -Wno-error} } cc-check-types "long long" cc-check-sizeof int define CCOPTS "" define CXXOPTS "" if {[cctest -cflags -fno-unwind-tables]} { define-append CCOPTS -fno-unwind-tables } if {[cctest -cflags -fno-asynchronous-unwind-tables]} { define-append CCOPTS -fno-asynchronous-unwind-tables } if {[opt-bool coverage]} { if {[cctest -link 1 -cflags --coverage]} { # When using coverage, disable ccache and compiler optimisation define CCACHE "" define-append CCOPTS --coverage -O0 define-append LDFLAGS --coverage define COVERAGE 1 if {[cc-check-progs gcovr]} { define COVERAGE_TOOL gcovr } elseif {[cc-check-progs lcov] && [cc-check-progs genhtml]} { define COVERAGE_TOOL lcov } else { define COVERAGE_TOOL gcov lappend warnings "Note: Neither lcov nor gcovr is available, falling back to gcov" } } else { lappend warnings "Warning: --coverage specified, but compiler does not support --coverage" } } cc-check-includes time.h sys/time.h sys/socket.h netinet/in.h arpa/inet.h netdb.h cc-check-includes util.h pty.h sys/un.h dlfcn.h unistd.h dirent.h crt_externs.h execinfo.h # Check sizeof time_t so we can warn on non-Y2038 compliance cc-with {-includes time.h} { cc-check-sizeof time_t } define LDLIBS "" # Haiku needs -lnetwork, Solaris needs -lnsl if {[cc-check-function-in-lib inet_ntop {nsl network}]} { # This does nothing if no libs are needed cc-with [list -libs [get-define lib_inet_ntop]] define-append LDLIBS [get-define lib_inet_ntop] } # Solaris needs -lsocket, Windows needs -lwsock32 if {[cc-check-function-in-lib socket socket]} { define-append LDLIBS [get-define lib_socket] } cc-check-functions ualarm lstat fork vfork system select execvpe cc-check-functions geteuid mkstemp realpath isatty cc-check-functions regcomp waitpid sigaction sys_signame sys_siglist isascii cc-check-functions syslog opendir readlink sleep usleep pipe getaddrinfo utimes cc-check-functions shutdown socketpair isinf isnan link symlink fsync dup umask cc-check-functions localtime gmtime strptime clock_gettime if {[cc-check-function-in-lib backtrace execinfo]} { define-append LDLIBS [get-define lib_backtrace] } if {[cc-check-function-in-lib openpty util]} { define-append LDLIBS [get-define lib_openpty] } if {[cc-check-functions sysinfo]} { cc-with {-includes sys/sysinfo.h} { cc-check-members "struct sysinfo.uptime" } } cc-with {-includes {sys/types.h sys/stat.h}} { cc-check-members "struct stat.st_mtimespec" cc-check-members "struct stat.st_mtim" } cc-with {-includes fcntl.h} { cc-check-types "struct flock" } cc-check-lfs cc-check-functions fseeko ftello define TCL_LIBRARY [get-define prefix]/lib/jim lassign [split [get-define host] -] host_cpu host_vendor host_os # Scrub revision from the host_os regsub -all {[0-9.]} $host_os {} host_os switch -glob -- $host_os { mingw* { # We provide our own implementation of dlopen for mingw32 define-feature dlopen-compat define-feature winconsole define TCL_PLATFORM_OS $host_os define TCL_PLATFORM_PLATFORM windows define TCL_PLATFORM_PATH_SEPARATOR {;} } default { # Note that cygwin is considered a unix platform define TCL_PLATFORM_OS $host_os define TCL_PLATFORM_PLATFORM unix define TCL_PLATFORM_PATH_SEPARATOR : } } # Find some tools cc-check-tools ar ranlib strip define tclsh [quote-if-needed [info nameofexecutable]] # We only support silent-rules for GNU Make define NO_SILENT_RULES if {[get-define AM_SILENT_RULES 0]} { if {[cc-check-progs [get-define MAKE make]]} { # Are we using GNU make? catch {exec [get-define MAKE] --version} makeversion if {[string match "GNU Make*" $makeversion]} { define NO_SILENT_RULES 0 } } } if {[opt-bool docs]} { if {[cc-check-progs asciidoc sed]} { define INSTALL_DOCS docs define HAVE_ASCIIDOC } else { define INSTALL_DOCS shipped } } else { define INSTALL_DOCS nodocs } if {![cc-check-functions _NSGetEnviron]} { msg-checking "Checking environ declared in unistd.h..." if {[cctest -cflags {-D_GNU_SOURCE -D_POSIX_SOURCE} -includes unistd.h -code {char **ep = environ;}]} { define NO_ENVIRON_EXTERN msg-result "yes" } else { msg-result "no" } } # Windows has a mkdir with no permission arg cc-check-includes sys/types.h sys/stat.h msg-checking "Checking for mkdir with one arg..." if {[cctest -includes {sys/types.h sys/stat.h} -code {mkdir("/dummy");}]} { define HAVE_MKDIR_ONE_ARG msg-result yes } else { msg-result no } cc-with {-includes sys/stat.h} { foreach i {S_IXUSR S_IRWXG S_IRWXO} { if {![cc-check-decls $i]} { define $i 0 } } } set extra_objs {} set jimregexp 0 # Returns 1 if either the given option is enabled, or # --full is enabled and the option isn't explicitly disabled # proc opt-bool-or-full {opt} { if {[opt-bool $opt]} { return 1 } if {[opt-bool full] && [opt-bool -nodefault $opt] != 0} { return 1 } return 0 } if {[opt-bool-or-full utf8]} { msg-result "Enabling UTF-8" define JIM_UTF8 define-append CCOPTS -DUSE_UTF8 define PARSE_UNIDATA_FLAGS "" incr jimregexp } else { define JIM_UTF8 0 } if {[opt-bool maintainer]} { msg-result "Enabling maintainer settings" define JIM_MAINTAINER } # If --math or --full and not --disable-math if {[opt-bool-or-full math]} { msg-result "Enabling math functions" define JIM_MATH_FUNCTIONS cc-check-function-in-lib sin m define-append LDLIBS [get-define lib_sin] } if {[opt-bool-or-full ipv6]} { msg-result "Enabling IPv6" define JIM_IPV6 } define-append PKG_CONFIG_REQUIRES "" if {[opt-bool-or-full ssl]} { if {[pkg-config-init 0]} { foreach pkg {openssl libssl} { if {[pkg-config $pkg]} { define JIM_SSL define-append LDLIBS [pkg-config-get $pkg LIBS] define-append LDFLAGS [pkg-config-get $pkg LDFLAGS] define-append CCOPTS [pkg-config-get $pkg CFLAGS] msg-result "Enabling SSL ($pkg)" define-append PKG_CONFIG_REQUIRES $pkg break } } } if {![is-defined JIM_SSL]} { if {[cc-check-includes openssl/ssl.h] && [cc-check-function-in-lib ERR_error_string crypto] && [cc-check-function-in-lib TLSv1_2_method ssl]} { msg-result "Enabling SSL" define JIM_SSL define-append LDLIBS [get-define lib_ERR_error_string] [get-define lib_TLSv1_2_method] } elseif {[opt-bool ssl]} { user-error "SSL support requires OpenSSL" } } # Later versions deprecate TLSv1_2_method, but older versions don't have TLS_method if {![cc-check-function-in-lib TLS_method ssl]} { define-append CCOPTS -DUSE_TLSv1_2_method } } if {[opt-bool-or-full lineedit]} { if {([cc-check-includes termios.h] && [have-feature isatty]) || [have-feature winconsole]} { msg-result "Enabling line editing" define USE_LINENOISE define-append PARSE_UNIDATA_FLAGS -width lappend extra_objs linenoise.o if {[cc-check-inline] && [is-defined inline]} { define-append CCOPTS -Dinline=[get-define inline] } } } if {[opt-bool references]} { msg-result "Enabling references" define JIM_REFERENCES } if {[opt-bool compat]} { msg-result "Enabling compatibility mode" define JIM_COMPAT } if {[opt-bool shared with-jim-shared]} { msg-result "Building shared library" } else { msg-result "Building static library" define JIM_STATICLIB } define VERSION [format %.2f [expr {[get-define JIM_VERSION] / 100.0}]] define LIBSOEXT [format [get-define SH_SOEXTVER] [get-define VERSION]] if {[get-define libdir] ni {/lib /usr/lib}} { define SH_LINKRPATH_FLAGS [format [get-define SH_LINKRPATH] [get-define libdir]] } else { define SH_LINKRPATH_FLAGS "" } define JIM_INSTALL [opt-bool install-jim] define JIM_DOCS [opt-bool docs] define JIM_RANDOMISE_HASH [opt-bool random-hash] define docdir [opt-str docdir o {${prefix}/docs/jim}] # autosetup cc-check-function-in-library can't handle C++ libraries proc check-metakit {} { set found 0 msg-checking "Checking for Metakit..." cc-with {-lang c++} { if {[cctest -includes mk4.h -libs -lmk4 -code {c4_Storage dummy();}]} { msg-result ok define lib_mk -lmk4 incr found } else { msg-result "not found" } } return $found } # Takes a list of module names, separated by spaces or commas # and returns them as a single list proc join-ext-names {list} { set result {} # Replace comma with space in each list then concatenate the result foreach l $list { lappend result {*}[string map {, " "} $l] } return $result } # Set up the withinfo array based on what the user selected global withinfo set withinfo(without) [join-ext-names [opt-val {without-ext with-out-jim-ext}]] set withinfo(ext) [join-ext-names [opt-val {with-ext with-jim-ext}]] set withinfo(mod) [join-ext-names [opt-val {with-mod with-jim-extmod}]] set withinfo(nodefault) 0 set withinfo(optional) [opt-bool full] if {$withinfo(without) eq "default"} { set withinfo(without) {} set withinfo(nodefault) 1 } # Now go check everything - see autosetup/local.tcl array set extinfo [check-extensions [opt-bool allextmod]] # Now special checks if {[have-feature windows]} { lappend extra_objs jim-win32compat.o if {[llength $extinfo(module-c)] && [get-define JIM_STATICLIB]} { user-error "cygwin/mingw require --shared for dynamic modules" } } if {[have-feature termios.h]} { lappend extra_objs jim-tty.o } if {[ext-get-status regexp] in {y m}} { if {![have-feature regcomp]} { # No regcomp means we need to use the built-in version incr jimregexp } } if {$jimregexp || [opt-bool jim-regexp]} { msg-result "Using built-in regexp" define JIM_REGEXP # If the built-in regexp overrides the system regcomp, etc. # jim must be built shared so that the correct symbols are found if {[ext-get-status regexp] eq "m" && [get-define JIM_STATICLIB] && [have-feature regcomp]} { user-error "Must use --shared with regexp module and built-in regexp" } } foreach mod $extinfo(static-c) { if {[dict exists $extdb info $mod extrasrcs]} { foreach src [dict get $extdb info $mod extrasrcs] { # In case we are building out-of-tree and $src is in a subdir file mkdir [file dirname $src] lappend extra_objs {*}[file rootname $src].o } } } # poor-man's signals if {"signal" ni $extinfo(static-c)} { lappend extra_objs jim-nosignal.o } if {[ext-get-status load] eq "n"} { # If we don't have load, no need to support shared objects define SH_LINKFLAGS "" } # Are we cross compiling? if {[get-define host] ne [get-define build]} { define cross_compiling 1 } else { define cross_compiling 0 } msg-result "Jim static extensions: [lsort [concat $extinfo(static-tcl) $extinfo(static-c)]]" if {[llength $extinfo(module-tcl)]} { msg-result "Jim Tcl extensions: [lsort $extinfo(module-tcl)]" } if {[llength $extinfo(module-c)]} { msg-result "Jim dynamic extensions: [lsort $extinfo(module-c)]" } define STATIC_EXTS [concat $extinfo(static-c) $extinfo(static-tcl)] define C_EXT_OBJS [prefix jim- [suffix .o $extinfo(static-c)]] define TCL_EXT_OBJS [suffix .o $extinfo(static-tcl)] define C_EXT_SHOBJS [suffix .so $extinfo(module-c)] define TCL_EXTS [suffix .tcl $extinfo(module-tcl)] define EXTRA_OBJS $extra_objs # Restore the user-specified LIBS define LIBS $LIBS # Now generate the Makefile rules to build the external C shared objects # It is easier to do this here rather than listing them out explicitly in Makefile.in set lines {} foreach mod $extinfo(module-c) { set objs {} set libs [get-define LDLIBS_$mod] set srcs jim-$mod.c if {[dict exists $extdb info $mod extrasrcs]} { lappend srcs {*}[dict get $extdb info $mod extrasrcs] } lappend lines "$mod.so: $srcs \$(LIBJIM)" foreach src $srcs { set obj [file rootname $src].o lappend objs $obj lappend lines "\t\$(ECHO)\t\"\tCC\t$obj\"" lappend lines "\t\$(Q)\$(CC) \$(CFLAGS) \$(SHOBJ_CFLAGS) -c -o $obj \$(srcdir)/$src" } lappend lines "\t\$(ECHO)\t\"\tLDSO\t\$@\"" lappend lines "\t\$(Q)\$(CC) \$(CFLAGS) \$(LDFLAGS) \$(SHOBJ_LDFLAGS) -o \$@ $objs \$(SH_LIBJIM) $libs" lappend lines "" } define BUILD_SHOBJS [join $lines \n] make-config-header jim-config.h -auto {HAVE_LONG_LONG* JIM_UTF8 SIZEOF_INT} -bare JIM_VERSION -none * make-config-header jimautoconf.h -auto {jim_ext_* TCL_PLATFORM_* TCL_LIBRARY USE_* JIM_* _FILE_OFFSET*} -bare {S_I*} make-template Makefile.in make-template tests/Makefile.in make-template examples.api/Makefile.in make-template build-jim-ext.in make-template jimtcl.pc.in catch {exec chmod +x build-jim-ext} if {[get-define SIZEOF_TIME_T] <= 4} { set note "" if {[have-feature windows]} { set note ", consider CFLAGS=-D__MINGW_USE_VC2005_COMPAT on mingw32" } lappend warnings "Warning: sizeof(time_t) is [get-define SIZEOF_TIME_T] -- not Y2038 compliant$note" } # Output any warnings at the end to make them easier to see foreach warning $warnings { user-notice $warning }