您好,欢迎访问三七文档
当前位置:首页 > IT计算机/网络 > 数据库 > TCL脚本语言-12-程序库和程序包
TCL、Python和软件测试自动化141作者:雷雨后Email:leiyuhou010@gmail.com程序库和程序包一门语言附带程序库的功能是否强大,对其能否获得广泛应用其有着重要的影响。程序库是那些可以被多个应用程序使用的、公共的代码或者程序。例如C/C++语言经过多年发展,有了CRTLibrary、STL、boost等通用库,以及Windows上的MFC等程序库。应该说正是这些功能强大无所不包的程序库,才使C/C++语言到现在仍然是最具有活力的系统编程语言。现在正在流行的C#语言,其运行的.net平台中更是包含了一个巨大的程序库。TCL语言也有很多程序库。如何组织这些程序库,让多个程序可以调用?C/C++中的程序库是通过头文件和库文件来进行的,而TCL的程序库的变迁经历了两种形式:程序库(library)和程序包(package)。library的方式比较原始和古老,现在一般都不采用了,package方式则比较全面。我们在介绍这两种方式之前,先介绍一下source命令和unknow命令。source:TCL中的#includeC/C++中使用库文件的方式,首先必须在源程序中#include相关的头文件,编译通过后,在链接(link)阶段与相关的库文件(.lib、.obj等)连接。在TCL中则没有所谓头文件和库文件,那么分散在其他多个文件的命令和程序,如何被我们的应用中加载引用呢?有一个命令可以完成类似#include的功能,这就是source。其命令语法如下:sourcefilename唯一的参数是文件名,source命令读取文件全部内容,然后交给TCL解释器来执行,source命令的结果就是文件中最后一个命令的结果。如果执行的时候发生了异常,source命令也会抛出异常。source命令在library和package两种模式中都得到了广泛的应用。unknow方法请先思考下面的问题:Windows操作系统下,当我们执行命令tclsh启动一个TCL解释器之后,进入交互模式,然后在TCL的命令提示符下面输入dir命令,会怎样?得出结论后,然后动动手实践一下来验证你的结论是否正确。创建一个文件test.tcl,其内容只有一行,就是dir命令,然后在命令提示符下面通过输入命令行tclshtest.tcl来执行这个TCL脚本,看看结果怎么样。结果比较让人诧异:交互模式下,dir命令能够执行,并且列出了当前目录下的所有内容,和一般情况下执行dir的结果并无差异;但是执行脚本,则报告了一个错误:invalidcommandname“dir”。怎么回事?dir是标准的DOS内部命令,它不属于Tcl的命令。这样的命令按照常理是不能够被执行的,但是事实上在交互模式下却正确执行了,那为何在脚本TCL、Python和软件测试自动化142作者:雷雨后Email:leiyuhou010@gmail.com里面就不能执行了呢?其实,这都是unknow命令在作怪。实际上,TCL解释器在解释执行的时候,如果碰上了当前不认识的命令名字,都会调用一个命令:unkonwn;并且把这个未知命令连同其参数作为unknow命令的参数。unknown命令一般是在TCL解释器初始化的时候来定义的。作为一个比较普遍的规则:1.每一个TCL应用程序都应该有一个init.tcl文件,该文件会做一些初始化的工作,这个文件都位于infolibrary命令所返回的目录中。2.unknown命令就是在这个init.tcl文件中定义的。例如我现在使用的ActiveTcl,运行infolibrary命令,返回解释器的库目录为:%infolibraryC:/Tcl/lib/tcl8.4在这个目录下存在文件init.tcl,其中就定义了unknown命令。大家有兴趣可以直接看看这个命令的源代码。TCL解释器碰到不认识的命令之后,处理流程如下:1.首先看看unknown命令是否存在,不存在则抛出异常;2.然后调用unknown命令,未知命令及其参数都作为unknown的参数;3.检查命令字是否具有“namespaceinscopenscmd”这样的格式,如果是,则直接执行该命令,然后返回;4.如果没有定义全局变量auto_noload,则调用auto_load命令来尝试从程序库中加载和寻找这个未知命令;如果找到则执行它,返回结果;5.如果auto_load没有找到该命令的实现,那么就判断是否是处在交互模式下;如果是交互模式:a)并且没有定义全局变量auto_noexec,那么就调用auto_execok命令来判断这个未知命令是否是DOS内部命令或者是某一个可执行程序。如果是,则执行它们,并且返回执行结果。b)如果没有找到可执行命令文件,或者定义了auto_noexec,那么就判断该未知命令是否是“!!”、“!(.+)$”等这样的格式;如果是,那么就调用对应的历史命令。6.如果不是交互模式,则抛出异常,退出unknown。上面是unknown命令的默认处理流程,我们可以自己重新编写这个命令,但是最好要保留原来的功能。因为其处理机制非常重要,保证了TCL程序库中定义的命令能够被自动的加载到TCL解释器中。完成这个功能的就是auto_load命令。auto_load:加载程序库auto_load命令是在init.tcl中定义,在解释器初始化的时候被创建。当解释器碰到了未定义命令的时候,unknown命令会被调用,在unknown中会调用auto_load命令来寻找这个TCL、Python和软件测试自动化143作者:雷雨后Email:leiyuhou010@gmail.com未定义命令。弄清楚auto_load的执行机制,会让我们更加清楚TCL程序库(library)的工作机制和自动加载的原理。首先得介绍一下和aoto_load相关的两个全局变量:1.auto_path:列表变量,其每一个元素是库文件所在的目录。这个变量在解释器初始化、执行init.tcl文件的时候被定义并且初始化,过程如下:a)如果有环境变量TCLLIBPATH,其值将是auto_path的第一个元素;b)命令infolibrary所返回的路径以及其父目录会加入到auto_path中;c)当前可执行文件所在目录的父目录下的lib子目录,会加入auto_path中;d)如果定义了变量tcl_pkgPath,其中每一个元素也会加入到auto_path中。可见我们可以将库文件放到很多分散的目录中,只要在auto_path变量中有这些目录中就行了。2.auto_index:一个数组变量。其中每一个元素的下标是命令名字,对应值则是一条TCL语句。通过执行该语句能够定义对应的命令。例如:元素parray对应的语句是“sourceC:/Tcl/lib/tcl8.4/parray.tcl”。执行该语句后,parray命令就会被定义。一般而言,这个语句类似sourcexxxfile的格式。过程就是在xxxfile中被定义。auto_load的语法格式如下:auto_loadcmd?namespace?;其中的cmd就是解释器碰到的未知命令,当它被调用的时候:1.判断数组auto_index中是否存在下标为cmd的元素。如果有则执行对应的语句,然后判断命令cmd是否被定义;如果存在就返回1,表示加载成功;2.接着判断auto_path变量是否存在,如果不存在就返回0,表示加载失败;3.然后依次在auto_path所包含的每一个目录下,寻找名字为“tclIndex”的文件,判断这个文件是否是有效文件。如果有效,那么就执行这个文件。4.然后再次判断auto_index中是否存在下标为cmd的元素,如果存在,则执行对应的语句,然后判断命令cmd是否存在(是否被定义了);如果存在,就返回1。5.最后返回0,表示自动加载失败。这就是auto_load命令的全部执行过程。可以看到,除了前面介绍的auto_path和auto_index变量之外,还涉及到了一个文件tclIndex。这个文件的内容很简单:就是用来设置auto_index变量的值。例如在我的系统上:%foreach{kv}[arraygetauto_index]{puts$k=$v}tcl_startOfNextWord=sourceC:/Tcl/lib/tcl8.4/word.tclparray=sourceC:/Tcl/lib/tcl8.4/parray.tclpkg_mkIndex=sourceC:/Tcl/lib/tcl8.4/package.tcl::safe::Lappend=sourceC:/Tcl/lib/tcl8.4/safe.tclhistory=sourceC:/Tcl/lib/tcl8.4/history.tcl::safe::AliasSubset=sourceC:/Tcl/lib/tcl8.4/safe.tcl„„%setauto_pathTCL、Python和软件测试自动化144作者:雷雨后Email:leiyuhou010@gmail.comC:/Tcl/lib/tcl8.4C:/Tcl/lib上面是auto_index和auto_path两个变量的内容。在C:/tcl/lib/tcl8.4目录下存在一个文件tclIndex,其内容如下:#Tclautoloadindexfile,version2.0#Thisfileisgeneratedbytheauto_mkindexcommand#andsourcedtosetupindexinginformationforoneor#morecommands.Typicallyeachlineisacommandthat#setsanelementintheauto_indexarray,wherethe#elementnameisthenameofacommandandthevalueis#ascriptthatloadsthecommand.setauto_index(auto_reset)[listsource[filejoin$dirauto.tcl]]setauto_index(tcl_findLibrary)[listsource[filejoin$dirauto.tcl]]setauto_index(auto_mkindex)[listsource[filejoin$dirauto.tcl]]setauto_index(auto_mkindex_old)[listsource[filejoin$dirauto.tcl]]„„里面就是一堆的setauto_index(cmd)这样的命令。可以看到,第一条auto_reset命令可以通过执行“sourceauto.tcl”语句来被定义。根据我们前面对unknown和auto_load命令的分析,如果解释器碰到了auto_reset命令并且该命令没有被定义,那么就会通过unknown和auto_load来执行sourceauto.tcl,而auto_reset命令就是在文件auto.tcl中被定义。所以auto_load能够加载成功,并且在unknown中会执行这个auto_reset命令。如果再次调用auto_reset命令,就不会再次进行同样的加载了,因为这个命令已经被定义了,可以被直接调用。tclIndex文件内容是不是很简单?确实很简单,读者可能会觉得自己动手写一个也不成问题,确实可以自己动手写,不过如果需要手动编写tclIndex文件,一定要注意文件的第一行内容必须是:#Tclautoloadindexfile,version2.0auto_load就是根据第一行的内容来判断该文件是否是有效的tclIndex文件。大部分情况下没有必要手动编写,因为TCL程序库中已经为我们定义了一个命令:auto_mkindex,来帮助我们自动生成tclIndex文件。创建程序库(library)经过前面的分析,相信大家对TCL自动加载library的过程
本文标题:TCL脚本语言-12-程序库和程序包
链接地址:https://www.777doc.com/doc-5884710 .html