# vim:se syn=tcl: # define JIM_VERSION 82 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 # CFLAGS, CXXFLAGS only come from the user define CFLAGS [get-env CFLAGS ""] define CXXFLAGS [get-env CFLAGS ""] options { utf8=1 => "Disable support for utf8-encoded strings" lineedit=1 => "Disable line editing" references=1 => "Disable support for references" math=1 => "Disable math functions" ssl=1 => "Disable ssl/tls support in the aio extension" ipv6=1 => "Disable ipv6 support in the aio extension" maintainer => {Enable the [debug] command and JimPanic} minimal => "Disable some optional features: ipv6, ssl, math, utf8 and some extensions. Also see --without-ext=default" # Note that full is now the default full 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" introspection=1 => "Disable introspection" 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 # always=Always include, even if minimal 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} ensemble { optional tcl } {Ensemble 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 always } {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 always } {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 full]} { user-notice "Note that --full is now the default, and need not be specified (see --minimal)" } 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 enabled by default, but disabled by --minimal:" $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 fork]) && [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-includes zlib.h] && [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} } # Very old compilers might not have restrict cc-check-some-feature restrict { cctest -declare {extern void restrict_test(const char * restrict param);} } cc-check-types "long long" cc-check-sizeof int # Default optimisation define-append AS_CPPFLAGS -O2 -Wall -D_GNU_SOURCE define-append AS_CFLAGS -I. define-append AS_CXXFLAGS -I. # check, but don't add to -cflags cc-with {} { cc-check-flags -fno-unwind-tables -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 AS_CFLAGS --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 strings.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 fork system select execvpe cc-check-functions geteuid mkstemp 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 link symlink fsync dup umask cc-check-functions localtime gmtime strptime if {![cc-check-functions realpath]} { cc-check-functions _fullpath } cc-with {-includes math.h} { cc-check-decls isinf isnan } if {[have-feature fork]} { # Only use vfork if not deprecated cc-with {-nooutput 1} { cc-check-functions vfork } } if {[cc-check-function-in-lib backtrace execinfo]} { define-append LDLIBS [get-define lib_backtrace] } 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 if {[get-define _FILE_OFFSET_BITS] != 64 || ![cc-check-functions stat64]} { # Modern systems and really old systems have plain stat, fstat, lstat cc-check-functions fstat lstat } else { # But perhaps some 32 bit systems still require explicit use of the 64 bit versions cc-check-functions fstat64 lstat64 lseek64 } define TCL_LIBRARY [get-define libdir]/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 {;} # Target WinXP or later. Should this be configurable? define-append AS_CFLAGS -D_WIN32_WINNT=0x501 -Wno-deprecated-declarations } 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 # Like opt-bool except defaults to on normally and off if --minimal # In either case if explicitly enable or disabled, that takes precedence proc opt-bool-unless-minimal {opt} { if {[opt-bool minimal]} { set default 0 } else { set default 1 } # If not explicitly enabled/disabled, use the default based on --minimal set val [opt-bool -nodefault $opt] if {$val < 0} { set val $default } return $val } if {[opt-bool-unless-minimal utf8]} { msg-result "Enabling UTF-8" define JIM_UTF8 define-append AS_CFLAGS -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 {[opt-bool-unless-minimal math]} { if {[cc-check-function-in-lib sin m]} { msg-result "Enabling math functions" define JIM_MATH_FUNCTIONS define-append LDLIBS [get-define lib_sin] } elseif {[opt-bool -nodefault math] > 0} { user-error "Math functions are not available" } } if {[opt-bool-unless-minimal ipv6]} { msg-result "Enabling IPv6" define JIM_IPV6 } define-append PKG_CONFIG_REQUIRES "" if {[opt-bool-unless-minimal 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 AS_CFLAGS [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 -nodefault ssl] > 0} { 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 AS_CFLAGS -DUSE_TLSv1_2_method } } # Still need to check termios.h and isatty even if lineedit is disabled if {([cc-check-includes termios.h] && [have-feature isatty]) || [have-feature winconsole]} { if {[opt-bool-unless-minimal lineedit]} { 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 AS_CFLAGS -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 introspection]} { msg-result "Disabling introspection" define JIM_NO_INTROSPECTION } 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 /usr/lib64}} { 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) 1 if {[opt-bool minimal]} { set withinfo(optional) 0 } 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]] set buildjimext 1 # Now special checks if {[have-feature windows]} { lappend extra_objs jim-win32compat.o if {[get-define JIM_STATICLIB]} { if {[llength $extinfo(module-c)]} { user-error "cygwin/mingw require --shared for dynamic modules" } else { user-notice "Building static library, so build-jim-ext will not work on cygwin/mingw" set buildjimext 0 } } } else { # We don't trust any version of clock_gettime on windows cc-check-functions clock_gettime } if {[have-feature termios.h]} { lappend extra_objs jim-tty.o } if {[have-feature termios.h] && [cc-check-functions posix_openpt]} { define-append AS_CFLAGS -DHAVE_OPENPTY lappend extra_objs openpty.o } elseif {[have-feature util.h]} { cc-check-function-in-lib openpty util } 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) \$(AS_CFLAGS) \$(AS_CPPFLAGS) \$(CFLAGS) \$(CPPFLAGS) \$(SHOBJ_CFLAGS) -c -o $obj \$(srcdir)/$src" } lappend lines "\t\$(ECHO)\t\"\tLDSO\t\$@\"" lappend lines "\t\$(Q)\$(CC) \$(AS_CFLAGS) \$(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 if {$buildjimext} { make-template build-jim-ext.in catch {exec chmod +x build-jim-ext} } make-template jimtcl.pc.in 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 }