📄 package.tcl
字号:
# package.tcl --## utility procs formerly in init.tcl which can be loaded on demand# for package management.## RCS: @(#) $Id: package.tcl,v 1.14.2.2 2001/08/24 16:19:10 dgp Exp $## Copyright (c) 1991-1993 The Regents of the University of California.# Copyright (c) 1994-1998 Sun Microsystems, Inc.## See the file "license.terms" for information on usage and redistribution# of this file, and for a DISCLAIMER OF ALL WARRANTIES.## Create the package namespacenamespace eval ::pkg {}# pkg_compareExtension --## Used internally by pkg_mkIndex to compare the extension of a file to# a given extension. On Windows, it uses a case-insensitive comparison# because the file system can be file insensitive.## Arguments:# fileName name of a file whose extension is compared# ext (optional) The extension to compare against; you must# provide the starting dot.# Defaults to [info sharedlibextension]## Results:# Returns 1 if the extension matches, 0 otherwiseproc pkg_compareExtension { fileName {ext {}} } { global tcl_platform if {![string length $ext]} {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 equal $currExt $ext]} { return 1 } # The current extension does not match; if it is not a numeric # value, quit, as we are only looking to ignore version number # extensions. Otherwise we might return 1 in this case: # pkg_compareExtension foo.so.bar .so # which should not match. if { ![string is integer -strict [string range $currExt 1 end]] } { return 0 } set root [file rootname $root] } }}# pkg_mkIndex --# This procedure creates a package index in a given directory. The# package index consists of a "pkgIndex.tcl" file whose contents are# a Tcl script that sets up package information with "package require"# commands. The commands describe all of the packages defined by the# files given as arguments.## Arguments:# -direct (optional) If this flag is present, the generated# code in pkgMkIndex.tcl will cause the package to be# loaded when "package require" is executed, rather# than lazily when the first reference to an exported# procedure in the package is made.# -verbose (optional) Verbose output; the name of each file that# was successfully rocessed is printed out. Additionally,# if processing of a file failed a message is printed.# -load pat (optional) Preload any packages whose names match# the pattern. Used to handle DLLs that depend on# other packages during their Init procedure.# dir - Name of the directory in which to create the index.# args - Any number of additional arguments, each giving# a glob pattern that matches the names of one or# more shared libraries or Tcl script files in# dir.proc pkg_mkIndex {args} { global errorCode errorInfo set usage {"pkg_mkIndex ?-direct? ?-lazy? ?-load pattern? ?-verbose? ?--? dir ?pattern ...?"}; set argCount [llength $args] if {$argCount < 1} { return -code error "wrong # args: should be\n$usage" } set more "" set direct 1 set doVerbose 0 set loadPat "" for {set idx 0} {$idx < $argCount} {incr idx} { set flag [lindex $args $idx] switch -glob -- $flag { -- { # done with the flags incr idx break } -verbose { set doVerbose 1 } -lazy { set direct 0 append more " -lazy" } -direct { append more " -direct" } -load { incr idx set loadPat [lindex $args $idx] append more " -load $loadPat" } -* { return -code error "unknown flag $flag: should be\n$usage" } default { # done with the flags break } } } set dir [lindex $args $idx] set patternList [lrange $args [expr {$idx + 1}] end] if {[llength $patternList] == 0} { set patternList [list "*.tcl" "*[info sharedlibextension]"] } set oldDir [pwd] cd $dir if {[catch {eval glob $patternList} fileList]} { global errorCode errorInfo cd $oldDir return -code error -errorcode $errorCode -errorinfo $errorInfo $fileList } foreach file $fileList { # For each file, figure out what commands and packages it provides. # To do this, create a child interpreter, load the file into the # interpreter, and get a list of the new commands and packages # that are defined. if {[string equal $file "pkgIndex.tcl"]} { continue } # Changed back to the original directory before initializing the # slave in case TCL_LIBRARY is a relative path (e.g. in the test # suite). cd $oldDir set c [interp create] # Load into the child any packages currently loaded in the parent # interpreter that match the -load pattern. if {[string length $loadPat]} { if {$doVerbose} { tclLog "currently loaded packages: '[info loaded]'" tclLog "trying to load all packages matching $loadPat" } if {![llength [info loaded]]} { tclLog "warning: no packages are currently loaded, nothing" tclLog "can possibly match '$loadPat'" } } foreach pkg [info loaded] { if {! [string match $loadPat [lindex $pkg 1]]} { continue } if {$doVerbose} { tclLog "package [lindex $pkg 1] matches '$loadPat'" } if {[catch { load [lindex $pkg 0] [lindex $pkg 1] $c } err]} { if {$doVerbose} { tclLog "warning: load [lindex $pkg 0] [lindex $pkg 1]\nfailed with: $err" } } elseif {$doVerbose} { tclLog "loaded [lindex $pkg 0] [lindex $pkg 1]" } if {[string equal [lindex $pkg 1] "Tk"]} { # Withdraw . if Tk was loaded, to avoid showing a window. $c eval [list wm withdraw .] } } cd $dir $c eval { # Stub out the package command so packages can # require other packages. rename package __package_orig proc package {what args} { switch -- $what { require { return ; # ignore transitive requires } default { eval __package_orig {$what} $args } } } proc tclPkgUnknown args {} package unknown tclPkgUnknown # Stub out the unknown command so package can call # into each other during their initialilzation. proc unknown {args} {} # Stub out the auto_import mechanism proc auto_import {args} {} # reserve the ::tcl namespace for support procs # and temporary variables. This might make it awkward # to generate a pkgIndex.tcl file for the ::tcl namespace. namespace eval ::tcl { variable file ;# Current file being processed variable direct ;# -direct flag value variable x ;# Loop variable variable debug ;# For debugging variable type ;# "load" or "source", for -direct variable namespaces ;# Existing namespaces (e.g., ::tcl) variable packages ;# Existing packages (e.g., Tcl) variable origCmds ;# Existing commands variable newCmds ;# Newly created commands variable newPkgs {} ;# Newly created packages } } $c eval [list set ::tcl::file $file] $c eval [list set ::tcl::direct $direct] # Download needed procedures into the slave because we've # just deleted the unknown procedure. This doesn't handle # procedures with default arguments. foreach p {pkg_compareExtension} { $c eval [list proc $p [info args $p] [info body $p]] } if {[catch { $c eval { set ::tcl::debug "loading or sourcing" # we need to track command defined by each package even in # the -direct case, because they are needed internally by # the "partial pkgIndex.tcl" step above. proc ::tcl::GetAllNamespaces {{root ::}} { set list $root foreach ns [namespace children $root] { eval lappend list [::tcl::GetAllNamespaces $ns] } return $list } # init the list of existing namespaces, packages, commands foreach ::tcl::x [::tcl::GetAllNamespaces] { set ::tcl::namespaces($::tcl::x) 1 } foreach ::tcl::x [package names] { set ::tcl::packages($::tcl::x) 1 } set ::tcl::origCmds [info commands] # Try to load the file if it has the shared library # extension, otherwise source it. It's important not to # try to load files that aren't shared libraries, because # on some systems (like SunOS) the loader will abort the # whole application when it gets an error. if {[pkg_compareExtension $::tcl::file [info sharedlibextension]]} { # The "file join ." command below is necessary. # Without it, if the file name has no \'s and we're # on UNIX, the load command will invoke the # LD_LIBRARY_PATH search mechanism, which could cause # the wrong file to be used. set ::tcl::debug loading load [file join . $::tcl::file] set ::tcl::type load } else { set ::tcl::debug sourcing source $::tcl::file set ::tcl::type source } # As a performance optimization, if we are creating # direct load packages, don't bother figuring out the # set of commands created by the new packages. We # only need that list for setting up the autoloading # used in the non-direct case. if { !$::tcl::direct } { # See what new namespaces appeared, and import commands # from them. Only exported commands go into the index. foreach ::tcl::x [::tcl::GetAllNamespaces] { if {! [info exists ::tcl::namespaces($::tcl::x)]} { namespace import -force ${::tcl::x}::* } # Figure out what commands appeared foreach ::tcl::x [info commands] { set ::tcl::newCmds($::tcl::x) 1 } foreach ::tcl::x $::tcl::origCmds { catch {unset ::tcl::newCmds($::tcl::x)} } foreach ::tcl::x [array names ::tcl::newCmds] { # determine which namespace a command comes from set ::tcl::abs [namespace origin $::tcl::x] # special case so that global names have no leading # ::, this is required by the unknown command set ::tcl::abs \ [lindex [auto_qualify $::tcl::abs ::] 0] if {[string compare $::tcl::x $::tcl::abs]} { # Name changed during qualification
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -