Purpose: discuss TEA - '''Tcl Extension Architecture''' (the developer's guide for TEA is at http://www.tcl.tk/doc/tea/tea_tcl2k.pdf ) was created in 1999. http://www.tcl.tk/doc/tea/ is the url where various TEA related documents exist. http://www.tcl.tk/doc/tea/windows.html , for instance, discusses TEA on Windows. See ftp://www.tcl.tk/pub/tcl/examples/tea/ for a sample extension that makes use of [TEA2]. However, TEA2 isn't the latest version of TEA - see [TEA3] or even better, the [sample] extension, for examples of TEA in its latest incarnation. Versions for Mac, [Unix], and [Windows] are available. Especially for the former of these, see [Jim Ingham]'s comments in ... ---- Many of the above documents (i) describe version 1 of TEA and (ii) are unfortunately written in a "you don't need to understand this stuff, we'll tell you which lines you need to change" style, that in combination make them rather irrelevant for anyone aiming at the (2005 current) [TEA3] system. More recent documentation can however be found in the sampleextension CVS directory, at http://tcl.cvs.sourceforge.net/tcl/sampleextension/tea/ Could anyone provide a link to a formatted version of these docs (if that exists)? [LV] To which docs do you refer? The documents at the www.tcl.tk directory are all in PDF, which is about as formatted as you can get. ---- [MAK] (9 Nov 2004) '''C++ Extensions with TEA''' I was going to submit this as a patch, but I don't have a complete and necessarily correct solution, it turns out. More on that in a moment. The template files and tests provided by TEA assume C-only extensions. A few quick and simple changes can put you on your way to using TEA for C++ extensions. First, in tcl.m4, find "AC_PROG_CC" in the TEA_SETUP_COMPILER_CC function, and add another line that says "AC_PROG_CXX" and then run autoconf to regenerate configure from configure.in. This adds the necessary tests to determine how to run the C++ compiler, whether it be called "g++" or "CC" or whatever. AC_DEFUN(TEA_SETUP_COMPILER_CC, [ ... AC_PROG_CC AC_PROG_CXX AC_PROG_CPP ... ]) Second, in Makefile.in, find the CC definition and add a CXX definition. The configure script will replace @CXX@ the way it does @CC@ so you can use $(CXX) to refer to the C++ compiler rather than the $(CC) for the C compiler. ... PACKAGE_VERSION = @PACKAGE_VERSION@ CC = @CC@ CXX = @CXX@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ ... Third, find the definition of the variable COMPILE and remove the $(CC) at the start of it: #COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) COMPILE = $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) Fourth, you'll need to add the $(CC) into the .c.o rule, and add a .cpp.o rule to call the appropriate compiler for .cpp files: .c.@OBJEXT@: $(CC) $(COMPILE) -c `@CYGPATH@ $<` -o $@ .cpp.@OBJEXT@: $(CXX) $(COMPILE) -c `@CYGPATH@ $<` -o $@ That's pretty much it, other than wrapping your extension's Init function in extern "C" {...} to prevent mangling so Tcl's load command can find it. (You don't need to wrap other functions, such as command functions, since they're provided to Tcl via pointers rather than Tcl needing to search the symbol table for them.) Now, the problem: later versions of gcc can't link C++ objects because it will try to use the wrong runtime library, and you'll get a number of unknown symbol errors (on new/delete and gxx_personality_v0 etc.) Unfortunately the command used for linking (assigned to the SHLIB_LD variable in the Makefile) either comes from tclConfig.sh, or else is re-determined (either way it looks the same to me), but either way it specifies the plain C compiler as the linker. You can get around the problem by linking to the C++ runtime library, for instance by adding "-lstdc++" to TEA_ADD_LIBS in your configure.in script, but I suspect this is GNU-specific, and thus is probably not a good to codify in the sample extension. The way TEA determines how to link shared libraries could stand a little improvement in this regard. Maybe someone more familiar with autoconf and m4 than I (who's not particularly familiar with either) can take the above information, figure out what to do about SHLIB_LD and make C++ extensions directly supported by TEA. ---- ''[Lars H], 6 Nov 2004: I've been told that TEA is a close relative (further development of?) some [GNU] build system. Could someone provide links to introductory material on that? It is my impression that the TEA docs are written with the assumption that the developer already has some knowledge of some similar system, so maybe there are some non-TEA-specific docs out there that explains the basics...'' [MAK] (9 Nov 2004) Not exactly a relative, but rather TEA uses GNU [autoconf]-generated configure scripts (i.e., rather than a relative, it is based on the GNU build systems). It provides a template configure.in (the input to [autoconf]) and Makefile.in (which the configure script uses to generate Makefile), and and some other support files such as tcl.m4, which defines the Tcl-specific tests done by the configure script. It also defines the common "generic/unix/win/mac" layout you see in extensions. For the most part, unless you need to write additional tests (e.g. determining if certain headers are present, whether or not the platform supports a particular function, etc.) the template files are pretty much "fill in the blanks" (or otherwise "replace the name 'sample' with your extension's name") and you don't have to worry about the nastiness of [m4]. ---- [JH]: [TEA2] (aka TEA2002) is currently in development, and is actually used for many key extensions (i.e., itcl/itk, TclX, tktable, Thread, vu, ...). It is a revamp with a bent towards simplification of the original TEA configuration files, with even more features. This page does not address TEA2, AFAIK. When that changes, remove this line. See also [Converting your Tcl extension to TEA2] . ---- [LV] Does anyone have tips, etc. they would like to add in here about the tools and steps a developer should follow to ensure a Tcl extension follows TEA 2 appropriately? ---- These are the notes I took while trying to use TEA, first on a Windows machine, and later the results of passing the 'TEA' code developed on windows to a Linux developer (and the problems observed there). Feel free to edit! This started life as a text only document so it doesn't yet have any Wiki formatting -- Vince Darley. ''Wiki-formatted by DKF'' ---- TEA: a summary of trying to use it ================================== Introduction: There are various goals to TEA (in no particular order): * a) making it easy for people to write extensions which work on many platforms, * b) making it easy for users to download, compile and install extensions, * c) making it easy to cross-compile extensions, etc. This document describes my attempts to: 1. install TEA (requires cygwin, autoconf, etc.) on Windows 1. compile and use the sample extension (related to (b) above) 1. create my own extension (related to (a) above) on windows. 1. pass my extension to a user on a different platform (linux) and have them compile, install and use it (related to (a) and (b) above). My primary platform (at the moment at least) is Windows, so I am trying to use TEA with the vc++ compiler (not with gcc/mingw/cygwin although that ought to be possible now). For the sake of consistency this document is in more or less chronological order, which means the more interesting issues/questions are towards the end. Any feedback on this much appreciated. I hope it helps others avoid some of the pitfalls I encountered, and any help on some of the questions/issues raised would be much appreciated. '''SECTION ONE: Installing TEA''' Installation is only really an issue for windows users, who are obliged to download the cygwin/autoconf system, which they will otherwise have little use for. First: read the instructions on scriptics web site, and try to follow them: http://www.tcl.tk/doc/tea/windows.html (1.1) I found the I could not ''make install'' autoconf -- it gave some error. This was because I had tried to use it a year ago, and had since changed my cygwin installation. I had to manually delete the file ''config.cache'' (''make clean'' isn't enough), and run through the whole ./configure ; make ; make install again. Then it worked. (Addendum: ''make distclean'' would clean up that file too, so I should've used that). I added the contents of ''vcvars.bat'' to my cygnus.bat startup file to ensure my environment was correctly setup for use of vc++ as a compiler. Installation isn't too complicated, although the default seems to be to create various /tmp, /opt, /lib, /usr, /bin directories all over the place. Now you have the ''bash'' shell which is used for all TEA-based activities. ADDENDUM: The entire cygwin setup/directory-structure etc has completely changed since ajuba's '10 steps to success' was written. It appears to have changed for the better, but still that change makes all the old instructions rather difficult to follow. There are various options for internet vs local installation process etc. Go to [Annotated 10 steps to success with TEA] for some help with that. '''SECTION TWO: Building the sample extension.''' Download the ''sampleextension''. I grabbed this with cvs, to make sure I had the latest. (2.1) ''autoconf'', ''configure'' and ''make'' After ''cd sampleextension ; autoconf ; mkdir win ; cd win'' I tried to ''../configure'' which failed --- the ''tclConfig.sh'' file could not be found. This file doesn't seem to come with the binary distributions of Tcl. So I download the Tcl8.3.1 sources, and did the following ''cd tcl8.3.1/win ; autoconf ; mkdir Release ; cd Release ; ../configure ; make'' and that all worked (phew!). So now I had a directory which contained all the .sh, .lib, .exe's etc. Now go back to ''sampleextension/win'' and try again. ../configure still fails, but if you do ../configure --with-tcl=//d/tcl-source/tcl8.3.1/win/Release/ it worked better, but couldn't find ''tcl.h'' this time. Fortunately the error message was better, so I then did ../configure --with-tcl=//d/tcl-source/tcl8.3.1/win/Release/ --with-tclinclude=//d/tcl-source/tcl8.3.1/generic/ and this completed! The next step is ''make'' which failed, this time with ''unterminated quoted string''. It doesn't like the fact that I used a trailing ''/'' on my directory names above (the forward slash was converted to a microsoft backslash which was followed by a quote...). So, back to configure: ../configure --with-tcl=//d/tcl-source/tcl8.3.1/win/Release --with-tclinclude=//d/tcl-source/tcl8.3.1/generic This works (seemingly the same as before) -- shame the code is fragile in this way. And I try ''make'' again... This time it works, and I appear to have a ''.dll'' present so compilation seems successful. There is even some advice about how to create documentation from xml files! (2.2) ''make install'' The next step is ''make install'' which will of course fail, since I didn't bother to tell configure where I wanted to install things. Let's try anyway. This tried to dump stuff into /usr/local/bin and /usr/local/lib (why do we have idiotic defaults like that on Windows? If it knows I'm using Windows, why can't it at least try C:/Program Files/Tcl/lib etc??). It also failed with on this: Making pkgIndex.tcl in d:/usr/local/lib/exampleA eval pkg_mkIndex exampleA0.2 ../../bin/exampleA02.dll *.tcl couldn't change working directory to "exampleA0.2": no such file or directory while executing "cd $dir" No idea what that's all about, so I ignored it all. Back to configure, this time with a correct prefix/exec-prefix? ../configure --with-tcl=//d/tcl-source/tcl8.3.1/win/Release --with-tclinclude=//d/tcl-source/tcl8.3.1/generic --prefix=//d/progra~1/tcl Now to avoid problems with spaces which I'm sure will arise (yet another reason not to use autoconf/configure/make as a cross platform tool --- what am I supposed to do if windows didn't provide the peculiar conversion of progra~1 into 'program files'?), I use progra~1. I didn't bother to set the ''exec-prefix'', since I assume that just with ''prefix'' set, the installer should know to split the installation into ''lib'' and ''bin'' as appropriate? make install Appears to work... (2.3) ''package require'' So I startup wish, and type ''package require exampleA'' since that seems to be the name of this thing. But no, I discover after reading the pkgIndex file that it is called ''Tclsha1''. What kind of name is that? (I guess, when I read the code it is a package ''sha1'' which makes some sense, except there was a recent thread on comp.lang.tcl suggesting the package names cannot contain numbers, I guess they cannot contain numbers ''in the middle'', perhaps that fragility should be changed!). It seems like a bad idea to have numbers as part of the name (this is version 0.2 of package Tclsha1 ...). Anyway, at least it works: % package require Tclsha1 0.2 The command it creates is ''sha1'': % sha1 wrong # args: should be either: sha1 ?-log2base log2base? -string string or sha1 ?-log2base log2base? ?-copychan chanID? -chan chanID or sha1 -init (returns descriptor) sha1 -update descriptor ?-maxbytes n? ?-copychan chanID? -chan chanID (any number of -update calls, returns number of bytes read) sha1 ?-log2base log2base? -final descriptor The default log2base is 4 (hex) So it has worked! Success! Now I have to get my own extension to compile. '''SECTION THREE: Building your own extension (on Windows)''' Make your directory ''myextension'' and copy all *.in, *.m4 and install-sh from the sampleextension to that directory. Edit the *.in files to fill in your own .c/.h information (the instructions are pretty good in the comments of the files). Place your .c/.h files in that directory. (ADDENDUM: you also need ''mkinstalldirs'' from the sampleextension -- see below). Do ''autoconf''. Hopefully it completes ok. mkdir win ; cd win ../configure --with-tcl=//d/tcl-source/tcl8.3.1/win/Release --with-tclinclude=//d/tcl-source/tcl8.3.1/generic --prefix=//d/progra~1/tcl again hopefully completes ok. Now ''make''. I got an error: make: *** No rule to make target 'tclMatrix.obj', needed by 'Matrix01.dll' This seems surprising. So I go to look at the makefile. It seems I have to manually list the object rules which comprise my shared library. So, back to makefile.in and edit those. Now a quick autoconf, cd win, ../configure ...., and I try to ''make'' again. This time it works, and I appear to have a dll! Jolly good. So I try ''make install'' and it complains it can't find ''mkinstalldirs''. So I copy that over from the sampleextension and try ''make install'' again. It seems to work, although at the end it complains about not finding ../*.n --- not surprising since I don't have any man pages. However what is it doing looking for man pages on Windows?? Very strange. (3.1) ''package require Matrix'' Anyway, it seems to have copied the important stuff over: .dll, creation of pkgIndex.tcl etc, so I startup Wish and try ''package require Matrix''. That fails. So I notice the pkgIndex.tcl file only contains a long comment, no ''package ifneeded ...'' command. Finally I try loading the .dll manually, and there is no _Init proc. It occurs to me that windows requires all that DLL_EXPORT stuff, so I go back to my sources, and add the relevant code (look at exampleA.h, it seems to contain the important stuff). Now I redo ''make, make install'' and I can finally ''package require xxxx'' and it works. Note that the first time that make install seemed to work, but didn't, the pkg_mkIndex step failed to find any packages at all, yet didn't signal any error or warning. That is not very helpful. Presumably any call to pkg_mkIndex which results in a pkgIndex.tcl devoid of anything except comments is an error, and should be signalled as such. '''SECTION FOUR: Passing your extension to another platform (Linux)''' I pass the code on to someone who is pretty experienced with Linux, but not so with Tcl, but TEA is designed to make their life easy... (4.1) basic line-endings problem. Had to convert all \r\n to \n. Eventually found a simple, repeatable solution to this, which would let us pass code back and forth. (4.2) autoconf, configure, make. This all appeared to work ok (provided configure is given the correct locations for tcl) (4.3) ''make install''. Again this appeared to work ok. NOTE: You can make life a bit easier, if you put some files (or symlinks to them) into the right directories (on SuSE linux): /usr/include/tcl.h /usr/include/tk.h /usr/include/tlcXXX.h ... /usr/include/tkXXX.h /usr/lib/libtclstub.NN.a /usr/lib/libtkstub.NN.a HRB. (4.4) ''package require Matrix''. This failed with "can't find package Matrix". It seems as if the pkgIndex.tcl file is again just full of comments. However the problem is far more subtle than simply forgetting the EXPORT stuff (which was the problem with the same symptoms on Windows). The problem turns out to be that pkg_mkIndex is ''sourcing'' the shared library libMatrix0.1.so.1, rather than loading it! This in turn is due to a bug in either the TEA installation on linux, or in the mkIndex.tcl.in installer (or both). The decision to source vs load is made by looking at the file's extension and comparing it with ''info sharedlibextension'', which is .so. However the file's extension is ''.1''. So, we can either fix ''pkg_compareExtension'', or make the installer create a soft link from libMatrix0.1.so.1 to libMatrix0.1.so, or perhaps both. Finally there is one more problem. If the library is installed somewhere which is not on LD_LIBRARY_PATH, the ''load'' also fails, so the installation code needs to do something like: pushd $(libdir) ; \ LD_LIBRARY_PATH=`pwd` ; \ export LD_LIBRARY_PATH ; \ popd \ before executing ''mkIndex.tcl''. With these changes the code finally works and ''package require Matrix'' does indeed work. Looking at other extensions I see nearly all of them actually have their own manually created pkgIndex.tcl which is installed rather than relying on pkg_mkIndex -- probably a good idea seeing as the code is both buggy (source vs load) and provides no useful feedback at all on whether the process was successful or not. '''SECTION FOUR, part 2: Stubifying your extension.''' So your extension has other extensions which rely upon it. You need to create and export your own stub table. I suggest you look at the ''Trf'' and ''Trfcrypt'' extensions for a good example, and for all the necessary stub/.in files from which you can re-use code (with global replacements of Trf by Mypackage etc). Problems observed: (4.2.1) It basically works after several hours work. (4.2.2) Passing the code over to another platform exposed the usual host of problems. You MUST MUST MUST use the ''-direct'' flag when calling pkg_mkIndex on the base shared library (in Tcl 8.3 or newer that is the default, but of course when you pass the code to someone using Tcl 8.2 the base extension will work, but the other one will not). This is my current code (from end of mkIndex.tcl.in): (base extension with stub table 'Matrix'): if {$tcl_platform(platform) == "unix"} { if {[llength $libraryList] > 0} { set libraryPathList {} foreach lib $libraryList { # shared lib extension is usually .so or .sl if {[regexp "^(.*\\[info sharedlibextension])((\\.\[0-9\]+)+)\$" $lib "" baselib]} { exec ln -s $lib $baselib lappend libraryPathList [file join .. $baselib] } else { lappend libraryPathList [file join .. $lib] } } puts "eval pkg_mkIndex -direct -verbose $package$version $libraryPathList *.tcl" eval pkg_mkIndex -direct -verbose $package$version $libraryPathList *.tcl } } else { if {[llength $libraryList] > 0} { set libraryPathList {} foreach lib $libraryList { lappend libraryPathList [file join .. .. bin $lib] } puts "eval pkg_mkIndex -direct -verbose $package$version $libraryPathList *.tcl" eval pkg_mkIndex -direct -verbose $package$version $libraryPathList *.tcl } } (dependent extension wanting to use the Matrix extension): proc pkg_ensurePreloaded {name} { puts "preloading $name package" set result [package require $name] puts "'package require $name' returned $result" # Make sure it was really loaded foreach pkg [info loaded] { if {[lindex $pkg 1] == $name} { puts "package $name loaded as '$pkg'" return } } puts "warning: package $name didn't appear to be loaded correctly" puts "perhaps its pkgIndex was built without the '-direct' flag," puts "in any case any use of 'pkg_mkIndex -load ...' will not" puts "be able to load the '$name' package." } if {[llength $libraryList] > 0} { set libraryPathList {} if {$tcl_platform(platform) == "unix"} { foreach lib $libraryList { # shared lib extension is usually .so or .sl if {[regexp "^(.*\\[info sharedlibextension])((\\.\[0-9\]+)+)\$" $lib "" baselib]} { exec ln -sf $lib $baselib lappend libraryPathList [file join .. $baselib] } else { lappend libraryPathList [file join .. $lib] } } } else { foreach lib $libraryList { lappend libraryPathList [file join .. .. bin $lib] } } # In case we are installing in a non-standard location lappend auto_path [pwd] pkg_ensurePreloaded Matrix puts "eval pkg_mkIndex -direct -verbose -load Matrix $package$version $libraryPathList *.tcl" eval pkg_mkIndex -direct -verbose -load Matrix $package$version $libraryPathList *.tcl } '''SECTION FIVE: Summary of problems with solutions.''' (5.1) If my Extension_Init symbol isn't correctly exported, I get no notification that the ''pkg_mkIndex'' didn't find anything. Usually (since packages usually include a XXX_Init function), this is an error. At the very least ''pkg_mkIndex'' should output the names and versions of the packages it found (something like: Creating pkgIndex file... added package entry for 'Foo 0.1'... added package entry for 'Blah 2.7'). I've submitted a patch to package.tcl to scriptics which adds better output with pkg_mkIndex -verbose : Index: package.tcl =================================================================== RCS file: /cvsroot/tcl/library/package.tcl,v retrieving revision 1.14 diff -c -r1.14 package.tcl *** package.tcl 2000/04/23 03:36:51 1.14 --- package.tcl 2000/05/22 16:42:44 *************** *** 328,336 **** --- 328,344 ---- tclLog "warning: error while $what $file: $msg" } } else { + set what [$c eval set ::tcl::debug] + if {$doVerbose} { + tclLog "successful $what of $file" + } set type [$c eval set ::tcl::type] set cmds [lsort [$c eval array names ::tcl::newCmds]] set pkgs [$c eval set ::tcl::newPkgs] + if {$doVerbose} { + tclLog "commands provided were $cmds" + tclLog "packages provided were $pkgs" + } if {[llength $pkgs] > 1} { tclLog "warning: \"$file\" provides more than one package ($pkgs)" } However, I would suggest going beyond this, to signal a make-time ''error'' if nothing is found in the package to install. After all an installation which provides no packages and no commands is rather useless, so it can be used to signal that something has gone wrong. Perhaps another flag to pkg_mkIndex? (Note that the -lazy flag is not properly documented in the comments or ''usage'' message of pkg_mkIndex). (6.2) Just prior to build the pkgIndex, make install gives the following message: Making pkgIndex.tcl in d:/progra~1/tcl/lib/Matrix This is incorrect. It is in ...../Matrix0.1 It is fixed below cd $libdir puts "Making pkgIndex.tcl in [file join [pwd] $package$version]" if {$tcl_platform(platform) == "unix"} { if {[llength $libraryList] > 0} { set libraryPathList {} foreach lib $libraryList { lappend libraryPathList [file join .. $lib] } puts "eval pkg_mkIndex -verbose $package$version $libraryPathList *.tcl" eval pkg_mkIndex -verbose $package$version $libraryPathList *.tcl } } else { if {[llength $libraryList] > 0} { set libraryPathList {} foreach lib $libraryList { lappend libraryPathList [file join .. .. bin $lib] } puts "eval pkg_mkIndex -verbose $package$version $libraryPathList *.tcl" eval pkg_mkIndex -verbose $package$version $libraryPathList *.tcl } } exit This also adds 'exit', which is required for Tk based extensions, but might as well be there for Tcl based ones too. It also adds the -verbose flag to pkg_mkIndex. (6.3) On Linux I find that shared libraries are created as blah.so.1 which pkg_mkIndex decides to source and hence generates an empty pkgIndex.tcl file. The following fixes that: # package.tcl proc pkg_compareExtension { fileName {ext {}} } { global tcl_platform set ext [info sharedlibextension] if {[string equal $tcl_platform(platform) "windows"]} { return [string equal -nocase [file extension $fileName] $ext] } else { # Some unices add trailing numbers after the .so, so # we could have something like '.so.1.2'. set root $fileName while {1} { set currExt [file extension $root] if {![string length $currExt]} { return 0 } if {[string equal $currExt $ext]} { return 1 } set root [file rootname $root] } } } Alernatively the installer needs to create a link from the .so.1 to .so The following adds such a link. # mkIndex.tcl.in if {$tcl_platform(platform) == "unix"} { if {[llength $libraryList] > 0} { set libraryPathList {} foreach lib $libraryList { if {[regexp {^(.*\.so)((\.[0-9]+)+)$} $lib "" baselib]} { exec ln -s $lib $baselib lappend libraryPathList [file join .. $baselib] } else { lappend libraryPathList [file join .. $lib] } } puts "eval pkg_mkIndex -verbose $package$version $libraryPathList *.tcl" eval pkg_mkIndex -verbose $package$version $libraryPathList *.tcl } } else ... (6.4) There also seem to be some requirements to set LD_LIBRARY_PATH during installation of the extension. Is this true? Almost every extension out there uses its own hand-made pkgIndex.tcl so problems with pkg_mkIndex/load/sharedlibraries are never seen. An install-binaries which looks like this should help: install-binaries: binaries install-lib-binaries install-bin-binaries - $(TCLSH_PROG) mkIndex.tcl $(Matrix_LIB_FILE) if test "x$(SHARED_BUILD)" = "x1"; then \ - $(TCLSH_PROG) mkIndex.tcl $(Matrix_LIB_FILE); \ + case "uname -s" in *win32* | *WIN32* | *CYGWIN_NT* | *CYGWIN_98* | *CYGWIN_95*) \ + ;; \ + *) \ + pushd $(libdir) ; \ + LD_LIBRARY_PATH=`pwd` ; \ + export LD_LIBRARY_PATH ; \ + ln -sf $(Matrix_LIB_FILE) lib$(PACKAGE)$(VERSION).so ; \ + popd \ + ;; \ + esac ; \ + $(TCLSH_PROG) mkIndex.tcl lib$(PACKAGE)$(VERSION).so ; \ fi Will this hard-coding of ''lib'' and ''.so'' work on all Unix platforms? '''SECTION SIX: Other miscellaneous problems/fragilities of TEA, without solutions:''' (6.1) Shouldn't configure/make be able to cope with directories given by the user with trailing backslashes? (6.2) When trying to compile Tk using the TEA makefiles on windows, if I do ''mkdir Release ; cd Release ; ../configure ...'', Tk looks for Tcl by default in ../../tcl8.3/ which isn't very helpful, it needs one more set of ''../''. Also ''tcl8.3'' isn't very helpful either, when the release is 8.3.1, and a ''tcl8.3.1'' directory is what cvs gives me. (6.3) Why is it using /usr/local/ as the default installation location on Windows? Almost all users will install in ''Program Files/Tcl'' on either the C or D drives (possibly with trailing 8.3 or whatever), so why not look there? (6.4) Why does ''make install'' look for *.n files on Windows, and then why does it fail when it can't find any? (6.5) Why do I have to list a separate .c to .o ''myfilename.$(OBJEXT): ...'' in makefile.in for every single source file. Why can't these be generated automatically? (So there's a comment saying this can't be done in a makefile-independent way -- what a feeble system!). (6.6) In the ''checking for tclsh...'' configuration step, one time (with I guess wrong --with-xx arguments), it picked up tclsh.rc instead of tclsh83.exe. Why is it even considering anything which isn't .exe on windows? (6.7) If I edit the Makefile.in and then don't do configure manually, (when I'm in a ''Release'' subdirectory, say), but just type ''make'', then the code tries to rebuild the makefile again (which is good), but it does it wrongly (it cd's up a level, and then things go wrong). (6.8) Why does this seem to be doing the mkIndex thing twice? install-binaries: binaries install-lib-binaries install-bin-binaries $(WISH_PROG) mkIndex.tcl $(Pltk_LIB_FILE) if test "x$(SHARED_BUILD)" = "x1"; then \ $(WISH_PROG) mkIndex.tcl $(Pltk_LIB_FILE); \ fi (6.9) Now that Scriptics is ''Ajuba'', what is going to happen to the ''SC_'' macros? Why are there so many bugs in TEA if Scriptics is really supporting it? '''SECTION SEVEN: Building multiple extensions:''' (7.1) How do I create a set of TEA files to handle a set of multiple extensions/packages? Let's say I have three extensions A, B, C. Extension A is a simple Tcl extension, and TEA works ok (subject to the million problems above). Extension B is a Tcl extension which also requires some code in A. How can I create that? Extension C is a Tk extensions which requires some code in A and B. (This is a real situation for the Plplot graphing library). Do I create one big configure.in/makefile.in (is that possible given the differing requirements of these libraries)? Or do I create 3 different sets of configure/makefile.in? How do I handle the linking issue on Unix? Where is the TEA documentation/examples on this kind of stuff? '''SECTION EIGHT: Conclusions''' The whole process is completely unintuitive to someone not familiar with these kinds of things. Once it works it is quite nice, but there are very large hurdles to be jumped, and the entire system is very fragile. It appears to be a very ''dumb'' system, which is trying to look rather clever. I guess it is basically a very simple text and rule based iterative system, which doesn't really have much embedded knowledge about files/directories, the structure of a tcl distribution or whatever. The fact that it contains numerous bugs/fragilities doesn't really help either. There is, I guess, the possibility of cross-compiling, and that is a pretty good reason for using the system (although, with perhaps one notable exception, one hardly sees a peep on comp.lang.tcl about announcements of binary distributions being available on many platforms through the advances of cross-compilation). Also, if TEA was replaced by something more user-friendly, perhaps people would be willing to compile extensions themselves, and we wouldn't have to worry about cross-compiling anyway. Jeff has raised the idea of getting rid of the tcl/tkConfig.sh files and embedding that information inside the Tcl/Tk binaries. I think that would be a big step forward. Then if Tcl/Tk are correctly installed (and have headers/libs installed as well in default locations), TEA could automatically work out where everything it requires (and if headers or libs are not present it can give a meaningful message). My suggestion would be to have that in Tcl8.4 as soon as possible. Right now the goal of ''configure, make, install'' isn't really possible (at least on windows). Then it might even be possible (for the enterprising ;-[], to have ''package require Blah'' download a .tar.gz, unpack it, configure, make and install, and continue running). I guess this is the ''package acquire'' idea. '''SECTION NINE: meta-questions and conclusions:''' Is TEA a good thing? Does it have the support of the community? Are people using it? My answer is "I'm not sure". I've run into sufficient problems using TEA on ''both'' windows and linux that I can't believe many people are really using it that extensively. In particular, associated pieces like ''pkg_mkIndex'' are hopelessly uninformative and fragile on all platforms, and almost every extension I've seen actually has its own hand-made pkgIndex.tcl which it installs, rather than building one. The TEA mailing list archive is full of debate, the need for better documentation (especially for windows, but from my own investigation it seems just as lacking on unix), etc. However there is very little action. Well, this is my tiny contribution to that ''action'', but frankly TEA needs some proper support and work which simply doesn't appear to be happening. ---- [Sean McKnight] posted the following information on his experiences: I posted a similar question about a month ago and got some pointers to the Minimal GNU Windows 32 environment (i.e. mingw32) from some Tcl programmers. Check out the mingw32 site for some good explanations as to how Windows DLLs work. Essentially, all I wanted to do was to create a DLL out of some basic C code that made some calls to the Tcl/Tk libraries. Note that in the instructions that follow I do not make use of the TEA specification but instead just use a single Makefile. I would have liked to stay with the TEA spec (and may do so eventually) but from my experience I have found that the TEA is somewhat incomplete at this point. I am hoping that will change at some point in future (I wonder if anyone in the Tcl core group would know what the plans for the TEA are at this point?). So here is what eventually worked: 1). I downloaded the "mingw32" enviroment for Windows and installed under WindowsNT 4.0 (also under Windows95). I also downloaded the "impdef" utility, which is used (explained below) to generate an "export list" of functions that can be called directly from the DLL. These can be found on the mingw32 site at http://www.mingw32.org. 2). My Tcl/Tk extension makes use of the Tcl C library. Under Windows, I am required to link with an import library when creating my extension DLL. The import library is created as follows: C:\TCL832\BIN> impdef tcl83.dll > tcl83.def C:\TCL832\BIN> impdef tk83.dll > tk83.def C:\TCL832\BIN> dlltool --dllname tcl83.dll --def tcl83.def \ --output-lib libtcl83.a C:\TCL832\BIN> dlltool --dllname tk83.dll --def tk83.def \ --output-lib libtk83.a 3). An export list for my Tcl extension also had to be created. Normally only the "Init" function from the extension is exported, as it is the entry point for the extension when the extension is loaded into Tcl. All I did to create the export list was echo a couple of lines into a text file: C:\MYEXT> echo EXPORTS > myext.def C:\MYEXT> echo Myext_Init >> myext.def 4). Each C source file in my extension is compiled using the "gcc" compiler from the "mingw32" installation. After all the objects are compiled, the final DLL is constructed. A snippet of the makefile is presented below: CC = gcc OBJS = myext1.o myext2.o myext3.o DLLTOOL = dlltool TCLLIBS = c:/tcl832/lib/libtcl83.a c:/tcl832/lib/libtk83.a RM = del dll: $(OBJS) $(CC) -mdll -o junk.tmp -Wl,--base-file,base.tmp $(OBJS) $(TCLLIBS) $(RM) junk.tmp $(DLLTOOL) --dllname myext.dll --base-file base.tmp --output-exp temp.exp --def myext.def $(RM) base.tmp $(CC) -mdll -o myext.dll $(OBJS) $(TCLLIBS) -Wl,temp.exp $(RM) temp.exp It seems to work, both under NT and 95 (at least for the extension that was tested, which is pretty basic). The main challenge is understanding the requirements for constructing a DLL. Check the "[mingw32]" site documentation for the dirty details. Sean ---- See also [Annotated 10 steps to success with TEA] ---- [tclguy] writes that, "If you have a TEA-based Makefile, with all the latest targets up-to-date, then [[to launch [gdb] usefully]] you should only need to do 'make gdb'. This will launch tclsh into gdb with the right environment that should allow you to say 'package require Receive' and get your debugging version." ---- [MSW] says: TEA doesn't pay attention to ''prefix''. If you specify "--prefix=something" TEA still insists on "exec-prefix" being the directory where tcl was found. '''THIS SUCKS'''. As a simple example, ''configure'' anything with a ''--prefix'' of ''something'', it'll try to install into ''/usr/local/tcl/'' or wherever tcl is found. Have you people not ever tried installing something as non-root???? TEA-based Makefiles thus mean breaking any locality of installed extensions. Welcome to the great wonderful world of tomorrow. '''[DGP]''' So, the complaint is that ''--prefix='' and ''--exec-prefix='' options must both be provided? It's a sensible complaint. Register it as either a bug or feature request. [LV] I've found that, at least at times, the sample, tcl, and tk distributed packages do the prefix/exec_prefix correctly. The way these are supposed to work are that man pages, tcl scripts, script demos, etc. go under prefix while binary libraries and binary .exe (a.out) commands would be installed under exec_prefix. AND, when configure goes looking for things, it should use exec_prefix and prefix as the first locations to look for the various things it needs. Not every use of TEA gets these things right, it seems. Another tip - if you hard code path names (with versions in them ) into configure, make certain these are updated each time a new version of tcl comes out. ---- [Category Acronym] - [Category Package] - [Category Porting]