Hosted by |
|
Overview and Requirements
Introduction Downloading from the Internet, configuring, building, and incorporating any more than one extension into any given environment, is a major challenge. Tcl extensions are each different in their own regard, no doubt, and at a minimum they each extend the functionality to the core Tcl language and services. But the configuration properties of each Tcl extension are these days disparate enough that it takes many hours, if not days, to build a complete extended Tcl subsystem that actually works. Attempt this cycle later when Tcl and associated extensions have been upgraded, and your asking for very much the same challenges all over again. The purpose of this document is to identify the myriad of issues that Tcl users, Tcl extension writers, and Tcl integrators, encounter when using, developing and releasing, and incorporating (respectively) Tcl and Tcl extensions. Ultimately the goal of the Tcl developers and Tcl extension developers should be to make Tcl much simpler for their end userswhich quite often are mutual Tcl developers themselves. The time is right for restructuring of the Tcl extension architecture. Given the fact that, for the first time in the development history of Tcl, there will be simultaneous development tracks for multiple versions of Tcl8.0 and 8.1there is even more a requirement for such an extension architecture. Classes of Tcl Users and Issues They Encounter To better understand the issues associated with Tcl and Tcl extensions, we can look at the various groups of users who deal with Tcl and Tcl extensions on a regular basis. We look at the Tcl end user, the Tcl extension writers, integrators of Tcl into value added products, and packagers of Tcl into larger systems. We shall see that while there are unique some unique problems and issues to each group, there are also many other classes of problems that span these groups as well. Tcl and Tcl Extension End Users Simply stated, end users of Tcl and Tcl extensions are our customers. Such end users have varying level of sophistication and expertise and thus what is an issue or problem associated with Tcl and extensions for one user may not be an issue or problem for another end user. In addition some end users may themselves be developers who understand how to build and manage Tcl and extension sources, while others may simply want to use Tcl immediately after downloading and installing. Recognizing the issues and problems encountered by our customers will help us better architect a new strategy for deliver Tcl and Tcl extensions. In general Tcl end users find it difficult to download and install an extension into an existing Tcl installation. The simple process of download, install, and run, of Tcl extensions simply does not exist. Quite often extensions are delivered in the form of sources and most Tcl users don't want to have to build (e.g., type a variation of configure and make) an extension to use it. Requiring them to do so implies the user to have a C compiler environment and possibly knowledge of how their installed Tcl environment was previously built. Installations of Tcl and Tcl extensions are difficult to manage. During the compile stage Tcl and Tcl extensions incorporate a path describing the location of their respective script libraries. Environment variables equivalent to TCL_LIBRARY need to be used to override this compiledin value. Furthermore, network installations of Tcl are hard to manage in a site where. the value of exec-prefix (and prefix) may be different when building an extension to where an extension is actually installed. For example, it is not uncommon for users to have to configure and build Tcl and Tcl extensions with a interim value for exec-prefix set to /home/joe/tcl/solaris-sparc/bin, and install Tcl using exec-prefix set to /usr/local/bin. Upgrading Tcl and extensions is problematic. When upgrading a Tcl installation, Tcl extension may need to be upgraded as well. Or it might be the case that in order to upgrade a Tcl extension, the Tcl core needs to be upgraded. Users with stable environments are unwilling to take such drastic steps. Ultimately the whole upgrading issues becomes chaotic if one extension or another have not yet released a version of their extension to match a new version of Tcl, leaving the user with the dilemma of least common denominator environment. A Tcl installation tree does not support building against multiply installed Tcl version. Binary files (Tcl shells, shared libraries, static archives) are versioned, but the include directory does not support multiple versions of the Tcl header file; the same is true for the tclConfig.sh file which only represents a single configuration. In both cases, only the most recent installation instance of Tcl is represented by these files. For users who use Tcl as a development platform and want to compile against header files in the include directory and link against those libraries in the lib directory, this poses a problem when different versions of these files are required. The fact that Tcl and Tcl extensions use varying form of documentation makes Tcl harder to learn and use. Users require nroff for UNIX, WinHelp for Windows, and perhaps HTML for Mac. While some tools exist in the Tcl core to go from UNIX nroff to the latter, extensions authors do not employ them and often have their own formats for UNIX manual pages or HTML documentation. Documentation includes demonstration or example programs as well; some extensions are really good at providing complete applications that show off their feature set, but others are either sloppy, incomplete, or completely without them. Finally, Tcl users do not have a single one-stop resource for locating prebuilt Tcl extensions. Scriptics does provide the Tcl Resource Center as a repository for extensions and uploading new extensions to this location is fairly easy. But extensions come in various shapes and sizessome are Tcl only extensions, but most these days are written in C and require that they be downloaded and built. Overall, the Tcl community needs a better way to distribute Tcl extensions in the form of easily installable entities that just work out of the box. Let us next turn our attention to Tcl extension authors. Over time experienced extension writers have developed special skills to design, implement, and distribute their respective extensions. While this continues to work for the experienced elite of extension authors, there exists a steep learning curve for new extension authors wanting to write their own extensions or ones they wish to distribute. There is no basis or template new extension authors can use to begin their work and reduce this learning curve. Cross platform issues are plentiful and mastering them all takes significant effort. Finally writing documentation for an extensioneven ones that have been around a long timeis challenging when having to fulfill many different documentation formats: UNIX nroff manual pages, WinHelp, and HTML. Upgrading to new versions of Tcl is painful. For an extension author to upgrade their work to newer versions of Tcl, this sometimes involves modifying their code to changes or additions to Tcl internal APIs and sometimes even Tcl public APIs. Tcl public and internal APIs change too often and API signatures that change over time cause extensions relying upon them to be brittle. While extensions should not use Tcl internal APIs it is sometimes inevitable for those extension that greatly depend on internal structures (for example, CTRL+C support in TclX) and ultimately find themselves being compatible with only the version they were built against. Programming languages other than C, such as C++ and Java, need better support. Extension development traditionally began in C, because the Tcl core was developed in C. C++ is now very popular for building Tcl extensions, particularly on platforms where it is the language of choice for nonTcl development (e.g., MFC on Windows). As such, Tcl and Tcl extensions need to deal with this issue head on. For example, there is little in the way of examples on how to develop a Tcl extension in C++ and over time most users discovered and dealt with issues such as static class methods and name mangling on their own. But because there is no template example, these types of issues are not widely known. The Tcl header files are guilty of using C++ keyword (e.g., string if STL is used) sometimes requiring users to edit these headers when using a compiler that can't deal with this. Java also poses interesting opportunities for extension developers. While TclBlend, exists there is little in the way of support for its facilities in the core. Tcl users and extension developers must rely upon an older version of the Tcl core in order to create Java based extensions. There are few Tclscript only Tcl extensions. Such extensions are easier to write, distribute, and maintain. But there is little support in the Tcl core for aiding in this endeavor. The tclIndex and pkgIndex.tcl mechanisms often conflict with each other creating brittle runtime environments. Tools for building indexes for Tclscript only extensions exist (e.g., pkg_mkIndex), but they have not proven to work (until maybe recently) and Tcl users are left to create pkgIndex.tcl files by hand. As such, extensions such as TclX have their own command indexing schemes that are very different than those built into the core either because of history or resistance to move to something standard. Finally, while namespaces do exist, there is still a potential for name collision; there is no central repository for registering namespace names for publicly distributed extensions. Finally, assuming a Tcl extension author has successfully written an extension, there comes a point when it's time to release the product. Unfortunately there is no standard packaging utility to easily distribute extensions other than in source form. In addition the expectation of endusers vary from platform to platform: UNIX users are accustomed to receiving source distributions; Windows and Mac users are more likely to accept native installation applications. Some other issues related to installation of an extension (but not limited to) include ensuring that the target Tcl installation hierarchy is version compatible, copying all required to the correct places in the Tcl installation hierarchy, etc. Tcl Extension Integrators We refer to integrators as people who want to integrate Tcl and/or Tcl extensions into as part of a larger product. We may also classify integrators as advanced Tcl users, so therefore man of the same issue described in sections 1.1.1 and 1.1.2 may equally apply to these folks as well. Integration may take the form of, but not limited to:
An example of one such integrator is Ajuba Solutions' development team that has built TclPro utilizing Tcl and Tcl extensions in the ways described above. Extensions don't inherit information from the configuration process of Tcl via tclConfig.sh on UNIX or makefile.vc on Windows. Compiler switches configured by Tcl on UNIX are lost. Extensions are not built with the same configuration as the Tcl core. An integrated product needs to have a consistent build configuration and extensions that have poor configuration schemes create unreliable runtime environments. Building static Tcl and static Tcl extension variants is difficult. It is interesting to not that several years ago, Tcl and Tcl extensions were all statically linked together. Extending a Tcl shell simply meant adding the extension's Init routine to your Tcl_AppInit(..) and augmented the link line for your Tcl shell to include the new extension. With the introduction of the load command and the package mechanism, support for building completely static Tcl shells with extensions almost is nonexistenteven in the Tcl core. Issues include those related to makefiles, the right way to initialize an extension (especially when taking subinterpretters into consideration), and priming the package mechanism for a static package. During development of large complex projects, building a debug only environment of the Tcl core and Tcl extensions is often required but hard to do. In general, during development, if Tcl is built for debugging, it is probably desirable to have the remaining Tcl extensions also built for debugging. In fact on Windows, it is unfortunate, but you cannot have a mixed environment of debug and nondebug modulesit's debug or all nondebug. Extensions provide little or no support for adding the necessary compiler flags for debugging and do not link with the correct Tcl libraries (dynamic or otherwise) to create a well behaved development environment. Building an integrated product of Tcl, Tcl extensions, and value add tools is a major task. Most end users build Tcl and Tcl extensions probably only as often as required to keep up with new versions or site configuration changes. Integrators on the other hand, need to build many variants of Tcl and extensions (dynamic, static, debug, nondebug, etc.) on a regular basis. Automation of building such a product is extremely importantespecially towards the release phase of a project. Lastly, as stated earlier, upgrading of extensions, C++ and Java issues, disparate extension documentation formats, and the bevy of other issues that affect Tcl extension writers and end users of Tcl also relate to the Tcl integrator. For the integratordeveloper these problems compound themselves and directly effect project schedules and product development. Tcl Packagers We refer to packagers as people or organizations that include Tcl and Tcl extensions as part of their complete product offering. Packagers are different from integrators in that they are not trying to add value to Tcl or Tcl extensions. They may not even be supporting Tcl, but simply packaging it in. Examples of packagers include Red Hat Linux who package Tcl and Tcl extensions into Red Hat Linux in the form of RPMs. For this class of user, it must be easy for a third party (the "packager") to download a source distribution, build it on a particular platform, and create a built distribution for that platform which can then be trivially used by less sophisticated users of that platform. Similar to integrators, reproducibility and reliability of source distributions of Tcl and extensions is very important. Requirements >From the discussions of problems and issues faced by the various classes of Tcl users, we can group requirements for the Tcl Extension Architecture into a few categories: build configuration, documentation, testing, distribution and installation. For each of these areas we will specify a set of requirements that will comprise the Tcl Extension Architecture. Each of these areas and their requirements are given below. Further in this document we will propose some solutions and changes to the Tcl core and Tcl extensions to satisfy these requirements. Tcl and Tcl Extension Build Configuration
Tcl and Tcl Extension Documentation
Tcl and Tcl Extension Testing
Distribution and Installation of Tcl Extensions
Tcl Extension Configuration The requirements set forth for configuration of Tcl and Tcl extensions are geared mainly toward development issues. Many are based on the collective experience of groups of individuals alike: Tcl end users, Tcl developers, and Tcl extension developers. Some issues are platform specific, others are general subtle issues relating to dynamic linking, static linking, multiple versions of Tcl, etc. Some Platform Specific Issues The purpose of this section is to briefly mention some platform specific issues and also about. Presented below are issues regarding the various ways Tcl and Tcl extensions are configured and built today on both UNIX and Windows. Some these issues are particularly problematic for most all of the class of users discussed earlier in this document. As we think about the Tcl Extension Architecture, we should be factoring these issues into our solution. Configuring and Building for UNIX Because Tcl and Tcl extensions are traditionally developed on UNIX and given the fact that UNIX tools are fairly robust and powerful, building a Tcl subsystem is fairly well understood among the masses. The Tcl configure mechanism alone is fairly good about determining individual UNIX operating system/host/compiler flags on its own. Other issues include library switches to compiler drivers and linkers. Over time, however, extensions have developed their own personalities and ways of configuring and building. It is sometimes possible for a Tcl extension to be built incorrectly because it did not inherit some special compiler switches determined during the configure step of Tcl. We recently saw this at Scriptics when we built TclX and Expect for Irix; both extensions had missed the n32 flag required by the SGI compiler. One solution for this is for extensions to rely entirely upon the tclConfig.sh shell script generated during the configure step of Tcl itself. This script should be the central repository for as many compiler and linker flags as possible. Tcl extensions should augment the compiler and linker lines only those flags they need that do not already exist. Configuring and Building for Windows Sad but true, it is often the case that Windows follows an implementation of an extension on UNIXor not in the case of Expect. As UNIX is generally the reference platform for most extension developers, Windows versions of extensions often follow long after the original UNIX implementation; with such work often performed by someone other than the original extension author. A few reasons why certain extensions have this characteristic are:
The latter of these factors should not be an impediment for other developers to take the extension and make it available on the Windows host. However, there is little in the way of support in the core of Tcl for moving an extension to Windowsassuming the functionality is technically feasible. The lack of a mechanism similar to the UNIX configure/make can and is definitely an impediment. Our Tcl extension distribution and installation strategy should address deploying extensions on Windows head on! As Tcl continues to become popular on the Windows, this pattern will reverse and we will begin to see extensions that originate on the Windows platform. APIs for such things as ActiveX, COM, and MAPI are likely candidates for extensions originating on Windows. In addition there are subtle differences in the way dynamic libraries and debug libraries are built on Windows (see 3.1.3 Building Dynamically Linked Tcl Extensions and 3.1.5 Building Debug vs. Nondebug Extension Libraries). As well, static Tcl shells that have extensions statically linked have a different set of issues than the dynamic case (see 3.1.4 Building Statically Linked Tcl Shells "Big" Tcl Shells). It is also safe to say that generally there is only one compiler in use today, Microsoft Visual C++. Most of the Tcl extension architecture will be centered around this compiler platform. There is the GNU C compiler available based on the CYGWIN library. Support for Tcl in a CYGWIN environment is derived from the UNIX configure/make mechanism and any extension architecture implementation that is made will be readily inherited. While CYGWIN may be used in a development environment where UNIX and Windows are mixed, it is not common where Microsoft Visual C++ is the predominant Windows development environment. Most certainly it is not used as a delivery vehicle for Windows applications to end users. Building Dynamically Linked Tcl Extensions In general Tcl and Tcl extensions are built dynamically. This reduces codebloat and makes it easier to maintain and manage installations of Tcl and Tcl extensions. In any single Tcl subsystem environment, either everything is built dynamically or everything is built statically. (The issues associated with building Tcl and Tcl extensions statically, usually uncommon, is discussed in 3.1.4 Building Statically Linked Tcl Shells "Big" Tcl Shells.) Rare is the case that environments are mixed between dynamic and static and is in fact problematic on UNIX and downright impossible on Windows. Closely related to dynamically built Tcl extensions is the topic of the workinprogress of the new stubs library discussed in 3.2 The Stub Library. This work will enable the need to not to have to link directly to Tcl shared library on UNIX or to a Tcl DLL export library on Windows. With the proposal described in 3.1.1 to do away with --enable-shared and --enable-symbols building dynamic --> --link libraries of either Tcl or Tcl extensions is now fairly --> --straight forward. As long as care is taken to ensure that everything in a Tcl subsystem is built dynamically then everything should just work. In other words the Visual C++ compiler switches /MD needs to be used when build code for linking and /MDd when code for dynamic linking in a debug environment. Building Statically Linked Tcl Shells "Big" Tcl Shells A framework for building a statically linked Tcl shell consisting of any combination of Tcl extensions. is currently missing The framework should require very little from the user which may include adding code to their Tcl_AppInit( ) as described in below, but easily add the necessary static archive entries for a respective extension to a Makefile. It turns out that the Tcl_AppInit procedure for a statically built Tcl shell that contains any number extensions is fairly simple to create. Generally all that is required are Tcl_StaticPackage( ) statements for each extension that is statically linked into the Tcl shell. Providing the value of NULL for the pointer to the interpreter to Tcl_StaticPackage( ) arranges for the statically linked packaged to be loaded whenever package require is used for that extensioneven for a subinterp. For each extension that is statically linked into a Tcl shell, the equivalent of a package ifneeded statement is required; the associated is script performs a load {} which effectively synthesizes the loading of the statically linked extension and ultimately calls its _Init routine. Such a file should exist in a place where the statically linked shell can access it when needed. Unfortunately the location of this file needs to be in a place that can be seen by the static package mechanism and not conflict with the dynamic package mechanism. Alternatively, the call to Tcl_StaticPackage( ) for each statically linked extension needs to handle the synthesis of this package ifneeded process. Such functionality does not currently exist in Tcl_StaticPackage( ) today and will need to be made if statically linked packages are to work seamlessly. Building Debug vs. Nondebug Extension Libraries Similar to dynamic and static builds, generally if a Tcl shell is built for debugging, it is likely that other extensions want to be built for debugging as well. Tcl and Tk 8.0.3 added a special tag to the target binaries to denote that they contain debug information. The target names includes the "g" character on UNIX and "d" character on Windows. So for example, libtcl80g.a contains debugging symbols of Tcl. A new variable in the tclConfig.sh, TCL_DBGX, now exists and will contain the value "g" if Tcl is built with --enable-symbols. Currently UNIX configure scripts for --> --Tcl and Tk appy the tag of "g" to dynamic shared objects and static --> --archives that are built with --enable-symbols. The proposal --> --to do away with the enable-* switches wont change --> --this, but when make is invoked with the DEBUG macro --> --set to 0 (or 1), the associated targets will need to deal without --> --applying the TCL_DBGX macro to generated libraries (or --> --apply). On Windows, it is a foregone conclusion that s system of modules cannot be built with mixed debug and nondebug. This is because any module built for debug (or non-debug) must link with the Microsoft C runtime library built for debug, MSVCRTD.LIB (or nondebug, MSVCRT.LIB). A system of modules loaded at runtime in this manner, result in having multiple instances of the C runtime librarywhich include multiple instances of the memory heap and other C runtime global variables such as errno.. Similarly a static library built for debug (or nondebugging) must link with the static Microsoft C runtime library built for debug LIBCD.LIB (or nondebug, LIBC.LIB). Requirements
Description The Tcl stubs mechanism defines a way to dynamically bind extensions to a particular Tcl implementation at run time. This is accomplished by exporting function tables that define a particular interface. All access to the interface in question is done through offsets into the function table so there are no direct references to any of the library's symbols. Using the Stub Library In order to use the stubs interface to Tcl or Tk, an extension must do the following:
This will initialize the Tcl function vector and set up macros so that every call ends up going through this table. The resulting library will have no linker dependencies on the Tcl library. Everything is resolved at initialization time when Tcl_Required() is called. Defining a New Stub Library Extensions that want to define a stub interface of their own need to do the following:
Tcl Extension Versioning Issues With the introduction of the stubs library (3.2 The Stub Library) it should now be possible for extensions to distance themselves from keeping in sync with Tcl versions as they are released. Now that it is possible for extensions to query the Tcl core for its version, extensions can be written to be backward compatible through API interfaces provided via the stubs library. In particular version numbers need to be isolated from versions of Tcl. For example, TclX now need to have a version number consistent with that of Tcl (Tcl 8.0.5, Tclx8.0.5). Simplifying tclConfig.sh It has also been suggested that the tclConfig.sh file has outgrown its purpose in life, containing too many variables and indirections making it harder to use over time. A long term alternative to the tclConfig.sh file is for Tcl to be able to report at runtime, the way in which it was built. Such a report may include the Tcl version, the compiler switches, the linker switches, whether it is built dynamically or statically, whether it is built with debugging symbols or not, etc.. Extensions that are to be built against and work against a particular instance of Tcl can interrogate the Tcl runtime for all salient information required to build itself. Proposal to Do Away with the enableshared and enable-symbols Flags of Tcls UNIX configure: To achieve the uniformity discussed above, we propose to remove the flags --enable-shared, --enable-symbols, --> ----disable-shared from Tcl's UNIX configure script. This --> --will basically push the decision of building either dynamic or --> --static and either debug or non-debug down into the Makefile. --> --Once we do this, the tclConfig.sh file will contain all the --> --necessary variables to build either static, dynamic, debug, or --> --non-debug. In other words tclConfig.sh will contain the --> --union of all variables that would individually be generated today if --> --you use the associated enable-? flag. As part of this change, we propose that each variant is built to a separate target directory. So dynamic build would go to a directory named dynamic, dynamic/debug will go to a directory named dynamic-debug, etc. The result of this change finally is that on UNIX you configure once and from one generated Makefile build any combination of either static or dynamic and either debug or non-debug. It does, however, have the added disadvantage that the Makefile is a bit more complicated and must include implementations of targets that conditionally test for values of macros selected by the user on which variant to build (see 3.4.7 Makefile Targets for both UNIX and Windows). File Layout of Installed Tcl Currently the installed Tcl tree includes the binaries (executables, shared libraries, and static archives), script libraries, header files, and some configuration files (on UNIX, tclConfig.sh). Except for the files in the include directory and the case of the tclConfig.sh (on UNX), multiple versions of all other files (binaries and script libraries) can live heterogeneously. This is because the naming of these files include the version number from which the particular file was generated (binary) or contributed from (script libraries). So therefore users who build extensions against a Tcl installation tree have access to only the version of the headers and tclConfig.sh that were installed most recently. In other words, even though the installation tree may contain multiple versions of the Tcl runtime, there is effectively only one version of Tcl files used for building against. Even though this may be problematic, we propose not to change this structure at this time. In general if an extension is to be built from an installed version of Tcl, it is likely that the version of the header file in the include directory will more than likely suffice. If you consider that installing into a Tcl installation tree is chronologically oriented (maybe), then a user is likely to find the most recent version of the Tcl header files in the include directory. Regarding the tclConfig.sh file, the proposal to make this file configuration inspecific (do away with enablesymbols and enableshared) also will likely represent configuration information of the most recent installed version of Tcl. So, as it is today, if a user wants to build an extension against an alternate version of headers and configuration files than those in the installed Tcl tree, they will have to resort to a source distribution of Tcl. configure Flags, tclConfig.sh Variabls, and Configure switches and .Makefile targets today are disparate in nature and it is difficult, if not annoying, to have to figure out and deal with these disparities. For example, Tk uses the switch --with-tcl; while Expect provides the same --> --functionality with the flag --with-tclconfig. An ideal goal is being able to reproduce the download, configure, and build cycle on a regular basis for Tcl and all other extensions. For example, given that Scriptics currently hosts the CVS repositories for Tcl, Tk, TclX, Expect, and [incr Tcl], we should be able to synthesize the download via CVS checkouts, configure, and build all extensions in various configurations on a regular basis. Given the new proposal to do away with the enable-* flags, we summarize below the list of configure flags extended by Tcl, variables generated in tclConfig.sh, and Makefile targets uniform across UNIX and Windws. configure Flag Flags to configure remain as before but are fewer with the proposal to remove --enable-shared and --> ----enable-symbols.
tclConfig.sh VariablesFlags that exist today to represent a singular build of either dynamic or static, will need to be duplicated for both dynamic and static. To represent the complete set of configurations (dynamic, dynamic/debug, static, and static/debug), not many variables need to change. In fact most every flag required for multiple configurations currently exists. There are some variables such as TCL_LIB_FILE, that need to be replicated. The complete set of tclConfig.sh flags include:
Where before a singular makefile only built either static or dynamic will now need to build both. This implies almost twice the number of targets. UNIX only built the variant configured during the configure process using (or not using) the --enable-shared and --enable-symbols flags. On Windows, --> --only shared (dynamic) versions of the Tcl libraries were built so it --> --was only possible to build dynamic extensions. Building for either dynamic or static will be selected based on a macro at the top of the Makefile, DYNAMIC. DYNAMIC will take the default of 1 and can either be changed in the file or on the command line. Other Makefile variables below this macro definition will conditionally switch their contents based on the boolean value of based on the boolean value of DYNAMIC. Building for either debug or non-debug will be selected based on a macro at the top of the Makefile, DEBUG. DEBUG will take the default of 0 and can either be changed in the file or on the command line. Variables below this macro definition that need to conditionally switch their contents based on the boolean value of DEBUG and do not include the flags for non-debugging (if DEBUG set to 0, such as "" for CFLAGS) or debugging if DEBUG set to 1, such as "-g" for CFLAGS). The actual implementation of switching compiler and linker flags based on the boolean values will vary between UNIX and Windows, because simple make on UNIX (not GNU make) does not support conditional testing as nmake on Windows does. The minimum set of targets a Tcl extension should support are:
An example of the implementation of the all target is: all: @if test "$(DYNAMIC)" = "1" -a "$(DEBUG)" = "0"; then OBJDIR=$(DYNAMIC_OBJDIR); TCL_LIB_FILE=$(TCL_DYNAMIC_LIB_FILE); CC_SWITCHES='-o $$@ $(CC_DYNAMIC_SWITCHES)'; else if test "$(DYNAMIC)" = "1" -a "$(DEBUG)" = "1"; then OBJDIR=$(DYNAMIC_DEBUG_OBJDIR); TCL_LIB_FILE=$(TCL_DYNAMIC_DEBUG_LIB_FILE); CC_SWITCHES='-o $$@ $(CC_DYNAMIC_DEBUG_SWITCHES)'; else if test "$(DYNAMIC)" = "0" -a "$(DEBUG)" = "0"; then OBJDIR=$(STATIC_OBJDIR); TCL_LIB_FILE=$(TCL_STATIC_LIB_FILE); CC_SWITCHES='-o $$@ $(CC_STATIC_SWITCHES)'; else if test "$(DYNAMIC)" = "0" -a "$(DEBUG)" = "1"; then OBJDIR=$(STATIC_DEBUG_OBJDIR); TCL_LIB_FILE=$(TCL_STATIC_DEBUG_LIB_FILE); CC_SWITCHES='-o $$@ $(CC_STATIC_DEBUG_SWITCHES)'; else echo "Error: Must specify values of DYNAMIC and DEBUG!"; exit; fi; fi; fi; fi; if test ! -d $$OBJDIR; then mkdir $$OBJDIR; fi; TCLSH=$$OBJDIR/tclsh; $(MAKE) $(MAKEFLAGS) OBJDIR=$$OBJDIR TCL_LIB_FILE=$$TCL_LIB_FILE CC_SWITCHES="$$CC_SWITCHES" TCLSH=$$OBJDIR/tclsh $$TCL_LIB_FILE $$TCL_STUB_LIB_FILE $$TCLSH Tclscript Only Extensions Tclscript only extensions are easier to write and deploy because they require no C code and thus no configuration and compiler to build them. But the package mechanism for such extensions is currently broken or weak in some regards. As part of the Tcl Extension Architecture we should address any and all issues with this mechanism and even consider revamping it if necessary. An issue for Tclscript only extensions is how do you define a package that spans multiple files? The problem is that the namespace command may be in one file but the other file (which relies on state in the namespace eval) gets called first. The result can cause Tcl errors that are hard to track down. A solution to this issue is to use the -direct fag of pkg_mkInd. Doing so will arrange for the entire package to be loaded immediately upon package require instead of delaying loading until actual use of one of the commands. Proposal to fix pkg_mkIndex: In the short term, we propose here to change the pkg_mkIndex command to make the direct flag the default. Doing this will have the unfortunate performance sideaffect that all files of a package will be sourced before any routine in the package is used. We also propose to add the flag indirect to the pkg_mkIndex command. A Tclscript only developer who is concerned about performance can use this flag and can arrange for the core file containing the namespace eval and the remaining package source files to all be sourced when any method of a namespace is invoked. Some questions raised by Jeffrey Hobbs (but not necessarily restricted to Tcl only extensions):
Environment Variables and Windows Registry Entries Moving forward, Scriptics proposes to deprecate the environment variables, TCL_LIBRARY and TK_LIBRARY, etc. for Tcl installations. These environment variables may be necessary for development where intermediate Tcl shells are not installed and need to be told where the Tcl script library is. This basically involves removing references to these environment variables from documentation where an enduser may not see this information. Similarly, on Windows, we should deprecate the registry entry for tcl_PkgPath. These environment variables have in the past been problematic and prone to error. An issue, however, with attempting to remove them is the fact that the Tcl test suite requires these environment variables today to specify the location of the Tcl script library; because the directory from which the binary resides may not be anywhere relative to the location of the Tcl script library search mechanism. More extensions should begin to support searching for their script library relative to the installed Tcl library; i.e., relative to the value of the tcl_library Tcl variable. Doing so will ensure that all extensions are installed in a clean and consistent environment. If however an extensions script library is not installed relative to the Tcl library, then the value of the extension library variable, for example tclx_library, should be used. A user, or script, could set tclx_library to the correct location of the TclX script library and then proceed to package require Tclx. To assist in located an extensions script library, extension initialization routines should use the new Tcl library routine tcl_findLibrary located in Tcls init.tcl file to locate their library initialization script file. Documentation Strategy For many of the reasons outlined in 1.1.1 Tcl and Tcl Extension End Users and 1.1.2 Tcl Extension Authors, there is a definite need for a unified documentation strategy for the Tcl core and Tcl extensions. Currently there are too many maintenance issues associated with UNIX nroff manual pages and the tools associated with creating the associated WinHelp and HTML equivalents. It is our goal at Scriptics to one day create a unified documentation strategy for at least Tcl and Tk and suggest that extensions employ it as well. XML has been proposed as the source form for such a strategy. Moving to an XML will allow Tcl to easily generate UNIX nroff, HTML, and Windows RTF help formats. Adoption of XML cannot happen overnight, however. But to reach this goal it is probably best for the Tcl core developers and Tcl extension developers to agree upon a standardized DTD, that defines the structure of the source XML, in the short term, while planning the work for actually moving existing nroff based documentation to XML. Richard Hipp has put together the beginnings of XML based Tcl documentation. Fore more information see http://www.hwaci.com/sw/tcldoc/. A preliminary DTD has been written by Joe English and is available at: http://www.egroups.com/list/tcl-xmldoc/ and is included below for reference: <!-- $Id: TEAOverview.tml,v 1.1.1.1 2001/04/24 13:35:04 andreask Exp $
Author: Joe English, < [email protected] > Created: 8 Feb 1999
XML DTD for TMML, version 0.2.
Notes: Some elements have a #FIXED attribute named NOTATION. This is a temporary place-holder to indicate that they have a special semantic interpretation (for example, cross-references). In the future these will be replaced with a general-purpose architecture that can be automatically processed.
"%%%" is a "FIXME indicator".
Usage:
For a single manual page: <!DOCTYPE MANPAGE SYSTEM "tmml.dtd">
For a complete reference manual: <!DOCTYPE TCLDOC SYSTEM "tmml.dtd"> -->
<!ENTITY nbsp " ">
<!-- Parameter entities for use in ATTLIST declarations: -->
<!ENTITY % lineSpecific "xml:space (default|preserve) 'preserve'" >
<!-- Information pool:
%syntax; Phrase-level elements that refer to Tcl syntactic entities. %inline; All phrase-level elements %block; Block-level elements %mixed; All block- and phrase-level elements %structure; Structural elements that can appear directly in a MANPAGE
-->
<!ENTITY % syntax " META|M | LIT|L | I | B | BR | COMMAND | VARIABLE | METHOD | SYSCMD | FUNCTION | OPTION | WIDGET | SYSFUNC | OPT | GROUP ">
<!ENTITY % inline " #PCDATA | EMPH | REF | NEW | %syntax; ">
<!ENTITY % block " P | UL | OL | DL | EXAMPLE | SYNTAX | SYNOPSIS | METHODDEF | OPTIONDEF " >
<!ENTITY % mixed "%inline; | %block;">
<!ENTITY % structure " VARDEF | METHODLIST | OPTIONLIST | FUNCARG " >
<!-- ============================================================ Top-level document structure: ============================================================ -->
<!ELEMENT TCLDOC (SECTION*) > <!ELEMENT SECTION (TITLE, ((MANPAGE|COMMENT)* | SECTION*)) > <!ELEMENT TITLE (#PCDATA) > <!ELEMENT MANPAGE (%mixed; | %structure; | NAME | DESC | HEADING | KEYWORDS | SEEALSO)* > <!-- %%% WANT: ELEMENT MANPAGE (NAME, DESC, SYNOPSIS?, (HEADING, (%structure;|%block;)*)*, KEYWORDS?, SEEALSO? ) --> <!ELEMENT COMMENT (#PCDATA) > <!-- %%% WANT: Change COMMENT element into a ?COPYRIGHT processing instruction. -->
<!ATTLIST MANPAGE TYPE CDATA #REQUIRED EXTENSION CDATA #REQUIRED > <!ELEMENT NAME (#PCDATA) > <!ELEMENT DESC (%inline;)* >
<!-- ============================================================ Structural elements: ============================================================ -->
<!ELEMENT HEADING (#PCDATA) > <!ATTLIST HEADING ID CDATA #IMPLIED > <!-- Note: ID is declared CDATA rather than ID to allow more than one MANPAGE per document, since XML does not support SUBDOC. -->
<!ELEMENT KEYWORDS (#PCDATA) > <!ATTLIST KEYWORDS NOTATION CDATA #FIXED "list of keywords (ws- or comma-separated)" > <!ELEMENT SEEALSO (#PCDATA) > <!ATTLIST SEEALSO NOTATION CDATA #FIXED "list of cross-references" > <!ELEMENT SYNOPSIS (SYNTAX|NEW)+ >
<!-- ============================================================ Block-level elements: ============================================================ -->
<!ELEMENT UL (%mixed; | LI)* > <!ELEMENT OL (%mixed; | LI)* > <!ELEMENT LI EMPTY > <!-- %%% WANT: ELEMENT UL (LI+) ELEMENT OL (LI+) ELEMENT LI (%mixed;)* -->
<!-- %%% DL content model is "(DT+, DD)* +NEW", sort of --> <!ELEMENT DL ((DT, (DT|NEW)*, DD) | NEW)* > <!ELEMENT DT (%inline;)* > <!ELEMENT DD (%mixed;)* >
<!ELEMENT P EMPTY > <!-- %%% WANT: ELEMENT P (%inline;)* -->
<!ELEMENT EXAMPLE (%inline;)* > <!ATTLIST EXAMPLE %lineSpecific; >
<!ELEMENT SYNTAX (#PCDATA | %syntax;)* > <!ATTLIST SYNTAX %lineSpecific; >
<!-- ============================================================ Inline elements: ============================================================ -->
<!ELEMENT I (%inline;)* > <!-- deprecate --> <!ELEMENT B (%inline;)* > <!-- deprecate --> <!ELEMENT EMPH (%inline;)* > <!ELEMENT BR EMPTY > <!ELEMENT REF (#PCDATA) > <!ATTLIST REF ID CDATA #REQUIRED PAGE CDATA #IMPLIED COMMAND CDATA #IMPLIED WIDGET CDATA #IMPLIED FUNCTION CDATA #IMPLIED NOTATION CDATA #FIXED "reference to HEADING" >
<!-- ============================================================ Syntax elements: ============================================================ -->
<!ELEMENT META (#PCDATA|%syntax;)* > <!ELEMENT M (#PCDATA) > <!ELEMENT LIT (#PCDATA|%syntax;)* > <!ELEMENT L (#PCDATA) > <!-- %%% WANT: ELEMENT (META|LIT) (#PCDATA) --> <!ELEMENT FUNC (#PCDATA) > <!ELEMENT INFO (#PCDATA) > <!ELEMENT SYSCMD (#PCDATA) > <!ELEMENT WIDGET (#PCDATA) > <!ELEMENT OPT (#PCDATA | %syntax;)* > <!ELEMENT GROUP (#PCDATA | OR | %syntax;)* > <!ELEMENT OR EMPTY > <!ELEMENT COMMAND (#PCDATA) > <!ATTLIST COMMAND PAGE CDATA #IMPLIED >
<!ELEMENT FUNCTION (#PCDATA) > <!ATTLIST FUNCTION PAGE CDATA #IMPLIED NOTATION CDATA #FIXED "Reference to MANPAGE TYPE=FUNC" >
<!ELEMENT VARIABLE (#PCDATA) > <!ATTLIST VARIABLE NAME CDATA #IMPLIED > <!-- %%% VARIABLE NAME is actually a hyperlink. Only used once. -->
<!ELEMENT METHOD (#PCDATA) > <!ATTLIST METHOD NAME CDATA #IMPLIED COMMAND CDATA #IMPLIED WIDGET CDATA #IMPLIED PAGE CDATA #IMPLIED > <!-- %%% METHOD attlist: documentation says "COMMAND/WIDGET/NAME"; actually uses: PAGE/NAME. PAGE is probably a bad idea. -->
<!-- ============================================================ Tcl-specific block-level elements: ============================================================ --> <!ELEMENT VARDEF (%mixed;)* > <!ATTLIST VARDEF NAME CDATA #REQUIRED >
<!-- %%% WANT: ELEMENT METHODDEF (SYNTAX, METHODDESC) ELEMENT METHODDESC (%mixed; | METHODDEF)* --> <!ELEMENT METHODDEF (%mixed;)* > <!ATTLIST METHODDEF NAME CDATA #REQUIRED > <!ELEMENT METHODLIST (#PCDATA) > <!ATTLIST METHODLIST NOTATION CDATA #FIXED "List of methods" >
<!ELEMENT OPTIONDEF (%mixed;)* > <!ATTLIST OPTIONDEF SWITCH CDATA #REQUIRED ARG CDATA #IMPLIED NAME CDATA #IMPLIED WIDGET CDATA #IMPLIED CLASS CDATA #IMPLIED ALT CDATA #IMPLIED > <!ELEMENT OPTIONLIST (#PCDATA) > <!ATTLIST OPTIONLIST SUPERCLASS CDATA #IMPLIED NOTATION CDATA #FIXED "List of options inherited from superclass" > <!ELEMENT OPTION (#PCDATA) > <!ATTLIST OPTION COMMAND CDATA #IMPLIED WIDGET CDATA #IMPLIED SWITCH CDATA #IMPLIED PAGE CDATA #IMPLIED NOTATION CDATA #FIXED "reference to option" > <!-- %%% OPTION: PAGE attribute not documented. %%% What is the SWITCH attribute? -->
<!ELEMENT FUNCARG (ARGTYPE|ARGNAME|ARGDESC|NEW)*> <!ATTLIST FUNCARG MODE CDATA #REQUIRED > <!-- %%% MODE: (in | out | in/out) %%% Want: (in | out | inout) --> <!ELEMENT ARGTYPE (#PCDATA) > <!ELEMENT ARGNAME (#PCDATA) > <!ELEMENT ARGDESC (%inline;)* >
<!-- ============================================================ Version control: ============================================================ --> <!ELEMENT NEW ANY > <!ATTLIST NEW VERSION CDATA #IMPLIED >
<!-- EOF --> Our goal is to make the test suites for Tcl and extensions easy to create and maintain as well as invoke and interpret results. Uniformity across extension test suites can improve all of these things. For test suites to be uniform across extensions, they must have the same internal code structure and usage. They must also have the same (minimal) side effects. This outline contains our proposal for test suite specs that can help us achieve these goals. Usage Mechanism for Invocation
Print Testing Statistics Use the ::test::printStats command at the end of each test file to print the number of tests passed, failed, and skipped. Structural Uniformity Code structure
test getAttribute-1.1 {testing file permissions} {unixOnly} { lindex [file attributes foo.tcl] 5 } {00644} File Nomenclature and Structure tests | -------------------------------------- | | | | README all.tcl defs.tcl <same as source dir heirarchy> | --------------------- | | | ?README? all.tcl *.test
Tests Should Not Rely on the Current Working Directory Tests Should Clean Up After Themselves Imagine an environment in which you had nothing but Tcl running and you typed package require Expect! Wouldnt it be cool if by some automagical stroke of genius, Tcl reached out over the Internet and grabbed the extension, downloaded it to your local machine, installed it into your Tcl installation, and proceeded to load and initialize Expect. Maybejust maybeif the binary for you particular platform was unavailable, the sources are downloaded and built for you. Carrying this idea further, Tcl extensions can be upgraded in very much the same way: package upgrade command? All the pain end users feel today of locating, downloading, building, and installing extensions, would all go away. Tcl Extension writers would then have a vehicle for getting their packages out to more users, more often in a smooth and simple manner. A stepping stone for the above goal is to be able to give a Tcl extension install tool the URL of the location of where a packaged extension lives. The tool could interrogate a database at that URL to determine the best version of an extension against the version of Tcl you currently use. So if you were running Tcl 8.0.5, with the help of the database, the tool would determine it should retrieve TclX 8.0.5. The tool would download and install the extension into your Tcl instalaltion. Possibly a shorter term goal than either of the above is to have the equivalent of .tar balls for Tcl extensions that the user can download, untar, and run a Tcl script that proceeds to install the particular extension. A prerequisite to any of these automated installation strategies is having Tcl installed and working. For most platforms today, Tcl is installed from a source release. Tcl is likely to be installed using an OS specific installation format such as Solaris option package, Linux RPM, and Windows SETUP application. [Should Scriptics have as a goal to provide binary distribution of Tcl on many platform in respective formats (very much like what CPAN has for Perl; CPAN sends you to a site that has a binary version of Perl for a particular platform; for example they send you to Sun to get the Solaris version of Perl)?] A complete distribution and installation strategy includes two major area: the first, a packaging utility that puts together an extension including the complete manifest of files; the second, an installer that installs the extension into an end user's Tcl installation. The sections below discuss these two areas in further detail. It must be easy for a module developer to create both source and binary distributions. Tcl and Tcl extensions should continue to support source distributions. It must be possible (and preferably easy) to as well download and build from a source distribution. (Necessary for users who don't happen to be using one of the major platforms, or who don't trust built distributions.) To aid in installing all modules, and in building extension from C/C++ source, there must be a standardized way to get Python's configuration data (such as compiler, compiler flags, platform, default library directory, etc.). Packaging an Extension There must be an easy, standardized way to create "built distributions" (ready-to-install downloadable resources, with all compilation and other processing done) for the major platforms. Module distributions must have a standardized way to express their dependencies on other modules (both simple presence/absence and required version number) and on Tcl itself (version number), and these dependencies must be checked at install time to ensure that a proper version of Tcl is available. Defining an extensionsthe meta data
Once this information is collected, the makefile target make setup will invoke a Tcl script that will generate a single file (such as a gzipped-tar ball or zip compatible compressed archive, etc.). Source distributions Installing a Tcl Extension Into an End User's Tcl Installation There will likely be a Tcl package in the Tcl script library directory named setup. This package will performs all of the installation functions for a Tcl extension into the Tcl install tree. Some of the functionality is described below. The core installation package will show the following information user during extension installation process:
Preinstallation and postinstallation scripts: Extensions that require special handling or want to add their own incremental user interface to the setup application can hook into this part of the installation mechanism. Preinstallation scripts run before any files are copied to the file system and postinstallation scripts run after all files have been copied. So for example, a database extension can ask the user for special database access information if needed. Installation log: During installation of the extension a log file will be updated the provides all salient formation regarding the particular extension being installed. Information that will be placed in the log file includes time/date, list of files and their target locations, result of any preinstallation and postinstallation scripts, exceptions encountered, etc. This information in this file is used only for information purposes. It's exact location is to be determined. Installation test: Once the installation of the extension is complete a fairly simple sanity test should be performed to ensure that the extension has been installed correctly. This test will likely be in the form of a script provided by the Tcl extension itself. Extension patches: As part of the installation architecture, we may provide support installing a Tcl extension patch. A patch may include any number of files and simply install as another extension. Uninstallation: Uninstallation is going to be extremely important for users who want to test to extensions. Uninstallation is also important for when patches are being installed and user decides to back out of a patch. To perform uninstallation, the core package installer will need to record information of files copied and or modified. The uninstaller uses this information to undo and back out changes performed. Template Extension As part of the Tcl Extension Architecture a template extension will be developed to demonstrate how to write a new Tcl extension. The template will include some C source files, and configure and Makefiles for both UNIX and Windows as appropriate. The goal of this template extension is to give an adequate framework for an extension writer to base their work when creating a new extension. Requirements of the extension include:
| example1 | +--- README +--- generic | | | +--- tclCExample.c +--- win | | | +--- Makefile.vc +--- mac | | | +--- Makefile.??? +--- library | | | +--- example.tcl +--- doc | +--- ???? +--- tests | | | +--- example.test | +--- all.tcl | +--- example-bb.test example2 | +--- README +--- generic | | | +--- tclCppExample.cpp +--- unix | | | +--- configure | +--- Makefile | +--- tclUnixCode.c +--- win | | | +--- Makefile.vc | +--- tclWinCode.c +--- mac | | | +--- Makefile.??? | +--- tclMacCode.c +--- library | | | +--- example.tcl +--- doc | +--- ???? +--- tests | | | +--- example.test | +--- all.tcl | +--- example-bb.test = Other Opern Source Products and Perl For extensions, Perl does not use configure but rather a Makefile generator based on Perl. CPAN specifies ways in which to create module for distribution and installation at a user site. "Another difficulty is that some modules depend on others. While the CPAN administrators, module writers, and Makemaker gurus have tried to make downloading and installing modules as easy as possible (and see Andreas König's CPAN.pm module for a way to automate the process), it's a little frustrating to install a sleek new module only to find that it depends on something you don't have. That's where CPAN bundles come in: a bundle is a colllection of modules that comprise a cohesive unit, like the libwww bundle, which contains lots of modules to help you tangle with the World Wide Web." Documentation? "In Perl, there is a convention of embedding documentation inside your source code. (That way, you never lose it.) This embedded documentation is in a format called "POD" (for Plain Old Documentation); when you look through a module and see lines like =head1 or =cut, that's POD. POD is designed to be easily readable and translatable into whatever format you like. Use one of the programs in the pod2x directory (in your Perl distribution) to extract the documentation and convert to HTML, FrameMaker, a Unix man page, TeXinfo, or just plain text." CPAN is the accepted mechanism for locating, downloading, and installing Perl modules. The CPAN multiplexer facility helps locate Perl modules at a CPAN mirror site that is geographically close to the user.. Python The Python folks began an effort last November to reorganize the distribution strategy of Python modules (script only extension), module extensions (written in C, extensions for short), and packages (a group of two or more modules that work together). They are dealing with roughly the same issues we are today: making it easy for the classes of users (developers, packagers, and users) to develop and maintain, package and distribute, download and install Python and Python modules Thus far they have highlevel requirements and some design ideas for the distribution utilities. A few observations we can make from their efforts are:
For more information on their efforts start at http://www.foretec.com/python/workshops/1998-11/dd-ward-sum.html. Python has an interesting way of incorporating modules statically into the base Python interpreter: You basically drop your module's source files and a module description file into the Python source tree and rebuild all of Python. This is in contrast to building Tcl as static archives, creating a Tcl_AppInit( ), that initializes the static extension, and basically links Tcl static archive and the extension static archive together. Python does not use the standard extension, .dll, for DLLs, but rather the extension of .pyd. Perhaps to prevent people from linking their application to them explicitly. Python puts DLLs in the Windows system directory! Yuck! Lucky for us, Tcl has steered away from polluting the Windows system directory. Python uses straight HTML files for their documentation. Conclusions This document has covered many issues regarding software configuration, documentation, installation, testing. In some areas significant proposals have been made. In the area of configuration, Tcl and Tcl extensions should aim for simplicity for their source configuration and building. Cross platform issues are many. TODO! |