模块的存在是为了更好地代码重用。
当要执行的命令不存时,unknown
命令会被调用。
Tcl默认的unknown
命令实现会调用auto_load $cmd
。
当执行命令auto_load $cmd
时,Tcl解释器会在$auto_path
中列出的目录中寻找并加载(source)文件tclIndex。
tclIndex文件的内容如下,定义了加载某条命令的方法,比如:
set auto_index(assert) [list source [file join $dir assert.tcl]] set auto_index(%%) [list source [file join $dir assert.tcl]] # ... ...
tclIndex文件可以用下面的命令生成:
auto_mkindex $dir *.tcl
典型的package
的用法如下:
package require assert # 或者 package require assert 1.0
显然,问题的关键是如何找到要加载的文件。与auto_load
类似,package命令是在$auto_path
中列出的目录中寻找pkgIndex.tcl文件,其文件内容大致如下:
package ifneeded assert 0.1 [list source [file join $dir assert.tcl]]
pkgIndex.tcl文件可以用下面的命令生成:
pkg_mkIndex -direct $dir ;# -direct 选项可以省略
相应的tcl文件中需要包含package provide
命令,比如
package provide assert 0.1
上面这种"-direct"的方式会在package require
命令执行时加载相应的Tcl文件。还有一种-lazy
模式,其对应的"pkgIndex.tcl"文件内容看起来如下:
package ifneeded assert 0.1 [list tclPkgSetup $dir assert 0.1 \ {{assert.tcl source {%% assert}}}]
这可以通过命令pkg_mkIndex -lazy $dir
来生成。
tclPkgSetup
的作用是设置$auto_index
变量,将加载tcl文件的时间推迟到第一次使用包中的命令时,即所谓的lazy loading.
tm是Tcl8.5中开始出现的,用于辅助定位和加载Tcl模块文件。
加载一个模块文件本质上就是source
文件。tm约定了一种模块文件的命名和寻找方式。
::tcl::tm::path add
命令可以指定一组搜寻目录(search path)。模块文件以PNAME-PVERSION.tm
的形式命名。
tm只是一种辅助工具,具体的文件加载还是要依赖于package
方法。一个tm模块文件会被自动添加到package database中:
package ifneeded PNAME PVERSION [list source MF] # MF = $tm_path/PNAME-PVERSION.tm
两个(其实是一个,只是不同的写法)新的环境变量用于设置search path:
tm的好处是省去了创建和管理"pkgIndex.tcl"文件的麻烦。