package require

Difference between version 37 and 38 - Previous - Next
'''[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 onexact
version specified version 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.

<<categories>> Command