ADDED .fossil-settings/crlf-glob Index: .fossil-settings/crlf-glob ================================================================== --- /dev/null +++ .fossil-settings/crlf-glob @@ -0,0 +1,1 @@ +win/*.vc Index: .fossil-settings/crnl-glob ================================================================== --- .fossil-settings/crnl-glob +++ .fossil-settings/crnl-glob @@ -1,2 +1,1 @@ -win/makefile.vc -win/rules.vc +win/*.vc Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -13,5 +13,10 @@ config.cache config.log config.status pkgIndex.tcl */versions.vc +win/Release* +win/Debug* +win/nmhlp-out.txt +tclconfig/* +*~ Index: ChangeLog ================================================================== --- ChangeLog +++ ChangeLog @@ -1,5 +1,9 @@ +2018-01-19 Sean Woods + + * Rewrote build system to use practcl + 2015-08-28 Jan Nijtmans * configure: Rfe [00189c4afc]: Allow semi-static UCRT build on * win/makefile.vc Windows with VC 14.0 * win/rules.vc Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -52,12 +52,10 @@ #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== -include sample.mk - PKG_LIB_FILE = @SAMPLE_SHLIB@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) @@ -80,19 +78,19 @@ PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) -top_builddir = . +top_builddir = @abs_top_builddir@ INSTALL_OPTIONS = -INSTALL = @INSTALL@ ${INSTALL_OPTIONS} -INSTALL_DATA_DIR = @INSTALL_DATA_DIR@ +INSTALL = @INSTALL@ $(INSTALL_OPTIONS) +INSTALL_DATA_DIR = ${INSTALL} -d -m 755 INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_LIBRARY = @INSTALL_LIBRARY@ +INSTALL_LIBRARY = ${INSTALL_DATA} PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ CC = @CC@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ @@ -133,15 +131,15 @@ PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(TCLLIBPATH)" TCLSH_PROG = @TCLSH_PROG@ -TCLSH = $(PKG_ENV) $(TCLSH_ENV) $(TCLSH_PROG) +TCLSH = $(TCLSH_ENV) $(PKG_ENV) $(TCLSH_PROG) #WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` #WISH_PROG = @WISH_PROG@ -#WISH = $(PKG_ENV) $(TCLSH_ENV) $(WISH_ENV) $(WISH_PROG) +#WISH = $(TCLSH_ENV) $(WISH_ENV) $(PKG_ENV) $(WISH_PROG) SHARED_BUILD = @SHARED_BUILD@ INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ #INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ @@ -162,11 +160,17 @@ CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = @AR@ CFLAGS = @CFLAGS@ -COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \ + $(CFLAGS_DEFAULT) $(CFLAGS_WARNING) $(SHLIB_CFLAGS) $(CFLAGS) + +GDB = gdb +VALGRIND = valgrind +VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \ + --leak-check=yes --show-reachable=yes -v .SUFFIXES: .c .$(OBJEXT) #======================================================================== # Start of user-definable TARGETS section @@ -187,76 +191,61 @@ # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== -binaries: $(BINARIES) - +binaries: + $(TCLSH) ${srcdir}/make.tcl binaries + libraries: + $(TCLSH) ${srcdir}/make.tcl library #======================================================================== # Your doc target should differentiate from doc builds (by the developer) # and doc installs (see install-doc), which just install the docs on the # end user machine when building from source. #======================================================================== doc: - @echo "If you have documentation to create, place the commands to" - @echo "build the docs in the 'doc:' target. For example:" - @echo " xml2nroff sample.xml > sample.n" - @echo " xml2html sample.xml > sample.html" - -install: all install-binaries install-libraries install-doc - -install-binaries: binaries install-lib-binaries install-bin-binaries - -#======================================================================== -# This rule installs platform-independent files, such as header files. -# The list=...; for p in $$list handles the empty list case x-platform. -#======================================================================== - -install-libraries: libraries - @$(INSTALL_DATA_DIR) $(DESTDIR)$(includedir) - @echo "Installing header files in $(DESTDIR)$(includedir)" - @list='$(PKG_HEADERS)'; for i in $$list; do \ - echo "Installing $(srcdir)/$$i" ; \ - $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ - done; - -#======================================================================== -# Install documentation. Unix manpages should go in the $(mandir) -# directory. -#======================================================================== - -install-doc: doc - @$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/mann - @echo "Installing documentation in $(DESTDIR)$(mandir)" - @list='$(srcdir)/doc/*.n'; for i in $$list; do \ - echo "Installing $$i"; \ - $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ - done + $(TCLSH) ${srcdir}/make.tcl doc + +#======================================================================== +# Performs a full install with documentation and headers +#======================================================================== +install: + $(TCLSH) ${srcdir}/make.tcl install $(DESTDIR) + +#======================================================================== +# Performs a minimum install of the dll and Tcl library files +#======================================================================== +install-package: + $(TCLSH) ${srcdir}/make.tcl install-package $(DESTDIR) test: binaries libraries $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ - -load "package ifneeded ${PACKAGE_NAME} ${PACKAGE_VERSION} \ - [list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" + -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \ + [list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: - $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) + $(TCLSH_ENV) $(PKG_ENV) $(GDB) $(TCLSH_PROG) $(SCRIPT) -VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \ - --leak-check=yes --show-reachable=yes -v +gdb-test: binaries libraries + $(TCLSH_ENV) $(PKG_ENV) $(GDB) \ + --args $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` \ + $(TESTFLAGS) -singleproc 1 \ + -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \ + [list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" valgrind: binaries libraries - $(TCLSH_ENV) valgrind $(VALGRINDARGS) $(TCLSH_PROG) \ - `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) + $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) \ + `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) valgrindshell: binaries libraries - $(TCLSH_ENV) valgrind $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT) + $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT) depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable @@ -301,38 +290,44 @@ #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) +DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644 +DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755 + dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean $(INSTALL_DATA_DIR) $(DIST_DIR) - cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \ - $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ - $(srcdir)/configure.ac $(DIST_DIR)/ - chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 - chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.ac - - for i in $(srcdir)/*.[ch]; do \ - if [ -f $$i ]; then \ - cp -p $$i $(DIST_DIR)/ ; \ - fi; \ - done; + + # TEA files + $(DIST_INSTALL_DATA) $(srcdir)/Makefile.in \ + $(srcdir)/aclocal.m4 $(srcdir)/configure.ac \ + $(DIST_DIR)/ + $(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/ $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig - cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ - $(DIST_DIR)/tclconfig/ - chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 - chmod +x $(DIST_DIR)/tclconfig/install-sh + $(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \ + $(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \ + $(DIST_DIR)/tclconfig/ + + # Extension files + $(DIST_INSTALL_DATA) \ + $(srcdir)/ChangeLog \ + $(srcdir)/README.sha \ + $(srcdir)/license.terms \ + $(srcdir)/README \ + $(srcdir)/pkgIndex.tcl.in \ + $(DIST_DIR)/ list='demos doc generic library mac tests unix win'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \ - cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ + $(DIST_INSTALL_DATA) $(srcdir)/$$p/* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) @@ -370,18 +365,10 @@ @$(INSTALL_DATA_DIR) $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p; \ - stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ - if test "x$$stub" = "xstub"; then \ - echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ - $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ - else \ - echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ - $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ - fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ @@ -435,9 +422,10 @@ list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test +.PHONY: gdb gdb-test valgrind valgrindshell # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: Index: configure ================================================================== --- configure +++ configure @@ -1,13 +1,11 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for sample 0.6. +# Generated by GNU Autoconf 2.69 for sample 0.6. # # -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -# Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## @@ -132,10 +130,35 @@ export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which @@ -165,11 +188,12 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi -test x\$exitcode = x0 || exit 1" +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" @@ -210,25 +234,29 @@ fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : - # We cannot yet assume a decent shell, so we have to provide a - # neutralization value for shells without unset; and this also - # works around shells that cannot unset nonexistent variables. - # Preserve -v and -x to the replacement shell. - BASH_ENV=/dev/null - ENV=/dev/null - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV - export CONFIG_SHELL - case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; - esac - exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." @@ -326,10 +354,18 @@ test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive @@ -447,10 +483,14 @@ s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. @@ -481,20 +521,20 @@ if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then @@ -502,32 +542,12 @@ else test -d ./-p && rmdir ./-p as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. @@ -598,10 +618,17 @@ # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS +TEACUP_PROFILE +TEACUP_TOOLSET +TEACUP_ARCH +TEACUP_OS +TEA_WINDOWINGSYSTEM +TEA_PLATFORM +TEA_SYSTEM TCLSH_PROG PRACTCL_NAME_LIBRARY PRACTCL_VC_MANIFEST_EMBED_EXE PRACTCL_VC_MANIFEST_EMBED_DLL PRACTCL_STUB_LIB @@ -635,21 +662,14 @@ SHARED_BUILD TCL_THREADS TCL_INCLUDES PKG_OBJECTS PKG_SOURCES -MATH_LIBS EGREP GREP RANLIB SET_MAKE -INSTALL_LIBRARY -INSTALL_SCRIPT -INSTALL_PROGRAM -INSTALL_DATA -INSTALL_DATA_DIR -INSTALL CPP TCL_SHLIB_LD_LIBS TCL_LD_FLAGS TCL_EXTRA_CFLAGS TCL_DEFS @@ -671,10 +691,16 @@ TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION CONFIG_CLEAN_FILES LN_S +INSTALL_LIBRARY +INSTALL_SCRIPT +INSTALL_PROGRAM +INSTALL_DATA +INSTALL_DATA_DIR +INSTALL PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES @@ -682,10 +708,11 @@ PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE EXEEXT CYGPATH +TEA_TK_EXTENSION target_alias host_alias build_alias LIBS ECHO_T @@ -1200,12 +1227,10 @@ # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi @@ -1356,11 +1381,11 @@ Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-threads build with threads + --enable-threads build with threads (default: on) --enable-shared build and link with shared libraries (default: on) --enable-stubs build and link with stub libraries. Always true for shared builds (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) @@ -1452,13 +1477,13 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF sample configure 0.6 -generated by GNU Autoconf 2.68 +generated by GNU Autoconf 2.69 -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi @@ -1640,11 +1665,11 @@ test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext + test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 @@ -1725,103 +1750,16 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by sample $as_me 0.6, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log @@ -2075,11 +2013,11 @@ sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files @@ -2171,39 +2109,29 @@ # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- - - # TEA extensions pass this us the version of TEA they think they - # are compatible with. - TEA_VERSION="3.10" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5 -$as_echo_n "checking for correct TEA configuration... " >&6; } + TEA_VERSION="4.0" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking TEA configuration" >&5 +$as_echo_n "checking TEA configuration... " >&6; } if test x"${PACKAGE_NAME}" = x ; then as_fn_error $? " The PACKAGE_NAME variable must be defined by your TEA configure.ac" "$LINENO" 5 fi - if test x"3.10" = x ; then - as_fn_error $? " -TEA version not specified." "$LINENO" 5 - elif test "3.10" != "${TEA_VERSION}" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: warning: requested TEA version \"3.10\", have \"${TEA_VERSION}\"" >&5 -$as_echo "warning: requested TEA version \"3.10\", have \"${TEA_VERSION}\"" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 $as_echo "ok (TEA ${TEA_VERSION})" >&6; } - fi # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi + TEA_TK_EXTENSION=0 case "`uname -s`" in - *win32*|*WIN32*|*MINGW32_*) + *win32*|*WIN32*|*MINGW32_*|*MINGW64_*) # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CYGPATH+:} false; then : @@ -2216,11 +2144,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2290,10 +2218,59 @@ + + # Configure the installer. + + INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' + INSTALL_DATA_DIR='${INSTALL} -d -m 755' + INSTALL_DATA='${INSTALL} -m 644' + INSTALL_PROGRAM='${INSTALL} -m 755' + INSTALL_SCRIPT='${INSTALL} -m 755' + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5 +$as_echo_n "checking system version... " >&6; } +if ${tcl_cv_sys_version+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # TEA specific: + if test "${TEA_PLATFORM}" = "windows" ; then + tcl_cv_sys_version=windows + else + tcl_cv_sys_version=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 +$as_echo "$as_me: WARNING: can't find uname command" >&2;} + tcl_cv_sys_version=unknown + else + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + fi + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 +$as_echo "$tcl_cv_sys_version" >&6; } + system=$tcl_cv_sys_version + + case $system in + HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; + *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; + esac + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then @@ -2309,10 +2286,11 @@ if test -d $srcdir/../tclconfig ; then $LN_S $srcdir/../tclconfig tclconfig CONFIG_CLEAN_FILES=tclconfig fi fi + ac_aux_dir= for ac_dir in tclconfig "$srcdir"/tclconfig; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir @@ -2418,10 +2396,13 @@ if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ + `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi @@ -2446,14 +2427,19 @@ for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ + `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi @@ -2513,11 +2499,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2553,11 +2539,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2606,11 +2592,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2647,11 +2633,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" @@ -2705,11 +2691,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2749,11 +2735,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2792,11 +2778,11 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 @@ -2907,11 +2893,11 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 @@ -2950,11 +2936,11 @@ done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } @@ -3009,11 +2995,11 @@ else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } @@ -3061,11 +3047,11 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } @@ -3195,12 +3181,11 @@ ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; @@ -3393,11 +3378,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3516,11 +3501,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3556,11 +3541,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3609,11 +3594,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3650,11 +3635,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" @@ -3708,11 +3693,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3752,11 +3737,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3795,11 +3780,11 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 @@ -3948,12 +3933,11 @@ ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; @@ -4162,32 +4146,18 @@ else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' - INSTALL_DATA_DIR='${INSTALL} -d -m 755' - INSTALL_DATA='${INSTALL} -m 644' - INSTALL_PROGRAM='${INSTALL}' - INSTALL_SCRIPT='${INSTALL}' - INSTALL_LIBRARY='${INSTALL_DATA}' - - - - - - #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- @@ -4243,11 +4213,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4283,11 +4253,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -4343,11 +4313,11 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; @@ -4409,11 +4379,11 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; @@ -4854,487 +4824,13 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac - if test "${TEA_PLATFORM}" = "unix" ; then - - #-------------------------------------------------------------------- - # On a few very rare systems, all of the libm.a stuff is - # already in libc.a. Set compiler flags accordingly. - # Also, Linux requires the "ieee" library for math to work - # right (and it must appear before "-lm"). - #-------------------------------------------------------------------- - - ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin" -if test "x$ac_cv_func_sin" = xyes; then : - MATH_LIBS="" -else - MATH_LIBS="-lm" -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lieee" >&5 -$as_echo_n "checking for main in -lieee... " >&6; } -if ${ac_cv_lib_ieee_main+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lieee $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - -int -main () -{ -return main (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ieee_main=yes -else - ac_cv_lib_ieee_main=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee_main" >&5 -$as_echo "$ac_cv_lib_ieee_main" >&6; } -if test "x$ac_cv_lib_ieee_main" = xyes; then : - MATH_LIBS="-lieee $MATH_LIBS" -fi - - - #-------------------------------------------------------------------- - # Interactive UNIX requires -linet instead of -lsocket, plus it - # needs net/errno.h to define the socket-related error codes. - #-------------------------------------------------------------------- - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 -$as_echo_n "checking for main in -linet... " >&6; } -if ${ac_cv_lib_inet_main+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-linet $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - -int -main () -{ -return main (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_inet_main=yes -else - ac_cv_lib_inet_main=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 -$as_echo "$ac_cv_lib_inet_main" >&6; } -if test "x$ac_cv_lib_inet_main" = xyes; then : - LIBS="$LIBS -linet" -fi - - ac_fn_c_check_header_mongrel "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default" -if test "x$ac_cv_header_net_errno_h" = xyes; then : - - -$as_echo "#define HAVE_NET_ERRNO_H 1" >>confdefs.h - -fi - - - - #-------------------------------------------------------------------- - # Check for the existence of the -lsocket and -lnsl libraries. - # The order here is important, so that they end up in the right - # order in the command line generated by make. Here are some - # special considerations: - # 1. Use "connect" and "accept" to check for -lsocket, and - # "gethostbyname" to check for -lnsl. - # 2. Use each function name only once: can't redo a check because - # autoconf caches the results of the last check and won't redo it. - # 3. Use -lnsl and -lsocket only if they supply procedures that - # aren't already present in the normal libraries. This is because - # IRIX 5.2 has libraries, but they aren't needed and they're - # bogus: they goof up name resolution if used. - # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. - # To get around this problem, check for both libraries together - # if -lsocket doesn't work by itself. - #-------------------------------------------------------------------- - - tcl_checkBoth=0 - ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" -if test "x$ac_cv_func_connect" = xyes; then : - tcl_checkSocket=0 -else - tcl_checkSocket=1 -fi - - if test "$tcl_checkSocket" = 1; then - ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt" -if test "x$ac_cv_func_setsockopt" = xyes; then : - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 -$as_echo_n "checking for setsockopt in -lsocket... " >&6; } -if ${ac_cv_lib_socket_setsockopt+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char setsockopt (); -int -main () -{ -return setsockopt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_socket_setsockopt=yes -else - ac_cv_lib_socket_setsockopt=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 -$as_echo "$ac_cv_lib_socket_setsockopt" >&6; } -if test "x$ac_cv_lib_socket_setsockopt" = xyes; then : - LIBS="$LIBS -lsocket" -else - tcl_checkBoth=1 -fi - -fi - - fi - if test "$tcl_checkBoth" = 1; then - tk_oldLibs=$LIBS - LIBS="$LIBS -lsocket -lnsl" - ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" -if test "x$ac_cv_func_accept" = xyes; then : - tcl_checkNsl=0 -else - LIBS=$tk_oldLibs -fi - - fi - ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes; then : - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 -$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } -if ${ac_cv_lib_nsl_gethostbyname+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char gethostbyname (); -int -main () -{ -return gethostbyname (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_nsl_gethostbyname=yes -else - ac_cv_lib_nsl_gethostbyname=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 -$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } -if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : - LIBS="$LIBS -lnsl" -fi - -fi - - - # TEA specific: Don't perform the eval of the libraries here because - # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS - - TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5 -$as_echo_n "checking dirent.h... " >&6; } -if ${tcl_cv_dirent_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main () -{ - -#ifndef _POSIX_SOURCE -# ifdef __Lynx__ - /* - * Generate compilation error to make the test fail: Lynx headers - * are only valid if really in the POSIX environment. - */ - - missing_procedure(); -# endif -#endif -DIR *d; -struct dirent *entryPtr; -char *p; -d = opendir("foobar"); -entryPtr = readdir(d); -p = entryPtr->d_name; -closedir(d); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - tcl_cv_dirent_h=yes -else - tcl_cv_dirent_h=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_dirent_h" >&5 -$as_echo "$tcl_cv_dirent_h" >&6; } - - if test $tcl_cv_dirent_h = no; then - -$as_echo "#define NO_DIRENT_H 1" >>confdefs.h - - fi - - # TEA specific: - ac_fn_c_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" -if test "x$ac_cv_header_errno_h" = xyes; then : - -else - -$as_echo "#define NO_ERRNO_H 1" >>confdefs.h - -fi - - - ac_fn_c_check_header_mongrel "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" -if test "x$ac_cv_header_float_h" = xyes; then : - -else - -$as_echo "#define NO_FLOAT_H 1" >>confdefs.h - -fi - - - ac_fn_c_check_header_mongrel "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default" -if test "x$ac_cv_header_values_h" = xyes; then : - -else - -$as_echo "#define NO_VALUES_H 1" >>confdefs.h - -fi - - - ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" -if test "x$ac_cv_header_limits_h" = xyes; then : - -$as_echo "#define HAVE_LIMITS_H 1" >>confdefs.h - -else - -$as_echo "#define NO_LIMITS_H 1" >>confdefs.h - -fi - - - ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" -if test "x$ac_cv_header_stdlib_h" = xyes; then : - tcl_ok=1 -else - tcl_ok=0 -fi - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "strtol" >/dev/null 2>&1; then : - -else - tcl_ok=0 -fi -rm -f conftest* - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "strtoul" >/dev/null 2>&1; then : - -else - tcl_ok=0 -fi -rm -f conftest* - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "strtod" >/dev/null 2>&1; then : - -else - tcl_ok=0 -fi -rm -f conftest* - - if test $tcl_ok = 0; then - -$as_echo "#define NO_STDLIB_H 1" >>confdefs.h - - fi - ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" -if test "x$ac_cv_header_string_h" = xyes; then : - tcl_ok=1 -else - tcl_ok=0 -fi - - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "strstr" >/dev/null 2>&1; then : - -else - tcl_ok=0 -fi -rm -f conftest* - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "strerror" >/dev/null 2>&1; then : - -else - tcl_ok=0 -fi -rm -f conftest* - - - # See also memmove check below for a place where NO_STRING_H can be - # set and why. - - if test $tcl_ok = 0; then - -$as_echo "#define NO_STRING_H 1" >>confdefs.h - - fi - - ac_fn_c_check_header_mongrel "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_wait_h" = xyes; then : - -else - -$as_echo "#define NO_SYS_WAIT_H 1" >>confdefs.h - -fi - - - ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" -if test "x$ac_cv_header_dlfcn_h" = xyes; then : - -else - -$as_echo "#define NO_DLFCN_H 1" >>confdefs.h - -fi - - - - # OS/390 lacks sys/param.h (and doesn't need it, by chance). - for ac_header in sys/param.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_param_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYS_PARAM_H 1 -_ACEOF - -fi - -done - - - # Let the user call this, because if it triggers, they will - # need a compat/strtod.c that is correct. Users can also - # use Tcl_GetDouble(FromObj) instead. - #TEA_BUGGY_STRTOD - fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, @@ -5400,12 +4896,16 @@ vars="" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then - # Convert foo.lib to -lfoo for GCC. No-op if not *.lib - i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` + case $i in + *.lib) + # Convert foo.lib to -lfoo for GCC + i=-l`echo "$i" | sed -e 's/\.[^.]*$//' -e 's/\.lib.*//'` + ;; + esac fi PKG_LIBS="$PKG_LIBS $i" done @@ -5586,39 +5086,39 @@ tcl_ok=yes fi if test "${enable_threads+set}" = set; then - enableval="$enable_threads" - tcl_ok=$enableval + enableval="$enable_threads" + tcl_ok=$enableval else - tcl_ok=yes + tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then - TCL_THREADS=1 + TCL_THREADS=1 - if test "${TEA_PLATFORM}" != "windows" ; then - # We are always OK on Windows, so check what this platform wants: + if test "${TEA_PLATFORM}" != "windows" ; then + # We are always OK on Windows, so check what this platform wants: - # USE_THREAD_ALLOC tells us to try the special thread-based - # allocator that significantly reduces lock contention + # USE_THREAD_ALLOC tells us to try the special thread-based + # allocator that significantly reduces lock contention $as_echo "#define USE_THREAD_ALLOC 1" >>confdefs.h $as_echo "#define _REENTRANT 1" >>confdefs.h - if test "`uname -s`" = "SunOS" ; then + if test "`uname -s`" = "SunOS" ; then $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - fi + fi $as_echo "#define _THREAD_SAFE 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_mutex_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -5656,17 +5156,17 @@ tcl_ok=yes else tcl_ok=no fi - if test "$tcl_ok" = "no"; then - # Check a little harder for __pthread_mutex_init in the same - # library, as some systems hide it there until pthread.h is - # defined. We could alternatively do an AC_TRY_COMPILE with - # pthread.h, but that will work with libpthread really doesn't - # exist, like AIX 4.2. [Bug: 4359] - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 + if test "$tcl_ok" = "no"; then + # Check a little harder for __pthread_mutex_init in the same + # library, as some systems hide it there until pthread.h is + # defined. We could alternatively do an AC_TRY_COMPILE with + # pthread.h, but that will work with libpthread really doesn't + # exist, like AIX 4.2. [Bug: 4359] + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for __pthread_mutex_init in -lpthread... " >&6; } if ${ac_cv_lib_pthread___pthread_mutex_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -5704,17 +5204,17 @@ tcl_ok=yes else tcl_ok=no fi - fi + fi - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -lpthread" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthreads... " >&6; } if ${ac_cv_lib_pthreads_pthread_mutex_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -5752,15 +5252,15 @@ tcl_ok=yes else tcl_ok=no fi - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -lpthreads" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthreads" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 $as_echo_n "checking for pthread_mutex_init in -lc... " >&6; } if ${ac_cv_lib_c_pthread_mutex_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -5798,12 +5298,12 @@ tcl_ok=yes else tcl_ok=no fi - if test "$tcl_ok" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 + if test "$tcl_ok" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 $as_echo_n "checking for pthread_mutex_init in -lc_r... " >&6; } if ${ac_cv_lib_c_r_pthread_mutex_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -5841,64 +5341,74 @@ tcl_ok=yes else tcl_ok=no fi - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -pthread" - else - TCL_THREADS=0 - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -pthread" + else + TCL_THREADS=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 $as_echo "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} - fi - fi - fi - fi - fi + fi + fi + fi + fi + fi else - TCL_THREADS=0 + TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output { $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5 $as_echo_n "checking for building with threads... " >&6; } if test "${TCL_THREADS}" = 1; then $as_echo "#define TCL_THREADS 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 $as_echo "yes (default)" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. - case ${TCL_DEFS} in - *THREADS=1*) - if test "${TCL_THREADS}" = "0"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: + + if test "${TCL_VERSION}" > "8.6" ; then + TCL_HAS_THREADS=1 + else + case ${TCL_DEFS} in + *THREADS=1*) + TCL_HAS_THREADS=1; + ;; + *) + TCL_HAS_THREADS=0; + ;; + esac + fi + if test "${TCL_HAS_THREADS}" = "1"; then + if test "${TCL_THREADS}" = "0"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&5 $as_echo "$as_me: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&2;} - fi - ;; - *) - if test "${TCL_THREADS}" = "1"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: + fi + else + if test "${TCL_THREADS}" = "1"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&5 $as_echo "$as_me: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&2;} - fi - ;; - esac + fi + fi #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to @@ -5996,11 +5506,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6036,11 +5546,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6264,11 +5774,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6304,11 +5814,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6515,12 +6025,16 @@ lflags="${lflags} -nodefaultlib:libucrt.lib" vars="ucrt.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then - # Convert foo.lib to -lfoo for GCC. No-op if not *.lib - i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` + case $i in + *.lib) + # Convert foo.lib to -lfoo for GCC + i=-l`echo "$i" | sed -e 's/\.[^.]*$//' -e 's/\.lib.*//'` + ;; + esac fi PKG_LIBS="$PKG_LIBS $i" done @@ -6542,12 +6056,16 @@ # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then - # Convert foo.lib to -lfoo for GCC. No-op if not *.lib - i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` + case $i in + *.lib) + # Convert foo.lib to -lfoo for GCC + i=-l`echo "$i" | sed -e 's/\.[^.]*$//' -e 's/\.lib.*//'` + ;; + esac fi PKG_LIBS="$PKG_LIBS $i" done @@ -6615,11 +6133,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RC="${ac_tool_prefix}windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6655,11 +6173,11 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RC="windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -6694,11 +6212,11 @@ CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - PRACTCL_UNSHARED_LIB_SUFFIX='.a' + PRACTCL_UNSHARED_LIB_SUFFIX='.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cross-compile version of gcc" >&5 @@ -6925,11 +6443,11 @@ ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" - SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5 $as_echo_n "checking for inet_ntoa in -lnetwork... " >&6; } if ${ac_cv_lib_network_inet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else @@ -7152,11 +6670,11 @@ # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS - SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' + SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi @@ -7228,43 +6746,27 @@ fi ;; OpenBSD-*) arch=`arch -s` case "$arch" in - vax) - SHLIB_SUFFIX="" - SHARED_LIB_SUFFIX="" - LDFLAGS="" - ;; - *) - case "$arch" in - alpha|sparc64) - SHLIB_CFLAGS="-fPIC" - ;; - *) - SHLIB_CFLAGS="-fpic" - ;; - esac - SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' - SHLIB_SUFFIX=".so" - if test $doRpath = yes; then : - - CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' -fi - LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' - LDFLAGS="-Wl,-export-dynamic" - ;; - esac - case "$arch" in - vax) - CFLAGS_OPTIMIZE="-O1" - ;; - *) - CFLAGS_OPTIMIZE="-O2" - ;; - esac + alpha|sparc64) + SHLIB_CFLAGS="-fPIC" + ;; + *) + SHLIB_CFLAGS="-fpic" + ;; + esac + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' + SHLIB_SUFFIX=".so" + if test $doRpath = yes; then : + + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' +fi + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' + LDFLAGS="-Wl,-export-dynamic" + CFLAGS_OPTIMIZE="-O2" if test "${TCL_THREADS}" = "1"; then : # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` @@ -7276,11 +6778,11 @@ TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" - SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' @@ -7927,11 +7429,11 @@ if test "$GCC" = yes; then : case $system in AIX-*) ;; BSD/OS*) ;; - CYGWIN_*|MINGW32_*) ;; + CYGWIN_*|MINGW32_*|MINGW64_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; @@ -8719,10 +8221,12 @@ if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" + elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}sg${EXEEXT}" ; then + TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}sg${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then @@ -8754,17 +8258,130 @@ $as_echo "${TCLSH_PROG}" >&6; } #TEA_PROG_WISH + + + TEACUP_OS=$system + TEACUP_ARCH="unknown" + TEACUP_TOOLSET="gcc" + TEACUP_PROFILE="unknown" + arch="unknown" + case ${host_alias} in + *mingw32*) + arch="ix86" + TEACUP_PROFILE="win32-ix86" + ;; + *mingw64*) + arch="x86_64" + TEACUP_PROFILE="win32-x86_64" + ;; + esac + if test "${arch}" = "unknown" ; then + if test "${TEA_PLATFORM}" = "windows" ; then + if test "$GCC" = "yes" ; then + TEACUP_TOOLSET="gcc" + else + TEACUP_TOOLSET="msvc" + fi + if test "$do64bit" != "no" ; then + case "$do64bit" in + amd64|x64|yes) + arch="x86_64" + TEACUP_PROFILE="win32-x86_64" + ;; + ia64) + arch="ia64" + TEACUP_PROFILE="win32-ia64" + ;; + esac + else + arch="ix86" + TEACUP_PROFILE="win32-ix86" + fi + else + case $system in + Linux*) + TEACUP_OS="linux" + arch=`uname -m` + TEACUP_PROFILE="linux-glibc2.3-$arch" + ;; + GNU*) + TEACUP_OS="gnu" + arch=`uname -m` + ;; + NetBSD-Debian) + TEACUP_OS="netbsd-debian" + arch=`uname -m` + ;; + OpenBSD-*) + TEACUP_OS="openbsd" + arch=`arch -s` + ;; + Darwin*) + TEACUP_OS="macosx" + TEACUP_PROFILE="macosx-universal" + arch=`uname -m` + if test $arch = "x86_64"; then + TEACUP_PROFILE="macosx10.5-i386-x86_84" + fi + ;; + OpenBSD*) + TEACUP_OS="openbsd" + arch=`arch -s` + ;; + esac + fi + fi + TEACUP_ARCH=$arch + if test "$TEACUP_PROFILE" = "unknown"; then + if test $arch = "unknown"; then + arch=`uname -m` + fi + case $arch in + i*86) + arch="ix86" + ;; + amd64) + arch="x86_64" + ;; + esac + TEACUP_PROFILE="$TEACUP_OS-$arch" + fi + TEA_SYSTEM=$system + + + + + + + + + +#-------------------------------------------------------------------- +# Setup a *Config.sh.in configuration file. +#-------------------------------------------------------------------- + +#TEA_EXPORT_CONFIG([sample]) +#AC_SUBST(SAMPLE_VAR) + +#-------------------------------------------------------------------- +# Specify files to substitute AC variables in. You may alternatively +# have a special pkgIndex.tcl.in or other files which require +# substituting the AC variables in. Include these here. +#-------------------------------------------------------------------- + +ac_config_files="$ac_config_files Makefile pkgIndex.tcl" + +#AC_CONFIG_FILES([sampleConfig.sh]) + #-------------------------------------------------------------------- -# Finally, substitute all of the various values into the Makefile. -# You may alternatively have a special pkgIndex.tcl.in or other files -# which require substituting th AC variables in. Include these here. +# Finally, substitute all of the various values into the files +# specified with AC_CONFIG_FILES. #-------------------------------------------------------------------- - -ac_config_files="$ac_config_files Makefile pkgIndex.tcl config.tcl:tclconfig/config.tcl.in" +ac_config_files="$ac_config_files config.tcl:tclconfig/config.tcl.in" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. @@ -9207,20 +8824,20 @@ if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -9276,32 +8893,20 @@ else test -d ./-p && rmdir ./-p as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. @@ -9319,11 +8924,11 @@ # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by sample $as_me 0.6, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS @@ -9372,14 +8977,14 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ sample config.status 0.6 -configured by $0, generated by GNU Autoconf 2.68, +configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' @@ -9452,11 +9057,11 @@ fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -9485,11 +9090,11 @@ case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES pkgIndex.tcl" ;; "config.tcl") CONFIG_FILES="$CONFIG_FILES config.tcl:tclconfig/config.tcl.in" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, @@ -9693,11 +9298,11 @@ case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: @@ -9721,11 +9326,11 @@ test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -9748,11 +9353,11 @@ *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || @@ -9933,6 +9538,6 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi -${TCLSH_PROG} ${srcdir}/make.tcl autoconf + Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -24,21 +24,21 @@ #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- - -TEA_INIT([3.10]) +TEA_INIT(4.0]) AC_PROG_LN_S CONFIG_CLEAN_FILES= if test ! -d $srcdir/tclconfig ; then if test -d $srcdir/../tclconfig ; then $LN_S $srcdir/../tclconfig tclconfig CONFIG_CLEAN_FILES=tclconfig fi fi AC_SUBST(CONFIG_CLEAN_FILES) + AC_CONFIG_AUX_DIR(tclconfig) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- @@ -172,14 +172,29 @@ # a pkgIndex.tcl file or anything else at extension build time. #-------------------------------------------------------------------- TEA_PROG_TCLSH #TEA_PROG_WISH +TEA_CONFIG_TEAPOT + +#-------------------------------------------------------------------- +# Setup a *Config.sh.in configuration file. +#-------------------------------------------------------------------- + +#TEA_EXPORT_CONFIG([sample]) +#AC_SUBST(SAMPLE_VAR) + +#-------------------------------------------------------------------- +# Specify files to substitute AC variables in. You may alternatively +# have a special pkgIndex.tcl.in or other files which require +# substituting the AC variables in. Include these here. +#-------------------------------------------------------------------- + +AC_CONFIG_FILES([Makefile pkgIndex.tcl]) +#AC_CONFIG_FILES([sampleConfig.sh]) #-------------------------------------------------------------------- -# Finally, substitute all of the various values into the Makefile. -# You may alternatively have a special pkgIndex.tcl.in or other files -# which require substituting th AC variables in. Include these here. +# Finally, substitute all of the various values into the files +# specified with AC_CONFIG_FILES. #-------------------------------------------------------------------- +AC_OUTPUT([config.tcl:tclconfig/config.tcl.in]) -AC_OUTPUT([Makefile pkgIndex.tcl config.tcl:tclconfig/config.tcl.in]) -${TCLSH_PROG} ${srcdir}/make.tcl autoconf Index: generic/sample.h ================================================================== --- generic/sample.h +++ generic/sample.h @@ -25,10 +25,11 @@ typedef unsigned long sha_uint32_t; # else typedef unsigned int sha_uint32_t; # endif #endif + /* * For C++ compilers, use extern "C" */ Index: make.tcl ================================================================== --- make.tcl +++ make.tcl @@ -1,39 +1,249 @@ set CWD [pwd] set ::project(builddir) $::CWD -set ::project(srcdir) [file dirname [file normalize [info script]]] -set ::project(sandbox) [file dirname $::project(srcdir)] - -if {[file exists [file join $CWD .. tclconfig practcl.tcl]]} { - source [file join $CWD .. tclconfig practcl.tcl] -} else { - source [file join $SRCPATH tclconfig practcl.tcl] -} - +set ::SRCDIR [file dirname [file normalize [info script]]] +set ::SANDBOX [file dirname $::SRCDIR] + +source [file join $SRCDIR tools practcl.tcl] array set ::project [::practcl::config.tcl $CWD] ::practcl::library create LIBRARY [array get ::project] -LIBRARY add [file join $::project(srcdir) generic sample.c] -LIBRARY add [file join $::project(srcdir) generic sample.tcl] +LIBRARY define set builddir $CWD +LIBRARY define set srcdir $SRCDIR +LIBRARY clay set meta license BSD +LIBRARY clay set meta description {The Reference TEA Extension for Developers} +### +# Generate List of Authors +### +set authors {} +foreach match [::practcl::grep \<.*\@ [file join $SRCDIR ChangeLog]] { + lappend authors [lrange $match 1 end] +} +LIBRARY clay set meta authors $authors + +LIBRARY add [file join $::SRCDIR generic sample.c] +LIBRARY add [file join $::SRCDIR generic sample.tcl] +LIBRARY define add public-verbatim [file join $::SRCDIR generic sample.h] + +if {![LIBRARY define exists TCL_SRC_DIR]} { + # Did not detect the Tcl source directory. Run autoconf + ::practcl::doexec sh [file join $::SRCDIR configure] + array set ::project [::practcl::config.tcl $CWD] + LIBRARY define set [array get ::project] + # Generate a make.tcl in this directory + if {![file exists make.tcl]} { + set fout [open make.tcl w] + puts $fout "# Redirect to the make file that lives in the project's source dir" + puts $fout [list source [file join $srcdir make.tcl]] + close $fout + if {$::tcl_platform(platform)!="windows"} { + file attributes -permission a+x make.tcl + } + } +} ### # Create build targets ### -::practcl::target autoconf {} + +# Virtual target to mimic the behavior of "make all" +LIBRARY make target all { + aliases {binaries libraries} + depends library +} + + +# Generate the dynamic library and pkgIndex.tcl +LIBRARY make target library { + triggers implement + files {sample.c sample.h pkgIndex.tcl [LIBRARY define get libfile]} +} { + # Collect configuration + my go + + ## + # Generate dynamic C files + ## + set builddir [my define get builddir] + my implement $builddir + + ### + # Compile the library + ### + puts "BUILDING [my define get libfile]" + my build-library [file join $builddir [my define get libfile]] [self] + + ## + # Generate pkgIndex.tcl + ## + set fout [open [file join $builddir pkgIndex.tcl] w] + puts $fout " +# +# Tcl package index file +# + " + puts $fout [my package-ifneeded] + close $fout +} -switch [lindex $argv 0] { - default { - ::practcl::trigger {*}$argv +if {"clean" in $argv} { + # Clean is a little weird because it screws with dependencies + # We do it as a separate action + foreach {name obj} [LIBRARY make objects] { + set files [$obj output] + foreach file $files { + file delete -force [file join $CWD $file] + } + } + foreach pattern {*.lib *.zip *.vfs objs/*} { + foreach file [glob -nocomplain [file join $CWD $file]] { + file delete -force $pattern + } } } -if {$make(autoconf)} { - LIBRARY implement $::project(builddir) - set fout [open pkgIndex.tcl w] - puts $fout " - # - # Tcl package index file - # - " - puts $fout [LIBRARY package-ifneeded] - close $fout +switch [lindex $argv 0] { + info { + set dat [LIBRARY make pkginfo] + foreach {field value} $dat { + puts [list $field: $value] + } + exit 0 + } + install { + if {[info exists ::env(DESTDIR)]} { + set DESTDIR $::env(DESTDIR) + } + LIBRARY make depends library doc + LIBRARY make do + if {[llength $argv]>1} { + set DESTDIR [file normalize [string trimright [lindex $argv 1]]] + } + set dat [LIBRARY make pkginfo] + dict with dat {} + if {$DESTDIR ne {}} { + foreach path { + includedir + mandir + datadir + libdir + } { + set $path [file join [string trimright $DESTDIR /] [string trimleft [set $path] /]] + } + } + set pkgdatadir [file join $datadir $PKG_DIR] + set pkglibdir [file join $libdir $PKG_DIR] + set pkgincludedir [file join $includedir $PKG_DIR] + #======================================================================== + # This rule installs platform-independent files, such as header files. + #======================================================================== + puts "Installing header files in ${includedir}" + foreach hfile [LIBRARY install-headers] { + ::practcl::copyDir [file join $srcdir $hfile] ${includedir} + } + #======================================================================== + # Install documentation. Unix manpages should go in the $(mandir) + # directory. + #======================================================================== + puts "Installing documentation in ${mandir}" + foreach file [glob -nocomplain [file join $srcdir doc *.n]] { + ::practcl::copyDir $file [file join ${mandir} mann] + } + #======================================================================== + # Install binary object libraries. On Windows this includes both .dll and + # .lib files. Because the .lib files are not explicitly listed anywhere, + # we need to deduce their existence from the .dll file of the same name. + # Library files go into the lib directory. + # In addition, this will generate the pkgIndex.tcl + # file in the install location (assuming it can find a usable tclsh shell) + #======================================================================== + puts "Installing Package to ${pkglibdir}" + ::practcl::copyDir [LIBRARY define get libfile] $pkglibdir + foreach file [glob -nocomplain *.lib] { + ::practcl::copyDir $file $pkglibdir + } + ::practcl::copyDir pkgIndex.tcl $pkglibdir + if {[LIBRARY define get output_tcl] ne {}} { + ::practcl::copyDir [LIBRARY define get output_tcl] $pkglibdir + } + } + install-package { + if {[llength $argv]<1} { + error "Usage: install DESTINATION" + } + LIBRARY make depends library doc + LIBRARY make do + set dat [LIBRARY make pkginfo] + dict with dat {} + set pkglibdir [file join [lindex $argv 1] $PKG_DIR] + #======================================================================== + # Install binary object libraries. On Windows this includes both .dll and + # .lib files. Because the .lib files are not explicitly listed anywhere, + # we need to deduce their existence from the .dll file of the same name. + # Library files go into the lib directory. + # In addition, this will generate the pkgIndex.tcl + # file in the install location (assuming it can find a usable tclsh shell) + #======================================================================== + puts "Installing Package to ${pkglibdir}" + ::practcl::copyDir [LIBRARY define get libfile] $pkglibdir + foreach file [glob -nocomplain *.lib] { + ::practcl::copyDir $file $pkglibdir + } + ::practcl::copyDir pkgIndex.tcl $pkglibdir + if {[LIBRARY define get output_tcl] ne {}} { + ::practcl::copyDir [LIBRARY define get output_tcl] $pkglibdir + } + } + teapot { + LIBRARY make depends library doc + LIBRARY make do + set dat [LIBRARY make pkginfo] + dict with dat {} + set teapotvfs [file join $CWD teapot.vfs] + if {[file exists $teapotvfs]} { + file delete -force $teapotvfs + } + file mkdir $teapotvfs + file copy -force [LIBRARY define get libfile] $teapotvfs + foreach file [glob -nocomplain *.lib] { + file copy -force $file $teapotvfs + } + file copy -force pkgIndex.tcl $teapotvfs + if {[LIBRARY define get output_tcl] ne {}} { + file copy -force [LIBRARY define get output_tcl] $teapotvfs + } + ### + # Generate the teapot meta file + ### + set fout [open [file join $teapotvfs teapot.txt] w] + puts $fout [list Package $name $version] + puts $fout [list Meta platform [LIBRARY define get TEACUP_PROFILE]] + puts $fout [list Meta practcl::build_date [clock format [file mtime [LIBRARY define get libfile]]]] + # Pull SCM checkout info + ::practcl::distribution select LIBRARY + set info [LIBRARY scm_info] + foreach item {scm hash isodate tags} { + if {![dict exists $info $item]} continue + set value [dict get $info $item] + if {$value eq {}} continue + puts $fout [list Meta practcl::scm_$item $value] + } + + set mdat [LIBRARY clay get meta] + foreach {field value} $mdat { + if {$field in {authors requires}} { + foreach item $value { + puts $fout [list Meta $field $item] + } + } else { + puts $fout [list Meta [string trimright $field :] $value] + } + } + close $fout + ::practcl::tcllib_require zipfile::mkzip + ::zipfile::mkzip::mkzip [dict get $dat zipfile] -directory $teapotvfs + } + default { + LIBRARY make trigger {*}$argv + LIBRARY make do + } } ADDED tools/practcl.tcl Index: tools/practcl.tcl ================================================================== --- /dev/null +++ tools/practcl.tcl @@ -0,0 +1,8331 @@ +### +# Amalgamated package for practcl +# Do not edit directly, tweak the source in src/ and rerun +# build.tcl +### +package require Tcl 8.6 +package provide practcl 0.15 +namespace eval ::practcl {} + +### +# START: httpwget/wget.tcl +### +package provide http::wget 0.1 +package require http +::namespace eval ::http { +} +proc ::http::_followRedirects {url args} { + while 1 { + set token [geturl $url -validate 1] + set ncode [ncode $token] + if { $ncode eq "404" } { + error "URL Not found" + } + switch -glob $ncode { + 30[1237] {### redirect - see below ###} + default {cleanup $token ; return $url} + } + upvar #0 $token state + array set meta [set ${token}(meta)] + cleanup $token + if {![info exists meta(Location)]} { + return $url + } + set url $meta(Location) + unset meta + } + return $url +} +proc ::http::wget {url destfile {verbose 1}} { + set tmpchan [open $destfile w] + fconfigure $tmpchan -translation binary + if { $verbose } { + puts [list GETTING [file tail $destfile] from $url] + } + set real_url [_followRedirects $url] + set token [geturl $real_url -channel $tmpchan -binary yes] + if {[ncode $token] != "200"} { + error "DOWNLOAD FAILED" + } + cleanup $token + close $tmpchan +} + +### +# END: httpwget/wget.tcl +### +### +# START: clay/clay.tcl +### +package provide clay 0.6 +namespace eval ::clay { +} +package require Tcl 8.5 +namespace eval uuid { + variable accel + array set accel {critcl 0} + namespace export uuid + variable uid + if {![info exists uid]} { + set uid 1 + } + proc K {a b} {set a} +} +proc ::uuid::generate_tcl_machinfo {} { + variable machinfo + if {[info exists machinfo]} { + return $machinfo + } + lappend machinfo [clock seconds]; # timestamp + lappend machinfo [clock clicks]; # system incrementing counter + lappend machinfo [info hostname]; # spatial unique id (poor) + lappend machinfo [pid]; # additional entropy + lappend machinfo [array get ::tcl_platform] + + ### + # If we have /dev/urandom just stream 128 bits from that + ### + if {[file exists /dev/urandom]} { + set fin [open /dev/urandom r] + binary scan [read $fin 128] H* machinfo + close $fin + } elseif {[catch {package require nettool}]} { + # More spatial information -- better than hostname. + # bug 1150714: opening a server socket may raise a warning messagebox + # with WinXP firewall, using ipconfig will return all IP addresses + # including ipv6 ones if available. ipconfig is OK on win98+ + if {[string equal $::tcl_platform(platform) "windows"]} { + catch {exec ipconfig} config + lappend machinfo $config + } else { + catch { + set s [socket -server void -myaddr [info hostname] 0] + K [fconfigure $s -sockname] [close $s] + } r + lappend machinfo $r + } + + if {[package provide Tk] != {}} { + lappend machinfo [winfo pointerxy .] + lappend machinfo [winfo id .] + } + } else { + ### + # If the nettool package works on this platform + # use the stream of hardware ids from it + ### + lappend machinfo {*}[::nettool::hwid_list] + } + return $machinfo +} +proc ::uuid::generate_tcl {} { + package require md5 2 + variable uid + + set tok [md5::MD5Init] + md5::MD5Update $tok [incr uid]; # package incrementing counter + foreach string [generate_tcl_machinfo] { + md5::MD5Update $tok $string + } + set r [md5::MD5Final $tok] + binary scan $r c* r + + # 3.4: set uuid versioning fields + lset r 8 [expr {([lindex $r 8] & 0x3F) | 0x80}] + lset r 6 [expr {([lindex $r 6] & 0x0F) | 0x40}] + + return [binary format c* $r] +} +if {[string equal $tcl_platform(platform) "windows"] + && [package provide critcl] != {}} { + namespace eval uuid { + critcl::ccode { + #define WIN32_LEAN_AND_MEAN + #define STRICT + #include + #include + typedef long (__stdcall *LPFNUUIDCREATE)(UUID *); + typedef const unsigned char cu_char; + } + critcl::cproc generate_c {Tcl_Interp* interp} ok { + HRESULT hr = S_OK; + int r = TCL_OK; + UUID uuid = {0}; + HMODULE hLib; + LPFNUUIDCREATE lpfnUuidCreate = NULL; + hLib = LoadLibraryA(("rpcrt4.dll")); + if (hLib) + lpfnUuidCreate = (LPFNUUIDCREATE) + GetProcAddress(hLib, "UuidCreate"); + if (lpfnUuidCreate) { + Tcl_Obj *obj; + lpfnUuidCreate(&uuid); + obj = Tcl_NewByteArrayObj((cu_char *)&uuid, sizeof(uuid)); + Tcl_SetObjResult(interp, obj); + } else { + Tcl_SetResult(interp, "error: failed to create a guid", + TCL_STATIC); + r = TCL_ERROR; + } + return r; + } + } +} +proc ::uuid::tostring {uuid} { + binary scan $uuid H* s + foreach {a b} {0 7 8 11 12 15 16 19 20 end} { + append r [string range $s $a $b] - + } + return [string tolower [string trimright $r -]] +} +proc ::uuid::fromstring {uuid} { + return [binary format H* [string map {- {}} $uuid]] +} +proc ::uuid::equal {left right} { + set l [fromstring $left] + set r [fromstring $right] + return [string equal $l $r] +} +proc ::uuid::generate {} { + variable accel + if {$accel(critcl)} { + return [generate_c] + } else { + return [generate_tcl] + } +} +proc uuid::uuid {cmd args} { + switch -exact -- $cmd { + generate { + if {[llength $args] != 0} { + return -code error "wrong # args:\ + should be \"uuid generate\"" + } + return [tostring [generate]] + } + equal { + if {[llength $args] != 2} { + return -code error "wrong \# args:\ + should be \"uuid equal uuid1 uuid2\"" + } + return [eval [linsert $args 0 equal]] + } + default { + return -code error "bad option \"$cmd\":\ + must be generate or equal" + } + } +} +proc ::uuid::LoadAccelerator {name} { + variable accel + set r 0 + switch -exact -- $name { + critcl { + if {![catch {package require tcllibc}]} { + set r [expr {[info commands ::uuid::generate_c] != {}}] + } + } + default { + return -code error "invalid accelerator package:\ + must be one of [join [array names accel] {, }]" + } + } + set accel($name) $r +} +namespace eval ::uuid { + variable e {} + foreach e {critcl} { + if {[LoadAccelerator $e]} break + } + unset e +} +package provide uuid 1.0.7 +namespace eval ::oo::dialect { + namespace export create +} +foreach {flag test} { + tip470 {package vsatisfies [package provide Tcl] 8.7} +} { + if {![info exists ::oo::dialect::has($flag)]} { + set ::oo::dialect::has($flag) [eval $test] + } +} +proc ::oo::dialect::Push {class} { + ::variable class_stack + lappend class_stack $class +} +proc ::oo::dialect::Peek {} { + ::variable class_stack + return [lindex $class_stack end] +} +proc ::oo::dialect::Pop {} { + ::variable class_stack + set class_stack [lrange $class_stack 0 end-1] +} +if {$::oo::dialect::has(tip470)} { +proc ::oo::dialect::current_class {} { + return [uplevel 1 self] +} +} else { +proc ::oo::dialect::current_class {} { + tailcall Peek +} +} +proc ::oo::dialect::create {name {parent ""}} { + variable has + set NSPACE [NSNormalize [uplevel 1 {namespace current}] $name] + ::namespace eval $NSPACE {::namespace eval define {}} + ### + # Build the "define" namespace + ### + + if {$parent eq ""} { + ### + # With no "parent" language, begin with all of the keywords in + # oo::define + ### + foreach command [info commands ::oo::define::*] { + set procname [namespace tail $command] + interp alias {} ${NSPACE}::define::$procname {} \ + ::oo::dialect::DefineThunk $procname + } + # Create an empty dynamic_methods proc + proc ${NSPACE}::dynamic_methods {class} {} + namespace eval $NSPACE { + ::namespace export dynamic_methods + ::namespace eval define {::namespace export *} + } + set ANCESTORS {} + } else { + ### + # If we have a parent language, that language already has the + # [oo::define] keywords as well as additional keywords and behaviors. + # We should begin with that + ### + set pnspace [NSNormalize [uplevel 1 {namespace current}] $parent] + apply [list parent { + ::namespace export dynamic_methods + ::namespace import -force ${parent}::dynamic_methods + } $NSPACE] $pnspace + + apply [list parent { + ::namespace import -force ${parent}::define::* + ::namespace export * + } ${NSPACE}::define] $pnspace + set ANCESTORS [list ${pnspace}::object] + } + ### + # Build our dialect template functions + ### + proc ${NSPACE}::define {oclass args} [string map [list %NSPACE% $NSPACE] { + ### + # To facilitate library reloading, allow + # a dialect to create a class from DEFINE + ### + set class [::oo::dialect::NSNormalize [uplevel 1 {namespace current}] $oclass] + if {[info commands $class] eq {}} { + %NSPACE%::class create $class {*}${args} + } else { + ::oo::dialect::Define %NSPACE% $class {*}${args} + } +}] + interp alias {} ${NSPACE}::define::current_class {} \ + ::oo::dialect::current_class + interp alias {} ${NSPACE}::define::aliases {} \ + ::oo::dialect::Aliases $NSPACE + interp alias {} ${NSPACE}::define::superclass {} \ + ::oo::dialect::SuperClass $NSPACE + + if {[info command ${NSPACE}::class] ne {}} { + ::rename ${NSPACE}::class {} + } + ### + # Build the metaclass for our language + ### + ::oo::class create ${NSPACE}::class { + superclass ::oo::dialect::MotherOfAllMetaClasses + } + # Wire up the create method to add in the extra argument we need; the + # MotherOfAllMetaClasses will know what to do with it. + ::oo::objdefine ${NSPACE}::class \ + method create {name {definitionScript ""}} \ + "next \$name [list ${NSPACE}::define] \$definitionScript" + + ### + # Build the mother of all classes. Note that $ANCESTORS is already + # guaranteed to be a list in canonical form. + ### + uplevel #0 [string map [list %NSPACE% [list $NSPACE] %name% [list $name] %ANCESTORS% $ANCESTORS] { + %NSPACE%::class create %NSPACE%::object { + superclass %ANCESTORS% + # Put MOACish stuff in here + } + }] + if { "${NSPACE}::class" ni $::oo::dialect::core_classes } { + lappend ::oo::dialect::core_classes "${NSPACE}::class" + } + if { "${NSPACE}::object" ni $::oo::dialect::core_classes } { + lappend ::oo::dialect::core_classes "${NSPACE}::object" + } +} +proc ::oo::dialect::NSNormalize {namespace qualname} { + if {![string match ::* $qualname]} { + set qualname ${namespace}::$qualname + } + regsub -all {::+} $qualname "::" +} +proc ::oo::dialect::DefineThunk {target args} { + tailcall ::oo::define [Peek] $target {*}$args +} +proc ::oo::dialect::Canonical {namespace NSpace class} { + namespace upvar $namespace cname cname + #if {[string match ::* $class]} { + # return $class + #} + if {[info exists cname($class)]} { + return $cname($class) + } + if {[info exists ::oo::dialect::cname($class)]} { + return $::oo::dialect::cname($class) + } + if {[info exists ::oo::dialect::cname(${NSpace}::${class})]} { + return $::oo::dialect::cname(${NSpace}::${class}) + } + foreach item [list "${NSpace}::$class" "::$class"] { + if {[info commands $item] ne {}} { + return $item + } + } + return ${NSpace}::$class +} +proc ::oo::dialect::Define {namespace class args} { + Push $class + try { + if {[llength $args]==1} { + namespace eval ${namespace}::define [lindex $args 0] + } else { + ${namespace}::define::[lindex $args 0] {*}[lrange $args 1 end] + } + ${namespace}::dynamic_methods $class + } finally { + Pop + } +} +proc ::oo::dialect::Aliases {namespace args} { + set class [Peek] + namespace upvar $namespace cname cname + set NSpace [join [lrange [split $class ::] 1 end-2] ::] + set cname($class) $class + foreach name $args { + set cname($name) $class + #set alias $name + set alias [NSNormalize $NSpace $name] + # Add a local metaclass reference + if {![info exists ::oo::dialect::cname($alias)]} { + lappend ::oo::dialect::aliases($class) $alias + ## + # Add a global reference, first come, first served + ## + set ::oo::dialect::cname($alias) $class + } + } +} +proc ::oo::dialect::SuperClass {namespace args} { + set class [Peek] + namespace upvar $namespace class_info class_info + dict set class_info($class) superclass 1 + set ::oo::dialect::cname($class) $class + set NSpace [join [lrange [split $class ::] 1 end-2] ::] + set unique {} + foreach item $args { + set Item [Canonical $namespace $NSpace $item] + dict set unique $Item $item + } + set root ${namespace}::object + if {$class ne $root} { + dict set unique $root $root + } + tailcall ::oo::define $class superclass {*}[dict keys $unique] +} +if {[info command ::oo::dialect::MotherOfAllMetaClasses] eq {}} { +::oo::class create ::oo::dialect::MotherOfAllMetaClasses { + superclass ::oo::class + constructor {define definitionScript} { + $define [self] { + superclass + } + $define [self] $definitionScript + } + method aliases {} { + if {[info exists ::oo::dialect::aliases([self])]} { + return $::oo::dialect::aliases([self]) + } + } +} +} +namespace eval ::oo::dialect { + variable core_classes {::oo::class ::oo::object} +} +package provide oo::dialect 0.4 +package provide dicttool 1.2 +namespace eval ::dicttool { +} +namespace eval ::dicttool { +} +namespace eval ::tcllib { +} +proc ::tcllib::PROC {name arglist body {ninja {}}} { + if {[info commands $name] ne {}} return + proc $name $arglist $body + eval $ninja +} +if {[info commands ::PROC] eq {}} { + namespace eval ::tcllib { namespace export PROC } + namespace eval :: { namespace import ::tcllib::PROC } +} +proc ::tcllib::noop args {} +if {[info commands ::noop] eq {}} { + namespace eval ::tcllib { namespace export noop } + namespace eval :: { namespace import ::tcllib::noop } +} +proc ::tcllib::putb {buffername args} { + upvar 1 $buffername buffer + switch [llength $args] { + 1 { + append buffer [lindex $args 0] \n + } + 2 { + append buffer [string map {*}$args] \n + } + default { + error "usage: putb buffername ?map? string" + } + } +} +if {[info command ::putb] eq {}} { + namespace eval ::tcllib { namespace export putb } + namespace eval :: { namespace import ::tcllib::putb } +} +::tcllib::PROC ::tcl::dict::getnull {dictionary args} { + if {[exists $dictionary {*}$args]} { + get $dictionary {*}$args + } +} { + namespace ensemble configure dict -map [dict replace\ + [namespace ensemble configure dict -map] getnull ::tcl::dict::getnull] +} +::tcllib::PROC ::tcl::dict::is_dict { d } { + # is it a dict, or can it be treated like one? + if {[catch {dict size $d} err]} { + #::set ::errorInfo {} + return 0 + } + return 1 +} { + namespace ensemble configure dict -map [dict replace\ + [namespace ensemble configure dict -map] is_dict ::tcl::dict::is_dict] +} +::tcllib::PROC ::tcl::dict::rmerge {args} { + ::set result [dict create . {}] + # Merge b into a, and handle nested dicts appropriately + ::foreach b $args { + for { k v } $b { + ::set field [string trim $k :/] + if {![::dicttool::is_branch $b $k]} { + # Element names that end in ":" are assumed to be literals + set result $k $v + } elseif { [exists $result $k] } { + # key exists in a and b? let's see if both values are dicts + # both are dicts, so merge the dicts + if { [is_dict [get $result $k]] && [is_dict $v] } { + set result $k [rmerge [get $result $k] $v] + } else { + set result $k $v + } + } else { + set result $k $v + } + } + } + return $result +} { + namespace ensemble configure dict -map [dict replace\ + [namespace ensemble configure dict -map] rmerge ::tcl::dict::rmerge] +} +::tcllib::PROC ::dicttool::is_branch { dict path } { + set field [lindex $path end] + if {[string index $field end] eq ":"} { + return 0 + } + if {[string index $field 0] eq "."} { + return 0 + } + if {[string index $field end] eq "/"} { + return 1 + } + return [dict exists $dict {*}$path .] +} +::tcllib::PROC ::dicttool::print {dict} { + ::set result {} + ::set level -1 + ::dicttool::_dictputb $level result $dict + return $result +} +::tcllib::PROC ::dicttool::_dictputb {level varname dict} { + upvar 1 $varname result + incr level + dict for {field value} $dict { + if {$field eq "."} continue + if {[dicttool::is_branch $dict $field]} { + putb result "[string repeat " " $level]$field \{" + _dictputb $level result $value + putb result "[string repeat " " $level]\}" + } else { + putb result "[string repeat " " $level][list $field $value]" + } + } +} +proc ::dicttool::sanitize {dict} { + ::set result {} + ::set level -1 + ::dicttool::_sanitizeb {} result $dict + return $result +} +proc ::dicttool::_sanitizeb {path varname dict} { + upvar 1 $varname result + dict for {field value} $dict { + if {$field eq "."} continue + if {[dicttool::is_branch $dict $field]} { + _sanitizeb [list {*}$path $field] result $value + } else { + dict set result {*}$path $field $value + } + } +} +proc ::dicttool::storage {rawpath} { + set isleafvar 0 + set path {} + set tail [string index $rawpath end] + foreach element $rawpath { + set items [split [string trim $element /] /] + foreach item $items { + if {$item eq {}} continue + lappend path $item + } + } + return $path +} +proc ::dicttool::dictset {varname args} { + upvar 1 $varname result + if {[llength $args] < 2} { + error "Usage: ?path...? path value" + } elseif {[llength $args]==2} { + set rawpath [lindex $args 0] + } else { + set rawpath [lrange $args 0 end-1] + } + set value [lindex $args end] + set path [storage $rawpath] + set dot . + set one {} + dict set result $dot $one + set dpath {} + foreach item [lrange $path 0 end-1] { + set field $item + lappend dpath [string trim $item /] + dict set result {*}$dpath $dot $one + } + set field [lindex $rawpath end] + set ext [string index $field end] + if {$ext eq {:} || ![dict is_dict $value]} { + dict set result {*}$path $value + return + } + if {$ext eq {/} && ![dict exists $result {*}$path $dot]} { + dict set result {*}$path $dot $one + } + if {[dict exists $result {*}$path $dot]} { + dict set result {*}$path [::dicttool::merge [dict get $result {*}$path] $value] + return + } + dict set result {*}$path $value +} +proc ::dicttool::dictmerge {varname args} { + upvar 1 $varname result + set dot . + set one {} + dict set result $dot $one + foreach dict $args { + dict for {f v} $dict { + set field [string trim $f /] + set bbranch [dicttool::is_branch $dict $f] + if {![dict exists $result $field]} { + dict set result $field $v + if {$bbranch} { + dict set result $field [dicttool::merge $v] + } else { + dict set result $field $v + } + } elseif {[dict exists $result $field $dot]} { + if {$bbranch} { + dict set result $field [dicttool::merge [dict get $result $field] $v] + } else { + dict set result $field $v + } + } + } + } + return $result +} +proc ::dicttool::merge {args} { + ### + # The result of a merge is always a dict with branches + ### + set dot . + set one {} + dict set result $dot $one + set argument 0 + foreach b $args { + # Merge b into a, and handle nested dicts appropriately + if {![dict is_dict $b]} { + error "Element $b is not a dictionary" + } + dict for { k v } $b { + if {$k eq $dot} { + dict set result $dot $one + continue + } + set bbranch [is_branch $b $k] + set field [string trim $k /] + if { ![dict exists $result $field] } { + if {$bbranch} { + dict set result $field [merge $v] + } else { + dict set result $field $v + } + } else { + set abranch [dict exists $result $field $dot] + if {$abranch && $bbranch} { + dict set result $field [merge [dict get $result $field] $v] + } else { + dict set result $field $v + if {$bbranch} { + dict set result $field $dot $one + } + } + } + } + } + return $result +} +::tcllib::PROC ::tcl::dict::isnull {dictionary args} { + if {![exists $dictionary {*}$args]} {return 1} + return [expr {[get $dictionary {*}$args] in {{} NULL null}}] +} { + namespace ensemble configure dict -map [dict replace\ + [namespace ensemble configure dict -map] isnull ::tcl::dict::isnull] +} +namespace eval ::dictargs { +} +if {[info commands ::dictargs::parse] eq {}} { + proc ::dictargs::parse {argdef argdict} { + set result {} + dict for {field info} $argdef { + if {![string is alnum [string index $field 0]]} { + error "$field is not a simple variable name" + } + upvar 1 $field _var + set aliases {} + if {[dict exists $argdict $field]} { + set _var [dict get $argdict $field] + continue + } + if {[dict exists $info aliases:]} { + set found 0 + foreach {name} [dict get $info aliases:] { + if {[dict exists $argdict $name]} { + set _var [dict get $argdict $name] + set found 1 + break + } + } + if {$found} continue + } + if {[dict exists $info default:]} { + set _var [dict get $info default:] \n + continue + } + set mandatory 1 + if {[dict exists $info mandatory:]} { + set mandatory [dict get $info mandatory:] + } + if {$mandatory} { + error "$field is required" + } + } + } +} +proc ::dictargs::proc {name argspec body} { + set result {} + append result "::dictargs::parse \{$argspec\} \$args" \; + append result $body + uplevel 1 [list ::proc $name [list [list args [list dictargs $argspec]]] $result] +} +proc ::dictargs::method {name argspec body} { + set class [lindex [::info level -1] 1] + set result {} + append result "::dictargs::parse \{$argspec\} \$args" \; + append result $body + oo::define $class method $name [list [list args [list dictargs $argspec]]] $result +} +::tcllib::PROC ::dicttool::ladd {varname args} { + upvar 1 $varname var + if ![info exists var] { + set var {} + } + foreach item $args { + if {$item in $var} continue + lappend var $item + } + return $var +} +::tcllib::PROC ::dicttool::ldelete {varname args} { + upvar 1 $varname var + if ![info exists var] { + return + } + foreach item [lsort -unique $args] { + while {[set i [lsearch $var $item]]>=0} { + set var [lreplace $var $i $i] + } + } + return $var +} +::tcllib::PROC ::dicttool::lrandom list { + set len [llength $list] + set idx [expr int(rand()*$len)] + return [lindex $list $idx] +} +namespace eval ::dicttool { + namespace export * +} +package require Tcl 8.6 ;# try in pipeline.tcl. Possibly other things. +package require TclOO +::oo::dialect::create ::clay +::namespace eval ::clay { +} +::namespace eval ::clay::classes { +} +::namespace eval ::clay::define { +} +namespace eval ::clay { +} +set ::clay::trace 0 +proc ::clay::ancestors args { + set result {} + set queue [lreverse $args] + set result $queue + set metaclasses {} + while {[llength $queue]} { + set tqueue $queue + set queue {} + foreach qclass $tqueue { + foreach aclass [::info class superclasses $qclass] { + if { $aclass in $result } continue + if { $aclass in $queue } continue + lappend queue $aclass + } + } + foreach item $tqueue { + if { $item ni $result } { + lappend result $item + } + } + } + lappend result {*}$metaclasses + ### + # Screen out classes that do not participate in clay + # interactions + ### + set output {} + foreach {item} $result { + if {[catch {$item clay noop} err]} { + continue + } + lappend output $item + } + return $output +} +proc ::clay::args_to_dict args { + if {[llength $args]==1} { + return [lindex $args 0] + } + return $args +} +proc ::clay::args_to_options args { + set result {} + foreach {var val} [args_to_dict {*}$args] { + lappend result [string trim $var -:] $val + } + return $result +} +proc ::clay::dynamic_arguments {ensemble method arglist args} { + set idx 0 + set len [llength $args] + if {$len > [llength $arglist]} { + ### + # Catch if the user supplies too many arguments + ### + set dargs 0 + if {[lindex $arglist end] ni {args dictargs}} { + return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" + } + } + foreach argdef $arglist { + if {$argdef eq "args"} { + ### + # Perform args processing in the style of tcl + ### + uplevel 1 [list set args [lrange $args $idx end]] + break + } + if {$argdef eq "dictargs"} { + ### + # Perform args processing in the style of tcl + ### + uplevel 1 [list set args [lrange $args $idx end]] + ### + # Perform args processing in the style of clay + ### + set dictargs [::clay::args_to_options {*}[lrange $args $idx end]] + uplevel 1 [list set dictargs $dictargs] + break + } + if {$idx > $len} { + ### + # Catch if the user supplies too few arguments + ### + if {[llength $argdef]==1} { + return -code error -level 2 "Usage: $ensemble $method [string trim [dynamic_wrongargs_message $arglist]]" + } else { + uplevel 1 [list set [lindex $argdef 0] [lindex $argdef 1]] + } + } else { + uplevel 1 [list set [lindex $argdef 0] [lindex $args $idx]] + } + incr idx + } +} +proc ::clay::dynamic_wrongargs_message {arglist} { + set result "" + set dargs 0 + foreach argdef $arglist { + if {$argdef in {args dictargs}} { + set dargs 1 + break + } + if {[llength $argdef]==1} { + append result " $argdef" + } else { + append result " ?[lindex $argdef 0]?" + } + } + if { $dargs } { + append result " ?option value?..." + } + return $result +} +proc ::clay::is_dict { d } { + # is it a dict, or can it be treated like one? + if {[catch {::dict size $d} err]} { + #::set ::errorInfo {} + return 0 + } + return 1 +} +proc ::clay::is_null value { + return [expr {$value in {{} NULL}}] +} +proc ::clay::leaf args { + set marker [string index [lindex $args end] end] + set result [path {*}${args}] + if {$marker eq "/"} { + return $result + } + return [list {*}[lrange $result 0 end-1] [string trim [string trim [lindex $result end]] /]] +} +proc ::clay::path args { + set result {} + foreach item $args { + set item [string trim $item :./] + foreach subitem [split $item /] { + lappend result [string trim ${subitem}]/ + } + } + return $result +} +proc ::clay::script_path {} { + set path [file dirname [file join [pwd] [info script]]] + return $path +} +proc ::clay::NSNormalize qualname { + if {![string match ::* $qualname]} { + set qualname ::clay::classes::$qualname + } + regsub -all {::+} $qualname "::" +} +proc ::clay::uuid_generate args { + return [uuid::uuid generate] +} +namespace eval ::clay { + variable option_class {} + variable core_classes {::oo::class ::oo::object} +} +proc ::clay::dynamic_methods class { + foreach command [info commands [namespace current]::dynamic_methods_*] { + $command $class + } +} +proc ::clay::dynamic_methods_class {thisclass} { + set methods {} + set mdata [$thisclass clay find class_typemethod] + foreach {method info} $mdata { + if {$method eq {.}} continue + set method [string trimright $method :/-] + if {$method in $methods} continue + lappend methods $method + set arglist [dict getnull $info arglist] + set body [dict getnull $info body] + ::oo::objdefine $thisclass method $method $arglist $body + } +} +proc ::clay::define::Array {name {values {}}} { + set class [current_class] + set name [string trim $name :/] + $class clay branch array $name + dict for {var val} $values { + $class clay set array/ $name $var $val + } +} +proc ::clay::define::Delegate {name info} { + set class [current_class] + foreach {field value} $info { + $class clay set component/ [string trim $name :/]/ $field $value + } +} +proc ::clay::define::constructor {arglist rawbody} { + set body { +my variable DestroyEvent +set DestroyEvent 0 +::clay::object_create [self] [info object class [self]] +# Initialize public variables and options +my InitializePublic + } + append body $rawbody + set class [current_class] + ::oo::define $class constructor $arglist $body +} +proc ::clay::define::class_method {name arglist body} { + set class [current_class] + $class clay set class_typemethod/ [string trim $name :/] [dict create arglist $arglist body $body] +} +proc ::clay::define::clay {args} { + set class [current_class] + if {[lindex $args 0] in "cget set branch"} { + $class clay {*}$args + } else { + $class clay set {*}$args + } +} +proc ::clay::define::destructor rawbody { + set body { +# Run the destructor once and only once +set self [self] +my variable DestroyEvent +if {$DestroyEvent} return +set DestroyEvent 1 +::clay::object_destroy $self +} + append body $rawbody + ::oo::define [current_class] destructor $body +} +proc ::clay::define::Dict {name {values {}}} { + set class [current_class] + set name [string trim $name :/] + $class clay branch dict $name + foreach {var val} $values { + $class clay set dict/ $name/ $var $val + } +} +proc ::clay::define::Option {name args} { + set class [current_class] + set dictargs {default {}} + foreach {var val} [::clay::args_to_dict {*}$args] { + dict set dictargs [string trim $var -:/] $val + } + set name [string trimleft $name -] + + ### + # Option Class handling + ### + set optclass [dict getnull $dictargs class] + if {$optclass ne {}} { + foreach {f v} [$class clay find option_class $optclass] { + if {![dict exists $dictargs $f]} { + dict set dictargs $f $v + } + } + if {$optclass eq "variable"} { + variable $name [dict getnull $dictargs default] + } + } + foreach {f v} $dictargs { + $class clay set option $name $f $v + } +} +proc ::clay::define::Option_Class {name args} { + set class [current_class] + set dictargs {default {}} + set name [string trimleft $name -:] + foreach {f v} [::clay::args_to_dict {*}$args] { + $class clay set option_class $name [string trim $f -/:] $v + } +} +proc ::clay::define::Variable {name {default {}}} { + set class [current_class] + set name [string trimright $name :/] + $class clay set variable/ $name $default +} +proc ::clay::object_create {objname {class {}}} { + #if {$::clay::trace>0} { + # puts [list $objname CREATE] + #} +} +proc ::clay::object_rename {object newname} { + if {$::clay::trace>0} { + puts [list $object RENAME -> $newname] + } +} +proc ::clay::object_destroy objname { + if {$::clay::trace>0} { + puts [list $objname DESTROY] + } + ::cron::object_destroy $objname +} +::namespace eval ::clay::define { +} +proc ::clay::ensemble_methodbody {ensemble einfo} { + set default standard + set preamble {} + set eswitch {} + if {[dict exists $einfo default]} { + set emethodinfo [dict get $einfo default] + set arglist [dict getnull $emethodinfo arglist] + set realbody [dict get $emethodinfo body] + if {[llength $arglist]==1 && [lindex $arglist 0] in {{} args arglist}} { + set body {} + } else { + set body "\n ::clay::dynamic_arguments $ensemble \$method [list $arglist] {*}\$args" + } + append body "\n " [string trim $realbody] " \n" + set default $body + dict unset einfo default + } + foreach {msubmethod esubmethodinfo} [lsort -dictionary -stride 2 $einfo] { + set submethod [string trim $msubmethod :/-] + if {$submethod eq "_body"} continue + if {$submethod eq "_preamble"} { + set preamble [dict getnull $esubmethodinfo body] + continue + } + set arglist [dict getnull $esubmethodinfo arglist] + set realbody [dict getnull $esubmethodinfo body] + if {[string length [string trim $realbody]] eq {}} { + dict set eswitch $submethod {} + } else { + if {[llength $arglist]==1 && [lindex $arglist 0] in {{} args arglist}} { + set body {} + } else { + set body "\n ::clay::dynamic_arguments $ensemble \$method [list $arglist] {*}\$args" + } + append body "\n " [string trim $realbody] " \n" + if {$submethod eq "default"} { + set default $body + } else { + foreach alias [dict getnull $esubmethodinfo aliases] { + dict set eswitch $alias - + } + dict set eswitch $submethod $body + } + } + } + set methodlist [lsort -dictionary [dict keys $eswitch]] + if {![dict exists $eswitch ]} { + dict set eswitch {return $methodlist} + } + if {$default eq "standard"} { + set default "error \"unknown method $ensemble \$method. Valid: \$methodlist\"" + } + dict set eswitch default $default + set mbody {} + + append mbody $preamble \n + + append mbody \n [list set methodlist $methodlist] + append mbody \n "set code \[catch {switch -- \$method [list $eswitch]} result opts\]" + append mbody \n {return -options $opts $result} + return $mbody +} +::proc ::clay::define::Ensemble {rawmethod arglist body} { + set class [current_class] + #if {$::clay::trace>2} { + # puts [list $class Ensemble $rawmethod $arglist $body] + #} + set mlist [split $rawmethod "::"] + set ensemble [string trim [lindex $mlist 0] :/] + set mensemble ${ensemble}/ + if {[llength $mlist]==1 || [lindex $mlist 1] in "_body"} { + set method _body + ### + # Simple method, needs no parsing, but we do need to record we have one + ### + $class clay set method_ensemble/ $mensemble _body [dict create arglist $arglist body $body] + if {$::clay::trace>2} { + puts [list $class clay set method_ensemble/ $mensemble _body ...] + } + set method $rawmethod + if {$::clay::trace>2} { + puts [list $class Ensemble $rawmethod $arglist $body] + set rawbody $body + set body {puts [list [self] $class [self method]]} + append body \n $rawbody + } + ::oo::define $class method $rawmethod $arglist $body + return + } + set method [join [lrange $mlist 2 end] "::"] + $class clay set method_ensemble/ $mensemble [string trim [lindex $method 0] :/] [dict create arglist $arglist body $body] + if {$::clay::trace>2} { + puts [list $class clay set method_ensemble/ $mensemble [string trim $method :/] ...] + } +} +::oo::define ::clay::class { + method clay {submethod args} { + my variable clay + if {![info exists clay]} { + set clay {} + } + switch $submethod { + ancestors { + tailcall ::clay::ancestors [self] + } + branch { + set path [::dicttool::storage $args] + if {![dict exists $clay {*}$path .]} { + dict set clay {*}$path . {} + } + } + exists { + if {![info exists clay]} { + return 0 + } + set path [::dicttool::storage $args] + if {[dict exists $clay {*}$path]} { + return 1 + } + if {[dict exists $clay {*}[lrange $path 0 end-1] [lindex $path end]:]} { + return 1 + } + return 0 + } + dump { + return $clay + } + dget { + if {![info exists clay]} { + return {} + } + set path [::dicttool::storage $args] + if {[dict exists $clay {*}$path]} { + return [dict get $clay {*}$path] + } + if {[dict exists $clay {*}[lrange $path 0 end-1] [lindex $path end]:]} { + return [dict get $clay {*}[lrange $path 0 end-1] [lindex $path end]:] + } + return {} + } + is_branch { + set path [::dicttool::storage $args] + return [dict exists $clay {*}$path .] + } + getnull - + get { + if {![info exists clay]} { + return {} + } + set path [::dicttool::storage $args] + if {[llength $path]==0} { + return $clay + } + if {[dict exists $clay {*}$path .]} { + return [::dicttool::sanitize [dict get $clay {*}$path]] + } + if {[dict exists $clay {*}$path]} { + return [dict get $clay {*}$path] + } + if {[dict exists $clay {*}[lrange $path 0 end-1] [lindex $path end]:]} { + return [dict get $clay {*}[lrange $path 0 end-1] [lindex $path end]:] + } + return {} + } + find { + set path [::dicttool::storage $args] + if {![info exists clay]} { + set clay {} + } + set clayorder [::clay::ancestors [self]] + set found 0 + if {[llength $path]==0} { + set result [dict create . {}] + foreach class $clayorder { + ::dicttool::dictmerge result [$class clay dump] + } + return [::dicttool::sanitize $result] + } + foreach class $clayorder { + if {[$class clay exists {*}$path .]} { + # Found a branch break + set found 1 + break + } + if {[$class clay exists {*}$path]} { + # Found a leaf. Return that value immediately + return [$class clay get {*}$path] + } + if {[dict exists $clay {*}[lrange $path 0 end-1] [lindex $path end]:]} { + return [dict get $clay {*}[lrange $path 0 end-1] [lindex $path end]:] + } + } + if {!$found} { + return {} + } + set result {} + # Leaf searches return one data field at a time + # Search in our local dict + # Search in the in our list of classes for an answer + foreach class [lreverse $clayorder] { + ::dicttool::dictmerge result [$class clay dget {*}$path] + } + return [::dicttool::sanitize $result] + } + merge { + foreach arg $args { + ::dicttool::dictmerge clay {*}$arg + } + } + noop { + # Do nothing. Used as a sign of clay savviness + } + search { + foreach aclass [::clay::ancestors [self]] { + if {[$aclass clay exists {*}$args]} { + return [$aclass clay get {*}$args] + } + } + } + set { + ::dicttool::dictset clay {*}$args + } + unset { + dict unset clay {*}$args + } + default { + dict $submethod clay {*}$args + } + } + } +} +::oo::define ::clay::object { + method clay {submethod args} { + my variable clay claycache clayorder config option_canonical + if {![info exists clay]} {set clay {}} + if {![info exists claycache]} {set claycache {}} + if {![info exists config]} {set config {}} + if {![info exists clayorder] || [llength $clayorder]==0} { + set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] + } + switch $submethod { + ancestors { + return $clayorder + } + branch { + set path [::dicttool::storage $args] + if {![dict exists $clay {*}$path .]} { + dict set clay {*}$path . {} + } + } + cget { + # Leaf searches return one data field at a time + # Search in our local dict + if {[llength $args]==1} { + set field [string trim [lindex $args 0] -:/] + if {[info exists option_canonical($field)]} { + set field $option_canonical($field) + } + if {[dict exists $config $field]} { + return [dict get $config $field] + } + } + set path [::dicttool::storage $args] + if {[dict exists $clay {*}$path]} { + return [dict get $clay {*}$path] + } + # Search in our local cache + if {[dict exists $claycache {*}$path]} { + if {[dict exists $claycache {*}$path .]} { + return [dict remove [dict get $claycache {*}$path] .] + } else { + return [dict get $claycache {*}$path] + } + } + # Search in the in our list of classes for an answer + foreach class $clayorder { + if {[$class clay exists {*}$path]} { + set value [$class clay get {*}$path] + dict set claycache {*}$path $value + return $value + } + if {[$class clay exists const {*}$path]} { + set value [$class clay get const {*}$path] + dict set claycache {*}$path $value + return $value + } + if {[$class clay exists option {*}$path default]} { + set value [$class clay get option {*}$path default] + dict set claycache {*}$path $value + return $value + } + } + return {} + } + delegate { + if {![dict exists $clay .delegate ]} { + dict set clay .delegate [info object class [self]] + } + if {[llength $args]==0} { + return [dict get $clay .delegate] + } + if {[llength $args]==1} { + set stub <[string trim [lindex $args 0] <>]> + if {![dict exists $clay .delegate $stub]} { + return {} + } + return [dict get $clay .delegate $stub] + } + if {([llength $args] % 2)} { + error "Usage: delegate + OR + delegate stub + OR + delegate stub OBJECT ?stub OBJECT? ..." + } + foreach {stub object} $args { + set stub <[string trim $stub <>]> + dict set clay .delegate $stub $object + oo::objdefine [self] forward ${stub} $object + oo::objdefine [self] export ${stub} + } + } + dump { + # Do a full dump of clay data + set result {} + # Search in the in our list of classes for an answer + foreach class $clayorder { + ::dicttool::dictmerge result [$class clay dump] + } + ::dicttool::dictmerge result $clay + return $result + } + ensemble_map { + set ensemble [lindex $args 0] + my variable claycache + set mensemble [string trim $ensemble :/] + if {[dict exists $claycache method_ensemble $mensemble]} { + return [dicttool::sanitize [dict get $claycache method_ensemble $mensemble]] + } + set emap [my clay dget method_ensemble $mensemble] + dict set claycache method_ensemble $mensemble $emap + return [dicttool::sanitize $emap] + } + eval { + set script [lindex $args 0] + set buffer {} + set thisline {} + foreach line [split $script \n] { + append thisline $line + if {![info complete $thisline]} { + append thisline \n + continue + } + set thisline [string trim $thisline] + if {[string index $thisline 0] eq "#"} continue + if {[string length $thisline]==0} continue + if {[lindex $thisline 0] eq "my"} { + # Line already calls out "my", accept verbatim + append buffer $thisline \n + } elseif {[string range $thisline 0 2] eq "::"} { + # Fully qualified commands accepted verbatim + append buffer $thisline \n + } elseif { + append buffer "my $thisline" \n + } + set thisline {} + } + eval $buffer + } + evolve - + initialize { + my InitializePublic + } + exists { + # Leaf searches return one data field at a time + # Search in our local dict + set path [::dicttool::storage $args] + if {[dict exists $clay {*}$path]} { + return 1 + } + # Search in our local cache + if {[dict exists $claycache {*}$path]} { + return 2 + } + set count 2 + # Search in the in our list of classes for an answer + foreach class $clayorder { + incr count + if {[$class clay exists {*}$path]} { + return $count + } + } + return 0 + } + flush { + set claycache {} + set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] + } + forward { + oo::objdefine [self] forward {*}$args + } + dget { + # Search in our local cache + set path [::dicttool::storage $args] + if {[llength $path]==0} { + # Do a full dump of clay data + set result {} + # Search in the in our list of classes for an answer + foreach class $clayorder { + ::dicttool::dictmerge result [$class clay dump] + } + ::dicttool::dictmerge result $clay + return $result + } + #if {[dict exists $claycache {*}$path]} { + # return [dict get $claycache {*}$path] + #} + if {[dict exists $clay {*}$path .]} { + # Path is a branch + set result {} + foreach class [lreverse $clayorder] { + if {[$class clay exists {*}$path .]} { + set value [$class clay dget {*}$path] + ::dicttool::dictmerge result $value + } + } + ::dicttool::dictmerge result [dict get $clay {*}$path] + dict set claycache {*}$path $result + return $result + } elseif {[dict exists $clay {*}$path]} { + # Path is a leaf + return [dict get $clay {*}$path] + } + # Search in the in our list of classes for an answer + set found 0 + foreach class $clayorder { + if {[$class clay exists {*}$path .]} { + set found 1 + break + } + if {[$class clay exists {*}$path]} { + # Found a leaf. + set result [$class clay get {*}$path] + dict set claycache {*}$path $result + return $result + } + } + set result {} + if {$found} { + # One of our ancestors has this as a branch + # Do a recursive merge across all classes + foreach class [lreverse $clayorder] { + if {[$class clay exists {*}$path .]} { + set value [$class clay dget {*}$path] + ::dicttool::dictmerge result $value + } + } + } + dict set claycache {*}$path $result + return $result + } + getnull - + get { + set path [::dicttool::storage $args] + if {[llength $path]==0} { + # Do a full dump of clay data + set result {} + # Search in the in our list of classes for an answer + foreach class $clayorder { + ::dicttool::dictmerge result [$class clay dump] + } + ::dicttool::dictmerge result $clay + return [::dicttool::sanitize $result] + } + if {[dict exists $claycache {*}$path .]} { + return [::dicttool::sanitize [dict get $claycache {*}$path]] + } + if {[dict exists $claycache {*}$path]} { + return [dict get $claycache {*}$path] + } + if {[dict exists $clay {*}$path] && ![dict exists $clay {*}$path .]} { + # Path is a leaf + return [dict get $clay {*}$path] + } + set found 0 + set branch [dict exists $clay {*}$path .] + foreach class $clayorder { + if {[$class clay exists {*}$path .]} { + set found 1 + break + } + if {!$branch && [$class clay exists {*}$path]} { + set result [$class clay dget {*}$path] + dict set claycache {*}$path $result + return $result + } + } + # Path is a branch + set result {} + foreach class [lreverse $clayorder] { + if {[$class clay exists {*}$path .]} { + set value [$class clay dget {*}$path] + ::dicttool::dictmerge result $value + } + } + if {[dict exists $clay {*}$path .]} { + ::dicttool::dictmerge result [dict get $clay {*}$path] + } + dict set claycache {*}$path $result + return [dicttool::sanitize $result] + } + leaf { + # Leaf searches return one data field at a time + # Search in our local dict + set path [::dicttool::storage $args] + if {[dict exists $clay {*}$path .]} { + return [dicttool::sanitize [dict get $clay {*}$path]] + } + if {[dict exists $clay {*}$path]} { + return [dict get $clay {*}$path] + } + # Search in our local cache + if {[dict exists $claycache {*}$path .]} { + return [dicttool::sanitize [dict get $claycache {*}$path]] + } + if {[dict exists $claycache {*}$path]} { + return [dict get $claycache {*}$path] + } + # Search in the in our list of classes for an answer + foreach class $clayorder { + if {[$class clay exists {*}$path]} { + set value [$class clay get {*}$path] + dict set claycache {*}$path $value + return $value + } + } + } + merge { + foreach arg $args { + ::dicttool::dictmerge clay {*}$arg + } + } + mixin { + ### + # Mix in the class + ### + set prior [info object mixins [self]] + set newmixin {} + foreach item $args { + lappend newmixin ::[string trimleft $item :] + } + set newmap $args + foreach class $prior { + if {$class ni $newmixin} { + set script [$class clay search mixin/ unmap-script] + if {[string length $script]} { + if {[catch $script err errdat]} { + puts stderr "[self] MIXIN ERROR POPPING $class:\n[dict get $errdat -errorinfo]" + } + } + } + } + ::oo::objdefine [self] mixin {*}$args + ### + # Build a compsite map of all ensembles defined by the object's current + # class as well as all of the classes being mixed in + ### + my InitializePublic + foreach class $newmixin { + if {$class ni $prior} { + set script [$class clay search mixin/ map-script] + if {[string length $script]} { + if {[catch $script err errdat]} { + puts stderr "[self] MIXIN ERROR PUSHING $class:\n[dict get $errdat -errorinfo]" + } + } + } + } + foreach class $newmixin { + set script [$class clay search mixin/ react-script] + if {[string length $script]} { + if {[catch $script err errdat]} { + puts stderr "[self] MIXIN ERROR PEEKING $class:\n[dict get $errdat -errorinfo]" + } + break + } + } + } + mixinmap { + my variable clay + if {![dict exists $clay .mixin]} { + dict set clay .mixin {} + } + if {[llength $args]==0} { + return [dict get $clay .mixin] + } elseif {[llength $args]==1} { + return [dict getnull $clay .mixin [lindex $args 0]] + } else { + foreach {slot classes} $args { + dict set clay .mixin $slot $classes + } + set claycache {} + set classlist {} + foreach {item class} [dict get $clay .mixin] { + if {$class ne {}} { + lappend classlist $class + } + } + my clay mixin {*}[lreverse $classlist] + } + } + provenance { + if {[dict exists $clay {*}$args]} { + return self + } + foreach class $clayorder { + if {[$class clay exists {*}$args]} { + return $class + } + } + return {} + } + replace { + set clay [lindex $args 0] + } + source { + source [lindex $args 0] + } + set { + #puts [list [self] clay SET {*}$args] + set claycache {} + ::dicttool::dictset clay {*}$args + } + default { + dict $submethod clay {*}$args + } + } + } + method InitializePublic {} { + my variable clayorder clay claycache config option_canonical + set claycache {} + set clayorder [::clay::ancestors [info object class [self]] {*}[info object mixins [self]]] + if {![info exists clay]} { + set clay {} + } + if {![info exists config]} { + set config {} + } + dict for {var value} [my clay get variable] { + if { $var in {. clay} } continue + set var [string trim $var :/] + my variable $var + if {![info exists $var]} { + if {$::clay::trace>2} {puts [list initialize variable $var $value]} + set $var $value + } + } + dict for {var value} [my clay get dict/] { + if { $var in {. clay} } continue + set var [string trim $var :/] + my variable $var + if {![info exists $var]} { + set $var {} + } + foreach {f v} $value { + if {$f eq "."} continue + if {![dict exists ${var} $f]} { + if {$::clay::trace>2} {puts [list initialize dict $var $f $v]} + dict set ${var} $f $v + } + } + } + foreach {var value} [my clay get array/] { + if { $var in {. clay} } continue + set var [string trim $var :/] + if { $var eq {clay} } continue + my variable $var + if {![info exists $var]} { array set $var {} } + foreach {f v} $value { + if {![array exists ${var}($f)]} { + if {$f eq "."} continue + if {$::clay::trace>2} {puts [list initialize array $var\($f\) $v]} + set ${var}($f) $v + } + } + } + foreach {field info} [my clay get option/] { + if { $field in {. clay} } continue + set field [string trim $field -/:] + foreach alias [dict getnull $info aliases] { + set option_canonical($alias) $field + } + if {[dict exists $config $field]} continue + set getcmd [dict getnull $info default-command] + if {$getcmd ne {}} { + set value [{*}[string map [list %field% $field %self% [namespace which my]] $getcmd]] + } else { + set value [dict getnull $info default] + } + dict set config $field $value + set setcmd [dict getnull $info set-command] + if {$setcmd ne {}} { + {*}[string map [list %field% [list $field] %value% [list $value] %self% [namespace which my]] $setcmd] + } + } + my variable clayorder clay claycache + if {[info exists clay]} { + set emap [dict getnull $clay method_ensemble] + } else { + set emap {} + } + foreach class [lreverse $clayorder] { + ### + # Build a compsite map of all ensembles defined by the object's current + # class as well as all of the classes being mixed in + ### + dict for {mensemble einfo} [$class clay get method_ensemble] { + if {$mensemble eq {.}} continue + set ensemble [string trim $mensemble :/] + if {$::clay::trace>2} {puts [list Defining $ensemble from $class]} + + dict for {method info} $einfo { + if {$method eq {.}} continue + if {![dict is_dict $info]} { + puts [list WARNING: class: $class method: $method not dict: $info] + continue + } + dict set info source $class + if {$::clay::trace>2} {puts [list Defining $ensemble -> $method from $class - $info]} + dict set emap $ensemble $method $info + } + } + } + foreach {ensemble einfo} $emap { + #if {[dict exists $einfo _body]} continue + set body [::clay::ensemble_methodbody $ensemble $einfo] + if {$::clay::trace>2} { + set rawbody $body + set body {puts [list [self] [self method]]} + append body \n $rawbody + } + oo::objdefine [self] method $ensemble {{method default} args} $body + } + } +} +::clay::object clay branch array +::clay::object clay branch mixin +::clay::object clay branch option +::clay::object clay branch dict clay +::clay::object clay set variable DestroyEvent 0 +namespace eval ::clay { + namespace export * +} + +### +# END: clay/clay.tcl +### +### +# START: setup.tcl +### +package require TclOO +set tcllib_path {} +foreach path {.. ../.. ../../..} { + foreach path [glob -nocomplain [file join [file normalize $path] tcllib* modules]] { + set tclib_path $path + lappend ::auto_path $path + break + } + if {$tcllib_path ne {}} break +} +namespace eval ::practcl { +} +namespace eval ::practcl::OBJECT { +} + +### +# END: setup.tcl +### +### +# START: doctool.tcl +### +namespace eval ::practcl { +} +proc ::practcl::cat fname { + if {![file exists $fname]} { + return + } + set fin [open $fname r] + set data [read $fin] + close $fin + return $data +} +proc ::practcl::docstrip text { + set result {} + foreach line [split $text \n] { + append thisline $line \n + if {![info complete $thisline]} continue + set outline $thisline + set thisline {} + if {[string trim $outline] eq {}} { + continue + } + if {[string index [string trim $outline] 0] eq "#"} continue + set cmd [string trim [lindex $outline 0] :] + if {$cmd eq "namespace" && [lindex $outline 1] eq "eval"} { + append result [list {*}[lrange $outline 0 end-1]] " " \{ \n [docstrip [lindex $outline end]]\} \n + continue + } + if {[string match "*::define" $cmd] && [llength $outline]==3} { + append result [list {*}[lrange $outline 0 end-1]] " " \{ \n [docstrip [lindex $outline end]]\} \n + continue + } + if {$cmd eq "oo::class" && [lindex $outline 1] eq "create"} { + append result [list {*}[lrange $outline 0 end-1]] " " \{ \n [docstrip [lindex $outline end]]\} \n + continue + } + append result $outline + } + return $result +} +proc ::putb {buffername args} { + upvar 1 $buffername buffer + switch [llength $args] { + 1 { + append buffer [lindex $args 0] \n + } + 2 { + append buffer [string map {*}$args] \n + } + default { + error "usage: putb buffername ?map? string" + } + } +} +::oo::class create ::practcl::doctool { + constructor {} { + my reset + } + method arglist {arglist} { + set result [dict create] + foreach arg $arglist { + set name [lindex $arg 0] + dict set result $name positional 1 + dict set result $name mandatory 1 + if {$name in {args dictargs}} { + switch [llength $arg] { + 1 { + dict set result $name mandatory 0 + } + 2 { + dict for {optname optinfo} [lindex $arg 1] { + set optname [string trim $optname -:] + dict set result $optname {positional 1 mandatory 0} + dict for {f v} $optinfo { + dict set result $optname [string trim $f -:] $v + } + } + } + default { + error "Bad argument" + } + } + } else { + switch [llength $arg] { + 1 { + dict set result $name mandatory 1 + } + 2 { + dict set result $name mandatory 0 + dict set result $name default [lindex $arg 1] + } + default { + error "Bad argument" + } + } + } + } + return $result + } + method comment block { + set count 0 + set field description + set result [dict create description {}] + foreach line [split $block \n] { + set sline [string trim $line] + set fwidx [string first " " $sline] + if {$fwidx < 0} { + set firstword [string range $sline 0 end] + set restline {} + } else { + set firstword [string range $sline 0 [expr {$fwidx-1}]] + set restline [string range $sline [expr {$fwidx+1}] end] + } + if {[string index $firstword end] eq ":"} { + set field [string tolower [string trim $firstword -:]] + switch $field { + desc { + set field description + } + } + if {[string length $restline]} { + dict append result $field "$restline\n" + } + } else { + dict append result $field "$line\n" + } + } + return $result + } + method keyword.Annotation {resultvar commentblock type name body} { + upvar 1 $resultvar result + set name [string trim $name :] + if {[dict exists $result $type $name]} { + set info [dict get $result $type $name] + } else { + set info [my comment $commentblock] + } + foreach {f v} $body { + dict set info $f $v + } + dict set result $type $name $info + } + method keyword.Class {resultvar commentblock name body} { + upvar 1 $resultvar result + set name [string trim $name :] + if {[dict exists $result class $name]} { + set info [dict get $result class $name] + } else { + set info [my comment $commentblock] + } + set commentblock {} + foreach line [split $body \n] { + append thisline $line \n + if {![info complete $thisline]} continue + set thisline [string trim $thisline] + if {[string index $thisline 0] eq "#"} { + append commentblock [string trimleft $thisline #] \n + set thisline {} + continue + } + set cmd [string trim [lindex $thisline 0] ":"] + switch $cmd { + Option - + option { + my keyword.Annotation info $commentblock option [lindex $thisline 1] [lindex $thisline 2] + set commentblock {} + } + variable - + Variable { + my keyword.Annotation info $commentblock variable [lindex $thisline 1] [list type scaler default [lindex $thisline 2]] + set commentblock {} + } + Dict - + Array { + set iinfo [lindex $thisline 2] + dict set iinfo type [string tolower $cmd] + my keyword.Annotation info $commentblock variable [lindex $thisline 1] $iinfo + set commentblock {} + } + Componant - + Delegate { + my keyword.Annotation info $commentblock delegate [lindex $thisline 1] [lindex $thisline 2] + set commentblock {} + } + method - + Ensemble { + my keyword.class_method info $commentblock {*}[lrange $thisline 1 end-1] + set commentblock {} + } + } + set thisline {} + } + dict set result class $name $info + } + method keyword.class {resultvar commentblock name body} { + upvar 1 $resultvar result + set name [string trim $name :] + if {[dict exists $result class $name]} { + set info [dict get $result class $name] + } else { + set info [my comment $commentblock] + } + set commentblock {} + foreach line [split $body \n] { + append thisline $line \n + if {![info complete $thisline]} continue + set thisline [string trim $thisline] + if {[string index $thisline 0] eq "#"} { + append commentblock [string trimleft $thisline #] \n + set thisline {} + continue + } + set cmd [string trim [lindex $thisline 0] ":"] + switch $cmd { + Option - + option { + puts [list keyword.Annotation $cmd $thisline] + my keyword.Annotation info $commentblock option [lindex $thisline 1] [lindex $thisline 2] + set commentblock {} + } + variable - + Variable { + my keyword.Annotation info $commentblock variable [lindex $thisline 1] [list default [lindex $thisline 2]] + set commentblock {} + } + Dict - + Array { + set iinfo [lindex $thisline 2] + dict set iinfo type [string tolower $cmd] + my keyword.Annotation info $commentblock variable [lindex $thisline 1] $iinfo + set commentblock {} + } + Componant - + Delegate { + my keyword.Annotation info $commentblock delegate [lindex $thisline 1] [lindex $thisline 2] + set commentblock {} + } + superclass { + dict set info ancestors [lrange $thisline 1 end] + set commentblock {} + } + class_method { + my keyword.class_method info $commentblock {*}[lrange $thisline 1 end-1] + set commentblock {} + } + destructor - + constructor { + my keyword.method info $commentblock {*}[lrange $thisline 0 end-1] + set commentblock {} + } + method - + Ensemble { + my keyword.method info $commentblock {*}[lrange $thisline 1 end-1] + set commentblock {} + } + } + set thisline {} + } + dict set result class $name $info + } + method keyword.class_method {resultvar commentblock name args} { + upvar 1 $resultvar result + set info [my comment $commentblock] + if {[dict exists $info show_body] && [dict get $info show_body]} { + dict set info internals [lindex $args end] + } + if {[dict exists $info ensemble]} { + dict for {method minfo} [dict get $info ensemble] { + dict set result class_method "${name} $method" $minfo + } + } else { + switch [llength $args] { + 1 { + set arglist [lindex $args 0] + } + 0 { + set arglist dictargs + #set body [lindex $args 0] + } + default {error "could not interpret method $name {*}$args"} + } + if {![dict exists $info arglist]} { + dict set info arglist [my arglist $arglist] + } + dict set result class_method [string trim $name :] $info + } + } + method keyword.method {resultvar commentblock name args} { + upvar 1 $resultvar result + set info [my comment $commentblock] + if {[dict exists $info show_body] && [dict get $info show_body]} { + dict set info internals [lindex $args end] + } + if {[dict exists $info ensemble]} { + dict for {method minfo} [dict get $info ensemble] { + dict set result method "\"${name} $method\"" $minfo + } + } else { + switch [llength $args] { + 1 { + set arglist [lindex $args 0] + } + 0 { + set arglist dictargs + #set body [lindex $args 0] + } + default {error "could not interpret method $name {*}$args"} + } + if {![dict exists $info arglist]} { + dict set info arglist [my arglist $arglist] + } + dict set result method "\"[split [string trim $name :] ::]\"" $info + } + } + method keyword.proc {commentblock name arglist} { + set info [my comment $commentblock] + if {![dict exists $info arglist]} { + dict set info arglist [my arglist $arglist] + } + return $info + } + method reset {} { + my variable coro + set coro [info object namespace [self]]::coro + oo::objdefine [self] forward coro $coro + if {[info command $coro] ne {}} { + rename $coro {} + } + coroutine $coro {*}[namespace code {my Main}] + } + method Main {} { + + my variable info + set info [dict create] + yield [info coroutine] + set thisline {} + set commentblock {} + set linec 0 + while 1 { + set line [yield] + append thisline $line \n + if {![info complete $thisline]} continue + set thisline [string trim $thisline] + if {[string index $thisline 0] eq "#"} { + append commentblock [string trimleft $thisline #] \n + set thisline {} + continue + } + set cmd [string trim [lindex $thisline 0] ":"] + switch $cmd { + dictargs::proc { + set procinfo [my keyword.proc $commentblock [lindex $thisline 1] [list args [list dictargs [lindex $thisline 2]]]] + if {[dict exists $procinfo show_body] && [dict get $procinfo show_body]} { + dict set procinfo internals [lindex $thisline end] + } + dict set info proc [string trim [lindex $thisline 1] :] $procinfo + set commentblock {} + } + tcllib::PROC - + PROC - + Proc - + proc { + set procinfo [my keyword.proc $commentblock {*}[lrange $thisline 1 2]] + if {[dict exists $procinfo show_body] && [dict get $procinfo show_body]} { + dict set procinfo internals [lindex $thisline end] + } + dict set info proc [string trim [lindex $thisline 1] :] $procinfo + set commentblock {} + } + oo::objdefine { + if {[llength $thisline]==3} { + lassign $thisline tcmd name body + my keyword.Class info $commentblock $name $body + } else { + puts "Warning: bare oo::define in library" + } + } + oo::define { + if {[llength $thisline]==3} { + lassign $thisline tcmd name body + my keyword.class info $commentblock $name $body + } else { + puts "Warning: bare oo::define in library" + } + } + tao::define - + clay::define - + tool::define { + lassign $thisline tcmd name body + my keyword.class info $commentblock $name $body + set commentblock {} + } + oo::class { + lassign $thisline tcmd mthd name body + my keyword.class info $commentblock $name $body + set commentblock {} + } + default { + if {[lindex [split $cmd ::] end] eq "define"} { + lassign $thisline tcmd name body + my keyword.class info $commentblock $name $body + set commentblock {} + } + set commentblock {} + } + } + set thisline {} + } + } + method section.method {keyword method minfo} { + set result {} + set line "\[call $keyword \[cmd $method\]" + if {[dict exists $minfo arglist]} { + dict for {argname arginfo} [dict get $minfo arglist] { + set positional 1 + set mandatory 1 + set repeating 0 + dict with arginfo {} + if {$mandatory==0} { + append line " \[opt \"" + } else { + append line " " + } + if {$positional} { + append line "\[arg $argname" + } else { + append line "\[option \"$argname" + if {[dict exists $arginfo type]} { + append line " \[emph [dict get $arginfo type]\]" + } else { + append line " \[emph value\]" + } + append line "\"" + } + append line "\]" + if {$mandatory==0} { + if {[dict exists $arginfo default]} { + append line " \[const \"[dict get $arginfo default]\"\]" + } + append line "\"\]" + } + if {$repeating} { + append line " \[opt \[option \"$argname...\"\]\]" + } + } + } + append line \] + putb result $line + if {[dict exists $minfo description]} { + putb result [dict get $minfo description] + } + if {[dict exists $minfo example]} { + putb result "\[para\]Example: \[example [list [dict get $minfo example]]\]" + } + if {[dict exists $minfo internals]} { + putb result "\[para\]Internals: \[example [list [dict get $minfo internals]]\]" + } + return $result + } + method section.annotation {type name iinfo} { + set result "\[call $type \[cmd $name\]\]" + if {[dict exists $iinfo description]} { + putb result [dict get $iinfo description] + } + if {[dict exists $iinfo example]} { + putb result "\[para\]Example: \[example [list [dict get $minfo example]]\]" + } + return $result + } + method section.class {class_name class_info} { + set result {} + putb result "\[subsection \{Class $class_name\}\]" + if {[dict exists $class_info ancestors]} { + set line "\[emph \"ancestors\"\]:" + foreach {c} [dict get $class_info ancestors] { + append line " \[class [string trim $c :]\]" + } + putb result $line + putb result {[para]} + } + dict for {f v} $class_info { + if {$f in {class_method method description ancestors example option variable delegate}} continue + putb result "\[emph \"$f\"\]: $v" + putb result {[para]} + } + if {[dict exists $class_info example]} { + putb result "\[example \{[list [dict get $class_info example]]\}\]" + putb result {[para]} + } + if {[dict exists $class_info description]} { + putb result [dict get $class_info description] + putb result {[para]} + } + dict for {f v} $class_info { + if {$f ni {option variable delegate}} continue + putb result "\[class \{[string totitle $f]\}\]" + #putb result "Methods on the class object itself." + putb result {[list_begin definitions]} + dict for {item iinfo} [dict get $class_info $f] { + putb result [my section.annotation $f $item $iinfo] + } + putb result {[list_end]} + putb result {[para]} + } + if {[dict exists $class_info class_method]} { + putb result "\[class \{Class Methods\}\]" + #putb result "Methods on the class object itself." + putb result {[list_begin definitions]} + dict for {method minfo} [dict get $class_info class_method] { + putb result [my section.method classmethod $method $minfo] + } + putb result {[list_end]} + putb result {[para]} + } + if {[dict exists $class_info method]} { + putb result "\[class {Methods}\]" + putb result {[list_begin definitions]} + dict for {method minfo} [dict get $class_info method] { + putb result [my section.method method $method $minfo] + } + putb result {[list_end]} + putb result {[para]} + } + return $result + } + method section.command {procinfo} { + set result {} + putb result "\[section \{Commands\}\]" + putb result {[list_begin definitions]} + dict for {method minfo} $procinfo { + putb result [my section.method proc $method $minfo] + } + putb result {[list_end]} + return $result + } + method manpage args { + my variable info + set map {%version% 0.0 %module% {Your_Module_Here}} + set result {} + set header {} + set footer {} + set authors {} + dict with args {} + dict set map %keyword% comment + putb result $map {[%keyword% {-*- tcl -*- doctools manpage}] +[vset PACKAGE_VERSION %version%] +[manpage_begin %module% n [vset PACKAGE_VERSION]]} + putb result $map $header + + dict for {sec_type sec_info} $info { + switch $sec_type { + proc { + putb result [my section.command $sec_info] + } + class { + putb result "\[section Classes\]" + dict for {class_name class_info} $sec_info { + putb result [my section.class $class_name $class_info] + } + } + default { + putb result "\[section [list $sec_type $sec_name]\]" + if {[dict exists $sec_info description]} { + putb result [dict get $sec_info description] + } + } + } + } + if {[llength $authors]} { + putb result {[section AUTHORS]} + foreach {name email} $authors { + putb result "$name \[uri mailto:$email\]\[para\]" + } + } + putb result $footer + putb result {[manpage_end]} + return $result + } + method scan_text {text} { + my variable linecount coro + set linecount 0 + foreach line [split $text \n] { + incr linecount + $coro $line + } + } + method scan_file {filename} { + my variable linecount coro + set fin [open $filename r] + set linecount 0 + while {[gets $fin line]>=0} { + incr linecount + $coro $line + } + close $fin + } +} + +### +# END: doctool.tcl +### +### +# START: buildutil.tcl +### +proc Proc {name arglist body} { + if {[info command $name] ne {}} return + proc $name $arglist $body +} +Proc ::noop args {} +proc ::practcl::debug args { + #puts $args + ::practcl::cputs ::DEBUG_INFO $args +} +proc ::practcl::doexec args { + puts [list {*}$args] + exec {*}$args >&@ stdout +} +proc ::practcl::doexec_in {path args} { + set PWD [pwd] + cd $path + puts [list {*}$args] + exec {*}$args >&@ stdout + cd $PWD +} +proc ::practcl::dotclexec args { + puts [list [info nameofexecutable] {*}$args] + exec [info nameofexecutable] {*}$args >&@ stdout +} +proc ::practcl::domake {path args} { + set PWD [pwd] + cd $path + puts [list *** $path ***] + puts [list make {*}$args] + exec make {*}$args >&@ stdout + cd $PWD +} +proc ::practcl::domake.tcl {path args} { + set PWD [pwd] + cd $path + puts [list *** $path ***] + puts [list make.tcl {*}$args] + exec [info nameofexecutable] make.tcl {*}$args >&@ stdout + cd $PWD +} +proc ::practcl::fossil {path args} { + set PWD [pwd] + cd $path + puts [list {*}$args] + exec fossil {*}$args >&@ stdout + cd $PWD +} +proc ::practcl::fossil_status {dir} { + if {[info exists ::fosdat($dir)]} { + return $::fosdat($dir) + } + set result { +tags experimental +version {} + } + set pwd [pwd] + cd $dir + set info [exec fossil status] + cd $pwd + foreach line [split $info \n] { + if {[lindex $line 0] eq "checkout:"} { + set hash [lindex $line end-3] + set maxdate [lrange $line end-2 end-1] + dict set result hash $hash + dict set result maxdate $maxdate + regsub -all {[^0-9]} $maxdate {} isodate + dict set result isodate $isodate + } + if {[lindex $line 0] eq "tags:"} { + set tags [lrange $line 1 end] + dict set result tags $tags + break + } + } + set ::fosdat($dir) $result + return $result +} +proc ::practcl::os {} { + return [${::practcl::MAIN} define get TEACUP_OS] +} +proc ::practcl::mkzip {exename barekit vfspath} { + ::practcl::tcllib_require zipfile::mkzip + ::zipfile::mkzip::mkzip $exename -runtime $barekit -directory $vfspath +} +proc ::practcl::sort_dict list { + return [::lsort -stride 2 -dictionary $list] +} +if {[::package vcompare $::tcl_version 8.6] < 0} { + # Approximate ::zipfile::mkzip with exec calls + proc ::practcl::mkzip {exename barekit vfspath} { + set path [file dirname [file normalize $exename]] + set zipfile [file join $path [file rootname $exename].zip] + file copy -force $barekit $exename + set pwd [pwd] + cd $vfspath + exec zip -r $zipfile . + cd $pwd + set fout [open $exename a] + set fin [open $zipfile r] + chan configure $fout -translation binary + chan configure $fin -translation binary + chan copy $fin $fout + chan close $fin + chan close $fout + exec zip -A $exename + } + proc ::practcl::sort_dict list { + set result {} + foreach key [lsort -dictionary [dict keys $list]] { + dict set result $key [dict get $list $key] + } + return $result + } +} +proc ::practcl::local_os {} { + # If we have already run this command, return + # a cached copy of the data + if {[info exists ::practcl::LOCAL_INFO]} { + return $::practcl::LOCAL_INFO + } + set result [array get ::practcl::CONFIG] + dict set result TEACUP_PROFILE unknown + dict set result TEACUP_OS unknown + dict set result EXEEXT {} + set windows 0 + if {$::tcl_platform(platform) eq "windows"} { + set windows 1 + } + if {$windows} { + set system "windows" + set arch ix86 + dict set result TEACUP_PROFILE win32-ix86 + dict set result TEACUP_OS windows + dict set result EXEEXT .exe + } else { + set system [exec uname -s]-[exec uname -r] + set arch unknown + dict set result TEACUP_OS generic + } + dict set result TEA_PLATFORM $system + dict set result TEA_SYSTEM $system + if {[info exists ::SANDBOX]} { + dict set result sandbox $::SANDBOX + } + switch -glob $system { + Linux* { + dict set result TEACUP_OS linux + set arch [exec uname -m] + dict set result TEACUP_PROFILE "linux-glibc2.3-$arch" + } + GNU* { + set arch [exec uname -m] + dict set result TEACUP_OS "gnu" + } + NetBSD-Debian { + set arch [exec uname -m] + dict set result TEACUP_OS "netbsd-debian" + } + OpenBSD-* { + set arch [exec arch -s] + dict set result TEACUP_OS "openbsd" + } + Darwin* { + set arch [exec uname -m] + dict set result TEACUP_OS "macosx" + if {$arch eq "x86_64"} { + dict set result TEACUP_PROFILE "macosx10.5-i386-x86_84" + } else { + dict set result TEACUP_PROFILE "macosx-universal" + } + } + OpenBSD* { + set arch [exec arch -s] + dict set result TEACUP_OS "openbsd" + } + } + if {$arch eq "unknown"} { + catch {set arch [exec uname -m]} + } + switch -glob $arch { + i*86 { + set arch "ix86" + } + amd64 { + set arch "x86_64" + } + } + dict set result TEACUP_ARCH $arch + if {[dict get $result TEACUP_PROFILE] eq "unknown"} { + dict set result TEACUP_PROFILE [dict get $result TEACUP_OS]-$arch + } + set OS [dict get $result TEACUP_OS] + dict set result os $OS + + # Look for a local preference file + set pathlist {} + set userhome [file normalize ~/tcl] + set local_install [file join $userhome lib] + switch $OS { + windows { + set userhome [file join [file normalize $::env(LOCALAPPDATA)] Tcl] + if {[file exists c:/Tcl/Teapot]} { + dict set result teapot c:/Tcl/Teapot + } + } + macosx { + set userhome [file join [file normalize {~/Library/Application Support/}] Tcl] + if {[file exists {~/Library/Application Support/ActiveState/Teapot/repository/}]} { + dict set result teapot [file normalize {~/Library/Application Support/ActiveState/Teapot/repository/}] + } + dict set result local_install [file normalize ~/Library/Tcl] + if {![dict exists $result sandbox]} { + dict set result sandbox [file normalize ~/Library/Tcl/sandbox] + } + } + default { + } + } + dict set result userhome $userhome + # Load user preferences + if {[file exists [file join $userhome practcl.rc]]} { + set dat [::practcl::read_rc_file [file join $userhome practcl.rc]] + foreach {f v} $dat { + dict set result $f $v + } + } + if {![dict exists $result prefix]} { + dict set result prefix $userhome + } + + # Create a default path for the teapot + if {![dict exists $result teapot]} { + dict set result teapot [file join $userhome teapot] + } + # Create a default path for the local sandbox + if {![dict exists $result sandbox]} { + dict set result sandbox [file join $userhome sandbox] + } + # Create a default path for download folder + if {![dict exists $result download]} { + dict set result download [file join $userhome download] + } + # Path to install local packages + if {![dict exists $result local_install]} { + dict set result local_install [file join $userhome lib] + } + if {![dict exists result fossil_mirror] && [::info exists ::env(FOSSIL_MIRROR)]} { + dict set result fossil_mirror $::env(FOSSIL_MIRROR) + } + + set ::practcl::LOCAL_INFO $result + return $result +} +proc ::practcl::config.tcl {path} { + return [read_configuration $path] +} +proc ::practcl::read_configuration {path} { + dict set result buildpath $path + set result [local_os] + set OS [dict get $result TEACUP_OS] + set windows 0 + dict set result USEMSVC 0 + if {[file exists [file join $path config.tcl]]} { + # We have a definitive configuration file. Read its content + # and take it as gospel + set cresult [read_rc_file [file join $path config.tcl]] + set cresult [::practcl::de_shell $cresult] + if {[dict exists $cresult srcdir] && ![dict exists $cresult sandbox]} { + dict set cresult sandbox [file dirname [dict get $cresult srcdir]] + } + set result [dict merge $result [::practcl::de_shell $cresult]] + } + if {[file exists [file join $path config.site]]} { + # No config.tcl file is present but we do seed + dict set result USEMSVC 0 + foreach {f v} [::practcl::de_shell [::practcl::read_sh_file [file join $path config.site]]] { + dict set result $f $v + dict set result XCOMPILE_${f} $v + } + dict set result CONFIG_SITE [file join $path config.site] + if {[dict exist $result XCOMPILE_CC] && [regexp mingw [dict get $result XCOMPILE_CC]]} { + set windows 1 + } + } elseif {[info exists ::env(VisualStudioVersion)]} { + set windows 1 + dict set result USEMSVC 1 + } + if {$windows && [dict get $result TEACUP_OS] ne "windows"} { + if {![dict exists exists $result TEACUP_ARCH]} { + dict set result TEACUP_ARCH ix86 + } + dict set result TEACUP_PROFILE win32-[dict get $result TEACUP_ARCH] + dict set result TEACUP_OS windows + dict set result EXEEXT .exe + } + return $result +} +if {$::tcl_platform(platform) eq "windows"} { +proc ::practcl::msys_to_tclpath msyspath { + return [exec sh -c "cd $msyspath ; pwd -W"] +} +proc ::practcl::tcl_to_myspath tclpath { + set path [file normalize $tclpath] + return "/[string index $path 0][string range $path 2 end]" + #return [exec sh -c "cd $tclpath ; pwd"] +} +} else { +proc ::practcl::msys_to_tclpath msyspath { + return [file normalize $msyspath] +} +proc ::practcl::tcl_to_myspath msyspath { + return [file normalize $msyspath] +} +} +proc ::practcl::tcllib_require {pkg args} { + # Try to load the package from the local environment + if {[catch [list ::package require $pkg {*}$args] err]==0} { + return $err + } + ::practcl::LOCAL tool tcllib env-load + uplevel #0 [list ::package require $pkg {*}$args] +} +namespace eval ::practcl::platform { +} +proc ::practcl::platform::tcl_core_options {os} { + ### + # Download our required packages + ### + set tcl_config_opts {} + # Auto-guess options for the local operating system + switch $os { + windows { + #lappend tcl_config_opts --disable-stubs + } + linux { + } + macosx { + lappend tcl_config_opts --enable-corefoundation=yes --enable-framework=no + } + } + lappend tcl_config_opts --with-tzdata + return $tcl_config_opts +} +proc ::practcl::platform::tk_core_options {os} { + ### + # Download our required packages + ### + set tk_config_opts {} + + # Auto-guess options for the local operating system + switch $os { + windows { + } + linux { + lappend tk_config_opts --enable-xft=no --enable-xss=no + } + macosx { + lappend tk_config_opts --enable-aqua=yes + } + } + return $tk_config_opts +} +proc ::practcl::read_rc_file {filename {localdat {}}} { + set result $localdat + set fin [open $filename r] + set bufline {} + set rawcount 0 + set linecount 0 + while {[gets $fin thisline]>=0} { + incr rawcount + append bufline \n $thisline + if {![info complete $bufline]} continue + set line [string trimleft $bufline] + set bufline {} + if {[string index [string trimleft $line] 0] eq "#"} continue + append result \n $line + #incr linecount + #set key [lindex $line 0] + #set value [lindex $line 1] + #dict set result $key $value + } + close $fin + return $result +} +proc ::practcl::read_sh_subst {line info} { + regsub -all {\x28} $line \x7B line + regsub -all {\x29} $line \x7D line + + #set line [string map $key [string trim $line]] + foreach {field value} $info { + catch {set $field $value} + } + if [catch {subst $line} result] { + return {} + } + set result [string trim $result] + return [string trim $result '] +} +proc ::practcl::read_sh_file {filename {localdat {}}} { + set fin [open $filename r] + set result {} + if {$localdat eq {}} { + set top 1 + set local [array get ::env] + dict set local EXE {} + } else { + set top 0 + set local $localdat + } + while {[gets $fin line] >= 0} { + set line [string trim $line] + if {[string index $line 0] eq "#"} continue + if {$line eq {}} continue + catch { + if {[string range $line 0 6] eq "export "} { + set eq [string first "=" $line] + set field [string trim [string range $line 6 [expr {$eq - 1}]]] + set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local] + dict set result $field [read_sh_subst $value $local] + dict set local $field $value + } elseif {[string range $line 0 7] eq "include "} { + set subfile [read_sh_subst [string range $line 7 end] $local] + foreach {field value} [read_sh_file $subfile $local] { + dict set result $field $value + } + } else { + set eq [string first "=" $line] + if {$eq > 0} { + set field [read_sh_subst [string range $line 0 [expr {$eq - 1}]] $local] + set value [string trim [string range $line [expr {$eq+1}] end] '] + #set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local] + dict set local $field $value + dict set result $field $value + } + } + } err opts + if {[dict get $opts -code] != 0} { + #puts $opts + puts "Error reading line:\n$line\nerr: $err\n***" + return $err {*}$opts + } + } + return $result +} +proc ::practcl::read_Config.sh filename { + set fin [open $filename r] + set result {} + set linecount 0 + while {[gets $fin line] >= 0} { + set line [string trim $line] + if {[string index $line 0] eq "#"} continue + if {$line eq {}} continue + catch { + set eq [string first "=" $line] + if {$eq > 0} { + set field [string range $line 0 [expr {$eq - 1}]] + set value [string trim [string range $line [expr {$eq+1}] end] '] + #set value [read_sh_subst [string range $line [expr {$eq+1}] end] $local] + dict set result $field $value + incr $linecount + } + } err opts + if {[dict get $opts -code] != 0} { + #puts $opts + puts "Error reading line:\n$line\nerr: $err\n***" + return $err {*}$opts + } + } + return $result +} +proc ::practcl::read_Makefile filename { + set fin [open $filename r] + set result {} + while {[gets $fin line] >= 0} { + set line [string trim $line] + if {[string index $line 0] eq "#"} continue + if {$line eq {}} continue + catch { + set eq [string first "=" $line] + if {$eq > 0} { + set field [string trim [string range $line 0 [expr {$eq - 1}]]] + set value [string trim [string trim [string range $line [expr {$eq+1}] end] ']] + switch $field { + PKG_LIB_FILE { + dict set result libfile $value + } + srcdir { + if {$value eq "."} { + dict set result srcdir [file dirname $filename] + } else { + dict set result srcdir $value + } + } + PACKAGE_NAME { + dict set result name $value + } + PACKAGE_VERSION { + dict set result version $value + } + LIBS { + dict set result PRACTCL_LIBS $value + } + PKG_LIB_FILE { + dict set result libfile $value + } + } + } + } err opts + if {[dict get $opts -code] != 0} { + #puts $opts + puts "Error reading line:\n$line\nerr: $err\n***" + return $err {*}$opts + } + # the Compile field is about where most TEA files start getting silly + if {$field eq "compile"} { + break + } + } + return $result +} +proc ::practcl::cputs {varname args} { + upvar 1 $varname buffer + if {[llength $args]==1 && [string length [string trim [lindex $args 0]]] == 0} { + + } + if {[info exist buffer]} { + if {[string index $buffer end] ne "\n"} { + append buffer \n + } + } else { + set buffer \n + } + # Trim leading \n's + append buffer [string trimleft [lindex $args 0] \n] {*}[lrange $args 1 end] +} +proc ::practcl::tcl_to_c {body} { + set result {} + foreach rawline [split $body \n] { + set line [string map [list \" \\\" \\ \\\\] $rawline] + cputs result "\n \"$line\\n\" \\" + } + return [string trimright $result \\] +} +proc ::practcl::_tagblock {text {style tcl} {note {}}} { + if {[string length [string trim $text]]==0} { + return {} + } + set output {} + switch $style { + tcl { + ::practcl::cputs output "# BEGIN $note" + } + c { + ::practcl::cputs output "/* BEGIN $note */" + } + default { + ::practcl::cputs output "# BEGIN $note" + } + } + ::practcl::cputs output $text + switch $style { + tcl { + ::practcl::cputs output "# END $note" + } + c { + ::practcl::cputs output "/* END $note */" + } + default { + ::practcl::cputs output "# END $note" + } + } + return $output +} +proc ::practcl::de_shell {data} { + set values {} + foreach flag {DEFS TCL_DEFS TK_DEFS} { + if {[dict exists $data $flag]} { + #set value {} + #foreach item [dict get $data $flag] { + # append value " " [string map {{ } {\ }} $item] + #} + dict set values $flag [dict get $data $flag] + } + } + set map {} + lappend map {${PKG_OBJECTS}} %LIBRARY_OBJECTS% + lappend map {$(PKG_OBJECTS)} %LIBRARY_OBJECTS% + lappend map {${PKG_STUB_OBJECTS}} %LIBRARY_STUB_OBJECTS% + lappend map {$(PKG_STUB_OBJECTS)} %LIBRARY_STUB_OBJECTS% + + if {[dict exists $data name]} { + lappend map %LIBRARY_NAME% [dict get $data name] + lappend map %LIBRARY_VERSION% [dict get $data version] + lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} [dict get $data version]] + if {[dict exists $data libprefix]} { + lappend map %LIBRARY_PREFIX% [dict get $data libprefix] + } else { + lappend map %LIBRARY_PREFIX% [dict get $data prefix] + } + } + foreach flag [dict keys $data] { + if {$flag in {TCL_DEFS TK_DEFS DEFS}} continue + set value [string trim [dict get $data $flag] \"] + dict set map "\$\{${flag}\}" $value + dict set map "\$\(${flag}\)" $value + #dict set map "\$${flag}" $value + dict set map "%${flag}%" $value + dict set values $flag [dict get $data $flag] + #dict set map "\$\{${flag}\}" $proj($flag) + } + set changed 1 + while {$changed} { + set changed 0 + foreach {field value} $values { + if {$field in {TCL_DEFS TK_DEFS DEFS}} continue + dict with values {} + set newval [string map $map $value] + if {$newval eq $value} continue + set changed 1 + dict set values $field $newval + } + } + return $values +} + +### +# END: buildutil.tcl +### +### +# START: fileutil.tcl +### +proc ::practcl::grep {pattern {files {}}} { + set result [list] + if {[llength $files] == 0} { + # read from stdin + set lnum 0 + while {[gets stdin line] >= 0} { + incr lnum + if {[regexp -- $pattern $line]} { + lappend result "${lnum}:${line}" + } + } + } else { + foreach filename $files { + set file [open $filename r] + set lnum 0 + while {[gets $file line] >= 0} { + incr lnum + if {[regexp -- $pattern $line]} { + lappend result "${filename}:${lnum}:${line}" + } + } + close $file + } + } + return $result +} +proc ::practcl::file_lexnormalize {sp} { + set spx [file split $sp] + + # Resolution of embedded relative modifiers (., and ..). + + if { + ([lsearch -exact $spx . ] < 0) && + ([lsearch -exact $spx ..] < 0) + } { + # Quick path out if there are no relative modifiers + return $sp + } + + set absolute [expr {![string equal [file pathtype $sp] relative]}] + # A volumerelative path counts as absolute for our purposes. + + set sp $spx + set np {} + set noskip 1 + + while {[llength $sp]} { + set ele [lindex $sp 0] + set sp [lrange $sp 1 end] + set islast [expr {[llength $sp] == 0}] + + if {[string equal $ele ".."]} { + if { + ($absolute && ([llength $np] > 1)) || + (!$absolute && ([llength $np] >= 1)) + } { + # .. : Remove the previous element added to the + # new path, if there actually is enough to remove. + set np [lrange $np 0 end-1] + } + } elseif {[string equal $ele "."]} { + # Ignore .'s, they stay at the current location + continue + } else { + # A regular element. + lappend np $ele + } + } + if {[llength $np] > 0} { + return [eval [linsert $np 0 file join]] + # 8.5: return [file join {*}$np] + } + return {} +} +proc ::practcl::file_relative {base dst} { + # Ensure that the link to directory 'dst' is properly done relative to + # the directory 'base'. + + if {![string equal [file pathtype $base] [file pathtype $dst]]} { + return -code error "Unable to compute relation for paths of different pathtypes: [file pathtype $base] vs. [file pathtype $dst], ($base vs. $dst)" + } + + set base [file_lexnormalize [file join [pwd] $base]] + set dst [file_lexnormalize [file join [pwd] $dst]] + + set save $dst + set base [file split $base] + set dst [file split $dst] + + while {[string equal [lindex $dst 0] [lindex $base 0]]} { + set dst [lrange $dst 1 end] + set base [lrange $base 1 end] + if {![llength $dst]} {break} + } + + set dstlen [llength $dst] + set baselen [llength $base] + + if {($dstlen == 0) && ($baselen == 0)} { + # Cases: + # (a) base == dst + + set dst . + } else { + # Cases: + # (b) base is: base/sub = sub + # dst is: base = {} + + # (c) base is: base = {} + # dst is: base/sub = sub + + while {$baselen > 0} { + set dst [linsert $dst 0 ..] + incr baselen -1 + } + # 8.5: set dst [file join {*}$dst] + set dst [eval [linsert $dst 0 file join]] + } + + return $dst +} +proc ::practcl::findByPattern {basedir patterns} { + set queue $basedir + set result {} + while {[llength $queue]} { + set item [lindex $queue 0] + set queue [lrange $queue 1 end] + if {[file isdirectory $item]} { + foreach path [glob -nocomplain [file join $item *]] { + lappend queue $path + } + continue + } + foreach pattern $patterns { + set fname [file tail $item] + if {[string match $pattern $fname]} { + lappend result $item + break + } + } + } + return $result +} +proc ::practcl::log {fname comment} { + set fname [file normalize $fname] + if {[info exists ::practcl::logchan($fname)]} { + set fout $::practcl::logchan($fname) + after cancel $::practcl::logevent($fname) + } else { + set fout [open $fname a] + } + puts $fout $comment + # Defer close until idle + set ::practcl::logevent($fname) [after idle "close $fout ; unset ::practcl::logchan($fname)"] +} + +### +# END: fileutil.tcl +### +### +# START: installutil.tcl +### +proc ::practcl::_pkgindex_simpleIndex {path} { +set buffer {} + set pkgidxfile [file join $path pkgIndex.tcl] + set modfile [file join $path [file tail $path].tcl] + set use_pkgindex [file exists $pkgidxfile] + set tclfiles {} + set found 0 + set mlist [list pkgIndex.tcl index.tcl [file tail $modfile] version_info.tcl] + foreach file [glob -nocomplain [file join $path *.tcl]] { + if {[file tail $file] ni $mlist} { + puts [list NONMODFILE $file] + return {} + } + } + foreach file [glob -nocomplain [file join $path *.tcl]] { + if { [file tail $file] == "version_info.tcl" } continue + set fin [open $file r] + set dat [read $fin] + close $fin + if {![regexp "package provide" $dat]} continue + set fname [file rootname [file tail $file]] + # Look for a package provide statement + foreach line [split $dat \n] { + set line [string trim $line] + if { [string range $line 0 14] != "package provide" } continue + set package [lindex $line 2] + set version [lindex $line 3] + if {[string index $package 0] in "\$ \[ @"} continue + if {[string index $version 0] in "\$ \[ @"} continue + puts "PKGLINE $line" + append buffer "package ifneeded $package $version \[list source \[file join %DIR% [file tail $file]\]\]" \n + break + } + } + return $buffer +} +proc ::practcl::_pkgindex_directory {path} { + set buffer {} + set pkgidxfile [file join $path pkgIndex.tcl] + set modfile [file join $path [file tail $path].tcl] + set use_pkgindex [file exists $pkgidxfile] + set tclfiles {} + if {$use_pkgindex && [file exists $modfile]} { + set use_pkgindex 0 + set mlist [list pkgIndex.tcl [file tail $modfile]] + foreach file [glob -nocomplain [file join $path *.tcl]] { + lappend tclfiles [file tail $file] + if {[file tail $file] in $mlist} continue + incr use_pkgindex + } + } + if {!$use_pkgindex} { + # No pkgIndex file, read the source + foreach file [glob -nocomplain $path/*.tm] { + set file [file normalize $file] + set fname [file rootname [file tail $file]] + ### + # We used to be able to ... Assume the package is correct in the filename + # No hunt for a "package provides" + ### + set package [lindex [split $fname -] 0] + set version [lindex [split $fname -] 1] + ### + # Read the file, and override assumptions as needed + ### + set fin [open $file r] + set dat [read $fin] + close $fin + # Look for a teapot style Package statement + foreach line [split $dat \n] { + set line [string trim $line] + if { [string range $line 0 9] != "# Package " } continue + set package [lindex $line 2] + set version [lindex $line 3] + break + } + # Look for a package provide statement + foreach line [split $dat \n] { + set line [string trim $line] + if { [string range $line 0 14] != "package provide" } continue + set package [lindex $line 2] + set version [lindex $line 3] + break + } + if {[string trim $version] ne {}} { + append buffer "package ifneeded $package $version \[list source \[file join \$dir [file tail $file]\]\]" \n + } + } + foreach file [glob -nocomplain $path/*.tcl] { + if { [file tail $file] == "version_info.tcl" } continue + set fin [open $file r] + set dat [read $fin] + close $fin + if {![regexp "package provide" $dat]} continue + set fname [file rootname [file tail $file]] + # Look for a package provide statement + foreach line [split $dat \n] { + set line [string trim $line] + if { [string range $line 0 14] != "package provide" } continue + set package [lindex $line 2] + set version [lindex $line 3] + if {[string index $package 0] in "\$ \[ @"} continue + if {[string index $version 0] in "\$ \[ @"} continue + append buffer "package ifneeded $package $version \[list source \[file join \$dir [file tail $file]\]\]" \n + break + } + } + return $buffer + } + set fin [open $pkgidxfile r] + set dat [read $fin] + close $fin + set trace 0 + #if {[file tail $path] eq "tool"} { + # set trace 1 + #} + set thisline {} + foreach line [split $dat \n] { + append thisline $line \n + if {![info complete $thisline]} continue + set line [string trim $line] + if {[string length $line]==0} { + set thisline {} ; continue + } + if {[string index $line 0] eq "#"} { + set thisline {} ; continue + } + if {[regexp "if.*catch.*package.*Tcl.*return" $thisline]} { + if {$trace} {puts "[file dirname $pkgidxfile] Ignoring $thisline"} + set thisline {} ; continue + } + if {[regexp "if.*package.*vsatisfies.*package.*provide.*return" $thisline]} { + if {$trace} { puts "[file dirname $pkgidxfile] Ignoring $thisline" } + set thisline {} ; continue + } + if {![regexp "package.*ifneeded" $thisline]} { + # This package index contains arbitrary code + # source instead of trying to add it to the master + # package index + if {$trace} { puts "[file dirname $pkgidxfile] Arbitrary code $thisline" } + return {source [file join $dir pkgIndex.tcl]} + } + append buffer $thisline \n + set thisline {} + } + if {$trace} {puts [list [file dirname $pkgidxfile] $buffer]} + return $buffer +} +proc ::practcl::_pkgindex_path_subdir {path} { + set result {} + if {[file exists [file join $path src build.tcl]]} { + # Tool style module, don't dive into subdirectories + return $path + } + foreach subpath [glob -nocomplain [file join $path *]] { + if {[file isdirectory $subpath]} { + if {[file tail $subpath] eq "build" && [file exists [file join $subpath build.tcl]]} continue + lappend result $subpath {*}[_pkgindex_path_subdir $subpath] + } + } + return $result +} +proc ::practcl::pkgindex_path {args} { + set stack {} + set buffer { +lappend ::PATHSTACK $dir +set IDXPATH [lindex $::PATHSTACK end] + } + set preindexed {} + foreach base $args { + set base [file normalize $base] + set paths {} + foreach dir [glob -nocomplain [file join $base *]] { + set thisdir [file tail $dir] + if {$thisdir eq "teapot"} continue + if {$thisdir eq "pkgs"} { + foreach subdir [glob -nocomplain [file join $dir *]] { + set thissubdir [file tail $subdir] + set skip 0 + foreach file {pkgIndex.tcl tclIndex} { + if {[file exists [file join $subdir $file]]} { + set skip 1 + append buffer "set dir \[file join \$::IDXPATH [list $thisdir] [list $thissubdir]\] \; " + append buffer "source \[file join \$dir ${file}\]" \n + } + } + if {$skip} continue + lappend paths {*}[::practcl::_pkgindex_path_subdir $subdir] + } + continue + } + lappend paths $dir {*}[::practcl::_pkgindex_path_subdir $dir] + } + append buffer "" + set i [string length $base] + # Build a list of all of the paths + if {[llength $paths]} { + foreach path $paths { + if {$path eq $base} continue + set path_indexed($path) 0 + } + } else { + puts [list WARNING: NO PATHS FOUND IN $base] + } + set path_indexed($base) 1 + set path_indexed([file join $base boot tcl]) 1 + append buffer \n {# SINGLE FILE MODULES BEGIN} \n {set dir [file dirname $::PKGIDXFILE]} \n + foreach path $paths { + if {$path_indexed($path)} continue + set thisdir [file_relative $base $path] + set simpleIdx [_pkgindex_simpleIndex $path] + if {[string length $simpleIdx]==0} continue + incr path_indexed($path) + if {[string length $simpleIdx]} { + incr path_indexed($path) + append buffer [string map [list %DIR% "\$dir \{$thisdir\}"] [string trimright $simpleIdx]] \n + } + } + append buffer {# SINGLE FILE MODULES END} \n + foreach path $paths { + if {$path_indexed($path)} continue + set thisdir [file_relative $base $path] + set idxbuf [::practcl::_pkgindex_directory $path] + if {[string length $idxbuf]} { + incr path_indexed($path) + append buffer "set dir \[set PKGDIR \[file join \[lindex \$::PATHSTACK end\] $thisdir\]\]" \n + append buffer [string map {$dir $PKGDIR} [string trimright $idxbuf]] \n + } + } + } + append buffer { +set dir [lindex $::PATHSTACK end] +set ::PATHSTACK [lrange $::PATHSTACK 0 end-1] +} + return $buffer +} +proc ::practcl::installDir {d1 d2} { + puts [format {%*sCreating %s} [expr {4 * [info level]}] {} [file tail $d2]] + file delete -force -- $d2 + file mkdir $d2 + + foreach ftail [glob -directory $d1 -nocomplain -tails *] { + set f [file join $d1 $ftail] + if {[file isdirectory $f] && [string compare CVS $ftail]} { + installDir $f [file join $d2 $ftail] + } elseif {[file isfile $f]} { + file copy -force $f [file join $d2 $ftail] + if {$::tcl_platform(platform) eq {unix}} { + file attributes [file join $d2 $ftail] -permissions 0644 + } else { + file attributes [file join $d2 $ftail] -readonly 1 + } + } + } + + if {$::tcl_platform(platform) eq {unix}} { + file attributes $d2 -permissions 0755 + } else { + file attributes $d2 -readonly 1 + } +} +proc ::practcl::copyDir {d1 d2 {toplevel 1}} { + #if {$toplevel} { + # puts [list ::practcl::copyDir $d1 -> $d2] + #} + #file delete -force -- $d2 + file mkdir $d2 + if {[file isfile $d1]} { + file copy -force $d1 $d2 + set ftail [file tail $d1] + if {$::tcl_platform(platform) eq {unix}} { + file attributes [file join $d2 $ftail] -permissions 0644 + } else { + file attributes [file join $d2 $ftail] -readonly 1 + } + } else { + foreach ftail [glob -directory $d1 -nocomplain -tails *] { + set f [file join $d1 $ftail] + if {[file isdirectory $f] && [string compare CVS $ftail]} { + copyDir $f [file join $d2 $ftail] 0 + } elseif {[file isfile $f]} { + file copy -force $f [file join $d2 $ftail] + if {$::tcl_platform(platform) eq {unix}} { + file attributes [file join $d2 $ftail] -permissions 0644 + } else { + file attributes [file join $d2 $ftail] -readonly 1 + } + } + } + } +} +proc ::practcl::buildModule {modpath} { + set buildscript [file join $modpath build build.tcl] + if {![file exists $buildscript]} return + set pkgIndexFile [file join $modpath pkgIndex.tcl] + if {[file exists $pkgIndexFile]} { + set latest 0 + foreach file [::practcl::findByPattern [file dirname $buildscript] *.tcl] { + set mtime [file mtime $file] + if {$mtime>$latest} { + set latest $mtime + } + } + set IdxTime [file mtime $pkgIndexFile] + if {$latest<$IdxTime} return + } + ::practcl::dotclexec $buildscript +} +proc ::practcl::installModule {modpath DEST} { + puts [list installModule $modpath $DEST] + set dpath [file join $DEST modules [file tail $modpath]] + if {[file exists [file join $modpath build build.tcl]]} { + buildModule $modpath + } elseif {![file exists [file join $modpath pkgIndex.tcl]]} { + puts [list Reindex $modpath] + pkg_mkIndex $modpath + } + file delete -force $dpath + file mkdir $dpath + foreach file [glob [file join $modpath *.tcl]] { + file copy $file $dpath + } + if {[file exists [file join $modpath htdocs]]} { + ::practcl::copyDir [file join $modpath htdocs] [file join $dpath htdocs] + } +} + +### +# END: installutil.tcl +### +### +# START: makeutil.tcl +### +proc ::practcl::trigger {args} { + ::practcl::LOCAL make trigger {*}$args + foreach {name obj} [::practcl::LOCAL make objects] { + set ::make($name) [$obj do] + } +} +proc ::practcl::depends {args} { + ::practcl::LOCAL make depends {*}$args +} +proc ::practcl::target {name info {action {}}} { + set obj [::practcl::LOCAL make task $name $info $action] + set ::make($name) 0 + set filename [$obj define get filename] + if {$filename ne {}} { + set ::target($name) $filename + } +} + +### +# END: makeutil.tcl +### +### +# START: class metaclass.tcl +### +::clay::define ::practcl::metaclass { + method _MorphPatterns {} { + return {{@name@} {::practcl::@name@} {::practcl::*@name@} {::practcl::*@name@*}} + } + method define {submethod args} { + my variable define + switch $submethod { + dump { + return [array get define] + } + add { + set field [lindex $args 0] + if {![info exists define($field)]} { + set define($field) {} + } + foreach arg [lrange $args 1 end] { + if {$arg ni $define($field)} { + lappend define($field) $arg + } + } + return $define($field) + } + remove { + set field [lindex $args 0] + if {![info exists define($field)]} { + return + } + set rlist [lrange $args 1 end] + set olist $define($field) + set nlist {} + foreach arg $olist { + if {$arg in $rlist} continue + lappend nlist $arg + } + set define($field) $nlist + return $nlist + } + exists { + set field [lindex $args 0] + return [info exists define($field)] + } + getnull - + get - + cget { + set field [lindex $args 0] + if {[info exists define($field)]} { + return $define($field) + } + return [lindex $args 1] + } + set { + if {[llength $args]==1} { + set arglist [lindex $args 0] + } else { + set arglist $args + } + array set define $arglist + if {[dict exists $arglist class]} { + my select + } + } + default { + array $submethod define {*}$args + } + } + } + method graft args { + return [my clay delegate {*}$args] + } + method initialize {} {} + method link {command args} { + my variable links + switch $command { + object { + foreach obj $args { + foreach linktype [$obj linktype] { + my link add $linktype $obj + } + } + } + add { + ### + # Add a link to an object that was externally created + ### + if {[llength $args] ne 2} { error "Usage: link add LINKTYPE OBJECT"} + lassign $args linktype object + if {[info exists links($linktype)] && $object in $links($linktype)} { + return + } + lappend links($linktype) $object + } + remove { + set object [lindex $args 0] + if {[llength $args]==1} { + set ltype * + } else { + set ltype [lindex $args 1] + } + foreach {linktype elements} [array get links $ltype] { + if {$object in $elements} { + set nlist {} + foreach e $elements { + if { $object ne $e } { lappend nlist $e } + } + set links($linktype) $nlist + } + } + } + list { + if {[llength $args]==0} { + return [array get links] + } + if {[llength $args] != 1} { error "Usage: link list LINKTYPE"} + set linktype [lindex $args 0] + if {![info exists links($linktype)]} { + return {} + } + return $links($linktype) + } + dump { + return [array get links] + } + } + } + method morph classname { + my variable define + if {$classname ne {}} { + set map [list @name@ $classname] + foreach pattern [string map $map [my _MorphPatterns]] { + set pattern [string trim $pattern] + set matches [info commands $pattern] + if {![llength $matches]} continue + set class [lindex $matches 0] + break + } + set mixinslot {} + foreach {slot pattern} { + distribution ::practcl::distribution* + product ::practcl::product* + toolset ::practcl::toolset* + } { + if {[string match $pattern $class]} { + set mixinslot $slot + break + } + } + if {$mixinslot ne {}} { + my clay mixinmap $mixinslot $class + } elseif {[info command $class] ne {}} { + if {[info object class [self]] ne $class} { + ::oo::objdefine [self] class $class + ::practcl::debug [self] morph $class + my define set class $class + } + } else { + error "[self] Could not detect class for $classname" + } + } + if {[::info exists define(oodefine)]} { + ::oo::objdefine [self] $define(oodefine) + #unset define(oodefine) + } + } + method script script { + eval $script + } + method select {} { + my variable define + if {[info exists define(class)]} { + my morph $define(class) + } else { + if {[::info exists define(oodefine)]} { + ::oo::objdefine [self] $define(oodefine) + #unset define(oodefine) + } + } + } + method source filename { + source $filename + } +} + +### +# END: class metaclass.tcl +### +### +# START: class toolset baseclass.tcl +### +::clay::define ::practcl::toolset { + method config.sh {} { + return [my read_configuration] + } + method BuildDir {PWD} { + set name [my define get name] + set debug [my define get debug 0] + if {[my define get LOCAL 0]} { + return [my define get builddir [file join $PWD local $name]] + } + if {$debug} { + return [my define get builddir [file join $PWD debug $name]] + } else { + return [my define get builddir [file join $PWD pkg $name]] + } + } + method MakeDir {srcdir} { + return $srcdir + } + method read_configuration {} { + my variable conf_result + if {[info exists conf_result]} { + return $conf_result + } + set result {} + set name [my define get name] + set PWD $::CWD + set builddir [my define get builddir] + my unpack + set srcdir [my define get srcdir] + if {![file exists $builddir]} { + my Configure + } + set filename [file join $builddir config.tcl] + # Project uses the practcl template. Use the leavings from autoconf + if {[file exists $filename]} { + set dat [::practcl::read_configuration $builddir] + foreach {item value} [::practcl::sort_dict $dat] { + dict set result $item $value + } + set conf_result $result + return $result + } + set filename [file join $builddir ${name}Config.sh] + if {[file exists $filename]} { + set l [expr {[string length $name]+1}] + foreach {field dat} [::practcl::read_Config.sh $filename] { + set field [string tolower $field] + if {[string match ${name}_* $field]} { + set field [string range $field $l end] + } + switch $field { + version { + dict set result pkg_vers $dat + } + lib_file { + set field libfile + } + } + dict set result $field $dat + } + set conf_result $result + return $result + } + ### + # Oh man... we have to guess + ### + if {![file exists [file join $builddir Makefile]]} { + my Configure + } + set filename [file join $builddir Makefile] + if {![file exists $filename]} { + error "Could not locate any configuration data in $srcdir" + } + foreach {field dat} [::practcl::read_Makefile $filename] { + dict set result $field $dat + } + if {![dict exists $result PRACTCL_PKG_LIBS] && [dict exists $result LIBS]} { + dict set result PRACTCL_PKG_LIBS [dict get $result LIBS] + } + set conf_result $result + cd $PWD + return $result + } + method build-cflags {PROJECT DEFS namevar versionvar defsvar} { + upvar 1 $namevar name $versionvar version NAME NAME $defsvar defs + set name [string tolower [${PROJECT} define get name [${PROJECT} define get pkg_name]]] + set NAME [string toupper $name] + set version [${PROJECT} define get version [${PROJECT} define get pkg_vers]] + if {$version eq {}} { + set version 0.1a + } + set defs $DEFS + foreach flag { + -DPACKAGE_NAME + -DPACKAGE_VERSION + -DPACKAGE_TARNAME + -DPACKAGE_STRING + } { + if {[set i [string first $flag $defs]] >= 0} { + set j [string first -D $flag [expr {$i+[string length $flag]}]] + set predef [string range $defs 0 [expr {$i-1}]] + set postdef [string range $defs $j end] + set defs "$predef $postdef" + } + } + append defs " -DPACKAGE_NAME=\"${name}\" -DPACKAGE_VERSION=\"${version}\"" + append defs " -DPACKAGE_TARNAME=\"${name}\" -DPACKAGE_STRING=\"${name}\x5c\x20${version}\"" + return $defs + } + method critcl args { + if {![info exists critcl]} { + ::practcl::LOCAL tool critcl env-load + set critcl [file join [::practcl::LOCAL tool critcl define get srcdir] main.tcl + } + set srcdir [my SourceRoot] + set PWD [pwd] + cd $srcdir + ::practcl::dotclexec $critcl {*}$args + cd $PWD + } +} +oo::objdefine ::practcl::toolset { + # Perform the selection for the toolset mixin + method select object { + ### + # Select the toolset to use for this project + ### + if {[$object define exists toolset]} { + return [$object define get toolset] + } + set class [$object define get toolset] + if {$class ne {}} { + $object clay mixinmap toolset $class + } else { + if {[info exists ::env(VisualStudioVersion)]} { + $object clay mixinmap toolset ::practcl::toolset.msvc + } else { + $object clay mixinmap toolset ::practcl::toolset.gcc + } + } + } +} + +### +# END: class toolset baseclass.tcl +### +### +# START: class toolset gcc.tcl +### +::clay::define ::practcl::toolset.gcc { + superclass ::practcl::toolset + method Autoconf {} { + ### + # Re-run autoconf for this project + # Not a good idea in practice... but in the right hands it can be useful + ### + set pwd [pwd] + set srcdir [file normalize [my define get srcdir]] + cd $srcdir + foreach template {configure.ac configure.in} { + set input [file join $srcdir $template] + if {[file exists $input]} { + puts "autoconf -f $input > [file join $srcdir configure]" + exec autoconf -f $input > [file join $srcdir configure] + } + } + cd $pwd + } + method BuildDir {PWD} { + set name [my define get name] + set debug [my define get debug 0] + if {[my define get LOCAL 0]} { + return [my define get builddir [file join $PWD local $name]] + } + if {$debug} { + return [my define get builddir [file join $PWD debug $name]] + } else { + return [my define get builddir [file join $PWD pkg $name]] + } + } + method ConfigureOpts {} { + set opts {} + set builddir [my define get builddir] + + if {[my define get broken_destroot 0]} { + set PREFIX [my define get prefix_broken_destdir] + } else { + set PREFIX [my define get prefix] + } + switch [my define get name] { + tcl { + set opts [::practcl::platform::tcl_core_options [my define get TEACUP_OS]] + } + tk { + set opts [::practcl::platform::tk_core_options [my define get TEACUP_OS]] + } + } + if {[my define get CONFIG_SITE] != {}} { + lappend opts --host=[my define get HOST] + } + set inside_msys [string is true -strict [my define get MSYS_ENV 0]] + lappend opts --with-tclsh=[info nameofexecutable] + + if {[my define get tk 0]} { + if {![my define get LOCAL 0]} { + set obj [my tclcore] + if {$obj ne {}} { + if {$inside_msys} { + lappend opts --with-tcl=[::practcl::file_relative [file normalize $builddir] [$obj define get builddir]] + } else { + lappend opts --with-tcl=[file normalize [$obj define get builddir]] + } + } + set obj [my tkcore] + if {$obj ne {}} { + if {$inside_msys} { + lappend opts --with-tk=[::practcl::file_relative [file normalize $builddir] [$obj define get builddir]] + } else { + lappend opts --with-tk=[file normalize [$obj define get builddir]] + } + } + } else { + lappend opts --with-tcl=[file join $PREFIX lib] + lappend opts --with-tk=[file join $PREFIX lib] + } + } else { + if {![my define get LOCAL 0]} { + set obj [my tclcore] + if {$obj ne {}} { + if {$inside_msys} { + lappend opts --with-tcl=[::practcl::file_relative [file normalize $builddir] [$obj define get builddir]] + } else { + lappend opts --with-tcl=[file normalize [$obj define get builddir]] + } + } + } else { + lappend opts --with-tcl=[file join $PREFIX lib] + } + } + + lappend opts {*}[my define get config_opts] + if {![regexp -- "--prefix" $opts]} { + lappend opts --prefix=$PREFIX --exec-prefix=$PREFIX + } + if {[my define get debug 0]} { + lappend opts --enable-symbols=true + } + #--exec_prefix=$PREFIX + #if {$::tcl_platform(platform) eq "windows"} { + # lappend opts --disable-64bit + #} + if {[my define get static 1]} { + lappend opts --disable-shared + #--disable-stubs + # + } else { + lappend opts --enable-shared + } + return $opts + } + method MakeDir {srcdir} { + set localsrcdir $srcdir + if {[file exists [file join $srcdir generic]]} { + my define add include_dir [file join $srcdir generic] + } + set os [my define get TEACUP_OS] + switch $os { + windows { + if {[file exists [file join $srcdir win]]} { + my define add include_dir [file join $srcdir win] + } + if {[file exists [file join $srcdir win Makefile.in]]} { + set localsrcdir [file join $srcdir win] + } + } + default { + if {[file exists [file join $srcdir $os]]} { + my define add include_dir [file join $srcdir $os] + } + if {[file exists [file join $srcdir unix]]} { + my define add include_dir [file join $srcdir unix] + } + if {[file exists [file join $srcdir $os Makefile.in]]} { + set localsrcdir [file join $srcdir $os] + } elseif {[file exists [file join $srcdir unix Makefile.in]]} { + set localsrcdir [file join $srcdir unix] + } + } + } + return $localsrcdir + } + Ensemble make::autodetect {} { + set srcdir [my define get srcdir] + set localsrcdir [my define get localsrcdir] + if {$localsrcdir eq {}} { + set localsrcdir $srcdir + } + if {$srcdir eq $localsrcdir} { + if {![file exists [file join $srcdir tclconfig install-sh]]} { + # ensure we have tclconfig with all of the trimmings + set teapath {} + if {[file exists [file join $srcdir .. tclconfig install-sh]]} { + set teapath [file join $srcdir .. tclconfig] + } else { + set tclConfigObj [::practcl::LOCAL tool tclconfig] + $tclConfigObj load + set teapath [$tclConfigObj define get srcdir] + } + set teapath [file normalize $teapath] + #file mkdir [file join $srcdir tclconfig] + if {[catch {file link -symbolic [file join $srcdir tclconfig] $teapath}]} { + ::practcl::copyDir [file join $teapath] [file join $srcdir tclconfig] + } + } + } + set builddir [my define get builddir] + file mkdir $builddir + if {![file exists [file join $localsrcdir configure]]} { + if {[file exists [file join $localsrcdir autogen.sh]]} { + cd $localsrcdir + catch {exec sh autogen.sh >>& [file join $builddir autoconf.log]} + cd $::CWD + } + } + set opts [my ConfigureOpts] + if {[file exists [file join $builddir autoconf.log]]} { + file delete [file join $builddir autoconf.log] + } + ::practcl::debug [list PKG [my define get name] CONFIGURE {*}$opts] + ::practcl::log [file join $builddir autoconf.log] [list CONFIGURE {*}$opts] + cd $builddir + if {[my define get CONFIG_SITE] ne {}} { + set ::env(CONFIG_SITE) [my define get CONFIG_SITE] + } + catch {exec sh [file join $localsrcdir configure] {*}$opts >>& [file join $builddir autoconf.log]} + cd $::CWD + } + Ensemble make::clean {} { + set builddir [file normalize [my define get builddir]] + catch {::practcl::domake $builddir clean} + } + Ensemble make::compile {} { + set name [my define get name] + set srcdir [my define get srcdir] + if {[my define get static 1]} { + puts "BUILDING Static $name $srcdir" + } else { + puts "BUILDING Dynamic $name $srcdir" + } + cd $::CWD + set builddir [file normalize [my define get builddir]] + file mkdir $builddir + if {![file exists [file join $builddir Makefile]]} { + my Configure + } + if {[file exists [file join $builddir make.tcl]]} { + if {[my define get debug 0]} { + ::practcl::domake.tcl $builddir debug all + } else { + ::practcl::domake.tcl $builddir all + } + } else { + ::practcl::domake $builddir all + } + } + Ensemble make::install DEST { + set PWD [pwd] + set builddir [my define get builddir] + if {[my define get LOCAL 0] || $DEST eq {}} { + if {[file exists [file join $builddir make.tcl]]} { + puts "[self] Local INSTALL (Practcl)" + ::practcl::domake.tcl $builddir install + } elseif {[my define get broken_destroot 0] == 0} { + puts "[self] Local INSTALL (TEA)" + ::practcl::domake $builddir install + } + } else { + if {[file exists [file join $builddir make.tcl]]} { + # Practcl builds can inject right to where we need them + puts "[self] VFS INSTALL $DEST (Practcl)" + ::practcl::domake.tcl $builddir install-package $DEST + } elseif {[my define get broken_destroot 0] == 0} { + # Most modern TEA projects understand DESTROOT in the makefile + puts "[self] VFS INSTALL $DEST (TEA)" + ::practcl::domake $builddir install DESTDIR=[::practcl::file_relative $builddir $DEST] + } else { + # But some require us to do an install into a fictitious filesystem + # and then extract the gooey parts within. + # (*cough*) TkImg + set PREFIX [my define get prefix] + set BROKENROOT [::practcl::msys_to_tclpath [my define get prefix_broken_destdir]] + file delete -force $BROKENROOT + file mkdir $BROKENROOT + ::practcl::domake $builddir $install + ::practcl::copyDir $BROKENROOT [file join $DEST [string trimleft $PREFIX /]] + file delete -force $BROKENROOT + } + } + cd $PWD + } + method build-compile-sources {PROJECT COMPILE CPPCOMPILE INCLUDES} { + set objext [my define get OBJEXT o] + set EXTERN_OBJS {} + set OBJECTS {} + set result {} + set builddir [$PROJECT define get builddir] + file mkdir [file join $builddir objs] + set debug [$PROJECT define get debug 0] + + set task {} + ### + # Compile the C sources + ### + ::practcl::debug ### COMPILE PRODUCTS + foreach {ofile info} [${PROJECT} project-compile-products] { + ::practcl::debug $ofile $info + if {[dict exists $info library]} { + #dict set task $ofile done 1 + continue + } + # Products with no cfile aren't compiled + if {![dict exists $info cfile] || [set cfile [dict get $info cfile]] eq {}} { + #dict set task $ofile done 1 + continue + } + set ofile [file rootname $ofile] + dict set task $ofile done 0 + if {[dict exists $info external] && [dict get $info external]==1} { + dict set task $ofile external 1 + } else { + dict set task $ofile external 0 + } + set cfile [dict get $info cfile] + if {$debug} { + set ofilename [file join $builddir objs [file rootname [file tail $ofile]].debug.${objext}] + } else { + set ofilename [file join $builddir objs [file tail $ofile]].${objext} + } + dict set task $ofile source $cfile + dict set task $ofile objfile $ofilename + if {![dict exist $info command]} { + if {[file extension $cfile] in {.c++ .cpp}} { + set cmd $CPPCOMPILE + } else { + set cmd $COMPILE + } + if {[dict exists $info extra]} { + append cmd " [dict get $info extra]" + } + append cmd " $INCLUDES" + append cmd " -c $cfile" + append cmd " -o $ofilename" + dict set task $ofile command $cmd + } + } + set completed 0 + while {$completed==0} { + set completed 1 + foreach {ofile info} $task { + set waiting {} + if {[dict exists $info done] && [dict get $info done]} continue + ::practcl::debug COMPILING $ofile $info + set filename [dict get $info objfile] + if {[file exists $filename] && [file mtime $filename]>[file mtime [dict get $info source]]} { + lappend result $filename + dict set task $ofile done 1 + continue + } + if {[dict exists $info depend]} { + foreach file [dict get $info depend] { + if {[dict exists $task $file command] && [dict exists $task $file done] && [dict get $task $file done] != 1} { + set waiting $file + break + } + } + } + if {$waiting ne {}} { + set completed 0 + puts "$ofile waiting for $waiting" + continue + } + if {[dict exists $info command]} { + set cmd [dict get $info command] + puts "$cmd" + exec {*}$cmd >&@ stdout + } + if {[file exists $filename]} { + lappend result $filename + dict set task $ofile done 1 + continue + } + error "Failed to produce $filename" + } + } + return $result + } +method build-Makefile {path PROJECT} { + array set proj [$PROJECT define dump] + set path $proj(builddir) + cd $path + set includedir . + set objext [my define get OBJEXT o] + + #lappend includedir [::practcl::file_relative $path $proj(TCL_INCLUDES)] + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TCL_SRC_DIR) generic]]] + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(srcdir) generic]]] + foreach include [$PROJECT toolset-include-directory] { + set cpath [::practcl::file_relative $path [file normalize $include]] + if {$cpath ni $includedir} { + lappend includedir $cpath + } + } + set INCLUDES "-I[join $includedir " -I"]" + set NAME [string toupper $proj(name)] + set result {} + set products {} + set libraries {} + set thisline {} + ::practcl::cputs result "${NAME}_DEFS = $proj(DEFS)\n" + ::practcl::cputs result "${NAME}_INCLUDES = -I\"[join $includedir "\" -I\""]\"\n" + ::practcl::cputs result "${NAME}_COMPILE = \$(CC) \$(CFLAGS) \$(PKG_CFLAGS) \$(${NAME}_DEFS) \$(${NAME}_INCLUDES) \$(INCLUDES) \$(AM_CPPFLAGS) \$(CPPFLAGS) \$(AM_CFLAGS)" + ::practcl::cputs result "${NAME}_CPPCOMPILE = \$(CXX) \$(CFLAGS) \$(PKG_CFLAGS) \$(${NAME}_DEFS) \$(${NAME}_INCLUDES) \$(INCLUDES) \$(AM_CPPFLAGS) \$(CPPFLAGS) \$(AM_CFLAGS)" + + foreach {ofile info} [$PROJECT project-compile-products] { + dict set products $ofile $info + set fname [file rootname ${ofile}].${objext} + if {[dict exists $info library]} { +lappend libraries $ofile +continue + } + if {[dict exists $info depend]} { + ::practcl::cputs result "\n${fname}: [dict get $info depend]" + } else { + ::practcl::cputs result "\n${fname}:" + } + set cfile [dict get $info cfile] + if {[file extension $cfile] in {.c++ .cpp}} { + set cmd "\t\$\(${NAME}_CPPCOMPILE\)" + } else { + set cmd "\t\$\(${NAME}_COMPILE\)" + } + if {[dict exists $info extra]} { + append cmd " [dict get $info extra]" + } + append cmd " -c [dict get $info cfile] -o \$@\n\t" + ::practcl::cputs result $cmd + } + + set map {} + lappend map %LIBRARY_NAME% $proj(name) + lappend map %LIBRARY_VERSION% $proj(version) + lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} $proj(version)] + lappend map %LIBRARY_PREFIX% [$PROJECT define getnull libprefix] + + if {[string is true [$PROJECT define get SHARED_BUILD]]} { + set outfile [$PROJECT define get libfile] + } else { + set outfile [$PROJECT shared_library] + } + $PROJECT define set shared_library $outfile + ::practcl::cputs result " +${NAME}_SHLIB = $outfile +${NAME}_OBJS = [dict keys $products] +" + + #lappend map %OUTFILE% {\[$]@} + lappend map %OUTFILE% $outfile + lappend map %LIBRARY_OBJECTS% "\$(${NAME}_OBJS)" + ::practcl::cputs result "$outfile: \$(${NAME}_OBJS)" + ::practcl::cputs result "\t[string map $map [$PROJECT define get PRACTCL_SHARED_LIB]]" + if {[$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL] ni {: {}}} { + ::practcl::cputs result "\t[string map $map [$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL]]" + } + ::practcl::cputs result {} + if {[string is true [$PROJECT define get SHARED_BUILD]]} { + #set outfile [$PROJECT static_library] + set outfile $proj(name).a + } else { + set outfile [$PROJECT define get libfile] + } + $PROJECT define set static_library $outfile + dict set map %OUTFILE% $outfile + ::practcl::cputs result "$outfile: \$(${NAME}_OBJS)" + ::practcl::cputs result "\t[string map $map [$PROJECT define get PRACTCL_STATIC_LIB]]" + ::practcl::cputs result {} + return $result +} +method build-library {outfile PROJECT} { + array set proj [$PROJECT define dump] + set path $proj(builddir) + cd $path + set includedir . + #lappend includedir [::practcl::file_relative $path $proj(TCL_INCLUDES)] + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TCL_SRC_DIR) generic]]] + if {[$PROJECT define get TEA_PRIVATE_TCL_HEADERS 0]} { + if {[$PROJECT define get TEA_PLATFORM] eq "windows"} { + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TCL_SRC_DIR) win]]] + } else { + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TCL_SRC_DIR) unix]]] + } + } + + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(srcdir) generic]]] + + if {[$PROJECT define get tk 0]} { + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) generic]]] + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) ttk]]] + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) xlib]]] + if {[$PROJECT define get TEA_PRIVATE_TK_HEADERS 0]} { + if {[$PROJECT define get TEA_PLATFORM] eq "windows"} { + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) win]]] + } else { + lappend includedir [::practcl::file_relative $path [file normalize [file join $proj(TK_SRC_DIR) unix]]] + } + } + lappend includedir [::practcl::file_relative $path [file normalize $proj(TK_BIN_DIR)]] + } + foreach include [$PROJECT toolset-include-directory] { + set cpath [::practcl::file_relative $path [file normalize $include]] + if {$cpath ni $includedir} { + lappend includedir $cpath + } + } + my build-cflags $PROJECT $proj(DEFS) name version defs + set NAME [string toupper $name] + set debug [$PROJECT define get debug 0] + set os [$PROJECT define get TEACUP_OS] + + set INCLUDES "-I[join $includedir " -I"]" + if {$debug} { + set COMPILE "$proj(CC) $proj(CFLAGS_DEBUG) -ggdb \ +$proj(CFLAGS_WARNING) $INCLUDES $defs" + + if {[info exists proc(CXX)]} { + set COMPILECPP "$proj(CXX) $defs $INCLUDES $proj(CFLAGS_DEBUG) -ggdb \ + $defs $proj(CFLAGS_WARNING)" + } else { + set COMPILECPP $COMPILE + } + } else { + set COMPILE "$proj(CC) $proj(CFLAGS) $defs" + + if {[info exists proc(CXX)]} { + set COMPILECPP "$proj(CXX) $defs $proj(CFLAGS)" + } else { + set COMPILECPP $COMPILE + } + } + + set products [my build-compile-sources $PROJECT $COMPILE $COMPILECPP $INCLUDES] + + set map {} + lappend map %LIBRARY_NAME% $proj(name) + lappend map %LIBRARY_VERSION% $proj(version) + lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} $proj(version)] + lappend map %OUTFILE% $outfile + lappend map %LIBRARY_OBJECTS% $products + lappend map {${CFLAGS}} "$proj(CFLAGS_DEFAULT) $proj(CFLAGS_WARNING)" + + if {[string is true [$PROJECT define get SHARED_BUILD 1]]} { + set cmd [$PROJECT define get PRACTCL_SHARED_LIB] + append cmd " [$PROJECT define get PRACTCL_LIBS]" + set cmd [string map $map $cmd] + puts $cmd + exec {*}$cmd >&@ stdout + if {[$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL] ni {: {}}} { + set cmd [string map $map [$PROJECT define get PRACTCL_VC_MANIFEST_EMBED_DLL]] + puts $cmd + exec {*}$cmd >&@ stdout + } + } else { + set cmd [string map $map [$PROJECT define get PRACTCL_STATIC_LIB]] + puts $cmd + exec {*}$cmd >&@ stdout + } + set ranlib [$PROJECT define get RANLIB] + if {$ranlib ni {{} :}} { + catch {exec $ranlib $outfile} + } +} +method build-tclsh {outfile PROJECT} { + if {[my define get tk 0] && [my define get static_tk 0]} { + puts " BUILDING STATIC TCL/TK EXE $PROJECT" + set TKOBJ [$PROJECT tkcore] + if {[info command $TKOBJ] eq {}} { + set TKOBJ ::noop + $PROJECT define set static_tk 0 + } else { + ::practcl::toolset select $TKOBJ + array set TK [$TKOBJ read_configuration] + set do_tk [$TKOBJ define get static] + $PROJECT define set static_tk $do_tk + $PROJECT define set tk $do_tk + set TKSRCDIR [$TKOBJ define get srcdir] + } + } else { + puts " BUILDING STATIC TCL EXE $PROJECT" + set TKOBJ ::noop + my define set static_tk 0 + } + set TCLOBJ [$PROJECT tclcore] + ::practcl::toolset select $TCLOBJ + set PKG_OBJS {} + foreach item [$PROJECT link list core.library] { + if {[string is true [$item define get static]]} { + lappend PKG_OBJS $item + } + } + foreach item [$PROJECT link list package] { + if {[string is true [$item define get static]]} { + lappend PKG_OBJS $item + } + } + array set TCL [$TCLOBJ read_configuration] + set path [file dirname $outfile] + cd $path + ### + # For a static Tcl shell, we need to build all local sources + # with the same DEFS flags as the tcl core was compiled with. + # The DEFS produced by a TEA extension aren't intended to operate + # with the internals of a staticly linked Tcl + ### + my build-cflags $PROJECT $TCL(defs) name version defs + set debug [$PROJECT define get debug 0] + set NAME [string toupper $name] + set result {} + set libraries {} + set thisline {} + set OBJECTS {} + set EXTERN_OBJS {} + foreach obj $PKG_OBJS { + $obj compile + set config($obj) [$obj read_configuration] + } + set os [$PROJECT define get TEACUP_OS] + set TCLSRCDIR [$TCLOBJ define get srcdir] + + set includedir . + foreach include [$TCLOBJ toolset-include-directory] { + set cpath [::practcl::file_relative $path [file normalize $include]] + if {$cpath ni $includedir} { + lappend includedir $cpath + } + } + lappend includedir [::practcl::file_relative $path [file normalize ../tcl/compat/zlib]] + if {[$PROJECT define get static_tk]} { + lappend includedir [::practcl::file_relative $path [file normalize [file join $TKSRCDIR generic]]] + lappend includedir [::practcl::file_relative $path [file normalize [file join $TKSRCDIR ttk]]] + lappend includedir [::practcl::file_relative $path [file normalize [file join $TKSRCDIR xlib]]] + lappend includedir [::practcl::file_relative $path [file normalize $TKSRCDIR]] + } + + foreach include [$PROJECT toolset-include-directory] { + set cpath [::practcl::file_relative $path [file normalize $include]] + if {$cpath ni $includedir} { + lappend includedir $cpath + } + } + + set INCLUDES "-I[join $includedir " -I"]" + if {$debug} { + set COMPILE "$TCL(cc) $TCL(shlib_cflags) $TCL(cflags_debug) -ggdb \ +$TCL(cflags_warning) $TCL(extra_cflags)" + } else { + set COMPILE "$TCL(cc) $TCL(shlib_cflags) $TCL(cflags_optimize) \ +$TCL(cflags_warning) $TCL(extra_cflags)" + } + append COMPILE " " $defs + lappend OBJECTS {*}[my build-compile-sources $PROJECT $COMPILE $COMPILE $INCLUDES] + + set TCLSRC [file normalize $TCLSRCDIR] + + if {[${PROJECT} define get TEACUP_OS] eq "windows"} { + set windres [$PROJECT define get RC windres] + set RSOBJ [file join $path build tclkit.res.o] + set RCSRC [${PROJECT} define get kit_resource_file] + set RCMAN [${PROJECT} define get kit_manifest_file] + + set cmd [list $windres -o $RSOBJ -DSTATIC_BUILD --include [::practcl::file_relative $path [file join $TCLSRC generic]]] + if {[$PROJECT define get static_tk]} { + if {$RCSRC eq {} || ![file exists $RCSRC]} { + set RCSRC [file join $TKSRCDIR win rc wish.rc] + } + if {$RCMAN eq {} || ![file exists $RCMAN]} { + set RCMAN [file join [$TKOBJ define get builddir] wish.exe.manifest] + } + set TKSRC [file normalize $TKSRCDIR] + lappend cmd --include [::practcl::file_relative $path [file join $TKSRC generic]] \ + --include [::practcl::file_relative $path [file join $TKSRC win]] \ + --include [::practcl::file_relative $path [file join $TKSRC win rc]] + } else { + if {$RCSRC eq {} || ![file exists $RCSRC]} { + set RCSRC [file join $TCLSRCDIR tclsh.rc] + } + if {$RCMAN eq {} || ![file exists $RCMAN]} { + set RCMAN [file join [$TCLOBJ define get builddir] tclsh.exe.manifest] + } + } + foreach item [${PROJECT} define get resource_include] { + lappend cmd --include [::practcl::file_relative $path [file normalize $item]] + } + lappend cmd [file tail $RCSRC] + if {![file exists [file join $path [file tail $RCSRC]]]} { + file copy -force $RCSRC [file join $path [file tail $RCSRC]] + } + if {![file exists [file join $path [file tail $RCMAN]]]} { + file copy -force $RCMAN [file join $path [file tail $RCMAN]] + } + ::practcl::doexec {*}$cmd + lappend OBJECTS $RSOBJ + } + puts "***" + set cmd "$TCL(cc)" + if {$debug} { + append cmd " $TCL(cflags_debug)" + } else { + append cmd " $TCL(cflags_optimize)" + } + append cmd " $TCL(ld_flags)" + if {$debug} { + append cmd " $TCL(ldflags_debug)" + } else { + append cmd " $TCL(ldflags_optimize)" + } + + append cmd " $OBJECTS" + append cmd " $EXTERN_OBJS" + if {$debug && $os eq "windows"} { + ### + # There is bug in the core's autoconf and the value for + # tcl_build_lib_spec does not have the 'g' suffix + ### + append cmd " -L[file dirname $TCL(build_stub_lib_path)] -ltcl86g" + if {[$PROJECT define get static_tk]} { + append cmd " -L[file dirname $TK(build_stub_lib_path)] -ltk86g" + } + } else { + append cmd " $TCL(build_lib_spec)" + if {[$PROJECT define get static_tk]} { + append cmd " $TK(build_lib_spec)" + } + } + foreach obj $PKG_OBJS { + append cmd " [$obj linker-products $config($obj)]" + } + set LIBS {} + foreach item $TCL(libs) { + if {[string range $item 0 1] eq "-l" && $item in $LIBS } continue + lappend LIBS $item + } + if {[$PROJECT define get static_tk]} { + foreach item $TK(libs) { + if {[string range $item 0 1] eq "-l" && $item in $LIBS } continue + lappend LIBS $item + } + } + if {[info exists TCL(extra_libs)]} { + foreach item $TCL(extra_libs) { + if {[string range $item 0 1] eq "-l" && $item in $LIBS } continue + lappend LIBS $item + } + } + foreach obj $PKG_OBJS { + puts [list Checking $obj for external dependencies] + foreach item [$obj linker-external $config($obj)] { + puts [list $obj adds $item] + if {[string range $item 0 1] eq "-l" && $item in $LIBS } continue + lappend LIBS $item + } + } + append cmd " ${LIBS}" + foreach obj $PKG_OBJS { + puts [list Checking $obj for additional link items] + foreach item [$obj linker-extra $config($obj)] { + append cmd $item + } + } + if {$debug && $os eq "windows"} { + append cmd " -L[file dirname $TCL(build_stub_lib_path)] ${TCL(stub_lib_flag)}" + if {[$PROJECT define get static_tk]} { + append cmd " -L[file dirname $TK(build_stub_lib_path)] ${TK(stub_lib_flag)}" + } + } else { + append cmd " $TCL(build_stub_lib_spec)" + if {[$PROJECT define get static_tk]} { + append cmd " $TK(build_stub_lib_spec)" + } + } + if {[info exists TCL(cc_search_flags)]} { + append cmd " $TCL(cc_search_flags)" + } + append cmd " -o $outfile " + if {$os eq "windows"} { + set LDFLAGS_CONSOLE {-mconsole -pipe -static-libgcc} + set LDFLAGS_WINDOW {-mwindows -pipe -static-libgcc} + append cmd " $LDFLAGS_CONSOLE" + } + puts "LINK: $cmd" + exec {*}[string map [list "\n" " " " " " "] $cmd] >&@ stdout +} +} + +### +# END: class toolset gcc.tcl +### +### +# START: class toolset msvc.tcl +### +::clay::define ::practcl::toolset.msvc { + superclass ::practcl::toolset + method BuildDir {PWD} { + set srcdir [my define get srcdir] + return $srcdir + } + Ensemble make::autodetect {} { + } + Ensemble make::clean {} { + set PWD [pwd] + set srcdir [my define get srcdir] + cd $srcdir + catch {::practcl::doexec nmake -f makefile.vc clean} + cd $PWD + } + Ensemble make::compile {} { + set srcdir [my define get srcdir] + if {[my define get static 1]} { + puts "BUILDING Static $name $srcdir" + } else { + puts "BUILDING Dynamic $name $srcdir" + } + cd $srcdir + if {[file exists [file join $srcdir make.tcl]]} { + if {[my define get debug 0]} { + ::practcl::domake.tcl $srcdir debug all + } else { + ::practcl::domake.tcl $srcdir all + } + } else { + if {[file exists [file join $srcdir makefile.vc]]} { + ::practcl::doexec nmake -f makefile.vc INSTALLDIR=[my define get installdir] {*}[my NmakeOpts] release + } elseif {[file exists [file join $srcdir win makefile.vc]]} { + cd [file join $srcdir win] + ::practcl::doexec nmake -f makefile.vc INSTALLDIR=[my define get installdir] {*}[my NmakeOpts] release + } else { + error "No make.tcl or makefile.vc found for project $name" + } + } + } + Ensemble make::install DEST { + set PWD [pwd] + set srcdir [my define get srcdir] + cd $srcdir + if {$DEST eq {}} { + error "No destination given" + } + if {[my define get LOCAL 0] || $DEST eq {}} { + if {[file exists [file join $srcdir make.tcl]]} { + # Practcl builds can inject right to where we need them + puts "[self] Local Install (Practcl)" + ::practcl::domake.tcl $srcdir install + } else { + puts "[self] Local Install (Nmake)" + ::practcl::doexec nmake -f makefile.vc {*}[my NmakeOpts] install + } + } else { + if {[file exists [file join $srcdir make.tcl]]} { + # Practcl builds can inject right to where we need them + puts "[self] VFS INSTALL $DEST (Practcl)" + ::practcl::domake.tcl $srcdir install-package $DEST + } else { + puts "[self] VFS INSTALL $DEST" + ::practcl::doexec nmake -f makefile.vc INSTALLDIR=$DEST {*}[my NmakeOpts] install + } + } + cd $PWD + } + method MakeDir {srcdir} { + set localsrcdir $srcdir + if {[file exists [file join $srcdir generic]]} { + my define add include_dir [file join $srcdir generic] + } + if {[file exists [file join $srcdir win]]} { + my define add include_dir [file join $srcdir win] + } + if {[file exists [file join $srcdir makefile.vc]]} { + set localsrcdir [file join $srcdir win] + } + return $localsrcdir + } + method NmakeOpts {} { + set opts {} + set builddir [file normalize [my define get builddir]] + + if {[my define exists tclsrcdir]} { + ### + # On Windows we are probably running under MSYS, which doesn't deal with + # spaces in filename well + ### + set TCLSRCDIR [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my define get tclsrcdir] ..]]] + set TCLGENERIC [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my define get tclsrcdir] .. generic]]] + lappend opts TCLDIR=[file normalize $TCLSRCDIR] + #--with-tclinclude=$TCLGENERIC + } + if {[my define exists tksrcdir]} { + set TKSRCDIR [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my define get tksrcdir] ..]]] + set TKGENERIC [::practcl::file_relative [file normalize $builddir] [file normalize [file join $::CWD [my define get tksrcdir] .. generic]]] + #lappend opts --with-tk=$TKSRCDIR --with-tkinclude=$TKGENERIC + lappend opts TKDIR=[file normalize $TKSRCDIR] + } + return $opts + } +} + +### +# END: class toolset msvc.tcl +### +### +# START: class target.tcl +### +::clay::define ::practcl::make_obj { + superclass ::practcl::metaclass + constructor {module_object name info {action_body {}}} { + my variable define triggered domake + set triggered 0 + set domake 0 + set define(name) $name + set define(action) {} + array set define $info + my select + my initialize + foreach {stub obj} [$module_object child organs] { + my graft $stub $obj + } + if {$action_body ne {}} { + set define(action) $action_body + } + } + method do {} { + my variable domake + return $domake + } + method check {} { + my variable needs_make domake + if {$domake} { + return 1 + } + if {[info exists needs_make]} { + return $needs_make + } + set make_objects [my make objects] + set needs_make 0 + foreach item [my define get depends] { + if {![dict exists $make_objects $item]} continue + set depobj [dict get $make_objects $item] + if {$depobj eq [self]} { + puts "WARNING [self] depends on itself" + continue + } + if {[$depobj check]} { + set needs_make 1 + } + } + if {!$needs_make} { + foreach filename [my output] { + if {$filename ne {} && ![file exists $filename]} { + set needs_make 1 + } + } + } + return $needs_make + } + method output {} { + set result {} + set filename [my define get filename] + if {$filename ne {}} { + lappend result $filename + } + foreach filename [my define get files] { + if {$filename ne {}} { + lappend result $filename + } + } + return $result + } + method reset {} { + my variable triggered domake needs_make + set triggerd 0 + set domake 0 + set needs_make 0 + } + method triggers {} { + my variable triggered domake define + if {$triggered} { + return $domake + } + set triggered 1 + set make_objects [my make objects] + + foreach item [my define get depends] { + if {![dict exists $make_objects $item]} continue + set depobj [dict get $make_objects $item] + if {$depobj eq [self]} { + puts "WARNING [self] triggers itself" + continue + } else { + set r [$depobj check] + if {$r} { + $depobj triggers + } + } + } + set domake 1 + my make trigger {*}[my define get triggers] + } +} + +### +# END: class target.tcl +### +### +# START: class object.tcl +### +::clay::define ::practcl::object { + superclass ::practcl::metaclass + constructor {parent args} { + my variable links define + set organs [$parent child organs] + my clay delegate {*}$organs + array set define $organs + array set define [$parent child define] + array set links {} + if {[llength $args]==1 && [file exists [lindex $args 0]]} { + my define set filename [lindex $args 0] + ::practcl::product select [self] + } elseif {[llength $args] == 1} { + set data [uplevel 1 [list subst [lindex $args 0]]] + array set define $data + my select + } else { + array set define [uplevel 1 [list subst $args]] + my select + } + my initialize + + } + method child {method} { + return {} + } + method go {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable links + foreach {linktype objs} [array get links] { + foreach obj $objs { + $obj go + } + } + ::practcl::debug [list /[self] [self method] [self class]] + } +} + +### +# END: class object.tcl +### +### +# START: class dynamic.tcl +### +::clay::define ::practcl::dynamic { + method cstructure {name definition {argdat {}}} { + my variable cstruct + dict set cstruct $name body $definition + foreach {f v} $argdat { + dict set cstruct $name $f $v + } + if {![dict exists $cstruct $name public]} { + dict set cstruct $name public 1 + } + } + method include header { + my define add include $header + } + method include_dir args { + my define add include_dir {*}$args + } + method include_directory args { + my define add include_dir {*}$args + } + method c_header body { + my variable code + ::practcl::cputs code(header) $body + } + method c_code body { + my variable code + ::practcl::cputs code(funct) $body + } + method c_function {header body {info {}}} { + set header [string map "\t \ \n \ \ \ \ " $header] + my variable code cfunct + foreach regexp { + {(.*) ([a-zA-Z_][a-zA-Z0-9_]*) *\((.*)\)} + {(.*) (\x2a[a-zA-Z_][a-zA-Z0-9_]*) *\((.*)\)} + } { + if {[regexp $regexp $header all keywords funcname arglist]} { + set dat [dict merge {export 0 extern 0 public 1 inline 0} $info] + dict set dat header $header + dict set dat body $body + dict set dat keywords $keywords + dict set dat arglist $arglist + if {"IRM_INLINE" in $keywords || "CTHULHU_INLINE" in $keywords} { + dict set dat public 1 + dict set dat extern 0 + dict set dat inline 1 + } else { + if {"inline" in $keywords} { + dict set dat inline 1 + } + if {"STUB_EXPORT" in $keywords} { + dict set dat extern 1 + dict set dat public 1 + dict set dat export 1 + dict set dat inline 0 + } elseif {"extern" in $keywords} { + dict set dat extern 1 + dict set dat public 1 + } elseif {"static" in $keywords} { + dict set dat public 0 + } + } + if {[dict get $dat inline] && [dict get $dat public]} { + set header [string map {IRM_INLINE {} CTHULHU_INLINE {} static {} inline {} extern {}} [dict get $dat header]] + dict set dat header "extern $header" + } + dict set cfunct $funcname $dat + return + } + } + puts "WARNING: NON CONFORMING FUNCTION DEFINITION: $headers $body" + ::practcl::cputs code(header) "$header\;" + # Could not parse that block as a function + # append it verbatim to our c_implementation + ::practcl::cputs code(funct) "$header [list $body]" + } + method c_tcloomethod {name body {arginfo {}}} { + my variable methods code + foreach {f v} $arginfo { + dict set methods $name $f $v + } + dict set methods $name body "Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext); /* The current connection object */ +$body" + } + method cmethod {name body {arginfo {}}} { + my variable methods code + foreach {f v} $arginfo { + dict set methods $name $f $v + } + dict set methods $name body "Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext); /* The current connection object */ +$body" + } + method c_tclproc_nspace nspace { + my variable code + if {![info exists code(nspace)]} { + set code(nspace) {} + } + if {$nspace ni $code(nspace)} { + lappend code(nspace) $nspace + } + } + method c_tclcmd {name body {arginfo {}}} { + my variable tclprocs code + + foreach {f v} $arginfo { + dict set tclprocs $name $f $v + } + dict set tclprocs $name body $body + } + method c_tclproc_raw {name body {arginfo {}}} { + my variable tclprocs code + + foreach {f v} $arginfo { + dict set tclprocs $name $f $v + } + dict set tclprocs $name body $body + } + method tcltype {name argdat} { + my variable tcltype + foreach {f v} $argdat { + dict set tcltype $name $f $v + } + if {![dict exists tcltype $name cname]} { + dict set tcltype $name cname [string tolower $name]_tclobjtype + } + lappend map @NAME@ $name + set info [dict get $tcltype $name] + foreach {f v} $info { + lappend map @[string toupper $f]@ $v + } + foreach {func fpat template} { + freeproc {@Name@Obj_freeIntRepProc} {void @FNAME@(Tcl_Obj *objPtr)} + dupproc {@Name@Obj_dupIntRepProc} {void @FNAME@(Tcl_Obj *srcPtr,Tcl_Obj *dupPtr)} + updatestringproc {@Name@Obj_updateStringRepProc} {void @FNAME@(Tcl_Obj *objPtr)} + setfromanyproc {@Name@Obj_setFromAnyProc} {int @FNAME@(Tcl_Interp *interp,Tcl_Obj *objPtr)} + } { + if {![dict exists $info $func]} { + error "$name does not define $func" + } + set body [dict get $info $func] + # We were given a function name to call + if {[llength $body] eq 1} continue + set fname [string map [list @Name@ [string totitle $name]] $fpat] + my c_function [string map [list @FNAME@ $fname] $template] [string map $map $body] + dict set tcltype $name $func $fname + } + } + method project-compile-products {} { + set filename [my define get output_c] + set result {} + if {$filename ne {}} { + ::practcl::debug [self] [self class] [self method] project-compile-products $filename + + if {[my define exists ofile]} { + set ofile [my define get ofile] + } else { + set ofile [my Ofile $filename] + my define set ofile $ofile + } + lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]]] + } else { + set filename [my define get cfile] + if {$filename ne {}} { + ::practcl::debug [self] [self class] [self method] project-compile-products $filename + if {[my define exists ofile]} { + set ofile [my define get ofile] + } else { + set ofile [my Ofile $filename] + my define set ofile $ofile + } + lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]]] + } + } + foreach item [my link list subordinate] { + lappend result {*}[$item project-compile-products] + } + return $result + } + method implement path { + my go + my Collate_Source $path + if {[my define get output_c] eq {}} return + set filename [file join $path [my define get output_c]] + ::practcl::debug [self] [my define get filename] WANTS TO GENERATE $filename + my define set cfile $filename + set fout [open $filename w] + puts $fout [my generate-c] + if {[my define get initfunc] ne {}} { + puts $fout "extern int DLLEXPORT [my define get initfunc]( Tcl_Interp *interp ) \x7B" + puts $fout [my generate-loader-module] + if {[my define get pkg_name] ne {}} { + puts $fout " Tcl_PkgProvide(interp, \"[my define get pkg_name]\", \"[my define get pkg_vers]\");" + } + puts $fout " return TCL_OK\;" + puts $fout "\x7D" + } + close $fout + } + method initialize {} { + set filename [my define get filename] + if {$filename eq {}} { + return + } + if {[my define get name] eq {}} { + my define set name [file tail [file rootname $filename]] + } + if {[my define get localpath] eq {}} { + my define set localpath [my define get localpath]_[my define get name] + } + ::source $filename + } + method linktype {} { + return {subordinate product dynamic} + } + method generate-cfile-constant {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result {} + my variable code cstruct methods tcltype + if {[info exists code(constant)]} { + ::practcl::cputs result "/* [my define get filename] CONSTANT */" + ::practcl::cputs result $code(constant) + } + if {[info exists cstruct]} { + foreach {name info} $cstruct { + set map {} + lappend map @NAME@ $name + lappend map @MACRO@ GET[string toupper $name] + + if {[dict exists $info deleteproc]} { + lappend map @DELETEPROC@ [dict get $info deleteproc] + } else { + lappend map @DELETEPROC@ NULL + } + if {[dict exists $info cloneproc]} { + lappend map @CLONEPROC@ [dict get $info cloneproc] + } else { + lappend map @CLONEPROC@ NULL + } + ::practcl::cputs result [string map $map { +const static Tcl_ObjectMetadataType @NAME@DataType = { + TCL_OO_METADATA_VERSION_CURRENT, + "@NAME@", + @DELETEPROC@, + @CLONEPROC@ +}; +#define @MACRO@(OBJCONTEXT) (@NAME@ *) Tcl_ObjectGetMetadata(OBJCONTEXT,&@NAME@DataType) +}] + } + } + if {[info exists tcltype]} { + foreach {type info} $tcltype { + dict with info {} + ::practcl::cputs result "const Tcl_ObjType $cname = \{\n .name=\"$type\",\n .freeIntRepProc = &${freeproc},\n .dupIntRepProc = &${dupproc},\n .updateStringProc = &${updatestringproc},\n .setFromAnyProc = &${setfromanyproc}\n\}\;" + } + } + + if {[info exists methods]} { + set mtypes {} + foreach {name info} $methods { + set callproc [dict get $info callproc] + set methodtype [dict get $info methodtype] + if {$methodtype in $mtypes} continue + lappend mtypes $methodtype + ### + # Build the data struct for this method + ### + ::practcl::cputs result "const static Tcl_MethodType $methodtype = \{" + ::practcl::cputs result " .version = TCL_OO_METADATA_VERSION_CURRENT,\n .name = \"$name\",\n .callProc = $callproc," + if {[dict exists $info deleteproc]} { + set deleteproc [dict get $info deleteproc] + } else { + set deleteproc NULL + } + if {$deleteproc ni { {} NULL }} { + ::practcl::cputs result " .deleteProc = $deleteproc," + } else { + ::practcl::cputs result " .deleteProc = NULL," + } + if {[dict exists $info cloneproc]} { + set cloneproc [dict get $info cloneproc] + } else { + set cloneproc NULL + } + if {$cloneproc ni { {} NULL }} { + ::practcl::cputs result " .cloneProc = $cloneproc\n\}\;" + } else { + ::practcl::cputs result " .cloneProc = NULL\n\}\;" + } + dict set methods $name methodtype $methodtype + } + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + ::practcl::cputs result [$obj generate-cfile-constant] + } + return $result + } + method generate-cfile-header {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cfunct cstruct methods tcltype tclprocs + set result {} + if {[info exists code(header)]} { + ::practcl::cputs result $code(header) + } + ::practcl::debug [list cfunct [info exists cfunct]] + if {[info exists cfunct]} { + foreach {funcname info} $cfunct { + if {[dict get $info public]} continue + ::practcl::cputs result "[dict get $info header]\;" + } + } + ::practcl::debug [list tclprocs [info exists tclprocs]] + if {[info exists tclprocs]} { + foreach {name info} $tclprocs { + if {[dict exists $info header]} { + ::practcl::cputs result "[dict get $info header]\;" + } + } + } + ::practcl::debug [list methods [info exists methods] [my define get cclass]] + if {[info exists methods]} { + set thisclass [my define get cclass] + foreach {name info} $methods { + if {[dict exists $info header]} { + ::practcl::cputs result "[dict get $info header]\;" + } + } + # Add the initializer wrapper for the class + ::practcl::cputs result "static int ${thisclass}_OO_Init(Tcl_Interp *interp)\;" + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + set dat [$obj generate-cfile-header] + if {[string length [string trim $dat]]} { + ::practcl::cputs result "/* BEGIN [$obj define get filename] generate-cfile-header */" + ::practcl::cputs result $dat + ::practcl::cputs result "/* END [$obj define get filename] generate-cfile-header */" + } + } + return $result + } + method generate-cfile-tclapi {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code methods tclprocs + set result {} + if {[info exists code(method)]} { + ::practcl::cputs result $code(method) + } + + if {[info exists tclprocs]} { + foreach {name info} $tclprocs { + if {![dict exists $info body]} continue + set callproc [dict get $info callproc] + set header [dict get $info header] + set body [dict get $info body] + ::practcl::cputs result "/* Tcl Proc $name */" + ::practcl::cputs result "${header} \{${body}\}" + } + } + + + if {[info exists methods]} { + set thisclass [my define get cclass] + foreach {name info} $methods { + if {![dict exists $info body]} continue + set callproc [dict get $info callproc] + set header [dict get $info header] + set body [dict get $info body] + ::practcl::cputs result "/* OO Method $thisclass $name */" + ::practcl::cputs result "${header} \{${body}\}" + } + # Build the OO_Init function + ::practcl::cputs result "/* Loader for $thisclass */" + ::practcl::cputs result "static int ${thisclass}_OO_Init(Tcl_Interp *interp) \{" + ::practcl::cputs result [string map [list @CCLASS@ $thisclass @TCLCLASS@ [my define get class]] { + /* + ** Build the "@TCLCLASS@" class + */ + Tcl_Obj* nameObj; /* Name of a class or method being looked up */ + Tcl_Object curClassObject; /* Tcl_Object representing the current class */ + Tcl_Class curClass; /* Tcl_Class representing the current class */ + + /* + * Find the "@TCLCLASS@" class, and attach an 'init' method to it. + */ + + nameObj = Tcl_NewStringObj("@TCLCLASS@", -1); + Tcl_IncrRefCount(nameObj); + if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) { + Tcl_DecrRefCount(nameObj); + return TCL_ERROR; + } + Tcl_DecrRefCount(nameObj); + curClass = Tcl_GetObjectAsClass(curClassObject); +}] + if {[dict exists $methods constructor]} { + set mtype [dict get $methods constructor methodtype] + ::practcl::cputs result [string map [list @MTYPE@ $mtype] { + /* Attach the constructor to the class */ + Tcl_ClassSetConstructor(interp, curClass, Tcl_NewMethod(interp, curClass, NULL, 1, &@MTYPE@, NULL)); + }] + } + foreach {name info} $methods { + dict with info {} + if {$name in {constructor destructor}} continue + ::practcl::cputs result [string map [list @NAME@ $name @MTYPE@ $methodtype] { + nameObj=Tcl_NewStringObj("@NAME@",-1); + Tcl_NewMethod(interp, curClass, nameObj, 1, &@MTYPE@, (ClientData) NULL); + Tcl_DecrRefCount(nameObj); +}] + if {[dict exists $info aliases]} { + foreach alias [dict get $info aliases] { + if {[dict exists $methods $alias]} continue + ::practcl::cputs result [string map [list @NAME@ $alias @MTYPE@ $methodtype] { + nameObj=Tcl_NewStringObj("@NAME@",-1); + Tcl_NewMethod(interp, curClass, nameObj, 1, &@MTYPE@, (ClientData) NULL); + Tcl_DecrRefCount(nameObj); +}] + } + } + } + ::practcl::cputs result " return TCL_OK\;\n\}\n" + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + ::practcl::cputs result [$obj generate-cfile-tclapi] + } + return $result + } + method generate-loader-module {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result {} + my variable code methods tclprocs + if {[info exists code(nspace)]} { + ::practcl::cputs result " \{\n Tcl_Namespace *modPtr;" + foreach nspace $code(nspace) { + ::practcl::cputs result [string map [list @NSPACE@ $nspace] { + modPtr=Tcl_FindNamespace(interp,"@NSPACE@",NULL,TCL_NAMESPACE_ONLY); + if(!modPtr) { + modPtr = Tcl_CreateNamespace(interp, "@NSPACE@", NULL, NULL); + } +}] + } + ::practcl::cputs result " \}" + } + if {[info exists code(tclinit)]} { + ::practcl::cputs result $code(tclinit) + } + if {[info exists code(cinit)]} { + ::practcl::cputs result $code(cinit) + } + if {[info exists code(initfuncts)]} { + foreach func $code(initfuncts) { + ::practcl::cputs result " if (${func}(interp) != TCL_OK) return TCL_ERROR\;" + } + } + if {[info exists tclprocs]} { + foreach {name info} $tclprocs { + set map [list @NAME@ $name @CALLPROC@ [dict get $info callproc]] + ::practcl::cputs result [string map $map { Tcl_CreateObjCommand(interp,"@NAME@",(Tcl_ObjCmdProc *)@CALLPROC@,NULL,NULL);}] + if {[dict exists $info aliases]} { + foreach alias [dict get $info aliases] { + set map [list @NAME@ $alias @CALLPROC@ [dict get $info callproc]] + ::practcl::cputs result [string map $map { Tcl_CreateObjCommand(interp,"@NAME@",(Tcl_ObjCmdProc *)@CALLPROC@,NULL,NULL);}] + } + } + } + } + + if {[info exists code(nspace)]} { + ::practcl::cputs result " \{\n Tcl_Namespace *modPtr;" + foreach nspace $code(nspace) { + ::practcl::cputs result [string map [list @NSPACE@ $nspace] { + modPtr=Tcl_FindNamespace(interp,"@NSPACE@",NULL,TCL_NAMESPACE_ONLY); + Tcl_CreateEnsemble(interp, modPtr->fullName, modPtr, TCL_ENSEMBLE_PREFIX); + Tcl_Export(interp, modPtr, "[a-z]*", 1); +}] + } + ::practcl::cputs result " \}" + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} { + ::practcl::cputs result [$obj generate-loader-external] + } else { + ::practcl::cputs result [$obj generate-loader-module] + } + } + return $result + } + method Collate_Source CWD { + my variable methods code cstruct tclprocs + if {[info exists methods]} { + ::practcl::debug [self] methods [my define get cclass] + set thisclass [my define get cclass] + foreach {name info} $methods { + # Provide a callproc + if {![dict exists $info callproc]} { + set callproc [string map {____ _ ___ _ __ _} [string map {{ } _ : _} OOMethod_${thisclass}_${name}]] + dict set methods $name callproc $callproc + } else { + set callproc [dict get $info callproc] + } + if {[dict exists $info body] && ![dict exists $info header]} { + dict set methods $name header "static int ${callproc}(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)" + } + if {![dict exists $info methodtype]} { + set methodtype [string map {{ } _ : _} OOMethodType_${thisclass}_${name}] + dict set methods $name methodtype $methodtype + } + } + if {![info exists code(initfuncts)] || "${thisclass}_OO_Init" ni $code(initfuncts)} { + lappend code(initfuncts) "${thisclass}_OO_Init" + } + } + set thisnspace [my define get nspace] + + if {[info exists tclprocs]} { + ::practcl::debug [self] tclprocs [dict keys $tclprocs] + foreach {name info} $tclprocs { + if {![dict exists $info callproc]} { + set callproc [string map {____ _ ___ _ __ _} [string map {{ } _ : _} TclCmd_${thisnspace}_${name}]] + dict set tclprocs $name callproc $callproc + } else { + set callproc [dict get $info callproc] + } + if {[dict exists $info body] && ![dict exists $info header]} { + dict set tclprocs $name header "static int ${callproc}(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv\[\])" + } + } + } + } + method select {} {} +} + +### +# END: class dynamic.tcl +### +### +# START: class product.tcl +### +::clay::define ::practcl::product { + method code {section body} { + my variable code + ::practcl::cputs code($section) $body + } + method Collate_Source CWD {} + method project-compile-products {} { + set result {} + noop { + set filename [my define get filename] + if {$filename ne {}} { + ::practcl::debug [self] [self class] [self method] project-compile-products $filename + if {[my define exists ofile]} { + set ofile [my define get ofile] + } else { + set ofile [my Ofile $filename] + my define set ofile $ofile + } + lappend result $ofile [list cfile $filename include [my define get include] extra [my define get extra] external [string is true -strict [my define get external]] object [self]] + } + } + foreach item [my link list subordinate] { + lappend result {*}[$item project-compile-products] + } + return $result + } + method generate-debug {{spaces {}}} { + set result {} + ::practcl::cputs result "$spaces[list [self] [list class [info object class [self]] filename [my define get filename]] links [my link list]]" + foreach item [my link list subordinate] { + practcl::cputs result [$item generate-debug "$spaces "] + } + return $result + } + method generate-cfile-constant {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result {} + my variable code cstruct methods tcltype + if {[info exists code(constant)]} { + ::practcl::cputs result "/* [my define get filename] CONSTANT */" + ::practcl::cputs result $code(constant) + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + ::practcl::cputs result [$obj generate-cfile-constant] + } + return $result + } + method generate-cfile-public-structure {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cstruct methods tcltype + set result {} + if {[info exists code(struct)]} { + ::practcl::cputs result $code(struct) + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + ::practcl::cputs result [$obj generate-cfile-public-structure] + } + return $result + } + method generate-cfile-header {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cfunct cstruct methods tcltype tclprocs + set result {} + if {[info exists code(header)]} { + ::practcl::cputs result $code(header) + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + set dat [$obj generate-cfile-header] + if {[string length [string trim $dat]]} { + ::practcl::cputs result "/* BEGIN [$obj define get filename] generate-cfile-header */" + ::practcl::cputs result $dat + ::practcl::cputs result "/* END [$obj define get filename] generate-cfile-header */" + } + } + return $result + } + method generate-cfile-global {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cfunct cstruct methods tcltype tclprocs + set result {} + if {[info exists code(global)]} { + ::practcl::cputs result $code(global) + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + set dat [$obj generate-cfile-global] + if {[string length [string trim $dat]]} { + ::practcl::cputs result "/* BEGIN [$obj define get filename] generate-cfile-global */" + ::practcl::cputs result $dat + ::practcl::cputs result "/* END [$obj define get filename] generate-cfile-global */" + } + } + return $result + } + method generate-cfile-private-typedef {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cstruct + set result {} + if {[info exists code(private-typedef)]} { + ::practcl::cputs result $code(private-typedef) + } + if {[info exists cstruct]} { + # Add defintion for native c data structures + foreach {name info} $cstruct { + if {[dict get $info public]==1} continue + ::practcl::cputs result "typedef struct $name ${name}\;" + if {[dict exists $info aliases]} { + foreach n [dict get $info aliases] { + ::practcl::cputs result "typedef struct $name ${n}\;" + } + } + } + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-cfile-private-typedef] + } + return $result + } + method generate-cfile-private-structure {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cstruct + set result {} + if {[info exists code(private-structure)]} { + ::practcl::cputs result $code(private-structure) + } + if {[info exists cstruct]} { + foreach {name info} $cstruct { + if {[dict get $info public]==1} continue + if {[dict exists $info comment]} { + ::practcl::cputs result [dict get $info comment] + } + ::practcl::cputs result "struct $name \{[dict get $info body]\}\;" + } + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-cfile-private-structure] + } + return $result + } + method generate-cfile-functions {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cfunct + set result {} + if {[info exists code(funct)]} { + ::practcl::cputs result $code(funct) + } + if {[info exists cfunct]} { + foreach {funcname info} $cfunct { + ::practcl::cputs result "/* $funcname */" + if {[dict get $info inline] && [dict get $info public]} { + ::practcl::cputs result "\ninline [dict get $info header]\{[dict get $info body]\}" + } else { + ::practcl::cputs result "\n[dict get $info header]\{[dict get $info body]\}" + } + } + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} { + continue + } + ::practcl::cputs result [$obj generate-cfile-functions] + } + return $result + } + method generate-cfile-tclapi {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code methods tclprocs + set result {} + if {[info exists code(method)]} { + ::practcl::cputs result $code(method) + } + foreach obj [my link list product] { + # Exclude products that will generate their own C files + if {[$obj define get output_c] ne {}} continue + ::practcl::cputs result [$obj generate-cfile-tclapi] + } + return $result + } + method generate-hfile-public-define {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code + set result {} + if {[info exists code(public-define)]} { + ::practcl::cputs result $code(public-define) + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-hfile-public-define] + } + return $result + } + method generate-hfile-public-macro {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code + set result {} + if {[info exists code(public-macro)]} { + ::practcl::cputs result $code(public-macro) + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-hfile-public-macro] + } + return $result + } + method generate-hfile-public-typedef {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cstruct + set result {} + if {[info exists code(public-typedef)]} { + ::practcl::cputs result $code(public-typedef) + } + if {[info exists cstruct]} { + # Add defintion for native c data structures + foreach {name info} $cstruct { + if {[dict get $info public]==0} continue + ::practcl::cputs result "typedef struct $name ${name}\;" + if {[dict exists $info aliases]} { + foreach n [dict get $info aliases] { + ::practcl::cputs result "typedef struct $name ${n}\;" + } + } + } + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-hfile-public-typedef] + } + return $result + } + method generate-hfile-public-structure {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cstruct + set result {} + if {[info exists code(public-structure)]} { + ::practcl::cputs result $code(public-structure) + } + if {[info exists cstruct]} { + foreach {name info} $cstruct { + if {[dict get $info public]==0} continue + if {[dict exists $info comment]} { + ::practcl::cputs result [dict get $info comment] + } + ::practcl::cputs result "struct $name \{[dict get $info body]\}\;" + } + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-hfile-public-structure] + } + return $result + } + method generate-hfile-public-headers {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code tcltype + set result {} + if {[info exists code(public-header)]} { + ::practcl::cputs result $code(public-header) + } + if {[info exists tcltype]} { + foreach {type info} $tcltype { + if {![dict exists $info cname]} { + set cname [string tolower ${type}]_tclobjtype + dict set tcltype $type cname $cname + } else { + set cname [dict get $info cname] + } + ::practcl::cputs result "extern const Tcl_ObjType $cname\;" + } + } + if {[info exists code(public)]} { + ::practcl::cputs result $code(public) + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-hfile-public-headers] + } + return $result + } + method generate-hfile-public-function {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cfunct tcltype + set result {} + + if {[my define get initfunc] ne {}} { + ::practcl::cputs result "int [my define get initfunc](Tcl_Interp *interp);" + } + if {[info exists cfunct]} { + foreach {funcname info} $cfunct { + if {![dict get $info public]} continue + ::practcl::cputs result "[dict get $info header]\;" + } + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-hfile-public-function] + } + return $result + } + method generate-hfile-public-includes {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set includes {} + foreach item [my define get public-include] { + if {$item ni $includes} { + lappend includes $item + } + } + foreach mod [my link list product] { + foreach item [$mod generate-hfile-public-includes] { + if {$item ni $includes} { + lappend includes $item + } + } + } + return $includes + } + method generate-hfile-public-verbatim {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set includes {} + foreach item [my define get public-verbatim] { + if {$item ni $includes} { + lappend includes $item + } + } + foreach mod [my link list subordinate] { + foreach item [$mod generate-hfile-public-verbatim] { + if {$item ni $includes} { + lappend includes $item + } + } + } + return $includes + } + method generate-loader-external {} { + if {[my define get initfunc] eq {}} { + return "/* [my define get filename] declared not initfunc */" + } + return " if([my define get initfunc](interp)) return TCL_ERROR\;" + } + method generate-loader-module {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code + set result {} + if {[info exists code(cinit)]} { + ::practcl::cputs result $code(cinit) + } + if {[my define get initfunc] ne {}} { + ::practcl::cputs result " if([my define get initfunc](interp)!=TCL_OK) return TCL_ERROR\;" + } + set result [::practcl::_tagblock $result c [my define get filename]] + foreach item [my link list product] { + if {[$item define get output_c] ne {}} { + ::practcl::cputs result [$item generate-loader-external] + } else { + ::practcl::cputs result [$item generate-loader-module] + } + } + return $result + } + method generate-stub-function {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + my variable code cfunct tcltype + set result {} + foreach mod [my link list product] { + foreach {funct def} [$mod generate-stub-function] { + dict set result $funct $def + } + } + if {[info exists cfunct]} { + foreach {funcname info} $cfunct { + if {![dict get $info export]} continue + dict set result $funcname [dict get $info header] + } + } + return $result + } + method IncludeAdd {headervar args} { + upvar 1 $headervar headers + foreach inc $args { + if {[string index $inc 0] ni {< \"}} { + set inc "\"$inc\"" + } + if {$inc ni $headers} { + lappend headers $inc + } + } + } + method generate-tcl-loader {} { + set result {} + set PKGINIT [my define get pkginit] + set PKG_NAME [my define get name [my define get pkg_name]] + set PKG_VERSION [my define get pkg_vers [my define get version]] + if {[string is true [my define get SHARED_BUILD 0]]} { + set LIBFILE [my define get libfile] + ::practcl::cputs result [string map \ + [list @LIBFILE@ $LIBFILE @PKGINIT@ $PKGINIT @PKG_NAME@ $PKG_NAME @PKG_VERSION@ $PKG_VERSION] { +# Shared Library Style +load [file join [file dirname [file join [pwd] [info script]]] @LIBFILE@] @PKGINIT@ +package provide @PKG_NAME@ @PKG_VERSION@ +}] + } else { + ::practcl::cputs result [string map \ + [list @PKGINIT@ $PKGINIT @PKG_NAME@ $PKG_NAME @PKG_VERSION@ $PKG_VERSION] { +# Tclkit Style +load {} @PKGINIT@ +package provide @PKG_NAME@ @PKG_VERSION@ +}] + } + return $result + } + method generate-tcl-pre {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result {} + my variable code + if {[info exists code(tcl)]} { + set result [::practcl::_tagblock $code(tcl) tcl [my define get filename]] + } + if {[info exists code(tcl-pre)]} { + set result [::practcl::_tagblock $code(tcl) tcl [my define get filename]] + } + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-tcl-pre] + } + return $result + } + method generate-tcl-post {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result {} + my variable code + if {[info exists code(tcl-post)]} { + set result [::practcl::_tagblock $code(tcl-post) tcl [my define get filename]] + } + foreach mod [my link list product] { + ::practcl::cputs result [$mod generate-tcl-post] + } + return $result + } + method linktype {} { + return {subordinate product} + } + method Ofile filename { + set lpath [my define get localpath] + if {$lpath eq {}} { + set lpath [my define get name] + } + return ${lpath}_[file rootname [file tail $filename]] + } + method project-static-packages {} { + set result [my define get static_packages] + set initfunc [my define get initfunc] + if {$initfunc ne {}} { + set pkg_name [my define get pkg_name] + if {$pkg_name ne {}} { + dict set result $pkg_name initfunc $initfunc + dict set result $pkg_name version [my define get version [my define get pkg_vers]] + dict set result $pkg_name autoload [my define get autoload 0] + } + } + foreach item [my link list subordinate] { + foreach {pkg info} [$item project-static-packages] { + dict set result $pkg $info + } + } + return $result + } + method toolset-include-directory {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result [my define get include_dir] + foreach obj [my link list product] { + foreach path [$obj toolset-include-directory] { + lappend result $path + } + } + return $result + } + method target {method args} { + switch $method { + is_unix { return [expr {$::tcl_platform(platform) eq "unix"}] } + } + } +} +oo::objdefine ::practcl::product { + + method select {object} { + set class [$object define get class] + set mixin [$object define get product] + if {$class eq {} && $mixin eq {}} { + set filename [$object define get filename] + if {$filename ne {} && [file exists $filename]} { + switch [file extension $filename] { + .tcl { + set mixin ::practcl::product.dynamic + } + .h { + set mixin ::practcl::product.cheader + } + .c { + set mixin ::practcl::product.csource + } + .ini { + switch [file tail $filename] { + module.ini { + set class ::practcl::module + } + library.ini { + set class ::practcl::subproject + } + } + } + .so - + .dll - + .dylib - + .a { + set mixin ::practcl::product.clibrary + } + } + } + } + if {$class ne {}} { + $object clay mixinmap core $class + } + if {$mixin ne {}} { + $object clay mixinmap product $mixin + } + } +} +::clay::define ::practcl::product.cheader { + superclass ::practcl::product + method project-compile-products {} {} + method generate-loader-module {} {} +} +::clay::define ::practcl::product.csource { + superclass ::practcl::product + method project-compile-products {} { + set result {} + set filename [my define get filename] + if {$filename ne {}} { + ::practcl::debug [self] [self class] [self method] project-compile-products $filename + if {[my define exists ofile]} { + set ofile [my define get ofile] + } else { + set ofile [my Ofile $filename] + my define set ofile $ofile + } + lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]] object [self]] + } + foreach item [my link list subordinate] { + lappend result {*}[$item project-compile-products] + } + return $result + } +} +::clay::define ::practcl::product.clibrary { + superclass ::practcl::product + method linker-products {configdict} { + return [my define get filename] + } +} +::clay::define ::practcl::product.dynamic { + superclass ::practcl::dynamic ::practcl::product + method initialize {} { + set filename [my define get filename] + if {$filename eq {}} { + return + } + if {[my define get name] eq {}} { + my define set name [file tail [file rootname $filename]] + } + if {[my define get localpath] eq {}} { + my define set localpath [my define get localpath]_[my define get name] + } + # Future Development: + # Scan source file to see if it is encoded in criticl or practcl notation + #set thisline {} + #foreach line [split [::practcl::cat $filename] \n] { + # + #} + ::source $filename + if {[my define get output_c] ne {}} { + # Turn into a module if we have an output_c file + my morph ::practcl::module + } + } +} +::clay::define ::practcl::product.critcl { + superclass ::practcl::dynamic ::practcl::product +} + +### +# END: class product.tcl +### +### +# START: class module.tcl +### +::clay::define ::practcl::module { + superclass ::practcl::object ::practcl::product.dynamic + Dict make_object {} + method _MorphPatterns {} { + return {{@name@} {::practcl::module.@name@} ::practcl::module} + } + method add args { + my variable links + set object [::practcl::object new [self] {*}$args] + foreach linktype [$object linktype] { + lappend links($linktype) $object + } + return $object + } + method install-headers args {} + Ensemble make::_preamble {} { + my variable make_object + if {![info exists make_object]} { + set make_object {} + } + } + Ensemble make::pkginfo {} { + ### + # Build local variables needed for install + ### + package require platform + set result {} + set dat [my define dump] + set PKG_DIR [dict get $dat name][dict get $dat version] + dict set result PKG_DIR $PKG_DIR + dict with dat {} + if {![info exists DESTDIR]} { + set DESTDIR {} + } + dict set result profile [::platform::identify] + dict set result os $::tcl_platform(os) + dict set result platform $::tcl_platform(platform) + foreach {field value} $dat { + switch $field { + includedir - + mandir - + datadir - + libdir - + libfile - + name - + output_tcl - + version - + authors - + license - + requires { + dict set result $field $value + } + TEA_PLATFORM { + dict set result platform $value + } + TEACUP_OS { + dict set result os $value + } + TEACUP_PROFILE { + dict set result profile $value + } + TEACUP_ZIPFILE { + dict set result zipfile $value + } + } + } + if {![dict exists $result zipfile]} { + dict set result zipfile "[dict get $result name]-[dict get $result version]-[dict get $result profile].zip" + } + return $result + } + Ensemble make::objects {} { + return $make_object + } + Ensemble make::object name { + if {[dict exists $make_object $name]} { + return [dict get $make_object $name] + } + return {} + } + Ensemble make::reset {} { + foreach {name obj} $make_object { + $obj reset + } + } + Ensemble make::trigger args { + foreach {name obj} $make_object { + if {$name in $args} { + $obj triggers + } + } + } + Ensemble make::depends args { + foreach {name obj} $make_object { + if {$name in $args} { + $obj check + } + } + } + Ensemble make::filename name { + if {[dict exists $make_object $name]} { + return [[dict get $make_object $name] define get filename] + } + } + Ensemble make::target {name Info body} { + set info [uplevel #0 [list subst $Info]] + set nspace [namespace current] + if {[dict exist $make_object $name]} { + set obj [dict get $$make_object $name] + } else { + set obj [::practcl::make_obj new [self] $name $info $body] + dict set make_object $name $obj + dict set target_make $name 0 + dict set target_trigger $name 0 + } + if {[dict exists $info aliases]} { + foreach item [dict get $info aliases] { + if {![dict exists $make_object $item]} { + dict set make_object $item $obj + } + } + } + return $obj + } + clay set method_ensemble make target aliases {task add} + Ensemble make::todo {} { + foreach {name obj} $make_object { + if {[$obj do]} { + lappend result $name + } + } + return $result + } + Ensemble make::do {} { + global CWD SRCDIR project SANDBOX + foreach {name obj} $make_object { + if {[$obj do]} { + eval [$obj define get action] + } + } + } + method child which { + switch $which { + delegate - + organs { + return [list project [my define get project] module [self]] + } + } + } + method generate-c {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result { +/* This file was generated by practcl */ + } + set includes {} + + foreach mod [my link list product] { + # Signal modules to formulate final implementation + $mod go + } + set headers {} + + my IncludeAdd headers + if {[my define get tk 0]} { + my IncludeAdd headers + } + if {[my define get output_h] ne {}} { + my IncludeAdd headers [my define get output_h] + } + my IncludeAdd headers {*}[my define get include] + + foreach mod [my link list dynamic] { + my IncludeAdd headers {*}[$mod define get include] + } + foreach inc $headers { + ::practcl::cputs result "#include $inc" + } + foreach {method} { + generate-cfile-header + generate-cfile-private-typedef + generate-cfile-private-structure + generate-cfile-public-structure + generate-cfile-constant + generate-cfile-global + generate-cfile-functions + generate-cfile-tclapi + } { + set dat [my $method] + if {[string length [string trim $dat]]} { + ::practcl::cputs result "/* BEGIN $method [my define get filename] */" + ::practcl::cputs result $dat + ::practcl::cputs result "/* END $method [my define get filename] */" + } + } + ::practcl::debug [list /[self] [self method] [self class] -- [my define get filename] [info object class [self]]] + return $result + } + method generate-h {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result {} + foreach method { + generate-hfile-public-define + generate-hfile-public-macro + } { + ::practcl::cputs result "/* BEGIN SECTION $method */" + ::practcl::cputs result [my $method] + ::practcl::cputs result "/* END SECTION $method */" + } + set includes [my generate-hfile-public-includes] + foreach inc $includes { + if {[string index $inc 0] ni {< \"}} { + ::practcl::cputs result "#include \"$inc\"" + } else { + ::practcl::cputs result "#include $inc" + } + } + foreach method { + generate-hfile-public-typedef + generate-hfile-public-structure + } { + ::practcl::cputs result "/* BEGIN SECTION $method */" + ::practcl::cputs result [my $method] + ::practcl::cputs result "/* END SECTION $method */" + } + + foreach file [my generate-hfile-public-verbatim] { + ::practcl::cputs result "/* BEGIN $file */" + ::practcl::cputs result [::practcl::cat $file] + ::practcl::cputs result "/* END $file */" + } + + foreach method { + generate-hfile-public-headers + generate-hfile-public-function + } { + ::practcl::cputs result "/* BEGIN SECTION $method */" + ::practcl::cputs result [my $method] + ::practcl::cputs result "/* END SECTION $method */" + } + return $result + } + method generate-loader {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set result {} + if {[my define get initfunc] eq {}} return + ::practcl::cputs result " +extern int DLLEXPORT [my define get initfunc]( Tcl_Interp *interp ) \{" + ::practcl::cputs result { + /* Initialise the stubs tables. */ + #ifdef USE_TCL_STUBS + if (Tcl_InitStubs(interp, "8.6", 0)==NULL) return TCL_ERROR; + if (TclOOInitializeStubs(interp, "1.0") == NULL) return TCL_ERROR; +} + if {[my define get tk 0]} { + ::practcl::cputs result { if (Tk_InitStubs(interp, "8.6", 0)==NULL) return TCL_ERROR;} + } + ::practcl::cputs result { #endif} + set TCLINIT [my generate-tcl-pre] + if {[string length [string trim $TCLINIT]]} { + ::practcl::cputs result " if(interp) {\nif(Tcl_Eval(interp,[::practcl::tcl_to_c $TCLINIT])) return TCL_ERROR;\n }" + } + ::practcl::cputs result [my generate-loader-module] + + set TCLINIT [my generate-tcl-post] + if {[string length [string trim $TCLINIT]]} { + ::practcl::cputs result " if(interp) {\nif(Tcl_Eval(interp,[::practcl::tcl_to_c $TCLINIT])) return TCL_ERROR;\n }" + } + if {[my define exists pkg_name]} { + ::practcl::cputs result " if (Tcl_PkgProvide(interp, \"[my define get pkg_name [my define get name]]\" , \"[my define get pkg_vers [my define get version]]\" )) return TCL_ERROR\;" + } + ::practcl::cputs result " return TCL_OK\;\n\}\n" + return $result + } + method initialize {} { + set filename [my define get filename] + if {$filename eq {}} { + return + } + if {[my define get name] eq {}} { + my define set name [file tail [file dirname $filename]] + } + if {[my define get localpath] eq {}} { + my define set localpath [my define get name]_[my define get name] + } + my graft module [self] + ::practcl::debug [self] SOURCE $filename + my source $filename + } + method implement path { + my go + my Collate_Source $path + set errs {} + foreach item [my link list dynamic] { + if {[catch {$item implement $path} err errdat]} { + lappend errs "Skipped $item: [$item define get filename] $err" + if {[dict exists $errdat -errorinfo]} { + lappend errs [dict get $errdat -errorinfo] + } else { + lappend errs $errdat + } + } + } + foreach item [my link list module] { + if {[catch {$item implement $path} err errdat]} { + lappend errs "Skipped $item: [$item define get filename] $err" + if {[dict exists $errdat -errorinfo]} { + lappend errs [dict get $errdat -errorinfo] + } else { + lappend errs $errdat + } + } + } + if {[llength $errs]} { + set logfile [file join $::CWD practcl.log] + ::practcl::log $logfile "*** ERRORS ***" + foreach {item trace} $errs { + ::practcl::log $logfile "###\n# ERROR\n###\n$item" + ::practcl::log $logfile "###\n# TRACE\n###\n$trace" + } + ::practcl::log $logfile "*** DEBUG INFO ***" + ::practcl::log $logfile $::DEBUG_INFO + puts stderr "Errors saved to $logfile" + exit 1 + } + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set filename [my define get output_c] + if {$filename eq {}} { + ::practcl::debug [list /[self] [self method] [self class]] + return + } + set cout [open [file join $path [file rootname $filename].c] w] + puts $cout [subst {/* +** This file is generated by the [info script] script +** any changes will be overwritten the next time it is run +*/}] + puts $cout [my generate-c] + puts $cout [my generate-loader] + close $cout + ::practcl::debug [list /[self] [self method] [self class]] + } + method linktype {} { + return {subordinate product dynamic module} + } +} + +### +# END: class module.tcl +### +### +# START: class project baseclass.tcl +### +::clay::define ::practcl::project { + superclass ::practcl::module + method _MorphPatterns {} { + return {{@name@} {::practcl::@name@} {::practcl::project.@name@} {::practcl::project}} + } + constructor args { + my variable define + if {[llength $args] == 1} { + set rawcontents [lindex $args 0] + } else { + set rawcontents $args + } + if {[catch {uplevel 1 [list subst $rawcontents]} contents]} { + set contents $rawcontents + } + ### + # The first instance of ::practcl::project (or its descendents) + # registers itself as the ::practcl::MAIN. If a project other + # than ::practcl::LOCAL is created, odds are that was the one + # the developer intended to be the main project + ### + if {$::practcl::MAIN eq "::practcl::LOCAL"} { + set ::practcl::MAIN [self] + } + # DEFS fields need to be passed unchanged and unsubstituted + # as we need to preserve their escape characters + foreach field {TCL_DEFS DEFS TK_DEFS} { + if {[dict exists $rawcontents $field]} { + dict set contents $field [dict get $rawcontents $field] + } + } + my graft module [self] + array set define $contents + ::practcl::toolset select [self] + my initialize + } + method add_object object { + my link object $object + } + method add_project {pkg info {oodefine {}}} { + ::practcl::debug [self] add_project $pkg $info + set os [my define get TEACUP_OS] + if {$os eq {}} { + set os [::practcl::os] + my define set os $os + } + set fossilinfo [list download [my define get download] tag trunk sandbox [my define get sandbox]] + if {[dict exists $info os] && ($os ni [dict get $info os])} return + # Select which tag to use here. + # For production builds: tag-release + set profile [my define get profile release]: + if {[dict exists $info profile $profile]} { + dict set info tag [dict get $info profile $profile] + } + dict set info USEMSVC [my define get USEMSVC 0] + dict set info debug [my define get debug 0] + set obj [namespace current]::PROJECT.$pkg + if {[info command $obj] eq {}} { + set obj [::practcl::subproject create $obj [self] [dict merge $fossilinfo [list name $pkg pkg_name $pkg static 0 class subproject.binary] $info]] + } + my link object $obj + oo::objdefine $obj $oodefine + $obj define set masterpath $::CWD + $obj go + return $obj + } + method add_tool {pkg info {oodefine {}}} { + ::practcl::debug [self] add_tool $pkg $info + set info [dict merge [::practcl::local_os] $info] + + set os [dict get $info TEACUP_OS] + set fossilinfo [list download [my define get download] tag trunk sandbox [my define get sandbox]] + if {[dict exists $info os] && ($os ni [dict get $info os])} return + # Select which tag to use here. + # For production builds: tag-release + set profile [my define get profile release]: + if {[dict exists $info profile $profile]} { + dict set info tag [dict get $info profile $profile] + } + set obj ::practcl::OBJECT::TOOL.$pkg + if {[info command $obj] eq {}} { + set obj [::practcl::subproject create $obj [self] [dict merge $fossilinfo [list name $pkg pkg_name $pkg static 0] $info]] + } + my link add tool $obj + oo::objdefine $obj $oodefine + $obj define set masterpath $::CWD + $obj go + return $obj + } + method build-tclcore {} { + set os [my define get TEACUP_OS] + set tcl_config_opts [::practcl::platform::tcl_core_options $os] + set tk_config_opts [::practcl::platform::tk_core_options $os] + + lappend tcl_config_opts --prefix [my define get prefix] --exec-prefix [my define get prefix] + set tclobj [my tclcore] + if {[my define get debug 0]} { + $tclobj define set debug 1 + lappend tcl_config_opts --enable-symbols=true + } + $tclobj define set config_opts $tcl_config_opts + $tclobj go + $tclobj compile + + set _TclSrcDir [$tclobj define get localsrcdir] + my define set tclsrcdir $_TclSrcDir + if {[my define get tk 0]} { + set tkobj [my tkcore] + lappend tk_config_opts --with-tcl=[::practcl::file_relative [$tkobj define get builddir] [$tclobj define get builddir]] + if {[my define get debug 0]} { + $tkobj define set debug 1 + lappend tk_config_opts --enable-symbols=true + } + $tkobj define set config_opts $tk_config_opts + $tkobj compile + } + } + method child which { + switch $which { + delegate - + organs { + # A library can be a project, it can be a module. Any + # subordinate modules will indicate their existance + return [list project [self] module [self]] + } + } + } + method linktype {} { + return project + } + method project {pkg args} { + set obj [namespace current]::PROJECT.$pkg + if {[llength $args]==0} { + return $obj + } + ${obj} {*}$args + } + method tclcore {} { + if {[info commands [set obj [my clay delegate tclcore]]] ne {}} { + return $obj + } + if {[info commands [set obj [my project TCLCORE]]] ne {}} { + my graft tclcore $obj + return $obj + } + if {[info commands [set obj [my project tcl]]] ne {}} { + my graft tclcore $obj + return $obj + } + if {[info commands [set obj [my tool tcl]]] ne {}} { + my graft tclcore $obj + return $obj + } + # Provide a fallback + set obj [my add_tool tcl { + tag release class subproject.core + fossil_url http://core.tcl.tk/tcl + }] + my graft tclcore $obj + return $obj + } + method tkcore {} { + if {[set obj [my clay delegate tkcore]] ne {}} { + return $obj + } + if {[set obj [my project tk]] ne {}} { + my graft tkcore $obj + return $obj + } + if {[set obj [my tool tk]] ne {}} { + my graft tkcore $obj + return $obj + } + # Provide a fallback + set obj [my add_tool tk { + tag release class tool.core + fossil_url http://core.tcl.tk/tk + }] + my graft tkcore $obj + return $obj + } + method tool {pkg args} { + set obj ::practcl::OBJECT::TOOL.$pkg + if {[llength $args]==0} { + return $obj + } + ${obj} {*}$args + } +} + +### +# END: class project baseclass.tcl +### +### +# START: class project library.tcl +### +::clay::define ::practcl::library { + superclass ::practcl::project + method clean {PATH} { + set objext [my define get OBJEXT o] + foreach {ofile info} [my project-compile-products] { + if {[file exists [file join $PATH objs $ofile].${objext}]} { + file delete [file join $PATH objs $ofile].${objext} + } + } + foreach ofile [glob -nocomplain [file join $PATH *.${objext}]] { + file delete $ofile + } + foreach ofile [glob -nocomplain [file join $PATH objs *]] { + file delete $ofile + } + set libfile [my define get libfile] + if {[file exists [file join $PATH $libfile]]} { + file delete [file join $PATH $libfile] + } + my implement $PATH + } + method project-compile-products {} { + set result {} + foreach item [my link list subordinate] { + lappend result {*}[$item project-compile-products] + } + set filename [my define get output_c] + if {$filename ne {}} { + ::practcl::debug [self] [self class] [self method] project-compile-products $filename + set ofile [file rootname [file tail $filename]]_main + lappend result $ofile [list cfile $filename extra [my define get extra] external [string is true -strict [my define get external]]] + } + return $result + } + method go {} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set name [my define getnull name] + if {$name eq {}} { + set name generic + my define name generic + } + if {[my define get tk] eq {@TEA_TK_EXTENSION@}} { + my define set tk 0 + } + set output_c [my define getnull output_c] + if {$output_c eq {}} { + set output_c [file rootname $name].c + my define set output_c $output_c + } + set output_h [my define getnull output_h] + if {$output_h eq {}} { + set output_h [file rootname $output_c].h + my define set output_h $output_h + } + set output_tcl [my define getnull output_tcl] + #if {$output_tcl eq {}} { + # set output_tcl [file rootname $output_c].tcl + # my define set output_tcl $output_tcl + #} + #set output_mk [my define getnull output_mk] + #if {$output_mk eq {}} { + # set output_mk [file rootname $output_c].mk + # my define set output_mk $output_mk + #} + set initfunc [my define getnull initfunc] + if {$initfunc eq {}} { + set initfunc [string totitle $name]_Init + my define set initfunc $initfunc + } + set output_decls [my define getnull output_decls] + if {$output_decls eq {}} { + set output_decls [file rootname $output_c].decls + my define set output_decls $output_decls + } + my variable links + foreach {linktype objs} [array get links] { + foreach obj $objs { + $obj go + } + } + ::practcl::debug [list /[self] [self method] [self class] -- [my define get filename] [info object class [self]]] + } + method generate-decls {pkgname path} { + ::practcl::debug [list [self] [self method] [self class] -- [my define get filename] [info object class [self]]] + set outfile [file join $path/$pkgname.decls] + + ### + # Build the decls file + ## # + set fout [open $outfile w] + puts $fout [subst {### + # $outfile + # + # This file was generated by [info script] + ### + +library $pkgname +interface $pkgname +}] + + ### + # Generate list of functions + ### + set stubfuncts [my generate-stub-function] + set thisline {} + set functcount 0 + foreach {func header} $stubfuncts { + puts $fout [list declare [incr functcount] $header] + } + puts $fout [list export "int [my define get initfunc](Tcl_Inter *interp)"] + puts $fout [list export "char *[string totitle [my define get name]]_InitStubs(Tcl_Inter *interp, char *version, int exact)"] + + close $fout + + ### + # Build [package]Decls.h + ### + set hout [open [file join $path ${pkgname}Decls.h] w] + close $hout + + set cout [open [file join $path ${pkgname}StubInit.c] w] + puts $cout [string map [list %pkgname% $pkgname %PkgName% [string totitle $pkgname]] { +#ifndef USE_TCL_STUBS +#define USE_TCL_STUBS +#endif +#undef USE_TCL_STUB_PROCS + +#include "tcl.h" +#include "%pkgname%.h" + +/* +** Ensure that Tdom_InitStubs is built as an exported symbol. The other stub +** functions should be built as non-exported symbols. +*/ + +#undef TCL_STORAGE_CLASS +#define TCL_STORAGE_CLASS DLLEXPORT + +%PkgName%Stubs *%pkgname%StubsPtr; + + /* + **---------------------------------------------------------------------- + ** + ** %PkgName%_InitStubs -- + ** + ** Checks that the correct version of %PkgName% is loaded and that it + ** supports stubs. It then initialises the stub table pointers. + ** + ** Results: + ** The actual version of %PkgName% that satisfies the request, or + ** NULL to indicate that an error occurred. + ** + ** Side effects: + ** Sets the stub table pointers. + ** + **---------------------------------------------------------------------- + */ + +char * +%PkgName%_InitStubs (Tcl_Interp *interp, char *version, int exact) +{ + char *actualVersion; + actualVersion = Tcl_PkgRequireEx(interp, "%pkgname%", version, exact,(ClientData *) &%pkgname%StubsPtr); + if (!actualVersion) { + return NULL; + } + if (!%pkgname%StubsPtr) { + Tcl_SetResult(interp,"This implementation of %PkgName% does not support stubs",TCL_STATIC); + return NULL; + } + return actualVersion; +} +}] + close $cout + } + method implement path { + my go + my Collate_Source $path + set errs {} + foreach item [my link list dynamic] { + if {[catch {$item implement $path} err errdat]} { + lappend errs "Skipped $item: [$item define get filename] $err" + if {[dict exists $errdat -errorinfo]} { + lappend errs [dict get $errdat -errorinfo] + } else { + lappend errs $errdat + } + } + } + foreach item [my link list module] { + if {[catch {$item implement $path} err errdat]} { + lappend errs "Skipped $item: [$item define get filename] $err" + if {[dict exists $errdat -errorinfo]} { + lappend errs [dict get $errdat -errorinfo] + } else { + lappend errs $errdat + } + } + } + if {[llength $errs]} { + set logfile [file join $::CWD practcl.log] + ::practcl::log $logfile "*** ERRORS ***" + foreach {item trace} $errs { + ::practcl::log $logfile "###\n# ERROR\n###$item" + ::practcl::log $logfile "###\n# TRACE\n###$trace" + } + ::practcl::log $logfile "*** DEBUG INFO ***" + ::practcl::log $logfile $::DEBUG_INFO + puts stderr "Errors saved to $logfile" + exit 1 + } + set cout [open [file join $path [my define get output_c]] w] + puts $cout [subst {/* +** This file is generated by the [info script] script +** any changes will be overwritten the next time it is run +*/}] + puts $cout [my generate-c] + puts $cout [my generate-loader] + close $cout + + set macro HAVE_[string toupper [file rootname [my define get output_h]]]_H + set hout [open [file join $path [my define get output_h]] w] + puts $hout [subst {/* +** This file is generated by the [info script] script +** any changes will be overwritten the next time it is run +*/}] + puts $hout "#ifndef ${macro}" + puts $hout "#define ${macro} 1" + puts $hout [my generate-h] + puts $hout "#endif" + close $hout + + set output_tcl [my define get output_tcl] + if {$output_tcl ne {}} { + set tclout [open [file join $path [my define get output_tcl]] w] + puts $tclout "### +# This file is generated by the [info script] script +# any changes will be overwritten the next time it is run +###" + puts $tclout [my generate-tcl-pre] + puts $tclout [my generate-tcl-loader] + puts $tclout [my generate-tcl-post] + close $tclout + } + } + method generate-make path { + my build-Makefile $path [self] + } + method linktype {} { + return library + } + method package-ifneeded {args} { + set result {} + set name [my define get pkg_name [my define get name]] + set version [my define get pkg_vers [my define get version]] + if {$version eq {}} { + set version 0.1a + } + set output_tcl [my define get output_tcl] + if {$output_tcl ne {}} { + set script "\[list source \[file join \$dir $output_tcl\]\]" + } elseif {[my define get SHARED_BUILD 0]} { + set script "\[list load \[file join \$dir [my define get libfile]\] $name\]" + } else { + # Provide a null passthrough + set script "\[list package provide $name $version\]" + } + set result "package ifneeded [list $name] [list $version] $script" + foreach alias $args { + set script "package require $name $version \; package provide $alias $version" + append result \n\n [list package ifneeded $alias $version $script] + } + return $result + } + method shared_library {{filename {}}} { + set name [string tolower [my define get name [my define get pkg_name]]] + set NAME [string toupper $name] + set version [my define get version [my define get pkg_vers]] + set map {} + lappend map %LIBRARY_NAME% $name + lappend map %LIBRARY_VERSION% $version + lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} $version] + lappend map %LIBRARY_PREFIX% [my define getnull libprefix] + set outfile [string map $map [my define get PRACTCL_NAME_LIBRARY]][my define get SHLIB_SUFFIX] + return $outfile + } + method static_library {{filename {}}} { + set name [string tolower [my define get name [my define get pkg_name]]] + set NAME [string toupper $name] + set version [my define get version [my define get pkg_vers]] + set map {} + lappend map %LIBRARY_NAME% $name + lappend map %LIBRARY_VERSION% $version + lappend map %LIBRARY_VERSION_NODOTS% [string map {. {}} $version] + lappend map %LIBRARY_PREFIX% [my define getnull libprefix] + set outfile [string map $map [my define get PRACTCL_NAME_LIBRARY]].a + return $outfile + } +} + +### +# END: class project library.tcl +### +### +# START: class project tclkit.tcl +### +::clay::define ::practcl::tclkit { + superclass ::practcl::library + method build-tclkit_main {PROJECT PKG_OBJS} { + ### + # Build static package list + ### + set statpkglist {} + foreach cobj [list {*}${PKG_OBJS} $PROJECT] { + foreach {pkg info} [$cobj project-static-packages] { + dict set statpkglist $pkg $info + } + } + foreach {ofile info} [${PROJECT} project-compile-products] { + if {![dict exists $info object]} continue + set cobj [dict get $info object] + foreach {pkg info} [$cobj project-static-packages] { + dict set statpkglist $pkg $info + } + } + + set result {} + $PROJECT include {} + $PROJECT include {"tclInt.h"} + $PROJECT include {"tclFileSystem.h"} + $PROJECT include {} + $PROJECT include {} + $PROJECT include {} + $PROJECT include {} + $PROJECT include {} + + $PROJECT code header { +#ifndef MODULE_SCOPE +# define MODULE_SCOPE extern +#endif + +/* +** Provide a dummy Tcl_InitStubs if we are using this as a static +** library. +*/ +#ifndef USE_TCL_STUBS +# undef Tcl_InitStubs +# define Tcl_InitStubs(a,b,c) TCL_VERSION +#endif +#define STATIC_BUILD 1 +#undef USE_TCL_STUBS + +/* Make sure the stubbed variants of those are never used. */ +#undef Tcl_ObjSetVar2 +#undef Tcl_NewStringObj +#undef Tk_Init +#undef Tk_MainEx +#undef Tk_SafeInit +} + + # Build an area of the file for #define directives and + # function declarations + set define {} + set mainhook [$PROJECT define get TCL_LOCAL_MAIN_HOOK Tclkit_MainHook] + set mainfunc [$PROJECT define get TCL_LOCAL_APPINIT Tclkit_AppInit] + set mainscript [$PROJECT define get main.tcl main.tcl] + set vfsroot [$PROJECT define get vfsroot "[$PROJECT define get ZIPFS_VOLUME]app"] + set vfs_main "${vfsroot}/${mainscript}" + + set map {} + foreach var { + vfsroot mainhook mainfunc vfs_main + } { + dict set map %${var}% [set $var] + } + set preinitscript { +set ::odie(boot_vfs) %vfsroot% +set ::SRCDIR $::odie(boot_vfs) +if {[file exists [file join %vfsroot% tcl_library init.tcl]]} { + set ::tcl_library [file join %vfsroot% tcl_library] + set ::auto_path {} +} +if {[file exists [file join %vfsroot% tk_library tk.tcl]]} { + set ::tk_library [file join %vfsroot% tk_library] +} +} ; # Preinitscript + + set zvfsboot { +/* + * %mainhook% -- + * Performs the argument munging for the shell + */ + } + ::practcl::cputs zvfsboot { + CONST char *archive; + Tcl_FindExecutable(*argv[0]); + archive=Tcl_GetNameOfExecutable(); +} + # We have to initialize the virtual filesystem before calling + # Tcl_Init(). Otherwise, Tcl_Init() will not be able to find + # its startup script files. + if {![$PROJECT define get tip_430 0]} { + # Add declarations of functions that tip430 puts in the stub files + $PROJECT code public-header { +int TclZipfs_Init(Tcl_Interp *interp); +int TclZipfs_Mount( + Tcl_Interp *interp, + const char *mntpt, + const char *zipname, + const char *passwd +); +int TclZipfs_Mount_Buffer( + Tcl_Interp *interp, + const char *mntpt, + unsigned char *data, + size_t datalen, + int copy +); +} + ::practcl::cputs zvfsboot { TclZipfs_Init(NULL);} + } + ::practcl::cputs zvfsboot " if(!TclZipfs_Mount(NULL, \"app\", archive, NULL)) \x7B " + ::practcl::cputs zvfsboot { + Tcl_Obj *vfsinitscript; + vfsinitscript=Tcl_NewStringObj("%vfs_main%",-1); + Tcl_IncrRefCount(vfsinitscript); + if(Tcl_FSAccess(vfsinitscript,F_OK)==0) { + /* Startup script should be set before calling Tcl_AppInit */ + Tcl_SetStartupScript(vfsinitscript,NULL); + } + } + ::practcl::cputs zvfsboot " TclSetPreInitScript([::practcl::tcl_to_c $preinitscript])\;" + ::practcl::cputs zvfsboot " \x7D else \x7B" + ::practcl::cputs zvfsboot " TclSetPreInitScript([::practcl::tcl_to_c { +foreach path {../tcl} { + set p [file join $path library init.tcl] + if {[file exists [file join $path library init.tcl]]} { + set ::tcl_library [file normalize [file join $path library]] + break + } +} +foreach path { + ../tk +} { + if {[file exists [file join $path library tk.tcl]]} { + set ::tk_library [file normalize [file join $path library]] + break + } +} +}])\;" + ::practcl::cputs zvfsboot " \x7D" + ::practcl::cputs zvfsboot " return TCL_OK;" + + if {[$PROJECT define get TEACUP_OS] eq "windows"} { + set header {int %mainhook%(int *argc, TCHAR ***argv)} + } else { + set header {int %mainhook%(int *argc, char ***argv)} + } + $PROJECT c_function [string map $map $header] [string map $map $zvfsboot] + + practcl::cputs appinit "int %mainfunc%(Tcl_Interp *interp) \x7B" + + # Build AppInit() + set appinit {} + practcl::cputs appinit { + if ((Tcl_Init)(interp) == TCL_ERROR) { + return TCL_ERROR; + } + +} + if {![$PROJECT define get tip_430 0]} { + ::practcl::cputs appinit { TclZipfs_Init(interp);} + } + set main_init_script {} + + foreach {statpkg info} $statpkglist { + set initfunc {} + if {[dict exists $info initfunc]} { + set initfunc [dict get $info initfunc] + } + if {$initfunc eq {}} { + set initfunc [string totitle ${statpkg}]_Init + } + if {![dict exists $info version]} { + error "$statpkg HAS NO VERSION" + } + # We employ a NULL to prevent the package system from thinking the + # package is actually loaded into the interpreter + $PROJECT code header "extern Tcl_PackageInitProc $initfunc\;\n" + set script [list package ifneeded $statpkg [dict get $info version] [list ::load {} $statpkg]] + append main_init_script \n [list set ::kitpkg(${statpkg}) $script] + if {[dict get $info autoload]} { + ::practcl::cputs appinit " if(${initfunc}(interp)) return TCL_ERROR\;" + ::practcl::cputs appinit " Tcl_StaticPackage(interp,\"$statpkg\",$initfunc,NULL)\;" + } else { + ::practcl::cputs appinit "\n Tcl_StaticPackage(NULL,\"$statpkg\",$initfunc,NULL)\;" + append main_init_script \n $script + } + } + append main_init_script \n { +puts [list SRCDIR IS $::SRCDIR] +if {[file exists [file join $::SRCDIR pkgIndex.tcl]]} { + #In a wrapped exe, we don't go out to the environment + set dir $::SRCDIR + source [file join $::SRCDIR pkgIndex.tcl] +} +# Specify a user-specific startup file to invoke if the application +# is run interactively. Typically the startup file is "~/.apprc" +# where "app" is the name of the application. If this line is deleted +# then no user-specific startup file will be run under any conditions. +} + append main_init_script \n [list set tcl_rcFileName [$PROJECT define get tcl_rcFileName ~/.tclshrc]] + practcl::cputs appinit " Tcl_Eval(interp,[::practcl::tcl_to_c $main_init_script]);" + practcl::cputs appinit { return TCL_OK;} + $PROJECT c_function [string map $map "int %mainfunc%(Tcl_Interp *interp)"] [string map $map $appinit] + } + method Collate_Source CWD { + next $CWD + set name [my define get name] + # Assume a static shell + if {[my define exists SHARED_BUILD]} { + my define set SHARED_BUILD 0 + } + if {![my define exists TCL_LOCAL_APPINIT]} { + my define set TCL_LOCAL_APPINIT Tclkit_AppInit + } + if {![my define exists TCL_LOCAL_MAIN_HOOK]} { + my define set TCL_LOCAL_MAIN_HOOK Tclkit_MainHook + } + set PROJECT [self] + set os [$PROJECT define get TEACUP_OS] + if {[my define get SHARED_BUILD 0]} { + puts [list BUILDING TCLSH FOR OS $os] + } else { + puts [list BUILDING KIT FOR OS $os] + } + set TCLOBJ [$PROJECT tclcore] + ::practcl::toolset select $TCLOBJ + + set TCLSRCDIR [$TCLOBJ define get srcdir] + set PKG_OBJS {} + foreach item [$PROJECT link list core.library] { + if {[string is true [$item define get static]]} { + lappend PKG_OBJS $item + } + } + foreach item [$PROJECT link list package] { + if {[string is true [$item define get static]]} { + lappend PKG_OBJS $item + } + } + # Arrange to build an main.c that utilizes TCL_LOCAL_APPINIT and TCL_LOCAL_MAIN_HOOK + if {$os eq "windows"} { + set PLATFORM_SRC_DIR win + if {[my define get SHARED_BUILD 0]} { + my add class csource filename [file join $TCLSRCDIR win tclWinReg.c] initfunc Registry_Init pkg_name registry pkg_vers 1.3.1 autoload 1 + my add class csource filename [file join $TCLSRCDIR win tclWinDde.c] initfunc Dde_Init pkg_name dde pkg_vers 1.4.0 autoload 1 + } + my add class csource ofile [my define get name]_appinit.o filename [file join $TCLSRCDIR win tclAppInit.c] extra [list -DTCL_LOCAL_MAIN_HOOK=[my define get TCL_LOCAL_MAIN_HOOK Tclkit_MainHook] -DTCL_LOCAL_APPINIT=[my define get TCL_LOCAL_APPINIT Tclkit_AppInit]] + } else { + set PLATFORM_SRC_DIR unix + my add class csource ofile [my define get name]_appinit.o filename [file join $TCLSRCDIR unix tclAppInit.c] extra [list -DTCL_LOCAL_MAIN_HOOK=[my define get TCL_LOCAL_MAIN_HOOK Tclkit_MainHook] -DTCL_LOCAL_APPINIT=[my define get TCL_LOCAL_APPINIT Tclkit_AppInit]] + } + + if {[my define get SHARED_BUILD 0]} { + ### + # Add local static Zlib implementation + ### + set cdir [file join $TCLSRCDIR compat zlib] + foreach file { + adler32.c compress.c crc32.c + deflate.c infback.c inffast.c + inflate.c inftrees.c trees.c + uncompr.c zutil.c + } { + my add [file join $cdir $file] + } + } + ### + # Pre 8.7, Tcl doesn't include a Zipfs implementation + # in the core. Grab the one from odielib + ### + set zipfs [file join $TCLSRCDIR generic tclZipfs.c] + if {![$PROJECT define exists ZIPFS_VOLUME]} { + $PROJECT define set ZIPFS_VOLUME "zipfs:/" + } + $PROJECT code header "#define ZIPFS_VOLUME \"[$PROJECT define get ZIPFS_VOLUME]\"" + if {[file exists $zipfs]} { + $TCLOBJ define set tip_430 1 + my define set tip_430 1 + } else { + # The Tclconfig project maintains a mirror of the version + # released with the Tcl core + my define set tip_430 0 + ::practcl::LOCAL tool tclconfig unpack + set COMPATSRCROOT [::practcl::LOCAL tool tclconfig define get srcdir] + my add class csource ofile tclZipfs.o filename [file join $COMPATSRCROOT compat tclZipfs.c] extra -I[::practcl::file_relative $CWD [file join $TCLSRCDIR compat zlib contrib minizip]] + } + + my define add include_dir [file join $TCLSRCDIR generic] + my define add include_dir [file join $TCLSRCDIR $PLATFORM_SRC_DIR] + # This file will implement TCL_LOCAL_APPINIT and TCL_LOCAL_MAIN_HOOK + my build-tclkit_main $PROJECT $PKG_OBJS + } + method wrap {PWD exename vfspath args} { + cd $PWD + if {![file exists $vfspath]} { + file mkdir $vfspath + } + foreach item [my link list core.library] { + set name [$item define get name] + set libsrcdir [$item define get srcdir] + if {[file exists [file join $libsrcdir library]]} { + ::practcl::copyDir [file join $libsrcdir library] [file join $vfspath ${name}_library] + } + } + # Assume the user will populate the VFS path + #if {[my define get installdir] ne {}} { + # ::practcl::copyDir [file join [my define get installdir] [string trimleft [my define get prefix] /] lib] [file join $vfspath lib] + #} + foreach arg $args { + ::practcl::copyDir $arg $vfspath + } + + set fout [open [file join $vfspath pkgIndex.tcl] w] + puts $fout [string map [list %platform% [my define get TEACUP_PROFILE]] {set ::tcl_teapot_profile {%platform%}}] + puts $fout { +set ::PKGIDXFILE [info script] +set dir [file dirname $::PKGIDXFILE] +if {$::tcl_platform(platform) eq "windows"} { + set ::g(HOME) [file join [file normalize $::env(LOCALAPPDATA)] tcl] +} else { + set ::g(HOME) [file normalize ~/tcl] +} +set ::tcl_teapot [file join $::g(HOME) teapot $::tcl_teapot_profile] +lappend ::auto_path $::tcl_teapot +} + puts $fout [list proc installDir [info args ::practcl::installDir] [info body ::practcl::installDir]] + set buffer [::practcl::pkgindex_path $vfspath] + puts $fout $buffer + puts $fout { +# Advertise statically linked packages +foreach {pkg script} [array get ::kitpkg] { + eval $script +} +} + puts $fout { +### +# Cache binary packages distributed as dynamic libraries in a known location +### +foreach teapath [glob -nocomplain [file join $dir teapot $::tcl_teapot_profile *]] { + set pkg [file tail $teapath] + set pkginstall [file join $::tcl_teapot $pkg] + if {![file exists $pkginstall]} { + installDir $teapath $pkginstall + } +} +} + close $fout + + set EXEEXT [my define get EXEEXT] + set tclkit_bare [my define get tclkit_bare] + ::practcl::mkzip ${exename}${EXEEXT} $tclkit_bare $vfspath + if { [my define get TEACUP_OS] ne "windows" } { + file attributes ${exename}${EXEEXT} -permissions a+x + } + } +} + +### +# END: class project tclkit.tcl +### +### +# START: class distro baseclass.tcl +### +::clay::define ::practcl::distribution { + method scm_info {} { + return { + scm None + hash {} + maxdate {} + tags {} + isodate {} + } + } + method DistroMixIn {} { + my define set scm none + } + method Sandbox {} { + if {[my define exists sandbox]} { + return [my define get sandbox] + } + if {[my clay delegate project] ni {::noop {}}} { + set sandbox [my define get sandbox] + if {$sandbox ne {}} { + my define set sandbox $sandbox + return $sandbox + } + } + set sandbox [file normalize [file join $::CWD ..]] + my define set sandbox $sandbox + return $sandbox + } + method SrcDir {} { + set pkg [my define get name] + if {[my define exists srcdir]} { + return [my define get srcdir] + } + set sandbox [my Sandbox] + set srcdir [file join [my Sandbox] $pkg] + my define set srcdir $srcdir + return $srcdir + } + method ScmTag {} {} + method ScmClone {} {} + method ScmUnpack {} {} + method ScmUpdate {} {} + method Unpack {} { + set srcdir [my SrcDir] + if {[file exists $srcdir]} { + return + } + set pkg [my define get name] + if {[my define exists download]} { + # Utilize a staged download + set download [my define get download] + if {[file exists [file join $download $pkg.zip]]} { + ::practcl::tcllib_require zipfile::decode + ::zipfile::decode::unzipfile [file join $download $pkg.zip] $srcdir + return + } + } + my ScmUnpack + } +} +oo::objdefine ::practcl::distribution { + method Sandbox {object} { + if {[$object define exists sandbox]} { + return [$object define get sandbox] + } + if {[$object clay delegate project] ni {::noop {}}} { + set sandbox [$object define get sandbox] + if {$sandbox ne {}} { + $object define set sandbox $sandbox + return $sandbox + } + } + set pkg [$object define get name] + set sandbox [file normalize [file join $::CWD ..]] + $object define set sandbox $sandbox + return $sandbox + } + + method select object { + if {[$object define exists scm]} { + return [$object define get scm] + } + + set pkg [$object define get name] + if {[$object define get srcdir] ne {}} { + set srcdir [$object define get srcdir] + } else { + set srcdir [file join [my Sandbox $object] $pkg] + $object define set srcdir $srcdir + } + + set classprefix ::practcl::distribution. + if {[file exists $srcdir]} { + foreach class [::info commands ${classprefix}*] { + if {[$class claim_path $srcdir]} { + $object clay mixinmap distribution $class + set name [$class claim_option] + $object define set scm $name + return $name + } + } + } + foreach class [::info commands ${classprefix}*] { + if {[$class claim_object $object]} { + $object clay mixinmap distribution $class + set name [$class claim_option] + $object define set scm $name + return $name + } + } + if {[$object define get scm] eq {} && [$object define exists file_url]} { + set class ::practcl::distribution.snapshot + set name [$class claim_option] + $object define set scm $name + $object clay mixinmap distribution $class + return $name + } + error "Cannot determine source distribution method" + } + + method claim_option {} { + return Unknown + } + + method claim_object object { + return false + } + + method claim_path path { + return false + } +} + +### +# END: class distro baseclass.tcl +### +### +# START: class distro snapshot.tcl +### +::clay::define ::practcl::distribution.snapshot { + superclass ::practcl::distribution + method ScmUnpack {} { + set srcdir [my SrcDir] + if {[file exists [file join $srcdir .download]]} { + return 0 + } + set dpath [::practcl::LOCAL define get download] + set url [my define get file_url] + set fname [file tail $url] + set archive [file join $dpath $fname] + if {![file exists $archive]} { + ::http::wget $url $archive + } + set CWD [pwd] + switch [file extension $fname] { + .zip { + # Zipfile + + } + .tar { + ::practcl::tcllib_require tar + } + .tgz - + .gz { + # Tarball + ::practcl::tcllib_require tcl::transform::zlib + ::practcl::tcllib_require tar + set fh [::open $archive] + fconfigure $fh -encoding binary -translation lf -eofchar {} + ::tcl::transform::zlib $fh + } + } + set fosdb [my ScmClone] + set tag [my ScmTag] + file mkdir $srcdir + ::practcl::fossil $srcdir open $fosdb $tag + return 1 + } +} +oo::objdefine ::practcl::distribution.snapshot { + + method claim_object object { + return false + } + + method claim_option {} { + return snapshot + } + + method claim_path path { + if {[file exists [file join $path .download]]} { + return true + } + return false + } +} + +### +# END: class distro snapshot.tcl +### +### +# START: class distro fossil.tcl +### +::clay::define ::practcl::distribution.fossil { + superclass ::practcl::distribution + method scm_info {} { + set info [next] + dict set info scm fossil + foreach {field value} [::practcl::fossil_status [my define get srcdir]] { + dict set info $field $value + } + return $info + } + method ScmClone {} { + set srcdir [my SrcDir] + if {[file exists [file join $srcdir .fslckout]]} { + return + } + if {[file exists [file join $srcdir _FOSSIL_]]} { + return + } + if {![::info exists ::practcl::fossil_dbs]} { + # Get a list of local fossil databases + set ::practcl::fossil_dbs [exec fossil all list] + } + set pkg [my define get name] + # Return an already downloaded fossil repo + foreach line [split $::practcl::fossil_dbs \n] { + set line [string trim $line] + if {[file rootname [file tail $line]] eq $pkg} { + return $line + } + } + set download [::practcl::LOCAL define get download] + set fosdb [file join $download $pkg.fos] + if {[file exists $fosdb]} { + return $fosdb + } + + file mkdir [file join $download fossil] + set fosdb [file join $download fossil $pkg.fos] + if {[file exists $fosdb]} { + return $fosdb + } + + set cloned 0 + # Attempt to clone from a local network mirror + if {[::practcl::LOCAL define exists fossil_mirror]} { + set localmirror [::practcl::LOCAL define get fossil_mirror] + catch { + ::practcl::doexec fossil clone $localmirror/$pkg $fosdb + set cloned 1 + } + if {$cloned} { + return $fosdb + } + } + # Attempt to clone from the canonical source + if {[my define get fossil_url] ne {}} { + catch { + ::practcl::doexec fossil clone [my define get fossil_url] $fosdb + set cloned 1 + } + if {$cloned} { + return $fosdb + } + } + # Fall back to the fossil mirror on the island of misfit toys + ::practcl::doexec fossil clone http://fossil.etoyoc.com/fossil/$pkg $fosdb + return $fosdb + } + method ScmTag {} { + if {[my define exists scm_tag]} { + return [my define get scm_tag] + } + if {[my define exists tag]} { + set tag [my define get tag] + } else { + set tag trunk + } + my define set scm_tag $tag + return $tag + } + method ScmUnpack {} { + set srcdir [my SrcDir] + if {[file exists [file join $srcdir .fslckout]]} { + return 0 + } + if {[file exists [file join $srcdir _FOSSIL_]]} { + return 0 + } + set CWD [pwd] + set fosdb [my ScmClone] + set tag [my ScmTag] + file mkdir $srcdir + ::practcl::fossil $srcdir open $fosdb $tag + return 1 + } + method ScmUpdate {} { + if {[my ScmUnpack]} { + return + } + set srcdir [my SrcDir] + set tag [my ScmTag] + ::practcl::fossil $srcdir update $tag + } +} +oo::objdefine ::practcl::distribution.fossil { + + # Check for markers in the metadata + method claim_object obj { + set path [$obj define get srcdir] + if {[my claim_path $path]} { + return true + } + if {[$obj define get fossil_url] ne {}} { + return true + } + return false + } + + method claim_option {} { + return fossil + } + + # Check for markers in the source root + method claim_path path { + if {[file exists [file join $path .fslckout]]} { + return true + } + if {[file exists [file join $path _FOSSIL_]]} { + return true + } + return false + } +} + +### +# END: class distro fossil.tcl +### +### +# START: class distro git.tcl +### +::clay::define ::practcl::distribution.git { + superclass ::practcl::distribution + method ScmTag {} { + if {[my define exists scm_tag]} { + return [my define get scm_tag] + } + if {[my define exists tag]} { + set tag [my define get tag] + } else { + set tag master + } + my define set scm_tag $tag + return $tag + } + method ScmUnpack {} { + set srcdir [my SrcDir] + if {[file exists [file join $srcdir .git]]} { + return 0 + } + set CWD [pwd] + set tag [my ScmTag] + set pkg [my define get name] + if {[my define exists git_url]} { + ::practcl::doexec git clone --branch $tag [my define get git_url] $srcdir + } else { + ::practcl::doexec git clone --branch $tag https://github.com/eviltwinskippy/$pkg $srcdir + } + return 1 + } + method ScmUpdate {} { + if {[my ScmUnpack]} { + return + } + set CWD [pwd] + set srcdir [my SrcDir] + set tag [my ScmTag] + ::practcl::doexec_in $srcdir git pull + cd $CWD + } +} +oo::objdefine ::practcl::distribution.git { + + method claim_object obj { + set path [$obj define get srcdir] + if {[my claim_path $path]} { + return true + } + if {[$obj define get git_url] ne {}} { + return true + } + return false + } + + method claim_option {} { + return git + } + + method claim_path path { + if {[file exists [file join $path .git]]} { + return true + } + return false + } +} + +### +# END: class distro git.tcl +### +### +# START: class subproject baseclass.tcl +### +::clay::define ::practcl::subproject { + superclass ::practcl::module + method _MorphPatterns {} { + return {{::practcl::subproject.@name@} {::practcl::@name@} {@name@} {::practcl::subproject}} + } + method BuildDir {PWD} { + return [my define get srcdir] + } + method child which { + switch $which { + delegate - + organs { + # A library can be a project, it can be a module. Any + # subordinate modules will indicate their existance + return [list project [self] module [self]] + } + } + } + method compile {} {} + method go {} { + ::practcl::distribution select [self] + set name [my define get name] + my define set builddir [my BuildDir [my define get masterpath]] + my define set builddir [my BuildDir [my define get masterpath]] + my sources + } + method install args {} + method linktype {} { + return {subordinate package} + } + method linker-products {configdict} {} + method linker-external {configdict} { + if {[dict exists $configdict PRACTCL_PKG_LIBS]} { + return [dict get $configdict PRACTCL_PKG_LIBS] + } + if {[dict exists $configdict LIBS]} { + return [dict get $configdict LIBS] + } + } + method linker-extra {configdict} { + if {[dict exists $configdict PRACTCL_LINKER_EXTRA]} { + return [dict get $configdict PRACTCL_LINKER_EXTRA] + } + return {} + } + method env-bootstrap {} { + set pkg [my define get pkg_name [my define get name]] + package require $pkg + } + method env-exec {} {} + method env-install {} { + my unpack + } + method env-load {} { + my variable loaded + if {[info exists loaded]} { + return 0 + } + if {![my env-present]} { + my env-install + } + my env-bootstrap + set loaded 1 + } + method env-present {} { + set pkg [my define get pkg_name [my define get name]] + if {[catch [list package require $pkg]]} { + return 0 + } + return 1 + } + method sources {} {} + method update {} { + my ScmUpdate + } + method unpack {} { + cd $::CWD + ::practcl::distribution select [self] + my Unpack + ::practcl::toolset select [self] + cd $::CWD + } +} +::clay::define ::practcl::subproject.source { + superclass ::practcl::subproject ::practcl::library + method env-bootstrap {} { + set LibraryRoot [file join [my define get srcdir] [my define get module_root modules]] + if {[file exists $LibraryRoot] && $LibraryRoot ni $::auto_path} { + set ::auto_path [linsert $::auto_path 0 $LibraryRoot] + } + } + method env-present {} { + set path [my define get srcdir] + return [file exists $path] + } + method linktype {} { + return {subordinate package source} + } +} +::clay::define ::practcl::subproject.teapot { + superclass ::practcl::subproject + method env-bootstrap {} { + set pkg [my define get pkg_name [my define get name]] + package require $pkg + } + method env-install {} { + set pkg [my define get pkg_name [my define get name]] + set download [my define get download] + my unpack + set prefix [string trimleft [my define get prefix] /] + ::practcl::tcllib_require zipfile::decode + ::zipfile::decode::unzipfile [file join $download $pkg.zip] [file join $prefix lib $pkg] + } + method env-present {} { + set pkg [my define get pkg_name [my define get name]] + if {[catch [list package require $pkg]]} { + return 0 + } + return 1 + } + method install DEST { + set pkg [my define get pkg_name [my define get name]] + set download [my define get download] + my unpack + set prefix [string trimleft [my define get prefix] /] + ::practcl::tcllib_require zipfile::decode + ::zipfile::decode::unzipfile [file join $download $pkg.zip] [file join $DEST $prefix lib $pkg] + } +} +::clay::define ::practcl::subproject.kettle { + superclass ::practcl::subproject + method kettle {path args} { + my variable kettle + if {![info exists kettle]} { + ::practcl::LOCAL tool kettle env-load + set kettle [file join [::practcl::LOCAL tool kettle define get srcdir] kettle] + } + set srcdir [my SourceRoot] + ::practcl::dotclexec $kettle -f [file join $srcdir build.tcl] {*}$args + } + method install DEST { + my kettle reinstall --prefix $DEST + } +} +::clay::define ::practcl::subproject.critcl { + superclass ::practcl::subproject + method install DEST { + my critcl -pkg [my define get name] + set srcdir [my SourceRoot] + ::practcl::copyDir [file join $srcdir [my define get name]] [file join $DEST lib [my define get name]] + } +} +::clay::define ::practcl::subproject.sak { + superclass ::practcl::subproject + method env-bootstrap {} { + set LibraryRoot [file join [my define get srcdir] [my define get module_root modules]] + if {[file exists $LibraryRoot] && $LibraryRoot ni $::auto_path} { + set ::auto_path [linsert $::auto_path 0 $LibraryRoot] + } + } + method env-install {} { + ### + # Handle teapot installs + ### + set pkg [my define get pkg_name [my define get name]] + my unpack + set prefix [my define get prefix [file normalize [file join ~ tcl]]] + set srcdir [my define get srcdir] + ::practcl::dotclexec [file join $srcdir installer.tcl] \ + -apps -app-path [file join $prefix apps] \ + -html -html-path [file join $prefix doc html $pkg] \ + -pkg-path [file join $prefix lib $pkg] \ + -no-nroff -no-wait -no-gui + } + method env-present {} { + set path [my define get srcdir] + return [file exists $path] + } + method install DEST { + ### + # Handle teapot installs + ### + set pkg [my define get pkg_name [my define get name]] + my unpack + set prefix [string trimleft [my define get prefix] /] + set srcdir [my define get srcdir] + ::practcl::dotclexec [file join $srcdir installer.tcl] \ + -pkg-path [file join $DEST $prefix lib $pkg] \ + -no-examples -no-html -no-nroff \ + -no-wait -no-gui -no-apps + } + method install-module {DEST args} { + set srcdir [my define get srcdir] + if {[llength $args]==1 && [lindex $args 0] in {* all}} { + set pkg [my define get pkg_name [my define get name]] + ::practcl::dotclexec [file join $srcdir installer.tcl] \ + -pkg-path [file join $DEST $pkg] \ + -no-examples -no-html -no-nroff \ + -no-wait -no-gui -no-apps + } else { + foreach module $args { + ::practcl::installModule [file join $srcdir modules $module] [file join $DEST $module] + } + } + } +} +::clay::define ::practcl::subproject.practcl { + superclass ::practcl::subproject + method env-bootstrap {} { + set LibraryRoot [file join [my define get srcdir] [my define get module_root modules]] + if {[file exists $LibraryRoot] && $LibraryRoot ni $::auto_path} { + set ::auto_path [linsert $::auto_path 0 $LibraryRoot] + } + } + method env-install {} { + ### + # Handle teapot installs + ### + set pkg [my define get pkg_name [my define get name]] + my unpack + set prefix [my define get prefix [file normalize [file join ~ tcl]]] + set srcdir [my define get srcdir] + ::practcl::dotclexec [file join $srcdir make.tcl] install [file join $prefix lib $pkg] + } + method install DEST { + ### + # Handle teapot installs + ### + set pkg [my define get pkg_name [my define get name]] + my unpack + set prefix [string trimleft [my define get prefix] /] + set srcdir [my define get srcdir] + puts [list INSTALLING [my define get name] to [file join $DEST $prefix lib $pkg]] + ::practcl::dotclexec [file join $srcdir make.tcl] install [file join $DEST $prefix lib $pkg] + } + method install-module {DEST args} { + set pkg [my define get pkg_name [my define get name]] + set srcdir [my define get srcdir] + ::practcl::dotclexec [file join $srcdir make.tcl] install-module $DEST {*}$args + } +} + +### +# END: class subproject baseclass.tcl +### +### +# START: class subproject binary.tcl +### +::clay::define ::practcl::subproject.binary { + superclass ::practcl::subproject + method clean {} { + set builddir [file normalize [my define get builddir]] + if {![file exists $builddir]} return + if {[file exists [file join $builddir make.tcl]]} { + ::practcl::domake.tcl $builddir clean + } else { + catch {::practcl::domake $builddir clean} + } + } + method env-install {} { + ### + # Handle tea installs + ### + set pkg [my define get pkg_name [my define get name]] + set os [::practcl::local_os] + my define set os $os + my unpack + set prefix [my define get prefix [file normalize [file join ~ tcl]]] + set srcdir [my define get srcdir] + lappend options --prefix $prefix --exec-prefix $prefix + my define set config_opts $options + my go + my clean + my compile + my make install {} + } + method project-compile-products {} {} + method ComputeInstall {} { + if {[my define exists install]} { + switch [my define get install] { + static { + my define set static 1 + my define set autoload 0 + } + static-autoload { + my define set static 1 + my define set autoload 1 + } + vfs { + my define set static 0 + my define set autoload 0 + my define set vfsinstall 1 + } + null { + my define set static 0 + my define set autoload 0 + my define set vfsinstall 0 + } + default { + + } + } + } + } + method go {} { + next + ::practcl::distribution select [self] + my ComputeInstall + my define set builddir [my BuildDir [my define get masterpath]] + } + method linker-products {configdict} { + if {![my define get static 0]} { + return {} + } + set srcdir [my define get builddir] + if {[dict exists $configdict libfile]} { + return " [file join $srcdir [dict get $configdict libfile]]" + } + } + method project-static-packages {} { + if {![my define get static 0]} { + return {} + } + set result [my define get static_packages] + set statpkg [my define get static_pkg] + set initfunc [my define get initfunc] + if {$initfunc ne {}} { + set pkg_name [my define get pkg_name] + if {$pkg_name ne {}} { + dict set result $pkg_name initfunc $initfunc + set version [my define get version] + if {$version eq {}} { + my unpack + set info [my read_configuration] + set version [dict get $info version] + set pl {} + if {[dict exists $info patch_level]} { + set pl [dict get $info patch_level] + append version $pl + } + my define set version $version + } + dict set result $pkg_name version $version + dict set result $pkg_name autoload [my define get autoload 0] + } + } + foreach item [my link list subordinate] { + foreach {pkg info} [$item project-static-packages] { + dict set result $pkg $info + } + } + return $result + } + method BuildDir {PWD} { + set name [my define get name] + set debug [my define get debug 0] + if {[my define get LOCAL 0]} { + return [my define get builddir [file join $PWD local $name]] + } + if {$debug} { + return [my define get builddir [file join $PWD debug $name]] + } else { + return [my define get builddir [file join $PWD pkg $name]] + } + } + method compile {} { + set name [my define get name] + set PWD $::CWD + cd $PWD + my unpack + set srcdir [file normalize [my SrcDir]] + set localsrcdir [my MakeDir $srcdir] + my define set localsrcdir $localsrcdir + my Collate_Source $PWD + ### + # Build a starter VFS for both Tcl and wish + ### + set srcdir [my define get srcdir] + if {[my define get static 1]} { + puts "BUILDING Static $name $srcdir" + } else { + puts "BUILDING Dynamic $name $srcdir" + } + my make compile + cd $PWD + } + method Configure {} { + cd $::CWD + my unpack + ::practcl::toolset select [self] + set srcdir [file normalize [my define get srcdir]] + set builddir [file normalize [my define get builddir]] + file mkdir $builddir + my make autodetect + } + method install DEST { + set PWD [pwd] + set PREFIX [my define get prefix] + ### + # Handle teapot installs + ### + set pkg [my define get pkg_name [my define get name]] + if {[my define get teapot] ne {}} { + set TEAPOT [my define get teapot] + set found 0 + foreach ver [my define get pkg_vers [my define get version]] { + set teapath [file join $TEAPOT $pkg$ver] + if {[file exists $teapath]} { + set dest [file join $DEST [string trimleft $PREFIX /] lib [file tail $teapath]] + ::practcl::copyDir $teapath $dest + return + } + } + } + my compile + my make install $DEST + cd $PWD + } +} +::clay::define ::practcl::subproject.tea { + superclass ::practcl::subproject.binary +} +::clay::define ::practcl::subproject.library { + superclass ::practcl::subproject.binary ::practcl::library + method install DEST { + my compile + } +} +::clay::define ::practcl::subproject.external { + superclass ::practcl::subproject.binary + method install DEST { + my compile + } +} + +### +# END: class subproject binary.tcl +### +### +# START: class subproject core.tcl +### +::clay::define ::practcl::subproject.core { + superclass ::practcl::subproject.binary + method env-bootstrap {} {} + method env-present {} { + set PREFIX [my define get prefix] + set name [my define get name] + set fname [file join $PREFIX lib ${name}Config.sh] + return [file exists $fname] + } + method env-install {} { + my unpack + set os [::practcl::local_os] + + set prefix [my define get prefix [file normalize [file join ~ tcl]]] + lappend options --prefix $prefix --exec-prefix $prefix + my define set config_opts $options + puts [list [self] OS [dict get $os TEACUP_OS] options $options] + my go + my compile + my make install {} + } + method go {} { + my define set core_binary 1 + next + } + method linktype {} { + return {subordinate core.library} + } +} + +### +# END: class subproject core.tcl +### +### +# START: class tool.tcl +### +set ::practcl::MAIN ::practcl::LOCAL +set ::auto_index(::practcl::LOCAL) { + ::practcl::project create ::practcl::LOCAL + ::practcl::LOCAL define set [::practcl::local_os] + ::practcl::LOCAL define set LOCAL 1 + + # Until something better comes along, use ::practcl::LOCAL + # as our main project + # Add tclconfig as a project of record + ::practcl::LOCAL add_tool tclconfig { + name tclconfig tag practcl class subproject.source fossil_url http://core.tcl.tk/tclconfig + } + # Add tcllib as a project of record + ::practcl::LOCAL add_tool tcllib { + tag trunk class sak fossil_url http://core.tcl.tk/tcllib + } + ::practcl::LOCAL add_tool kettle { + tag trunk class sak fossil_url http://fossil.etoyoc.com/fossil/kettle + } + ::practcl::LOCAL add_tool tclvfs { + tag trunk class tea + fossil_url http://fossil.etoyoc.com/fossil/tclvfs + } + ::practcl::LOCAL add_tool critcl { + tag master class subproject.binary + git_url http://github.com/andreas-kupries/critcl + modules lib + } { + method env-bootstrap {} { + package require critcl::app + } + method env-install {} { + my unpack + set prefix [my define get prefix [file join [file normalize ~] tcl]] + set srcdir [my define get srcdir] + ::practcl::dotclexec [file join $srcdir build.tcl] install [file join $prefix lib] + } + } + ::practcl::LOCAL add_tool odie { + tag trunk class subproject.source + fossil_url http://fossil.etoyoc.com/fossil/odie + } + ::practcl::LOCAL add_tool tcl { + tag release class subproject.core + fossil_url http://core.tcl.tk/tcl + } + ::practcl::LOCAL add_tool tk { + tag release class subproject.core + fossil_url http://core.tcl.tk/tcl + } + ::practcl::LOCAL add_tool sqlite { + tag practcl + class subproject.tea + pkg_name sqlite3 + fossil_url http://fossil.etoyoc.com/fossil/sqlite + } +} + +### +# END: class tool.tcl +### + +namespace eval ::practcl { + namespace export * +} + Index: win/makefile.vc ================================================================== --- win/makefile.vc +++ win/makefile.vc @@ -1,487 +1,47 @@ -#------------------------------------------------------------- -# makefile.vc -- -# -# Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+) -# -# This makefile is based upon the Tcl 8.6 Makefile.vc and modified to -# make it suitable as a general package makefile. Look for the word EDIT -# which marks sections that may need modification. As a minumum you will -# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values -# relevant to your package. -# +#------------------------------------------------------------- -*- makefile -*- +# +# Sample makefile for building Tcl extensions. +# +# Basic build, test and install +# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl +# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl test +# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl install +# +# For other build options (debug, static etc.) +# See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for +# detailed documentation. +# # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# Copyright (c) 1995-1996 Sun Microsystems, Inc. -# Copyright (c) 1998-2000 Ajuba Solutions. -# Copyright (c) 2001-2005 ActiveState Corporation. -# Copyright (c) 2001-2004 David Gravereaux. -# Copyright (c) 2003-2008 Pat Thoyts. -#------------------------------------------------------------------------------ - -# Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or -# VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir) -!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) -MSG = ^ -You need to run vcvars32.bat from Developer Studio or setenv.bat from the^ -Platform SDK first to setup the environment. Jump to this line to read^ -the build instructions. -!error $(MSG) -!endif - -#------------------------------------------------------------------------------ -# HOW TO USE this makefile: -# -# 1) It is now necessary to have MSVCDir, MSDevDir or MSSDK set in the -# environment. This is used as a check to see if vcvars32.bat had been -# run prior to running nmake or during the installation of Microsoft -# Visual C++, MSVCDir had been set globally and the PATH adjusted. -# Either way is valid. -# -# You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin -# directory to setup the proper environment, if needed, for your -# current setup. This is a needed bootstrap requirement and allows the -# swapping of different environments to be easier. -# -# 2) To use the Platform SDK (not expressly needed), run setenv.bat after -# vcvars32.bat according to the instructions for it. This can also -# turn on the 64-bit compiler, if your SDK has it. -# -# 3) Targets are: -# all -- Builds everything. -# -- Builds the project (eg: nmake sample) -# test -- Builds and runs the test suite. -# install -- Installs the built binaries and libraries to $(INSTALLDIR) -# in an appropriate subdirectory. -# clean/realclean/distclean -- varying levels of cleaning. -# -# 4) Macros usable on the commandline: -# INSTALLDIR= -# Sets where to install Tcl from the built binaries. -# C:\Progra~1\Tcl is assumed when not specified. -# -# OPTS=loimpact,msvcrt,nothreads,pdbs,profile,static,symbols,unchecked,none -# Sets special options for the core. The default is for none. -# Any combination of the above may be used (comma separated). -# 'none' will over-ride everything to nothing. -# -# loimpact = Adds a flag for how NT treats the heap to keep memory -# in use, low. This is said to impact alloc performance. -# msvcrt = Affects the static option only to switch it from -# using libcmt(d) as the C runtime [by default] to -# msvcrt(d). This is useful for static embedding -# support. -# nothreads = Turns off multithreading support (not recommended) -# static = Builds a static library of the core instead of a -# dll. The shell will be static (and large), as well. -# pdbs = Build detached symbols for release builds. -# profile = Adds profiling hooks. Map file is assumed. -# symbols = Debug build. Links to the debug C runtime, disables -# optimizations and creates pdb symbols files. -# unchecked= Allows a symbols build to not use the debug -# enabled runtime (msvcrt.dll not msvcrtd.dll -# or libcmt.lib not libcmtd.lib). -# -# STATS=compdbg,memdbg,none -# Sets optional memory and bytecode compiler debugging code added -# to the core. The default is for none. Any combination of the -# above may be used (comma separated). 'none' will over-ride -# everything to nothing. -# -# compdbg = Enables byte compilation logging. -# memdbg = Enables the debugging memory allocator. -# -# CHECKS=64bit,fullwarn,nodep,none -# Sets special macros for checking compatability. -# -# 64bit = Enable 64bit portability warnings (if available) -# fullwarn = Builds with full compiler and link warnings enabled. -# Very verbose. -# nodep = Turns off compatability macros to ensure the extension -# isn't being built with deprecated functions. -# -# MACHINE=(ALPHA|AMD64|IA64|IX86) -# Set the machine type used for the compiler, linker, and -# resource compiler. This hook is needed to tell the tools -# when alternate platforms are requested. IX86 is the default -# when not specified. If the CPU environment variable has been -# set (ie: recent Platform SDK) then MACHINE is set from CPU. -# -# TMP_DIR= -# OUT_DIR= -# Hooks to allow the intermediate and output directories to be -# changed. $(OUT_DIR) is assumed to be -# $(BINROOT)\(Release|Debug) based on if symbols are requested. -# $(TMP_DIR) will de $(OUT_DIR)\ by default. -# -# TESTPAT= -# Reads the tests requested to be run from this file. -# -# 5) Examples: -# -# Basic syntax of calling nmake looks like this: -# nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]] -# -# Standard (no frills) -# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat -# Setting environment for using Microsoft Visual C++ tools. -# c:\tcl_src\win\>nmake -f makefile.vc all -# c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl -# -# Building for Win64 -# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat -# Setting environment for using Microsoft Visual C++ tools. -# c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL -# Targeting Windows pre64 RETAIL -# c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64 -# -#------------------------------------------------------------------------------ -#============================================================================== -#------------------------------------------------------------------------------ - -!if !exist("makefile.vc") -MSG = ^ -You must run this makefile only from the directory it is in.^ -Please `cd` to its location first. -!error $(MSG) -!endif - -#------------------------------------------------------------------------- -# Project specific information (EDIT) -# -# You should edit this with the name and version of your project. This -# information is used to generate the name of the package library and -# it's install location. -# -# For example, the sample extension is going to build sample05.dll and -# would install it into $(INSTALLDIR)\lib\sample05 -# -# You need to specify the object files that need to be linked into your -# binary here. -# -#------------------------------------------------------------------------- - +#------------------------------------------------------------------------------ + +# The name of the package PROJECT = sample -# Uncomment the following line if this is a Tk extension. -#PROJECT_REQUIRES_TK=1 -!include "rules.vc" - -# nmakehelp -V will search the file for tag, skips until a -# number and returns all character until a character not in [0-9.ab] -# is read. - -!if [echo REM = This file is generated from Makefile.vc > versions.vc] -!endif -# get project version from row "AC_INIT([project], [????])" -!if [echo DOTVERSION = \>> versions.vc] \ - && [nmakehlp -V ..\configure.ac sample >> versions.vc] -!endif -!include "versions.vc" - -VERSION = $(DOTVERSION:.=) -STUBPREFIX = $(PROJECT)stub - -DLLOBJS = \ - $(TMP_DIR)\tclsample.obj \ - $(TMP_DIR)\sample.obj \ -!if !$(STATIC_BUILD) - $(TMP_DIR)\sample.res -!endif - -PRJHEADERS = - -#------------------------------------------------------------------------- -# Target names and paths ( shouldn't need changing ) -#------------------------------------------------------------------------- - -BINROOT = $(MAKEDIR) -ROOT = $(MAKEDIR)\.. - -PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib -PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) -PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) - -PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib -PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) - -### Make sure we use backslash only. -PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) -LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) -BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) -DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) -SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) -INCLUDE_INSTALL_DIR = $(_TCLDIR)\include - -### The following paths CANNOT have spaces in them. -GENERICDIR = $(ROOT)\generic -WINDIR = $(ROOT)\win -LIBDIR = $(ROOT)\library -DOCDIR = $(ROOT)\doc -TOOLSDIR = $(ROOT)\tools -COMPATDIR = $(ROOT)\compat - -#--------------------------------------------------------------------- -# Compile flags -#--------------------------------------------------------------------- - -!if !$(DEBUG) -!if $(OPTIMIZING) -### This cranks the optimization level to maximize speed -cdebug = $(OPTIMIZATIONS) -!else -cdebug = -!endif -!else if "$(MACHINE)" == "IA64" -### Warnings are too many, can't support warnings into errors. -cdebug = -Zi -Od $(DEBUGFLAGS) -!else -cdebug = -Zi -WX $(DEBUGFLAGS) -!endif - -### Declarations common to all compiler options -cwarn = $(WARNINGS) -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE -cflags = -nologo -c $(COMPILERFLAGS) $(cwarn) -Fp$(TMP_DIR)^\ - -!if $(MSVCRT) -!if $(DEBUG) && !$(UNCHECKED) -crt = -MDd -!else -crt = -MD -!endif -!else -!if $(DEBUG) && !$(UNCHECKED) -crt = -MTd -!else -crt = -MT -!endif -!endif - -cflags = $(cflags) -DMODULE_SCOPE=extern - -!if !$(STATIC_BUILD) -cflags = $(cflags) -DUSE_TCL_STUBS -!if defined(TKSTUBLIB) -cflags = $(cflags) -DUSE_TK_STUBS -!endif -!endif - -INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" -BASE_CFLAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) -CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE -TCL_CFLAGS = -DPACKAGE_NAME="\"$(PROJECT)\"" \ - -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ - -DBUILD_$(PROJECT) \ - $(BASE_CFLAGS) $(OPTDEFINES) - -#--------------------------------------------------------------------- -# Link flags -#--------------------------------------------------------------------- - -!if $(DEBUG) -ldebug = -debug -debugtype:cv -!if $(MSVCRT) -ldebug = $(ldebug) -nodefaultlib:msvcrt -!endif -!else -ldebug = -release -opt:ref -opt:icf,3 -!endif - -### Declarations common to all linker options -lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) - -!if $(PROFILE) -lflags = $(lflags) -profile -!endif - -!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 -lflags = $(lflags) -nodefaultlib:libucrt.lib -!endif - -!if $(ALIGN98_HACK) && !$(STATIC_BUILD) -### Align sections for PE size savings. -lflags = $(lflags) -opt:nowin98 -!else if !$(ALIGN98_HACK) && $(STATIC_BUILD) -### Align sections for speed in loading by choosing the virtual page size. -lflags = $(lflags) -align:4096 -!endif - -!if $(LOIMPACT) -lflags = $(lflags) -ws:aggressive -!endif - -dlllflags = $(lflags) -dll -conlflags = $(lflags) -subsystem:console -guilflags = $(lflags) -subsystem:windows -!if !$(STATIC_BUILD) -baselibs = $(TCLSTUBLIB) -!if defined(TKSTUBLIB) -baselibs = $(baselibs) $(TKSTUBLIB) -!endif -!endif - -# Avoid 'unresolved external symbol __security_cookie' errors. -# c.f. http://support.microsoft.com/?id=894573 -!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" -!if $(VCVERSION) > 1399 && $(VCVERSION) < 1500 -baselibs = $(baselibs) bufferoverflowU.lib -!endif -!endif -!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 -baselibs = $(baselibs) ucrt.lib -!endif - -baselibs = $(baselibs) user32.lib gdi32.lib - -#--------------------------------------------------------------------- -# TclTest flags -#--------------------------------------------------------------------- - -!if "$(TESTPAT)" != "" -TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) -!endif - -#--------------------------------------------------------------------- -# Project specific targets (EDIT) -#--------------------------------------------------------------------- - -all: setup $(PROJECT) -$(PROJECT): setup pkgIndex $(PRJLIB) -install: install-binaries install-libraries install-docs -pkgIndex: $(OUT_DIR)\pkgIndex.tcl - -test: setup $(PROJECT) - @set TCL_LIBRARY=$(TCL_LIBRARY:\=/) - @set TCLLIBPATH=$(OUT_DIR_PATH:\=/) -!if $(TCLINSTALL) - @set PATH=$(_TCLDIR)\bin;$(PATH) -!else - @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH) -!endif - $(DEBUGGER) $(TCLSH) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) - -shell: setup $(PROJECT) - @set VLERQ_LIBRARY=$(LIBDIR:\=/) - @set TCL_LIBRARY=$(TCL_LIBRARY:\=/) - @set TCLLIBPATH=$(OUT_DIR_PATH:\=/) -!if $(TCLINSTALL) - @set PATH=$(_TCLDIR)\bin;$(PATH) -!else - @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH) -!endif - $(DEBUGGER) $(TCLSH) $(SCRIPT) - -setup: - @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) - @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) - -# See /win/coffbase.txt for extension base addresses. -$(PRJLIB): $(DLLOBJS) -!if $(STATIC_BUILD) - $(lib32) -nologo -out:$@ @<< -$** -<< -!else - $(link32) $(dlllflags) -base:@$(COFFBASE),thread -out:$@ $(baselibs) @<< -$** -<< - $(_VC_MANIFEST_EMBED_DLL) - -@del $*.exp -!endif - -$(PRJSTUBLIB): $(PRJSTUBOBJS) - $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) - -#--------------------------------------------------------------------- -# Implicit rules -#--------------------------------------------------------------------- - -{$(WINDIR)}.c{$(TMP_DIR)}.obj:: - $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< -$< -<< - -{$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: - $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< -$< -<< - -{$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: - $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< -$< -<< - -{$(WINDIR)}.rc{$(TMP_DIR)}.res: - $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ - -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ - -DDOTVERSION=\"$(DOTVERSION)\" \ - -DVERSION=\"$(VERSION)$(SUFX)\" \ -!if $(DEBUG) - -d DEBUG \ -!endif -!if $(TCL_THREADS) - -d TCL_THREADS \ -!endif -!if $(STATIC_BUILD) - -d STATIC_BUILD \ -!endif - $< - -.SUFFIXES: -.SUFFIXES:.c .rc - -#------------------------------------------------------------------------- -# Explicit dependency rules -# -#------------------------------------------------------------------------- - -$(OUT_DIR)\pkgIndex.tcl: $(ROOT)\pkgIndex.tcl.in - @nmakehlp -s << $** > $@ -@PACKAGE_VERSION@ $(DOTVERSION) -@PACKAGE_NAME@ $(PROJECT) -@PKG_LIB_FILE@ $(PRJLIBNAME) -<< - @echo package ifneeded sample $(DOTVERSION) \ - [list load [file join $$dir $(PRJLIBNAME)] Sample] >> $@ - -#--------------------------------------------------------------------- -# Installation. (EDIT) -# -# You may need to modify this section to reflect the final distribution -# of your files and possibly to generate documentation. -# -#--------------------------------------------------------------------- - -install-binaries: - @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' - @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" - @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL - -install-libraries: $(OUT_DIR)\pkgIndex.tcl - @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' - @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" - @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' - @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR) - -install-docs: - @echo Installing documentation files to '$(DOC_INSTALL_DIR)' - @if exist $(DOCDIR) $(CPY) $(DOCDIR)\*.n "$(DOC_INSTALL_DIR)" - -#--------------------------------------------------------------------- -# Clean up -#--------------------------------------------------------------------- - -clean: - @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) - @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc - @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc - @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i - @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x - @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch - -realclean: clean - @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) - -distclean: realclean - @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe - @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj +!include "rules-ext.vc" + +# Define the object files and resource file that make up the extension. +# Note the resource file does not makes sense if doing a static library build +# hence it is under that condition. TMP_DIR is the output directory +# defined by rules for object files. +PRJ_OBJS = \ + $(TMP_DIR)\tclsample.obj \ + $(TMP_DIR)\sample.obj + +# Define any additional compiler flags that might be required for the project +PRJ_DEFINES = -D_CRT_SECURE_NO_DEPRECATE + +# Define the standard targets +!include "$(_RULESDIR)\targets.vc" + +# We must define a pkgindex target that will create a pkgIndex.tcl +# file in the $(OUT_DIR) directory. We can just redirect to the +# default-pkgindex target for our sample extension. +pkgindex: default-pkgindex + +# The default install target only installs binaries and scripts so add +# an additional target for our documentation. Note this *adds* a target +# since no commands are listed after it. The original targets for +# install (from targets.vc) will remain. +install: default-install-docs-n Index: win/nmakehlp.c ================================================================== --- win/nmakehlp.c +++ win/nmakehlp.c @@ -12,17 +12,12 @@ * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include -#define NO_SHLWAPI_GDI -#define NO_SHLWAPI_STREAM -#define NO_SHLWAPI_REG -#include #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") -#pragma comment (lib, "shlwapi.lib") #include #include /* * This library is required for x64 builds with _some_ versions of MSVC @@ -37,18 +32,18 @@ #ifdef _MSC_VER #define snprintf _snprintf #endif - /* protos */ static int CheckForCompilerFeature(const char *option); -static int CheckForLinkerFeature(const char *option); +static int CheckForLinkerFeature(const char **options, int count); static int IsIn(const char *string, const char *substring); static int SubstituteFile(const char *substs, const char *filename); static int QualifyPath(const char *path); +static int LocateDependency(const char *keyfile); static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ @@ -72,10 +67,11 @@ char *argv[]) { char msg[300]; DWORD dwWritten; int chars; + const char *s; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ @@ -100,20 +96,20 @@ &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': - if (argc != 3) { + if (argc < 3) { chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -l \n" + "usage: %s -l ? ...?\n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } - return CheckForLinkerFeature(argv[2]); + return CheckForLinkerFeature(&argv[2], argc-2); case 'f': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -f \n" "Find a substring within another\n" @@ -151,12 +147,17 @@ argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } - printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0')); - return 0; + s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'); + if (s && *s) { + printf("%s\n", s); + return 0; + } else + return 1; /* Version not found. Return non-0 exit code */ + case 'Q': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -Q path\n" "Emit the fully qualified path\n" @@ -164,10 +165,22 @@ WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return QualifyPath(argv[2]); + + case 'L': + if (argc != 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -L keypath\n" + "Emit the fully qualified path of directory containing keypath\n" + "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return LocateDependency(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" @@ -311,20 +324,22 @@ || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( - const char *option) + const char **options, + int count) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; - char cmdline[100]; + int i; + char cmdline[255]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); @@ -366,11 +381,15 @@ /* * Append our option for testing. */ - lstrcat(cmdline, option); + for (i = 0; i < count; i++) { + lstrcat(cmdline, " \""); + lstrcat(cmdline, options[i]); + lstrcat(cmdline, "\""); + } ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ @@ -431,11 +450,13 @@ */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || - strstr(Err.buffer, "LNK4044") != NULL); + strstr(Err.buffer, "LNK4044") != NULL || + strstr(Out.buffer, "LNK4224") != NULL || + strstr(Err.buffer, "LNK4224") != NULL); } static DWORD WINAPI ReadFromPipe( LPVOID args) @@ -660,10 +681,21 @@ } fclose(fp); return 0; } +BOOL FileExists(LPCTSTR szPath) +{ +#ifndef INVALID_FILE_ATTRIBUTES + #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + DWORD pathAttr = GetFileAttributes(szPath); + return (pathAttr != INVALID_FILE_ATTRIBUTES && + !(pathAttr & FILE_ATTRIBUTE_DIRECTORY)); +} + + /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. @@ -673,20 +705,106 @@ static int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; - char szTmp[MAX_PATH + 1]; - char *p; - GetCurrentDirectory(MAX_PATH, szCwd); - while ((p = strchr(szPath, '/')) && *p) - *p = '\\'; - PathCombine(szTmp, szCwd, szPath); - PathCanonicalize(szCwd, szTmp); + + GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL); printf("%s\n", szCwd); return 0; } + +/* + * Implements LocateDependency for a single directory. See that command + * for an explanation. + * Returns 0 if found after printing the directory. + * Returns 1 if not found but no errors. + * Returns 2 on any kind of error + * Basically, these are used as exit codes for the process. + */ +static int LocateDependencyHelper(const char *dir, const char *keypath) +{ + HANDLE hSearch; + char path[MAX_PATH+1]; + int dirlen, keylen, ret; + WIN32_FIND_DATA finfo; + + if (dir == NULL || keypath == NULL) + return 2; /* Have no real error reporting mechanism into nmake */ + dirlen = strlen(dir); + if ((dirlen + 3) > sizeof(path)) + return 2; + strncpy(path, dir, dirlen); + strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */ + keylen = strlen(keypath); + +#if 0 /* This function is not available in Visual C++ 6 */ + /* + * Use numerics 0 -> FindExInfoStandard, + * 1 -> FindExSearchLimitToDirectories, + * as these are not defined in Visual C++ 6 + */ + hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0); +#else + hSearch = FindFirstFile(path, &finfo); +#endif + if (hSearch == INVALID_HANDLE_VALUE) + return 1; /* Not found */ + + /* Loop through all subdirs checking if the keypath is under there */ + ret = 1; /* Assume not found */ + do { + int sublen; + /* + * We need to check it is a directory despite the + * FindExSearchLimitToDirectories in the above call. See SDK docs + */ + if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) + continue; + sublen = strlen(finfo.cFileName); + if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) + continue; /* Path does not fit, assume not matched */ + strncpy(path+dirlen+1, finfo.cFileName, sublen); + path[dirlen+1+sublen] = '\\'; + strncpy(path+dirlen+1+sublen+1, keypath, keylen+1); + if (FileExists(path)) { + /* Found a match, print to stdout */ + path[dirlen+1+sublen] = '\0'; + QualifyPath(path); + ret = 0; + break; + } + } while (FindNextFile(hSearch, &finfo)); + FindClose(hSearch); + return ret; +} + +/* + * LocateDependency -- + * + * Locates a dependency for a package. + * keypath - a relative path within the package directory + * that is used to confirm it is the correct directory. + * The search path for the package directory is currently only + * the parent and grandparent of the current working directory. + * If found, the command prints + * name_DIRPATH= + * and returns 0. If not found, does not print anything and returns 1. + */ +static int LocateDependency(const char *keypath) +{ + int i, ret; + static char *paths[] = {"..", "..\\..", "..\\..\\.."}; + + for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) { + ret = LocateDependencyHelper(paths[i], keypath); + if (ret == 0) + return ret; + } + return ret; +} + /* * Local variables: * mode: c * c-basic-offset: 4 ADDED win/rules-ext.vc Index: win/rules-ext.vc ================================================================== --- /dev/null +++ win/rules-ext.vc @@ -0,0 +1,118 @@ +# This file should only be included in makefiles for Tcl extensions, +# NOT in the makefile for Tcl itself. + +!ifndef _RULES_EXT_VC + +# We need to run from the directory the parent makefile is located in. +# nmake does not tell us what makefile was used to invoke it so parent +# makefile has to set the MAKEFILEVC macro or we just make a guess and +# warn if we think that is not the case. +!if "$(MAKEFILEVC)" == "" + +!if exist("$(PROJECT).vc") +MAKEFILEVC = $(PROJECT).vc +!elseif exist("makefile.vc") +MAKEFILEVC = makefile.vc +!endif +!endif # "$(MAKEFILEVC)" == "" + +!if !exist("$(MAKEFILEVC)") +MSG = ^ +You must run nmake from the directory containing the project makefile.^ +If you are doing that and getting this message, set the MAKEFILEVC^ +macro to the name of the project makefile. +!message WARNING: $(MSG) +!endif + +!if "$(PROJECT)" == "tcl" +!error The rules-ext.vc file is not intended for Tcl itself. +!endif + +# We extract version numbers using the nmakehlp program. For now use +# the local copy of nmakehlp. Once we locate Tcl, we will use that +# one if it is newer. +!if [$(CC) -nologo "nmakehlp.c" -link -subsystem:console > nul] +!endif + +# First locate the Tcl directory that we are working with. +!if "$(TCLDIR)" != "" + +_RULESDIR = $(TCLDIR:/=\) + +!else + +# If an installation path is specified, that is also the Tcl directory. +# Also Tk never builds against an installed Tcl, it needs Tcl sources +!if defined(INSTALLDIR) && "$(PROJECT)" != "tk" +_RULESDIR=$(INSTALLDIR:/=\) +!else +# Locate Tcl sources +!if [echo _RULESDIR = \> nmakehlp.out] \ + || [nmakehlp -L generic\tcl.h >> nmakehlp.out] +_RULESDIR = ..\..\tcl +!else +!include nmakehlp.out +!endif + +!endif # defined(INSTALLDIR).... + +!endif # ifndef TCLDIR + +# Now look for the targets.vc file under the Tcl root. Note we check this +# file and not rules.vc because the latter also exists on older systems. +!if exist("$(_RULESDIR)\lib\nmake\targets.vc") # Building against installed Tcl +_RULESDIR = $(_RULESDIR)\lib\nmake +!elseif exist("$(_RULESDIR)\win\targets.vc") # Building against Tcl sources +_RULESDIR = $(_RULESDIR)\win +!else +# If we have not located Tcl's targets file, most likely we are compiling +# against an older version of Tcl and so must use our own support files. +_RULESDIR = . +!endif + +!if "$(_RULESDIR)" != "." +# Potentially using Tcl's support files. If this extension has its own +# nmake support files, need to compare the versions and pick newer. + +!if exist("rules.vc") # The extension has its own copy + +!if [echo TCL_RULES_MAJOR = \> versions.vc] \ + && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MAJOR >> versions.vc] +!endif +!if [echo TCL_RULES_MINOR = \>> versions.vc] \ + && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MINOR >> versions.vc] +!endif + +!if [echo OUR_RULES_MAJOR = \>> versions.vc] \ + && [nmakehlp -V "rules.vc" RULES_VERSION_MAJOR >> versions.vc] +!endif +!if [echo OUR_RULES_MINOR = \>> versions.vc] \ + && [nmakehlp -V "rules.vc" RULES_VERSION_MINOR >> versions.vc] +!endif +!include versions.vc +# We have a newer version of the support files, use them +!if ($(TCL_RULES_MAJOR) != $(OUR_RULES_MAJOR)) || ($(TCL_RULES_MINOR) < $(OUR_RULES_MINOR)) +_RULESDIR = . +!endif + +!endif # if exist("rules.vc") + +!endif # if $(_RULESDIR) != "." + +# Let rules.vc know what copy of nmakehlp.c to use. +NMAKEHLPC = $(_RULESDIR)\nmakehlp.c + +# Get rid of our internal defines before calling rules.vc +!undef TCL_RULES_MAJOR +!undef TCL_RULES_MINOR +!undef OUR_RULES_MAJOR +!undef OUR_RULES_MINOR + +!if exist("$(_RULESDIR)\rules.vc") +!message *** Using $(_RULESDIR)\rules.vc +!include "$(_RULESDIR)\rules.vc" +!else +!error *** Could not locate rules.vc in $(_RULESDIR) +!endif + +!endif # _RULES_EXT_VC Index: win/rules.vc ================================================================== --- win/rules.vc +++ win/rules.vc @@ -1,57 +1,437 @@ -#------------------------------------------------------------------------------ +#------------------------------------------------------------- -*- makefile -*- # rules.vc -- # -# Microsoft Visual C++ makefile include for decoding the commandline -# macros. This file does not need editing to build Tcl. +# Part of the nmake based build system for Tcl and its extensions. +# This file does all the hard work in terms of parsing build options, +# compiler switches, defining common targets and macros. The Tcl makefile +# directly includes this. Extensions include it via "rules-ext.vc". # -# This version is modified from the Tcl source version to support -# building extensions using nmake. +# See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for +# detailed documentation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2001-2003 David Gravereaux. # Copyright (c) 2003-2008 Patrick Thoyts +# Copyright (c) 2017 Ashok P. Nadkarni #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 -cc32 = $(CC) # built-in default. -link32 = link -lib32 = lib -rc32 = $(RC) # built-in default. - -!ifndef INSTALLDIR -### Assume the normal default. -_INSTALLDIR = C:\Program Files\Tcl +# The following macros define the version of the rules.vc nmake build system +# For modifications that are not backward-compatible, you *must* change +# the major version. +RULES_VERSION_MAJOR = 1 +RULES_VERSION_MINOR = 2 + +# The PROJECT macro must be defined by parent makefile. +!if "$(PROJECT)" == "" +!error *** Error: Macro PROJECT not defined! Please define it before including rules.vc +!endif + +!if "$(PRJ_PACKAGE_TCLNAME)" == "" +PRJ_PACKAGE_TCLNAME = $(PROJECT) +!endif + +# Also special case Tcl and Tk to save some typing later +DOING_TCL = 0 +DOING_TK = 0 +!if "$(PROJECT)" == "tcl" +DOING_TCL = 1 +!elseif "$(PROJECT)" == "tk" +DOING_TK = 1 +!endif + +!ifndef NEED_TK +# Backwards compatibility +!ifdef PROJECT_REQUIRES_TK +NEED_TK = $(PROJECT_REQUIRES_TK) +!else +NEED_TK = 0 +!endif +!endif + +!ifndef NEED_TCL_SOURCE +NEED_TCL_SOURCE = 0 +!endif + +!ifdef NEED_TK_SOURCE +!if $(NEED_TK_SOURCE) +NEED_TK = 1 +!endif !else -### Fix the path separators. -_INSTALLDIR = $(INSTALLDIR:/=\) +NEED_TK_SOURCE = 0 !endif + +################################################################ +# Nmake is a pretty weak environment in syntax and capabilities +# so this file is necessarily verbose. It's broken down into +# the following parts. +# +# 0. Sanity check that compiler environment is set up and initialize +# any built-in settings from the parent makefile +# 1. First define the external tools used for compiling, copying etc. +# as this is independent of everything else. +# 2. Figure out our build structure in terms of the directory, whether +# we are building Tcl or an extension, etc. +# 3. Determine the compiler and linker versions +# 4. Build the nmakehlp helper application +# 5. Determine the supported compiler options and features +# 6. Parse the OPTS macro value for user-specified build configuration +# 7. Parse the STATS macro value for statistics instrumentation +# 8. Parse the CHECKS macro for additional compilation checks +# 9. Extract Tcl, and possibly Tk, version numbers from the headers +# 10. Based on this selected configuration, construct the output +# directory and file paths +# 11. Construct the paths where the package is to be installed +# 12. Set up the actual options passed to compiler and linker based +# on the information gathered above. +# 13. Define some standard build targets and implicit rules. These may +# be optionally disabled by the parent makefile. +# 14. (For extensions only.) Compare the configuration of the target +# Tcl and the extensions and warn against discrepancies. +# +# One final note about the macro names used. They are as they are +# for historical reasons. We would like legacy extensions to +# continue to work with this make include file so be wary of +# changing them for consistency or clarity. + +# 0. Sanity check compiler environment + +# Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or +# VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir) + +!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) +MSG = ^ +Visual C++ compiler environment not initialized. +!error $(MSG) +!endif + +# We need to run from the directory the parent makefile is located in. +# nmake does not tell us what makefile was used to invoke it so parent +# makefile has to set the MAKEFILEVC macro or we just make a guess and +# warn if we think that is not the case. +!if "$(MAKEFILEVC)" == "" + +!if exist("$(PROJECT).vc") +MAKEFILEVC = $(PROJECT).vc +!elseif exist("makefile.vc") +MAKEFILEVC = makefile.vc +!endif +!endif # "$(MAKEFILEVC)" == "" + +!if !exist("$(MAKEFILEVC)") +MSG = ^ +You must run nmake from the directory containing the project makefile.^ +If you are doing that and getting this message, set the MAKEFILEVC^ +macro to the name of the project makefile. +!message WARNING: $(MSG) +!endif + + +################################################################ +# 1. Define external programs being used #---------------------------------------------------------- # Set the proper copy method to avoid overwrite questions # to the user when copying files and selecting the right # "delete all" method. #---------------------------------------------------------- RMDIR = rmdir /S /Q -ERRNULL = 2>NUL -!if ![ver | find "4.0" > nul] -CPY = echo y | xcopy /i >NUL -COPY = copy >NUL -!else CPY = xcopy /i /y >NUL +CPYDIR = xcopy /e /i /y >NUL COPY = copy /y >NUL -!endif MKDIR = mkdir -#------------------------------------------------------------------------------ -# Determine the host and target architectures and compiler version. -#------------------------------------------------------------------------------ +###################################################################### +# 2. Figure out our build environment in terms of what we're building. +# +# (a) Tcl itself +# (b) Tk +# (c) a Tcl extension using libraries/includes from an *installed* Tcl +# (d) a Tcl extension using libraries/includes from Tcl source directory +# +# This last is needed because some extensions still need +# some Tcl interfaces that are not publicly exposed. +# +# The fragment will set the following macros: +# ROOT - root of this module sources +# COMPATDIR - source directory that holds compatibility sources +# DOCDIR - source directory containing documentation files +# GENERICDIR - platform-independent source directory +# WINDIR - Windows-specific source directory +# TESTDIR - directory containing test files +# TOOLSDIR - directory containing build tools +# _TCLDIR - root of the Tcl installation OR the Tcl sources. Not set +# when building Tcl itself. +# _INSTALLDIR - native form of the installation path. For Tcl +# this will be the root of the Tcl installation. For extensions +# this will be the lib directory under the root. +# TCLINSTALL - set to 1 if _TCLDIR refers to +# headers and libraries from an installed Tcl, and 0 if built against +# Tcl sources. Not set when building Tcl itself. Yes, not very well +# named. +# _TCL_H - native path to the tcl.h file +# +# If Tk is involved, also sets the following +# _TKDIR - native form Tk installation OR Tk source. Not set if building +# Tk itself. +# TKINSTALL - set 1 if _TKDIR refers to installed Tk and 0 if Tk sources +# _TK_H - native path to the tk.h file + +# Root directory for sources and assumed subdirectories +ROOT = $(MAKEDIR)\.. +# The following paths CANNOT have spaces in them as they appear on the +# left side of implicit rules. +!ifndef COMPATDIR +COMPATDIR = $(ROOT)\compat +!endif +!ifndef DOCDIR +DOCDIR = $(ROOT)\doc +!endif +!ifndef GENERICDIR +GENERICDIR = $(ROOT)\generic +!endif +!ifndef TOOLSDIR +TOOLSDIR = $(ROOT)\tools +!endif +!ifndef TESTDIR +TESTDIR = $(ROOT)\tests +!endif +!ifndef LIBDIR +!if exist("$(ROOT)\library") +LIBDIR = $(ROOT)\library +!else +LIBDIR = $(ROOT)\lib +!endif +!endif +!ifndef DEMODIR +!if exist("$(LIBDIR)\demos") +DEMODIR = $(LIBDIR)\demos +!else +DEMODIR = $(ROOT)\demos +!endif +!endif # ifndef DEMODIR +# Do NOT enclose WINDIR in a !ifndef because Windows always defines +# WINDIR env var to point to c:\windows! +# TBD - This is a potentially dangerous conflict, rename WINDIR to +# something else +WINDIR = $(ROOT)\win + +!ifndef RCDIR +!if exist("$(WINDIR)\rc") +RCDIR = $(WINDIR)\rc +!else +RCDIR = $(WINDIR) +!endif +!endif +RCDIR = $(RCDIR:/=\) + +# The target directory where the built packages and binaries will be installed. +# INSTALLDIR is the (optional) path specified by the user. +# _INSTALLDIR is INSTALLDIR using the backslash separator syntax +!ifdef INSTALLDIR +### Fix the path separators. +_INSTALLDIR = $(INSTALLDIR:/=\) +!else +### Assume the normal default. +_INSTALLDIR = $(HOMEDRIVE)\Tcl +!endif + +!if $(DOING_TCL) + +# BEGIN Case 2(a) - Building Tcl itself + +# Only need to define _TCL_H +_TCL_H = ..\generic\tcl.h + +# END Case 2(a) - Building Tcl itself + +!elseif $(DOING_TK) + +# BEGIN Case 2(b) - Building Tk + +TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl +!if "$(TCLDIR)" == "" +!if [echo TCLDIR = \> nmakehlp.out] \ + || [nmakehlp -L generic\tcl.h >> nmakehlp.out] +!error *** Could not locate Tcl source directory. +!endif +!include nmakehlp.out +!endif # TCLDIR == "" + +_TCLDIR = $(TCLDIR:/=\) +_TCL_H = $(_TCLDIR)\generic\tcl.h +!if !exist("$(_TCL_H)") +!error Could not locate tcl.h. Please set the TCLDIR macro to point to the Tcl *source* directory. +!endif + +_TK_H = ..\generic\tk.h + +# END Case 2(b) - Building Tk + +!else + +# BEGIN Case 2(c) or (d) - Building an extension other than Tk + +# If command line has specified Tcl location through TCLDIR, use it +# else default to the INSTALLDIR setting +!if "$(TCLDIR)" != "" + +_TCLDIR = $(TCLDIR:/=\) +!if exist("$(_TCLDIR)\include\tcl.h") # Case 2(c) with TCLDIR defined +TCLINSTALL = 1 +_TCL_H = $(_TCLDIR)\include\tcl.h +!elseif exist("$(_TCLDIR)\generic\tcl.h") # Case 2(d) with TCLDIR defined +TCLINSTALL = 0 +_TCL_H = $(_TCLDIR)\generic\tcl.h +!endif + +!else # # Case 2(c) for extensions with TCLDIR undefined + +# Need to locate Tcl depending on whether it needs Tcl source or not. +# If we don't, check the INSTALLDIR for an installed Tcl first + +!if exist("$(_INSTALLDIR)\include\tcl.h") && !$(NEED_TCL_SOURCE) + +TCLINSTALL = 1 +TCLDIR = $(_INSTALLDIR)\.. +# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions +# later so the \.. accounts for the /lib +_TCLDIR = $(_INSTALLDIR)\.. +_TCL_H = $(_TCLDIR)\include\tcl.h + +!else # exist(...) && ! $(NEED_TCL_SOURCE) + +!if [echo _TCLDIR = \> nmakehlp.out] \ + || [nmakehlp -L generic\tcl.h >> nmakehlp.out] +!error *** Could not locate Tcl source directory. +!endif +!include nmakehlp.out +TCLINSTALL = 0 +TCLDIR = $(_TCLDIR) +_TCL_H = $(_TCLDIR)\generic\tcl.h + +!endif # exist(...) && ! $(NEED_TCL_SOURCE) + +!endif # TCLDIR + +!ifndef _TCL_H +MSG =^ +Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h. +!error $(MSG) +!endif + +# Now do the same to locate Tk headers and libs if project requires Tk +!if $(NEED_TK) + +!if "$(TKDIR)" != "" + +_TKDIR = $(TKDIR:/=\) +!if exist("$(_TKDIR)\include\tk.h") +TKINSTALL = 1 +_TK_H = $(_TKDIR)\include\tk.h +!elseif exist("$(_TKDIR)\generic\tk.h") +TKINSTALL = 0 +_TK_H = $(_TKDIR)\generic\tk.h +!endif + +!else # TKDIR not defined + +# Need to locate Tcl depending on whether it needs Tcl source or not. +# If we don't, check the INSTALLDIR for an installed Tcl first + +!if exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) + +TKINSTALL = 1 +# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions +# later so the \.. accounts for the /lib +_TKDIR = $(_INSTALLDIR)\.. +_TK_H = $(_TKDIR)\include\tk.h +TKDIR = $(_TKDIR) + +!else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) + +!if [echo _TKDIR = \> nmakehlp.out] \ + || [nmakehlp -L generic\tk.h >> nmakehlp.out] +!error *** Could not locate Tk source directory. +!endif +!include nmakehlp.out +TKINSTALL = 0 +TKDIR = $(_TKDIR) +_TK_H = $(_TKDIR)\generic\tk.h + +!endif # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) + +!endif # TKDIR + +!ifndef _TK_H +MSG =^ +Failed to find tk.h. The TKDIR macro is set incorrectly or is not set and default path does not contain tk.h. +!error $(MSG) +!endif + +!endif # NEED_TK + +!if $(NEED_TCL_SOURCE) && $(TCLINSTALL) +MSG = ^ +*** Warning: This extension requires the source distribution of Tcl.^ +*** Please set the TCLDIR macro to point to the Tcl sources. +!error $(MSG) +!endif + +!if $(NEED_TK_SOURCE) +!if $(TKINSTALL) +MSG = ^ +*** Warning: This extension requires the source distribution of Tk.^ +*** Please set the TKDIR macro to point to the Tk sources. +!error $(MSG) +!endif +!endif + + +# If INSTALLDIR set to Tcl installation root dir then reset to the +# lib dir for installing extensions +!if exist("$(_INSTALLDIR)\include\tcl.h") +_INSTALLDIR=$(_INSTALLDIR)\lib +!endif + +# END Case 2(c) or (d) - Building an extension +!endif # if $(DOING_TCL) + +################################################################ +# 3. Determine compiler version and architecture +# In this section, we figure out the compiler version and the +# architecture for which we are building. This sets the +# following macros: +# VCVERSION - the internal compiler version as 1200, 1400, 1910 etc. +# This is also printed by the compiler in dotted form 19.10 etc. +# VCVER - the "marketing version", for example Visual C++ 6 for internal +# compiler version 1200. This is kept only for legacy reasons as it +# does not make sense for recent Microsoft compilers. Only used for +# output directory names. +# ARCH - set to IX86 or AMD64 depending on 32- or 64-bit target +# NATIVE_ARCH - set to IX86 or AMD64 for the host machine +# MACHINE - same as $(ARCH) - legacy +# _VC_MANIFEST_EMBED_{DLL,EXE} - commands for embedding a manifest if needed +# CFG_ENCODING - set to an character encoding. +# TBD - this is passed to compiler as TCL_CFGVAL_ENCODING but can't +# see where it is used + +cc32 = $(CC) # built-in default. +link32 = link +lib32 = lib +rc32 = $(RC) # built-in default. + +#---------------------------------------------------------------- +# Figure out the compiler architecture and version by writing +# the C macros to a file, preprocessing them with the C +# preprocessor and reading back the created file _HASH=^# _VC_MANIFEST_EMBED_EXE= _VC_MANIFEST_EMBED_DLL= VCVER=0 @@ -59,20 +439,47 @@ && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ && ![echo ARCH=IX86 >> vercl.x] \ && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ && ![echo ARCH=AMD64 >> vercl.x] \ && ![echo $(_HASH)endif >> vercl.x] \ - && ![cl -nologo -TC -P vercl.x $(ERRNULL)] + && ![$(cc32) -nologo -TC -P vercl.x 2>NUL] !include vercl.i +!if $(VCVERSION) < 1900 !if ![echo VCVER= ^\> vercl.vc] \ && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] !include vercl.vc !endif +!else +# The simple calculation above does not apply to new Visual Studio releases +# Keep the compiler version in its native form. +VCVER = $(VCVERSION) !endif -!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc] !endif +!if ![del 2>NUL /q/f vercl.x vercl.i vercl.vc] +!endif + +#---------------------------------------------------------------- +# The MACHINE macro is used by legacy makefiles so set it as well +!ifdef MACHINE +!if "$(MACHINE)" == "x86" +!undef MACHINE +MACHINE = IX86 +!elseif "$(MACHINE)" == "x64" +!undef MACHINE +MACHINE = AMD64 +!endif +!if "$(MACHINE)" != "$(ARCH)" +!error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH). +!endif +!else +MACHINE=$(ARCH) +!endif + +#------------------------------------------------------------ +# Figure out the *host* architecture by reading the registry + !if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] NATIVE_ARCH=IX86 !else NATIVE_ARCH=AMD64 !endif @@ -81,227 +488,513 @@ !if $(VCVERSION) >= 1400 _VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 _VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 !endif -!ifndef MACHINE -MACHINE=$(ARCH) -!endif - !ifndef CFG_ENCODING CFG_ENCODING = \"cp1252\" !endif -!message =============================================================================== - -#---------------------------------------------------------- -# build the helper app we need to overcome nmake's limiting -# environment. -#---------------------------------------------------------- - -!if !exist(nmakehlp.exe) -!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul] -!endif -!endif - -#---------------------------------------------------------- -# Test for compiler features -#---------------------------------------------------------- - -### test for optimizations -!if [nmakehlp -c -Ot] -!message *** Compiler has 'Optimizations' -OPTIMIZING = 1 -!else -!message *** Compiler does not have 'Optimizations' -OPTIMIZING = 0 -!endif - -OPTIMIZATIONS = - -!if [nmakehlp -c -Ot] -OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot -!endif - -!if [nmakehlp -c -Oi] -OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi -!endif - +################################################################ +# 4. Build the nmakehlp program +# This is a helper app we need to overcome nmake's limiting +# environment. We will call out to it to get various bits of +# information about supported compiler options etc. +# +# Tcl itself will always use the nmakehlp.c program which is +# in its own source. This is the "master" copy and kept updated. +# +# Extensions built against an installed Tcl will use the installed +# copy of Tcl's nmakehlp.c if there is one and their own version +# otherwise. In the latter case, they would also be using their own +# rules.vc. Note that older versions of Tcl do not install nmakehlp.c +# or rules.vc. +# +# Extensions built against Tcl sources will use the one from the Tcl source. +# +# When building an extension using a sufficiently new version of Tcl, +# rules-ext.vc will define NMAKEHLPC appropriately to point to the +# copy of nmakehlp.c to be used. + +!ifndef NMAKEHLPC +# Default to the one in the current directory (the extension's own nmakehlp.c) +NMAKEHLPC = nmakehlp.c + +!if !$(DOING_TCL) +!if $(TCLINSTALL) +!if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c") +NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c +!endif +!else # ! $(TCLINSTALL) +!if exist("$(_TCLDIR)\win\nmakehlp.c") +NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c +!endif +!endif # $(TCLINSTALL) +!endif # !$(DOING_TCL) + +!endif # NMAKEHLPC + +# We always build nmakehlp even if it exists since we do not know +# what source it was built from. +!if [$(cc32) -nologo "$(NMAKEHLPC)" -link -subsystem:console > nul] +!endif + +################################################################ +# 5. Test for compiler features +# Visual C++ compiler options have changed over the years. Check +# which options are supported by the compiler in use. +# +# The following macros are set: +# OPTIMIZATIONS - the compiler flags to be used for optimized builds +# DEBUGFLAGS - the compiler flags to be used for debug builds +# LINKERFLAGS - Flags passed to the linker +# +# Note that these are the compiler settings *available*, not those +# that will be *used*. The latter depends on the OPTS macro settings +# which we have not yet parsed. +# +# Also note that some of the flags in OPTIMIZATIONS are not really +# related to optimization. They are placed there only for legacy reasons +# as some extensions expect them to be included in that macro. + +# -Op improves float consistency. Note only needed for older compilers +# Newer compilers do not need or support this option. !if [nmakehlp -c -Op] -OPTIMIZATIONS = $(OPTIMIZATIONS) -Op +FPOPTS = -Op !endif +# Strict floating point semantics - present in newer compilers in lieu of -Op !if [nmakehlp -c -fp:strict] -OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict -!endif - -!if [nmakehlp -c -Gs] -OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs -!endif - -!if [nmakehlp -c -GS] -OPTIMIZATIONS = $(OPTIMIZATIONS) -GS -!endif - -!if [nmakehlp -c -GL] -OPTIMIZATIONS = $(OPTIMIZATIONS) -GL -!endif - -DEBUGFLAGS = - -!if [nmakehlp -c -RTC1] -DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 -!elseif [nmakehlp -c -GZ] -DEBUGFLAGS = $(DEBUGFLAGS) -GZ -!endif - -COMPILERFLAGS =-W3 - -# In v13 -GL and -YX are incompatible. -!if [nmakehlp -c -YX] -!if ![nmakehlp -c -GL] -OPTIMIZATIONS = $(OPTIMIZATIONS) -YX -!endif +FPOPTS = $(FPOPTS) -fp:strict !endif !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' -COMPILERFLAGS = $(COMPILERFLAGS) -QI0f +FPOPTS = $(FPOPTS) -QI0f !else !message *** Compiler does not have 'Pentium 0x0f fix' !endif !endif -!if "$(MACHINE)" == "IA64" -### test for Itanium errata -!if [nmakehlp -c -QIA64_Bx] -!message *** Compiler has 'B-stepping errata workarounds' -COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx -!else -!message *** Compiler does not have 'B-stepping errata workarounds' -!endif -!endif - -!if "$(MACHINE)" == "IX86" -### test for -align:4096, when align:512 will do. -!if [nmakehlp -l -opt:nowin98] -!message *** Linker has 'Win98 alignment problem' -ALIGN98_HACK = 1 -!else -!message *** Linker does not have 'Win98 alignment problem' -ALIGN98_HACK = 0 -!endif -!else -ALIGN98_HACK = 0 +### test for optimizations +# /O2 optimization includes /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy as per +# documentation. Note we do NOT want /Gs as that inserts a _chkstk +# stack probe at *every* function entry, not just those with more than +# a page of stack allocation resulting in a performance hit. However, +# /O2 documentation is misleading as its stack probes are simply the +# default page size locals allocation probes and not what is implied +# by an explicit /Gs option. + +OPTIMIZATIONS = $(FPOPTS) + +!if [nmakehlp -c -O2] +OPTIMIZING = 1 +OPTIMIZATIONS = $(OPTIMIZATIONS) -O2 +!else +# Legacy, really. All modern compilers support this +!message *** Compiler does not have 'Optimizations' +OPTIMIZING = 0 +!endif + +# Checks for buffer overflows in local arrays +!if [nmakehlp -c -GS] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GS +!endif + +# Link time optimization. Note that this option (potentially) makes +# generated libraries only usable by the specific VC++ version that +# created it. Requires /LTCG linker option +!if [nmakehlp -c -GL] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GL +CC_GL_OPT_ENABLED = 1 +!else +# In newer compilers -GL and -YX are incompatible. +!if [nmakehlp -c -YX] +OPTIMIZATIONS = $(OPTIMIZATIONS) -YX +!endif +!endif # [nmakehlp -c -GL] + +DEBUGFLAGS = $(FPOPTS) + +# Run time error checks. Not available or valid in a release, non-debug build +# RTC is for modern compilers, -GZ is legacy +!if [nmakehlp -c -RTC1] +DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 +!elseif [nmakehlp -c -GZ] +DEBUGFLAGS = $(DEBUGFLAGS) -GZ +!endif + +#---------------------------------------------------------------- +# Linker flags + +# LINKER_TESTFLAGS are for internal use when we call nmakehlp to test +# if the linker supports a specific option. Without these flags link will +# return "LNK1561: entry point must be defined" error compiling from VS-IDE: +# They are not passed through to the actual application / extension +# link rules. +!ifndef LINKER_TESTFLAGS +LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmakehlp.out !endif LINKERFLAGS = -!if [nmakehlp -l -ltcg] -LINKERFLAGS =-ltcg +# If compiler has enabled link time optimization, linker must too with -ltcg +!ifdef CC_GL_OPT_ENABLED +!if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)] +LINKERFLAGS = $(LINKERFLAGS) -ltcg +!endif !endif -#---------------------------------------------------------- -# Decode the options requested. -#---------------------------------------------------------- +######################################################################## +# 6. Parse the OPTS macro to work out the requested build configuration. +# Based on this, we will construct the actual switches to be passed to the +# compiler and linker using the macros defined in the previous section. +# The following macros are defined by this section based on OPTS +# STATIC_BUILD - 0 -> Tcl is to be built as a shared library +# 1 -> build as a static library and shell +# TCL_THREADS - legacy but always 1 on Windows since winsock requires it. +# DEBUG - 1 -> debug build, 0 -> release builds +# SYMBOLS - 1 -> generate PDB's, 0 -> no PDB's +# PROFILE - 1 -> generate profiling info, 0 -> no profiling +# PGO - 1 -> profile based optimization, 0 -> no +# MSVCRT - 1 -> link to dynamic C runtime even when building static Tcl build +# 0 -> link to static C runtime for static Tcl build. +# Does not impact shared Tcl builds (STATIC_BUILD == 0) +# TCL_USE_STATIC_PACKAGES - 1 -> statically link the registry and dde extensions +# in the Tcl shell. 0 -> keep them as shared libraries +# Does not impact shared Tcl builds. +# USE_THREAD_ALLOC - 1 -> Use a shared global free pool for allocation. +# 0 -> Use the non-thread allocator. +# UNCHECKED - 1 -> when doing a debug build with symbols, use the release +# C runtime, 0 -> use the debug C runtime. +# USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking +# CONFIG_CHECK - 1 -> check current build configuration against Tcl +# configuration (ignored for Tcl itself) +# Further, LINKERFLAGS are modified based on above. -!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"] +# Default values for all the above STATIC_BUILD = 0 TCL_THREADS = 1 DEBUG = 0 SYMBOLS = 0 PROFILE = 0 PGO = 0 -MSVCRT = 0 -LOIMPACT = 0 +MSVCRT = 1 +TCL_USE_STATIC_PACKAGES = 0 +USE_THREAD_ALLOC = 1 UNCHECKED = 0 +CONFIG_CHECK = 1 +!if $(DOING_TCL) +USE_STUBS = 0 !else +USE_STUBS = 1 +!endif + +# If OPTS is not empty AND does not contain "none" which turns off all OPTS +# set the above macros based on OPTS content +!if "$(OPTS)" != "" && ![nmakehlp -f "$(OPTS)" "none"] + +# OPTS are specified, parse them + !if [nmakehlp -f $(OPTS) "static"] !message *** Doing static STATIC_BUILD = 1 +!endif + +!if [nmakehlp -f $(OPTS) "nostubs"] +!message *** Not using stubs +USE_STUBS = 0 +!endif + +!if [nmakehlp -f $(OPTS) "nomsvcrt"] +!message *** Doing nomsvcrt +MSVCRT = 0 !else -STATIC_BUILD = 0 -!endif !if [nmakehlp -f $(OPTS) "msvcrt"] !message *** Doing msvcrt MSVCRT = 1 !else +!if !$(STATIC_BUILD) +MSVCRT = 1 +!else MSVCRT = 0 !endif +!endif +!endif # [nmakehlp -f $(OPTS) "nomsvcrt"] + +!if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) +!message *** Doing staticpkg +TCL_USE_STATIC_PACKAGES = 1 +!else +TCL_USE_STATIC_PACKAGES = 0 +!endif + !if [nmakehlp -f $(OPTS) "nothreads"] !message *** Compile explicitly for non-threaded tcl TCL_THREADS = 0 +USE_THREAD_ALLOC= 0 !else TCL_THREADS = 1 +USE_THREAD_ALLOC= 1 !endif + !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif + !if [nmakehlp -f $(OPTS) "pdbs"] !message *** Doing pdbs SYMBOLS = 1 !else SYMBOLS = 0 !endif + !if [nmakehlp -f $(OPTS) "profile"] !message *** Doing profile PROFILE = 1 !else PROFILE = 0 !endif + !if [nmakehlp -f $(OPTS) "pgi"] !message *** Doing profile guided optimization instrumentation PGO = 1 !elseif [nmakehlp -f $(OPTS) "pgo"] !message *** Doing profile guided optimization PGO = 2 !else PGO = 0 !endif + !if [nmakehlp -f $(OPTS) "loimpact"] -!message *** Doing loimpact -LOIMPACT = 1 -!else -LOIMPACT = 0 +!message *** Warning: ignoring option "loimpact" - deprecated on modern Windows. !endif + +# TBD - should get rid of this option +!if [nmakehlp -f $(OPTS) "thrdalloc"] +!message *** Doing thrdalloc +USE_THREAD_ALLOC = 1 +!endif + +!if [nmakehlp -f $(OPTS) "tclalloc"] +USE_THREAD_ALLOC = 0 +!endif + !if [nmakehlp -f $(OPTS) "unchecked"] !message *** Doing unchecked UNCHECKED = 1 !else UNCHECKED = 0 !endif + +!if [nmakehlp -f $(OPTS) "noconfigcheck"] +CONFIG_CHECK = 1 +!else +CONFIG_CHECK = 0 !endif -!if !$(STATIC_BUILD) -# Make sure we don't build overly fat DLLs. -MSVCRT = 1 -# We shouldn't statically put the extensions inside the shell when dynamic. -TCL_USE_STATIC_PACKAGES = 0 +!endif # "$(OPTS)" != "" && ... parsing of OPTS + +# Set linker flags based on above + +!if $(PGO) > 1 +!if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)] +LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize +!else +MSG=^ +This compiler does not support profile guided optimization. +!error $(MSG) +!endif +!elseif $(PGO) > 0 +!if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)] +LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument +!else +MSG=^ +This compiler does not support profile guided optimization. +!error $(MSG) +!endif !endif -#---------------------------------------------------------- +################################################################ +# 7. Parse the STATS macro to configure code instrumentation +# The following macros are set by this section: +# TCL_MEM_DEBUG - 1 -> enables memory allocation instrumentation +# 0 -> disables +# TCL_COMPILE_DEBUG - 1 -> enables byte compiler logging +# 0 -> disables + +# Default both are off +TCL_MEM_DEBUG = 0 +TCL_COMPILE_DEBUG = 0 + +!if "$(STATS)" != "" && ![nmakehlp -f "$(STATS)" "none"] + +!if [nmakehlp -f $(STATS) "memdbg"] +!message *** Doing memdbg +TCL_MEM_DEBUG = 1 +!else +TCL_MEM_DEBUG = 0 +!endif + +!if [nmakehlp -f $(STATS) "compdbg"] +!message *** Doing compdbg +TCL_COMPILE_DEBUG = 1 +!else +TCL_COMPILE_DEBUG = 0 +!endif + +!endif + +#################################################################### +# 8. Parse the CHECKS macro to configure additional compiler checks +# The following macros are set by this section: +# WARNINGS - compiler switches that control the warnings level +# TCL_NO_DEPRECATED - 1 -> disable support for deprecated functions +# 0 -> enable deprecated functions + +# Defaults - Permit deprecated functions and warning level 3 +TCL_NO_DEPRECATED = 0 +WARNINGS = -W3 + +!if "$(CHECKS)" != "" && ![nmakehlp -f "$(CHECKS)" "none"] + +!if [nmakehlp -f $(CHECKS) "nodep"] +!message *** Doing nodep check +TCL_NO_DEPRECATED = 1 +!endif + +!if [nmakehlp -f $(CHECKS) "fullwarn"] +!message *** Doing full warnings check +WARNINGS = -W4 +!if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)] +LINKERFLAGS = $(LINKERFLAGS) -warn:3 +!endif +!endif + +!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] +!message *** Doing 64bit portability warnings +WARNINGS = $(WARNINGS) -Wp64 +!endif + +!endif + +################################################################ +# 9. Extract various version numbers +# For Tcl and Tk, version numbers are extracted from tcl.h and tk.h +# respectively. For extensions, versions are extracted from the +# configure.in or configure.ac from the TEA configuration if it +# exists, and unset otherwise. +# Sets the following macros: +# TCL_MAJOR_VERSION +# TCL_MINOR_VERSION +# TCL_PATCH_LEVEL +# TCL_VERSION +# TK_MAJOR_VERSION +# TK_MINOR_VERSION +# TK_PATCH_LEVEL +# TK_VERSION +# DOTVERSION - set as (for example) 2.5 +# VERSION - set as (for example 25) +#-------------------------------------------------------------- + +!if [echo REM = This file is generated from rules.vc > versions.vc] +!endif +!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc] +!endif +!if [echo TCL_MINOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc] +!endif +!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ + && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] +!endif + +!if defined(_TK_H) +!if [echo TK_MAJOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc] +!endif +!if [echo TK_MINOR_VERSION = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc] +!endif +!if [echo TK_PATCH_LEVEL = \>> versions.vc] \ + && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] +!endif +!endif # _TK_H + +!include versions.vc + +TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) +TCL_DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) +!if defined(_TK_H) +TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) +TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) +!endif + +# Set DOTVERSION and VERSION +!if $(DOING_TCL) + +DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) +VERSION = $(TCL_VERSION) + +!elseif $(DOING_TK) + +DOTVERSION = $(TK_DOTVERSION) +VERSION = $(TK_VERSION) + +!else # Doing a non-Tk extension + +# If parent makefile has not defined DOTVERSION, try to get it from TEA +# first from a configure.in file, and then from configure.ac +!ifndef DOTVERSION +!if [echo DOTVERSION = \> versions.vc] \ + || [nmakehlp -V $(ROOT)\configure.in ^[$(PROJECT)^] >> versions.vc] +!if [echo DOTVERSION = \> versions.vc] \ + || [nmakehlp -V $(ROOT)\configure.ac ^[$(PROJECT)^] >> versions.vc] +!error *** Could not figure out extension version. Please define DOTVERSION in parent makefile before including rules.vc. +!endif +!endif +!include versions.vc +!endif # DOTVERSION +VERSION = $(DOTVERSION:.=) + +!endif # $(DOING_TCL) ... etc. + +################################################################ +# 10. Construct output directory and file paths # Figure-out how to name our intermediate and output directories. -# We wouldn't want different builds to use the same .obj files -# by accident. -#---------------------------------------------------------- - -#---------------------------------------- -# Naming convention: +# In order to avoid inadvertent mixing of object files built using +# different compilers, build configurations etc., +# +# Naming convention (suffixes): # t = full thread support. -# s = static library (as opposed to an -# import library) -# g = linked to the debug enabled C -# run-time. -# x = special static build when it -# links to the dynamic C run-time. -#---------------------------------------- -SUFX = sgx +# s = static library (as opposed to an import library) +# g = linked to the debug enabled C run-time. +# x = special static build when it links to the dynamic C run-time. +# +# The following macros are set in this section: +# SUFX - the suffix to use for binaries based on above naming convention +# BUILDDIRTOP - the toplevel default output directory +# is of the form {Release,Debug}[_AMD64][_COMPILERVERSION] +# TMP_DIR - directory where object files are created +# OUT_DIR - directory where output executables are created +# Both TMP_DIR and OUT_DIR are defaulted only if not defined by the +# parent makefile (or command line). The default values are +# based on BUILDDIRTOP. +# STUBPREFIX - name of the stubs library for this project +# PRJIMPLIB - output path of the generated project import library +# PRJLIBNAME - name of generated project library +# PRJLIB - output path of generated project library +# PRJSTUBLIBNAME - name of the generated project stubs library +# PRJSTUBLIB - output path of the generated project stubs library +# RESFILE - output resource file (only if not static build) + +SUFX = tsgx !if $(DEBUG) BUILDDIRTOP = Debug !else BUILDDIRTOP = Release @@ -312,32 +1005,35 @@ !endif !if $(VCVER) > 6 BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) !endif -!if !$(DEBUG) || $(UNCHECKED) +!if !$(DEBUG) || $(DEBUG) && $(UNCHECKED) SUFX = $(SUFX:g=) !endif -TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_DynamicStaticX +TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX !if !$(STATIC_BUILD) TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll -!if $(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) -!endif !else TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) EXT = lib !if !$(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !endif !endif + +!if !$(TCL_THREADS) +TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) +SUFX = $(SUFX:t=) +!endif !ifndef TMP_DIR TMP_DIR = $(TMP_DIRFULL) !ifndef OUT_DIR OUT_DIR = .\$(BUILDDIRTOP) @@ -346,84 +1042,221 @@ !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif - -#---------------------------------------------------------- -# Decode the statistics requested. -#---------------------------------------------------------- - -!if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"] -TCL_MEM_DEBUG = 0 -TCL_COMPILE_DEBUG = 0 -!else -!if [nmakehlp -f $(STATS) "memdbg"] -!message *** Doing memdbg -TCL_MEM_DEBUG = 1 -!else -TCL_MEM_DEBUG = 0 -!endif -!if [nmakehlp -f $(STATS) "compdbg"] -!message *** Doing compdbg -TCL_COMPILE_DEBUG = 1 -!else -TCL_COMPILE_DEBUG = 0 -!endif -!endif - - -#---------------------------------------------------------- -# Decode the checks requested. -#---------------------------------------------------------- - -!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"] -TCL_NO_DEPRECATED = 0 -WARNINGS = -W3 -!else -!if [nmakehlp -f $(CHECKS) "nodep"] -!message *** Doing nodep check -TCL_NO_DEPRECATED = 1 -!else -TCL_NO_DEPRECATED = 0 -!endif -!if [nmakehlp -f $(CHECKS) "fullwarn"] -!message *** Doing full warnings check -WARNINGS = -W4 -!if [nmakehlp -l -warn:3] -LINKERFLAGS = $(LINKERFLAGS) -warn:3 -!endif -!else -WARNINGS = -W3 -!endif -!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] -!message *** Doing 64bit portability warnings -WARNINGS = $(WARNINGS) -Wp64 -!endif -!endif - -!if $(PGO) > 1 -!if [nmakehlp -l -ltcg:pgoptimize] -LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize -!else -MSG=^ -This compiler does not support profile guided optimization. -!error $(MSG) -!endif -!elseif $(PGO) > 0 -!if [nmakehlp -l -ltcg:pginstrument] -LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument -!else -MSG=^ -This compiler does not support profile guided optimization. -!error $(MSG) -!endif -!endif - -#---------------------------------------------------------- -# Set our defines now armed with our options. -#---------------------------------------------------------- +# Relative paths -> absolute +!if [echo OUT_DIR = \> nmakehlp.out] \ + || [nmakehlp -Q "$(OUT_DIR)" >> nmakehlp.out] +!error *** Could not fully qualify path OUT_DIR=$(OUT_DIR) +!endif +!if [echo TMP_DIR = \>> nmakehlp.out] \ + || [nmakehlp -Q "$(TMP_DIR)" >> nmakehlp.out] +!error *** Could not fully qualify path TMP_DIR=$(TMP_DIR) +!endif +!include nmakehlp.out + +# The name of the stubs library for the project being built +STUBPREFIX = $(PROJECT)stub + +# Set up paths to various Tcl executables and libraries needed by extensions +!if $(DOING_TCL) + +TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe +TCLSH = $(OUT_DIR)\$(TCLSHNAME) +TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib +TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) +TCLLIB = $(OUT_DIR)\$(TCLLIBNAME) + +TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib +TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME) +TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" + +!else # ! $(DOING_TCL) + +!if $(TCLINSTALL) # Building against an installed Tcl + +# When building extensions, we need to locate tclsh. Depending on version +# of Tcl we are building against, this may or may not have a "t" suffix. +# Try various possibilities in turn. +TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe +!if !exist("$(TCLSH)") && $(TCL_THREADS) +TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe +!endif +!if !exist("$(TCLSH)") +TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe +!endif + +TCLSTUBLIB = $(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib +TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib +# When building extensions, may be linking against Tcl that does not add +# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. +!if !exist("$(TCLIMPLIB)") +TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib +!endif +TCL_LIBRARY = $(_TCLDIR)\lib +TCLREGLIB = $(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib +TCLDDELIB = $(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib +TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target +TCL_INCLUDES = -I"$(_TCLDIR)\include" + +!else # Building against Tcl sources + +TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe +!if !exist($(TCLSH)) && $(TCL_THREADS) +TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe +!endif +!if !exist($(TCLSH)) +TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX:t=).exe +!endif +TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib +TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib +# When building extensions, may be linking against Tcl that does not add +# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. +!if !exist("$(TCLIMPLIB)") +TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib +!endif +TCL_LIBRARY = $(_TCLDIR)\library +TCLREGLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib +TCLDDELIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib +TCLTOOLSDIR = $(_TCLDIR)\tools +TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" + +!endif # TCLINSTALL + +tcllibs = "$(TCLSTUBLIB)" "$(TCLIMPLIB)" + +!endif # $(DOING_TCL) + +# We need a tclsh that will run on the host machine as part of the build. +# IX86 runs on all architectures. +!ifndef TCLSH_NATIVE +!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" +TCLSH_NATIVE = $(TCLSH) +!else +!error You must explicitly set TCLSH_NATIVE for cross-compilation +!endif +!endif + +# Do the same for Tk and Tk extensions that require the Tk libraries +!if $(DOING_TK) || $(NEED_TK) +WISHNAMEPREFIX = wish +WISHNAME = $(WISHNAMEPREFIX)$(TK_VERSION)$(SUFX).exe +TKLIBNAME = $(PROJECT)$(TK_VERSION)$(SUFX).$(EXT) +TKSTUBLIBNAME = tkstub$(TK_VERSION).lib +TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX).lib + +!if $(DOING_TK) +WISH = $(OUT_DIR)\$(WISHNAME) +TKSTUBLIB = $(OUT_DIR)\$(TKSTUBLIBNAME) +TKIMPLIB = $(OUT_DIR)\$(TKIMPLIBNAME) +TKLIB = $(OUT_DIR)\$(TKLIBNAME) +TK_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" + +!else # effectively NEED_TK + +!if $(TKINSTALL) # Building against installed Tk +WISH = $(_TKDIR)\bin\$(WISHNAME) +TKSTUBLIB = $(_TKDIR)\lib\$(TKSTUBLIBNAME) +TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME) +# When building extensions, may be linking against Tk that does not add +# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. +!if !exist("$(TKIMPLIB)") +TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib +TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME) +!endif +TK_INCLUDES = -I"$(_TKDIR)\include" +!else # Building against Tk sources +WISH = $(_TKDIR)\win\$(BUILDDIRTOP)\$(WISHNAME) +TKSTUBLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKSTUBLIBNAME) +TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME) +# When building extensions, may be linking against Tk that does not add +# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. +!if !exist("$(TKIMPLIB)") +TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib +TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME) +!endif +TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" +!endif # TKINSTALL +tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)" + +!endif # $(DOING_TK) +!endif # $(DOING_TK) || $(NEED_TK) + +# Various output paths +PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX:t=).lib +PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX:t=).$(EXT) +PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) + +PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib +PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) + +# If extension parent makefile has not defined a resource definition file, +# we will generate one from standard template. +!if !$(DOING_TCL) && !$(DOING_TK) && !$(STATIC_BUILD) +!ifdef RCFILE +RESFILE = $(TMP_DIR)\$(RCFILE:.rc=.res) +!else +RESFILE = $(TMP_DIR)\$(PROJECT).res +!endif +!endif + +################################################################### +# 11. Construct the paths for the installation directories +# The following macros get defined in this section: +# LIB_INSTALL_DIR - where libraries should be installed +# BIN_INSTALL_DIR - where the executables should be installed +# DOC_INSTALL_DIR - where documentation should be installed +# SCRIPT_INSTALL_DIR - where scripts should be installed +# INCLUDE_INSTALL_DIR - where C include files should be installed +# DEMO_INSTALL_DIR - where demos should be installed +# PRJ_INSTALL_DIR - where package will be installed (not set for Tcl and Tk) + +!if $(DOING_TCL) || $(DOING_TK) +LIB_INSTALL_DIR = $(_INSTALLDIR)\lib +BIN_INSTALL_DIR = $(_INSTALLDIR)\bin +DOC_INSTALL_DIR = $(_INSTALLDIR)\doc +!if $(DOING_TCL) +SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) +!else # DOING_TK +SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) +!endif +DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos +INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include + +!else # extension other than Tk + +PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) +LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) +BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) +DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) +SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) +DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos +INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include + +!endif + +################################################################### +# 12. Set up actual options to be passed to the compiler and linker +# Now we have all the information we need, set up the actual flags and +# options that we will pass to the compiler and linker. The main +# makefile should use these in combination with whatever other flags +# and switches are specific to it. +# The following macros are defined, names are for historical compatibility: +# OPTDEFINES - /Dxxx C macro flags based on user-specified OPTS +# COMPILERFLAGS - /Dxxx C macro flags independent of any configuration opttions +# crt - Compiler switch that selects the appropriate C runtime +# cdebug - Compiler switches related to debug AND optimizations +# cwarn - Compiler switches that set warning levels +# cflags - complete compiler switches (subsumes cdebug and cwarn) +# ldebug - Linker switches controlling debug information and optimization +# lflags - complete linker switches (subsumes ldebug) except subsystem type +# dlllflags - complete linker switches to build DLLs (subsumes lflags) +# conlflags - complete linker switches for console program (subsumes lflags) +# guilflags - complete linker switches for GUI program (subsumes lflags) +# baselibs - minimum Windows libraries required. Parent makefile can +# define PRJ_LIBS before including rules.rc if additional libs are needed OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS !if $(TCL_MEM_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG @@ -430,191 +1263,478 @@ !endif !if $(TCL_COMPILE_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS !endif !if $(TCL_THREADS) -OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 -DUSE_THREAD_ALLOC=1 +OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 +!if $(USE_THREAD_ALLOC) +OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 +!endif !endif !if $(STATIC_BUILD) OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD !endif !if $(TCL_NO_DEPRECATED) OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED !endif +!if $(USE_STUBS) +# Note we do not define USE_TCL_STUBS even when building tk since some +# test targets in tk do not use stubs +!if ! $(DOING_TCL) +USE_STUBS_DEFS = -DUSE_TCL_STUBS -DUSE_TCLOO_STUBS +!if $(NEED_TK) +USE_STUBS_DEFS = $(USE_STUBS_DEFS) -DUSE_TK_STUBS +!endif +!endif +!endif # USE_STUBS + !if !$(DEBUG) OPTDEFINES = $(OPTDEFINES) -DNDEBUG !if $(OPTIMIZING) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED !endif !endif !if $(PROFILE) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED !endif -!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" -OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT -!endif - - -#---------------------------------------------------------- -# Get common info used when building extensions. -#---------------------------------------------------------- - -!if "$(PROJECT)" != "tcl" - -# If INSTALLDIR set to tcl root dir then reset to the lib dir. -!if exist("$(_INSTALLDIR)\include\tcl.h") -_INSTALLDIR=$(_INSTALLDIR)\lib -!endif - -!if !defined(TCLDIR) -!if exist("$(_INSTALLDIR)\..\include\tcl.h") -TCLINSTALL = 1 -_TCLDIR = $(_INSTALLDIR)\.. -_TCL_H = $(_INSTALLDIR)\..\include\tcl.h -TCLDIR = $(_INSTALLDIR)\.. -!else -MSG=^ -Failed to find tcl.h. Set the TCLDIR macro. -!error $(MSG) -!endif -!else -_TCLDIR = $(TCLDIR:/=\) -!if exist("$(_TCLDIR)\include\tcl.h") -TCLINSTALL = 1 -_TCL_H = $(_TCLDIR)\include\tcl.h -!elseif exist("$(_TCLDIR)\generic\tcl.h") -TCLINSTALL = 0 -_TCL_H = $(_TCLDIR)\generic\tcl.h -!else -MSG =^ -Failed to find tcl.h. The TCLDIR macro does not appear correct. -!error $(MSG) -!endif -!endif - -!if [echo REM = This file is generated from rules.vc > versions.vc] -!endif -!if exist("$(_TCL_H)") -!if [echo TCL_DOTVERSION = \>> versions.vc] \ - && [nmakehlp -V "$(_TCL_H)" TCL_VERSION >> versions.vc] -!endif -!endif -!include versions.vc -TCL_VERSION = $(TCL_DOTVERSION:.=) - -!if $(TCLINSTALL) -TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe" -!if !exist($(TCLSH)) && $(TCL_THREADS) -TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe" -!endif -TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib" -TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib" -TCL_LIBRARY = $(_TCLDIR)\lib -COFFBASE = \must\have\tcl\sources\to\build\this\target -TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target -TCL_INCLUDES = -I"$(_TCLDIR)\include" -!else -TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe" -!if !exist($(TCLSH)) && $(TCL_THREADS) -TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe" -!endif -TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib" -TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib" -TCL_LIBRARY = $(_TCLDIR)\library -COFFBASE = "$(_TCLDIR)\win\coffbase.txt" -TCLTOOLSDIR = $(_TCLDIR)\tools -TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" -!endif - -!endif - -#---------------------------------------------------------- -# Optionally check for Tk info for building extensions. -#---------------------------------------------------------- - -!ifdef PROJECT_REQUIRES_TK -!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" - -!if !defined(TKDIR) -!if exist("$(_INSTALLDIR)\..\include\tk.h") -TKINSTALL = 1 -_TKDIR = $(_INSTALLDIR)\.. -_TK_H = $(_TKDIR)\include\tk.h -TKDIR = $(_TKDIR) -!elseif exist("$(_TCLDIR)\include\tk.h") -TKINSTALL = 1 -_TKDIR = $(_TCLDIR) -_TK_H = $(_TKDIR)\include\tk.h -TKDIR = $(_TKDIR) -!endif -!else -_TKDIR = $(TKDIR:/=\) -!if exist("$(_TKDIR)\include\tk.h") -TKINSTALL = 1 -_TK_H = $(_TKDIR)\include\tk.h -!elseif exist("$(_TKDIR)\generic\tk.h") -TKINSTALL = 0 -_TK_H = $(_TKDIR)\generic\tk.h -!else -MSG =^ -Failed to find tk.h. The TKDIR macro does not appear correct. -!error $(MSG) -!endif -!endif - -!if defined(TKDIR) -TK_DOTVERSION = 8.4 -!if exist("$(_TK_H)") -!if [echo TK_DOTVERSION = \>> versions.vc] \ - && [nmakehlp -V "$(_TK_H)" TK_VERSION >> versions.vc] -!endif -!endif -!include versions.vc -TK_VERSION = $(TK_DOTVERSION:.=) - -!if $(TKINSTALL) -WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)$(SUFX).exe" -!if !exist($(WISH)) && $(TCL_THREADS) -WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)t$(SUFX).exe" -!endif -TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib" -TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib" -TK_INCLUDES = -I"$(_TKDIR)\include" -!else -WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(SUFX).exe" -!if !exist($(WISH)) && $(TCL_THREADS) -WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)t$(SUFX).exe" -!endif -TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib" -TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib" -TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" -!endif - -!endif -!endif -!endif - - -#---------------------------------------------------------- -# Setup the fully qualified OUT_DIR path as OUT_DIR_PATH -#---------------------------------------------------------- -!if [echo OUT_DIR_PATH = \>> versions.vc] \ - && [nmakehlp -Q "$(OUT_DIR)" >> versions.vc] -!endif -!include versions.vc +!if "$(MACHINE)" == "AMD64" +OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT +!endif +!if $(VCVERSION) < 1300 +OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64 +!endif + +# _ATL_XP_TARGETING - Newer SDK's need this to build for XP +COMPILERFLAGS = /D_ATL_XP_TARGETING + +# Following is primarily for the benefit of extensions. Tcl 8.5 builds +# Tcl without /DUNICODE, while 8.6 builds with it defined. When building +# an extension, it is advisable (but not mandated) to use the same Windows +# API as the Tcl build. This is accordingly defaulted below. A particular +# extension can override this by pre-definining USE_WIDECHAR_API. +!ifndef USE_WIDECHAR_API +!if $(TCL_VERSION) > 85 +USE_WIDECHAR_API = 1 +!else +USE_WIDECHAR_API = 0 +!endif +!endif + +!if $(USE_WIDECHAR_API) +COMPILERFLAGS = $(COMPILERFLAGS) /DUNICODE /D_UNICODE +!endif + +# Like the TEA system only set this non empty for non-Tk extensions +# Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME +# so we pass both +!if !$(DOING_TCL) && !$(DOING_TK) +PKGNAMEFLAGS = -DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ + -DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ + -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ + -DMODULE_SCOPE=extern +!endif + +# crt picks the C run time based on selected OPTS +!if $(MSVCRT) +!if $(DEBUG) && !$(UNCHECKED) +crt = -MDd +!else +crt = -MD +!endif +!else +!if $(DEBUG) && !$(UNCHECKED) +crt = -MTd +!else +crt = -MT +!endif +!endif + +# cdebug includes compiler options for debugging as well as optimization. +!if $(DEBUG) + +# In debugging mode, optimizations need to be disabled +cdebug = -Zi -Od $(DEBUGFLAGS) + +!else + +cdebug = $(OPTIMIZATIONS) +!if $(SYMBOLS) +cdebug = $(cdebug) -Zi +!endif + +!endif # $(DEBUG) + +# cwarn includes default warning levels. +cwarn = $(WARNINGS) + +!if "$(MACHINE)" == "AMD64" +# Disable pointer<->int warnings related to cast between different sizes +# There are a gadzillion of these due to use of ClientData and +# clutter up compiler +# output increasing chance of a real warning getting lost. So disable them. +# Eventually some day, Tcl will be 64-bit clean. +cwarn = $(cwarn) -wd4311 -wd4312 +!endif + +### Common compiler options that are architecture specific +!if "$(MACHINE)" == "ARM" +carch = -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE +!else +carch = +!endif + +!if $(DEBUG) +# Turn warnings into errors +cwarn = $(cwarn) -WX +!endif + +INCLUDES = $(TCL_INCLUDES) $(TK_INCLUDES) $(PRJ_INCLUDES) +!if !$(DOING_TCL) && !$(DOING_TK) +INCLUDES = $(INCLUDES) -I"$(GENERICDIR)" -I"$(WINDIR)" -I"$(COMPATDIR)" +!endif + +# These flags are defined roughly in the order of the pre-reform +# rules.vc/makefile.vc to help visually compare that the pre- and +# post-reform build logs + +# cflags contains generic flags used for building practically all object files +cflags = -nologo -c $(COMPILERFLAGS) $(carch) $(cwarn) -Fp$(TMP_DIR)^\ $(cdebug) + +# appcflags contains $(cflags) and flags for building the application +# object files (e.g. tclsh, or wish) pkgcflags contains $(cflags) plus +# flags used for building shared object files The two differ in the +# BUILD_$(PROJECT) macro which should be defined only for the shared +# library *implementation* and not for its caller interface + +appcflags = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES) $(USE_STUBS_DEFS) +appcflags_nostubs = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES) +pkgcflags = $(appcflags) $(PKGNAMEFLAGS) -DBUILD_$(PROJECT) +pkgcflags_nostubs = $(appcflags_nostubs) $(PKGNAMEFLAGS) -DBUILD_$(PROJECT) + +# stubscflags contains $(cflags) plus flags used for building a stubs +# library for the package. Note: -DSTATIC_BUILD is defined in +# $(OPTDEFINES) only if the OPTS configuration indicates a static +# library. However the stubs library is ALWAYS static hence included +# here irrespective of the OPTS setting. +# +# TBD - tclvfs has a comment that stubs libs should not be compiled with -GL +# without stating why. Tcl itself compiled stubs libs with this flag. +# so we do not remove it from cflags. -GL may prevent extensions +# compiled with one VC version to fail to link against stubs library +# compiled with another VC version. Check for this and fix accordingly. +stubscflags = $(cflags) $(PKGNAMEFLAGS) $(PRJ_DEFINES) $(OPTDEFINES) -Zl -DSTATIC_BUILD $(INCLUDES) + +# Link flags + +!if $(DEBUG) +ldebug = -debug -debugtype:cv +!else +ldebug = -release -opt:ref -opt:icf,3 +!if $(SYMBOLS) +ldebug = $(ldebug) -debug -debugtype:cv +!endif +!endif + +# Note: Profiling is currently only possible with the Visual Studio Enterprise +!if $(PROFILE) +ldebug= $(ldebug) -profile +!endif + +### Declarations common to all linker versions +lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) + +!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 +lflags = $(lflags) -nodefaultlib:libucrt.lib +!endif + +dlllflags = $(lflags) -dll +conlflags = $(lflags) -subsystem:console +guilflags = $(lflags) -subsystem:windows + +# Libraries that are required for every image. +# Extensions should define any additional libraries with $(PRJ_LIBS) +winlibs = kernel32.lib advapi32.lib + +!if $(NEED_TK) +winlibs = $(winlibs) gdi32.lib user32.lib uxtheme.lib +!endif + +# Avoid 'unresolved external symbol __security_cookie' errors. +# c.f. http://support.microsoft.com/?id=894573 +!if "$(MACHINE)" == "AMD64" +!if $(VCVERSION) > 1399 && $(VCVERSION) < 1500 +winlibs = $(winlibs) bufferoverflowU.lib +!endif +!endif + +baselibs = $(winlibs) $(PRJ_LIBS) + +!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 +baselibs = $(baselibs) ucrt.lib +!endif + +################################################################ +# 13. Define standard commands, common make targets and implicit rules + +CCPKGCMD = $(cc32) $(pkgcflags) -Fo$(TMP_DIR)^\ +CCAPPCMD = $(cc32) $(appcflags) -Fo$(TMP_DIR)^\ +CCSTUBSCMD = $(cc32) $(stubscflags) -Fo$(TMP_DIR)^\ + +LIBCMD = $(lib32) -nologo $(LINKERFLAGS) -out:$@ +DLLCMD = $(link32) $(dlllflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) + +CONEXECMD = $(link32) $(conlflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) +GUIEXECMD = $(link32) $(guilflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) +RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \ + $(TCL_INCLUDES) \ + -DDEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \ + -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ + -DDOTVERSION=\"$(DOTVERSION)\" \ + -DVERSION=\"$(VERSION)\" \ + -DSUFX=\"$(SUFX:t=)\" \ + -DPROJECT=\"$(PROJECT)\" \ + -DPRJLIBNAME=\"$(PRJLIBNAME)\" + +!ifndef DEFAULT_BUILD_TARGET +DEFAULT_BUILD_TARGET = $(PROJECT) +!endif + +default-target: $(DEFAULT_BUILD_TARGET) + +default-pkgindex: + @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ + [list load [file join $$dir $(PRJLIBNAME)]] > $(OUT_DIR)\pkgIndex.tcl + +default-pkgindex-tea: + @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl +@PACKAGE_VERSION@ $(DOTVERSION) +@PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME) +@PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME) +@PKG_LIB_FILE@ $(PRJLIBNAME) +<< + + +default-install: default-install-binaries default-install-libraries + +default-install-binaries: $(PRJLIB) + @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' + @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" + @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL + +default-install-libraries: $(OUT_DIR)\pkgIndex.tcl + @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' + @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" + @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' + @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR) + +default-install-stubs: + @echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)' + @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" + @$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL + +default-install-docs-html: + @echo Installing documentation files to '$(DOC_INSTALL_DIR)' + @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" + @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)" + +default-install-docs-n: + @echo Installing documentation files to '$(DOC_INSTALL_DIR)' + @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" + @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.n") do @$(COPY) %f "$(DOC_INSTALL_DIR)" + +default-install-demos: + @echo Installing demos to '$(DEMO_INSTALL_DIR)' + @if not exist "$(DEMO_INSTALL_DIR)" mkdir "$(DEMO_INSTALL_DIR)" + @if exist $(DEMODIR) $(CPYDIR) "$(DEMODIR)" "$(DEMO_INSTALL_DIR)" + +default-clean: + @echo Cleaning $(TMP_DIR)\* ... + @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) + @echo Cleaning $(WINDIR)\nmakehlp.obj, nmakehlp.exe ... + @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj + @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe + @if exist $(WINDIR)\nmakehlp.out del $(WINDIR)\nmakehlp.out + @echo Cleaning $(WINDIR)\nmhlp-out.txt ... + @if exist $(WINDIR)\nmhlp-out.txt del $(WINDIR)\nmhlp-out.txt + @echo Cleaning $(WINDIR)\_junk.pch ... + @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch + @echo Cleaning $(WINDIR)\vercl.x, vercl.i ... + @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x + @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i + @echo Cleaning $(WINDIR)\versions.vc, version.vc ... + @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc + @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc + +default-hose: default-clean + @echo Hosing $(OUT_DIR)\* ... + @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) + +# Only for backward compatibility +default-distclean: default-hose + +default-setup: + @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) + @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) + +!if "$(TESTPAT)" != "" +TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) +!endif + +default-test: default-setup $(PROJECT) + @set TCLLIBPATH=$(OUT_DIR:\=/) + @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" + cd "$(TESTDIR)" && $(DEBUGGER) $(TCLSH) all.tcl $(TESTFLAGS) + +default-shell: default-setup $(PROJECT) + @set TCLLIBPATH=$(OUT_DIR:\=/) + @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" + $(DEBUGGER) $(TCLSH) + +# Generation of Windows version resource +!ifdef RCFILE + +# Note: don't use $** in below rule because there may be other dependencies +# and only the "master" rc must be passed to the resource compiler +$(TMP_DIR)\$(PROJECT).res: $(RCDIR)\$(PROJECT).rc + $(RESCMD) $(RCDIR)\$(PROJECT).rc + +!else + +# If parent makefile has not defined a resource definition file, +# we will generate one from standard template. +$(TMP_DIR)\$(PROJECT).res: $(TMP_DIR)\$(PROJECT).rc + +$(TMP_DIR)\$(PROJECT).rc: + @$(COPY) << $(TMP_DIR)\$(PROJECT).rc +#include + +VS_VERSION_INFO VERSIONINFO + FILEVERSION COMMAVERSION + PRODUCTVERSION COMMAVERSION + FILEFLAGSMASK 0x3fL +#ifdef DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "Tcl extension " PROJECT + VALUE "OriginalFilename", PRJLIBNAME + VALUE "FileVersion", DOTVERSION + VALUE "ProductName", "Package " PROJECT " for Tcl" + VALUE "ProductVersion", DOTVERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +<< + +!endif # ifdef RCFILE + +!ifndef DISABLE_IMPLICIT_RULES +DISABLE_IMPLICIT_RULES = 0 +!endif + +!if !$(DISABLE_IMPLICIT_RULES) +# Implicit rule definitions - only for building library objects. For stubs and +# main application, the master makefile should define explicit rules. + +{$(ROOT)}.c{$(TMP_DIR)}.obj:: + $(CCPKGCMD) @<< +$< +<< + +{$(WINDIR)}.c{$(TMP_DIR)}.obj:: + $(CCPKGCMD) @<< +$< +<< + +{$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: + $(CCPKGCMD) @<< +$< +<< + +{$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: + $(CCPKGCMD) @<< +$< +<< + +{$(RCDIR)}.rc{$(TMP_DIR)}.res: + $(RESCMD) $< + +{$(WINDIR)}.rc{$(TMP_DIR)}.res: + $(RESCMD) $< + +{$(TMP_DIR)}.rc{$(TMP_DIR)}.res: + $(RESCMD) $< + +.SUFFIXES: +.SUFFIXES:.c .rc + +!endif + +################################################################ +# 14. Sanity check selected options against Tcl build options +# When building an extension, certain configuration options should +# match the ones used when Tcl was built. Here we check and +# warn on a mismatch. +!if ! $(DOING_TCL) + +!if $(TCLINSTALL) # Building against an installed Tcl +!if exist("$(_TCLDIR)\lib\nmake\tcl.nmake") +TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake" +!endif +!else # ! $(TCLINSTALL) - building against Tcl source +!if exist("$(OUT_DIR)\tcl.nmake") +TCLNMAKECONFIG = "$(OUT_DIR)\tcl.nmake" +!endif +!endif # TCLINSTALL + +!if $(CONFIG_CHECK) +!ifdef TCLNMAKECONFIG +!include $(TCLNMAKECONFIG) + +!if defined(CORE_MACHINE) && "$(CORE_MACHINE)" != "$(MACHINE)" +!error ERROR: Build target ($(MACHINE)) does not match the Tcl library architecture ($(CORE_MACHINE)). +!endif +!if defined(CORE_USE_THREAD_ALLOC) && $(CORE_USE_THREAD_ALLOC) != $(USE_THREAD_ALLOC) +!message WARNING: Value of USE_THREAD_ALLOC ($(USE_THREAD_ALLOC)) does not match its Tcl core value ($(CORE_USE_THREAD_ALLOC)). +!endif +!if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG) +!message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)). +!endif +!endif + +!endif # TCLNMAKECONFIG + +!endif # ! $(DOING_TCL) #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- +!if !$(DOING_TCL) +!message *** Building against Tcl at '$(_TCLDIR)' +!endif +!if !$(DOING_TK) && $(NEED_TK) +!message *** Building against Tk at '$(_TKDIR)' +!endif !message *** Intermediate directory will be '$(TMP_DIR)' !message *** Output directory will be '$(OUT_DIR)' +!message *** Installation, if selected, will be in '$(_INSTALLDIR)' !message *** Suffix for binaries will be '$(SUFX)' -!message *** Optional defines are '$(OPTDEFINES)' -!message *** Compiler version $(VCVER). Target machine is $(MACHINE) -!message *** Host architecture is $(NATIVE_ARCH) -!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)' -!message *** Link options '$(LINKERFLAGS)' +!message *** Compiler version $(VCVER). Target $(MACHINE), host $(NATIVE_ARCH). -!endif +!endif # ifdef _RULES_VC DELETED win/sample.rc Index: win/sample.rc ================================================================== --- win/sample.rc +++ /dev/null @@ -1,38 +0,0 @@ -// sample.rc - Copyright (C) 2006 Pat Thoyts -// -// There is no need to modify this file. -// - -#include - -VS_VERSION_INFO VERSIONINFO - FILEVERSION COMMAVERSION - PRODUCTVERSION COMMAVERSION - FILEFLAGSMASK 0x3fL -#ifdef DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "FileDescription", "Tcl Sample Extension " DOTVERSION "\0" - VALUE "OriginalFilename", "sample" VERSION ".dll\0" - VALUE "CompanyName", "The Tcl Development Community\0" - VALUE "FileVersion", DOTVERSION "\0" - VALUE "LegalCopyright", "Copyright \251 1999 Scriptics Corp.\0" - VALUE "ProductName", "Tcl Sample Extension " DOTVERSION "\0" - VALUE "ProductVersion", DOTVERSION "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END ADDED win/targets.vc Index: win/targets.vc ================================================================== --- /dev/null +++ win/targets.vc @@ -0,0 +1,98 @@ +#------------------------------------------------------------- -*- makefile -*- +# targets.vc -- +# +# Part of the nmake based build system for Tcl and its extensions. +# This file defines some standard targets for the convenience of extensions +# and can be optionally included by the extension makefile. +# See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for docs. + +$(PROJECT): setup pkgindex $(PRJLIB) + +!ifdef PRJ_STUBOBJS +$(PROJECT): $(PRJSTUBLIB) +$(PRJSTUBLIB): $(PRJ_STUBOBJS) + $(LIBCMD) $** + +$(PRJ_STUBOBJS): + $(CCSTUBSCMD) %s +!endif # PRJ_STUBOBJS + +!ifdef PRJ_MANIFEST +$(PROJECT): $(PRJLIB).manifest +$(PRJLIB).manifest: $(PRJ_MANIFEST) + @nmakehlp -s << $** >$@ +@MACHINE@ $(MACHINE:IX86=X86) +<< +!endif + +!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" +$(PRJLIB): $(PRJ_OBJS) $(RESFILE) +!if $(STATIC_BUILD) + $(LIBCMD) $** +!else + $(DLLCMD) $** + $(_VC_MANIFEST_EMBED_DLL) +!endif + -@del $*.exp +!endif + +!if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != "" +$(PRJ_OBJS): $(PRJ_HEADERS) +!endif + +# If parent makefile has defined stub objects, add their installation +# to the default install +!if "$(PRJ_STUBOBJS)" != "" +default-install: default-install-stubs +!endif + +# Unlike the other default targets, these cannot be in rules.vc because +# the executed command depends on existence of macro PRJ_HEADERS_PUBLIC +# that the parent makefile will not define until after including rules-ext.vc +!if "$(PRJ_HEADERS_PUBLIC)" != "" +default-install: default-install-headers +default-install-headers: + @echo Installing headers to '$(INCLUDE_INSTALL_DIR)' + @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)" +!endif + +!if "$(DISABLE_STANDARD_TARGETS)" == "" +DISABLE_STANDARD_TARGETS = 0 +!endif + +!if "$(DISABLE_TARGET_setup)" == "" +DISABLE_TARGET_setup = 0 +!endif +!if "$(DISABLE_TARGET_install)" == "" +DISABLE_TARGET_install = 0 +!endif +!if "$(DISABLE_TARGET_clean)" == "" +DISABLE_TARGET_clean = 0 +!endif +!if "$(DISABLE_TARGET_test)" == "" +DISABLE_TARGET_test = 0 +!endif +!if "$(DISABLE_TARGET_shell)" == "" +DISABLE_TARGET_shell = 0 +!endif + +!if !$(DISABLE_STANDARD_TARGETS) +!if !$(DISABLE_TARGET_setup) +setup: default-setup +!endif +!if !$(DISABLE_TARGET_install) +install: default-install +!endif +!if !$(DISABLE_TARGET_clean) +clean: default-clean +realclean: hose +hose: default-hose +distclean: realclean default-distclean +!endif +!if !$(DISABLE_TARGET_test) +test: default-test +!endif +!if !$(DISABLE_TARGET_shell) +shell: default-shell +!endif +!endif # DISABLE_STANDARD_TARGETS