'''[package] require''' evaluates a script when a certain package is required and then ensures that the package is present. ** Synopsis ** '''[package] require''' ''?-'''''exact'''''? package ?version?'' ** Description ** `package require` evaluates a script that must [package provide%|%provide] the requested package. If a version specification is provided, only a matching version is selected. `package require` returns the version that was provided, or an error. If both the '''`-exact`''' and '''''version''''' are provided then only the exact version specified is acceptable. If `-exact` is omitted but ''version'' is specified, any version is acceptable whose major version is the same as ''version'' and whose minor version is equal to or greater than ''version''. If both `-exact` and ''version'' are omitted then any version is acceptable. If a matching version has already been provided, its version number is returned and no other action is taken. To find the required package, `[package require]` selects the highest acceptable version in a database that is built from calls to `[package ifneeded]` in `[pkgIndex.tcl]` files the first time a `package` routine is called. `[pkgIndex.tcl]` files are searched for in directories given in `[auto_path%|%$auto_path]`, and in their immediate subdirectories. To provide the required package, `[package require]` evaluates the selected script in the [global] namespace. The script must call `package provide` with the proper version. If the '''[package ifneeded]''' database does not contain an acceptable version of the package and a '''[package unknown]''' command has been registered then that command is evaluated in the [global] namespace, after which `[package require]` looks for the package in the database again. ** Reloading a package ** [HD]: Here's something I use all the time: ====== proc reloadPkg pkg { eval [package ifneeded $pkg [package require $pkg]] } ====== Example: ======none package require XYZ # Discover bug in package # Fix it in editor reloadPkg XYZ ====== ** Origin of a Package ** [escargo] 2003-11-20 [PYK] 2020-04-28: Is there a way to determine the provenance of a package? I have a script cals '''package require snit 0.9''' and the value returned is '''0.82''', and it is not at all obvious where that value is coming from. '''[DGP]''' Use [package ifneeded] to discover what script was used to load a package. ====== package ifneeded snit [package require snit] ====== That will return the script that loaded snit, which likely looks something like: ====== source /absolute/path/to/snit/snit.tcl ====== Is that what you were asking? [escargo]: Yes, modulo the correction of `[package provide]` to `package require` in the snippet above. I'm running some experimental [Snit] code which is at version 0.9; the version in [tcllib] 1.5 is 0.82 which seems to satisfy a `package require snit 0.9`. '''[DGP]''': My original code assumed you already had snit loaded in your interp. In that case, `[package provide]` (or even `[package present]`) is better than `[package require]`. And yes, 82 > 9, so 0.82 is a later release than 0.9. Any package developer that means 0.8.2 should say so. ---- But what about the developer who thought that 82 would be less than 90 ? '''[DGP]''' 82 is less than 90, and `[package]` knows it. It also knows that 9 and 90 are different values: ======none % package vcompare 0.82 0.9 1 % package vcompare 0.82 0.90 -1 % package vcompare 0.9 0.90 -1 % package vcompare 0.90 0.90 0 ====== ** Guidelines for Package Development ** '''reloadable''': `[package forget]` removes from an interpreter information that the package is loaded, but does not undo the effects of loading the package. A subsequent `[package require]` causes the load script for the package to be evaluated again. This is useful for updating a package in a running interpeter. Due to this feature, a load script should not attmpt to initialize the loaded package, as it may already have been initialized. A package should, however, determine at load time whether a backwards-incompatible version is being load, and make the required changes in-place to any relevant initialized objects. Alternatively, the package could refuse to reload if loading can't safely be performed. ** Questions ** [LV]: When writing Tcl package `A` that has dependencies on other packages, where is the best place to put the `package require` statements? In the `[pkgIndex.tcl]` for `A`, or in the ''A.tcl'', i.e. the file that `A`'s `pkgIndex.tcl` loads? What are the pros and cons for doing it each way? [Lars H]: Code in `pkgIndex.tcl` is evaluated the first time that Tcl searches for packages. This means that if you put a `package require` there, and provided the `[package ifneeded]` scripts are of the usual kind, then the required packages are loaded ''as soon as any package'' (not just yours) ''is required''. That is '''bad'''. Thus you should put the [[package require]] in your ''A.tcl''. ''[MGS]'' 2004-12-11: I put the `pkgIndex.tcl` file in the main package directory, then create a Tcl directory to contain all the Tcl files. See [http://tip.tcl.tk/55%|%TIP 55]. The `pkgIndex.tcl` points at `tcl/pkginit.tcl` which contains a single proc pkginit_ (in the package namespace) which sets package variables, requires dependent packages, then manually adds to the ::auto_index array (from the tcl/tclIndex file) to setup auto-loading for all the package procs, provides the specified package, then deletes its own proc. This way, package require'ing a package does not create any procs (except for initializing auto_loading), and only creates the package namespace with package variables in it. I think the pkgIndex.tcl file should be as simple as possible, and could (if necessary) be auto-created by some package repository. You can see examples of my structure in most of my packages at: [http://www.binarism.com/tcl/] and [http://www.binarism.com/tk/] [LV]: Here's a followup question. In [Img] 1.2 , the pkgIndex.tcl says: package ifneeded Img 1.2.4 "package require Tk; [list load [file join $dir libimg1.2.so] Img]" Based on your comments above, this should have the effect that anyone doing any package require would have to have a `[env%|%$DISPLAY]` variable set or the statement would fail. But that doesn't seem to have been my experience. Right now I can't duplicate the situation due to having [Img] 1.3 installed, which does the `pkgIndex.tcl` differently. Can someone else comment on this situation? [Lars H]: OK, perhaps I should have been clearer. In this case, the "package require" is not technically a command in the `pkgIndex.tcl` file, but merely part of a string. It is tucked away as the `[package ifneeded]` script of the [Img] package and thus does not get evaluated until someone does `package require Img`, so this is not bad. However had it been ====== package require Tk package ifneeded Img 1.2.4 [list load [file join $dir libimg1.2.so] Img] ====== then it would have been very bad. ---- [LV]: Recently [sbron%|%Schelte Bron] emailed me after reading a comment I'd posted in comp.lang.tcl, with this little Tcl example: ======none % package require bwidget can't find package bwidget % lsearch -inline -all -regexp [package names] (?iq)bwidget BWidget ====== In other words, if you don't know what sequence of upper and lower case characters a package developer has used, the above [lsearch], after a package require has finished, can provide that to you. ---- uwe posted this proc in response to the discussion about trying to figure out what case a particular extension used: ====== proc loadwhatimean packname { if {[catch {package require $packname} cerr]} { set whatwehave [package names] set found [lsearch -inline -regexp $whatwehave ***:(?i)$packname] puts stderr "required: $packname found : $found" if {$found ne {}} { return [package require $found] } else { puts stderr bahh # error or return -errorcode ..? } } return $cerr } ====== ---- '''[LV] 2007-10-18:''' I'd really like to know what kinds of code you've found helpful in tracking down problems getting packages to load. Example: I have a package installed in a directory. Other packages in sibling directories are loaded when I run a `package require`. However, when this one package require is invoked, I get ====== % package require TclOO can't find package TclOO % ====== How can I go about determining ''why'' this is not loading? There's a pkgIndex.tcl in a sub-directory in the [auto_path] variable. ---- '''[LV] 2007-10-26''' Here's a script that I have started writing. The intent is to do a `package require` on each package that a particular [tclsh] knows, reporting the success or failure. ====== #! /tmp/.lwv/ActiveTcl-8.5/bin/tclsh8.5 catch {package require lwvNotThere} set plist [package names] foreach package $plist { set rc [catch {set version [package require $package]} result options] puts "package require $package load rc: $rc result: $result options: $options" } ====== ---- [LV] 2008-03-28 Recently on comp.lang.tcl, I read: === > Actually it is a problem in one of my packages. Inside a pkgIndex.tcl, I > was doing "catch {package require some-package}". Never, never do that. No index script should make use of the [package require] command. If you need to test for the presence of a pre-requisite package, use [package present] or [package provide] to do that. See also Tcl Bug 1805928 and http://wiki.tcl.tk/5900 . === So, I then ran $ find /path/to/ActiveTcl-8.5/lib/. -name pkgIndex.tcl -print | xargs grep 'package.*require' > /tmp/pr.txt and found a large number of hits for this. I took a look and saw that the predominant use of package require was some variation of === package require Tcl 8.4 === However, after that was eliminated, I found a couple of dozen occurrences where Tk was the object of the package require, and then, after that, just over a dozen instances of package requiring img::base, followed by some cases of zlibtcl, or one of the struct packages from tcllib, etc. I am just wondering whether these cases are unsafe or whether the ''no index script should make use...'' statement means something else that I just am missing. ---- ** Page Authors ** [pyk]: Various editorial changes. <> Command