tm(3tcl)
π NAME π
hey bestie, welcome to the tm page β that's section 3tcl of the Tcl Built-In Commands manual, and honestly? it's giving infrastructure glamour β¨
tm β the whole entire facility for locating and loading Tcl Modules, no cap π
πΈ SYNOPSIS πΈ
::tcl::tm::path add ?path ...?
::tcl::tm::path remove ?path ...?
::tcl::tm::path list
::tcl::tm::roots paths
β¨ DESCRIPTION β¨
okay so. this doc is the full tour of how Tcl finds and loads Tcl Modules (peep the MODULE DEFINITION section for what even is a Tcl Module π ). here are the commands you get:
::tcl::tm::path add ?path ...?β the paths get added to the head of the module path list, in the order they show up as arguments. which meansβ¦ yeah, the last argument ends up being the brand new head of the list π
also it's strict about one thing: no path may be an ancestor directory of any other path on the list. if any of the new paths breaks that, an error gets raised before any of the paths are added. like, if even just one path argument violates it, then none of them get added. all or nothing, periodt.
and if a path is already on the list exactly as it is? no error, no action, no drama π silence.
paths get searched later in the order they appear in the list. since they're added to the front, they end up being searched in reverse order of addition β the paths added last are looked at first. last in, first searched, iconic behavior honestly π
::tcl::tm::path remove ?path ...?β removes those paths from the module path list. any path that isn't on the list gets silently ignored. no warnings, no notes, just vibes π¦::tcl::tm::path listβ returns a list with all the registered module paths, in the exact order they get searched for modules. the receipts, basically π§Ύ::tcl::tm::roots pathsβ similar topath add, layered on top of it. this one takes a single argument containing a list of paths, then extends each one withtclX/site-tcl, andtclX/X.y, where X is the major version of the Tcl interpreter and y is a minor version less than or equal to the interpreter's minor version. then the whole resulting set of paths gets added to the search path list β¨
this command is used internally by the system to set up the system-specific default paths β so it's the backstage crew fr fr.
and it's been exposed so that a build system can define additional root paths beyond the ones this document describes. slay for build systems π οΈ
π MODULE DEFINITION π
a Tcl Module is a Tcl Package living inside a single file, with no other files required by it. the file has to be sourceable. in other words, a Tcl Module is always imported via:
source module_file
the load command is not directly used. and listen β that's not an actual limitation like some people think. ever since 8.4, the Tcl source command only reads until the first ^Z character π. which lets us smush an arbitrary Tcl script together with arbitrary binary data into one file, where the script processes the attached data in any way it chooses to fully import and activate the package. it's giving two-in-one π«Ά
the name of a module file has to match this regular expression:
([_[:alpha:]][:_[:alnum:]]*)-([[:digit:]].*)\.tm
the first capturing parentheses gives you the name of the package, the second clause gives you its version. and on top of matching the pattern, the extracted version number must not raise an error when it's used in:
package vcompare $version 0
π¦ FINDING MODULES π¦
the directory tree where Tcl modules live is separate from the other parts of the filesystem, and it's independent of auto_path. it does its own thing π
Tcl Modules get searched for in all the directories listed in the result of:
::tcl::tm::path list
this is called the Module path. neither the auto_path nor the tcl_pkgPath variables get used here, nope. and every directory on the module path has to obey one restriction:
For any two directories, neither is an ancestor directory of the other.
why? to avoid ambiguities in package naming, bestie. say for example the two directories foo/ and foo/cool were both on the path β then a package named cool::ice could be found via the names cool::ice or ice, and that second one could potentially hide (obscure) a package named ice, unqualified. chaos. not allowed π
before the search even starts, the name of the requested package gets translated into a partial path, using this algorithm:
All occurrences of::in the package name are replaced by the appropriate directory separator character for the platform we are on. On Unix, for example, this is/.
example time π:
The requested package isencoding::base64. The generated partial path isencoding/base64.
after that translation, the package is looked for in all module paths, by combining them one-by-one, first to last, with the partial path to form a complete search pattern. note that the search algorithm rejects all files where the filename does not match the regular expression from the MODULE DEFINITION section. for the remaining files, provide scripts are generated and added to the package ifneeded database β¨
the algorithm falls back to the previous unknown handler when none of the found module files satisfy the request. but if the request was satisfied, the fall-back gets ignored. bye π
also note: packages in module form have no control over the index and provide scripts that get entered into the package database for them. for a module file MF, the index script is always:
package ifneeded PNAME PVERSION [list source MF]
and the provide script embedded in the above is:
source MF
both the package name PNAME and the package version PVERSION get extracted from the filename MF according to the definition below:
MF = /module_path/PNAMEβ²-PVERSION.tm
where PNAMEβ² is the partial path of the module as defined in the FINDING MODULES section, translated into PNAME by changing all directory separators to ::, and module_path is the path (from the list of paths to search) that we found the module file under π
and one more thing β we're literally creating a connection between package names and paths here. Tcl is case-sensitive when it compares package names, but some filesystems are not, like NTFS π luckily, those filesystems do store the case of the name, even though they don't use that info when comparing. so it works out.
given all of the above, we allow package names in Tcl modules to have mixed-case, but we also require that there are no collisions when comparing names in a case-insensitive way. in other words, if a package Foo is deployed as a Tcl Module, then packages like foo, fOo, etc. are not allowed anymore. pick one, king π
π DEFAULT PATHS π
the default list of paths on the module path gets computed by a tclsh like this, where X is the major version of the Tcl interpreter and y is less than or equal to the minor version of the Tcl interpreter.
all the default paths get added to the module path β even the ones that don't exist π« non-existent paths get filtered out during the actual searches. this is actually a feature: it lets a user create one of those searched paths whenever they need to, and every running application will automatically pick up any modules placed in them. future-proofing, we love to see it β¨
the paths are added in the order they're listed below, and for lists of paths defined by an environment variable, in the order they're found in the variable.
π SYSTEM SPECIFIC PATHS π
file normalize [info library]/../tclX/X.yβ so basically, the interpreter looks into a directory specified by its major version, whose minor versions are less than or equal to the interpreter's minor version.
for example, for Tcl 8.4 the paths searched are:
[info library]/../tcl8/8.4
[info library]/../tcl8/8.3
[info library]/../tcl8/8.2
[info library]/../tcl8/8.1
[info library]/../tcl8/8.0
this definition assumes that a package defined for Tcl X.y can also be used by all interpreters that have the same major number X and a minor number greater than y π
file normalize EXEC/tclX/X.yβ where EXEC isfile normalize [info nameofexecutable]/../liborfile normalize [::tcl::pkgconfig get libdir,runtime]
this set of paths is handled equivalently to the set just before it, except that it's anchored in EXEC_PREFIX. for a build with PREFIX = EXEC_PREFIX the two sets are identical. twins fr π―
π SITE SPECIFIC PATHS π
file normalize [info library]/../tclX/site-tclβ note that this is always a single entry, because X is always one specific value (the current major version of Tcl).
πΈ USER SPECIFIC PATHS πΈ
$::env(TCLX_y_TM_PATH)β a list of paths, separated by either:(Unix) or;(Windows). this one is user and site specific, because the environment variable can be set not only by the user's profile, but by system configuration scripts as well.$::env(TCLX.y_TM_PATH)β same meaning and content as the previous variable. however, using a dot.to separate the major and minor version numbers makes this name less-to-non-portable, and its use is discouraged π support for this variable has only been kept for backward compatibility with the original specification, i.e. TIP 189.
these paths are seen and therefore shared by all Tcl shells in the $::env(PATH) of the user.
note that X and y follow the general rules set out above. in other words, Tcl 9.1, for example, will look at these 4 environment variables:
$::env(TCL9.1_TM_PATH) $::env(TCL9_1_TM_PATH)
$::env(TCL9.0_TM_PATH) $::env(TCL9_0_TM_PATH)
paths initialized from the environment variables undergo tilde substitution (see filename). any path whose tilde substitution fails because the user is unknown gets omitted from the search paths. sorry bestie, if we don't know you, you don't get a path π
π₯ SEE ALSO π₯
package(3tcl), Tcl Improvement Proposal #189 βTcl Modulesβ (online at https://core.tcl-lang.org/tips/doc/trunk/tip/189.md), Tcl Improvement Proposal #190 βImplementation Choices for Tcl Modulesβ (online at https://core.tcl-lang.org/tips/doc/trunk/tip/190.md)
β KEYWORDS β
modules, package
and that's the whole page, bestie π
this was Tcl 8.5, page tm(3tcl) β go forth and load some modules, you absolute main character π¦β¨π
π¦ where this page comes from
- ubuntu stonking: tcl9.0-doc 9.0.4+dfsg-1
- Copyright (c) 2004-2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms