Where does the package command find the packages it seeks?

Wherever the script registered with package unknown is programmed to look. That is, this is completely application configurable.


MG Slightly related, you can check which files were loaded/sourced by a package by using package ifneeded:

 (User) 1 % package require Tk
 8.4
 (User) 2 % package ifneeded Tk 8.4
 load {C:/Program Files/Tcl/lib/tk8.4/../../bin/tk84.dll} Tk

Thanks to a pointer from DGP on Tcl chat about the use of package unknown, here is a proc to return the command that will be used to load a package without actually loading it. If you do not mind the package being loaded, you could just do package ifneeded foo package require foo instead.

proc get_package_load_command {name} {
    # Get the command to load a package without actually loading the package
    #
    # package ifneeded can return us the command to load a package but
    # it needs a version number. package versions will give us that
    set versions [package versions $name]
    if {[llength $versions] == 0} {
        # We do not know about this package yet. Invoke package unknown
        # to search
        {*}[package unknown] $name
        # Check again if we found anything
        set versions [package versions $name]
        if {[llength $versions] == 0} {
            error "Could not find package $name"
        }
    }
    return [package ifneeded $name [lindex $versions 0]]
}

Klaus Saalfeld Sometimes one prefers a non-flat directory structure to contain all packages. Directories can be used to group related packages. E.g. all GUI related packages can be put into one directory, all Web related packages into another directory, utilities into a third one and so on. This improves structure of big projects that use a lot of packages.

if {![package vsatisfies [package provide Tcl] 8.5]} {return}

if {0 != [string length [info script]]} {
   # Note that we must take care that we do not source this file recursively.
   # Therefore we can't start with the directory containing this script.
   set dirs [glob -nocomplain -directory [file dirname [info script]] -types d *]
   # Loop through directories sourcing all libraries
   while {0 != [llength $dirs]} {
      # Get next directory and remove it from list
      set dir [lindex $dirs 0]
      set dirs [lreplace $dirs 0 0]
      # Work with current directory selection here.
      # We want to source all packages within the directory tree.
      # We stop diving deeper into the directory tree
      # as soon as there is a pkgIndex.tcl file.
      catch {
         if {[file exists [file join $dir "pkgIndex.tcl"]]} {
            # The script sourced expects $dir to be its location directory
            source [file join $dir "pkgIndex.tcl"]
         } else {
            # There is no pkgIndex.tcl file in current directory.
            # Continue checking all subdirectories of current directory.
            set dirs [concat $dirs [glob -directory $dir -types d *]]
         }
      }
   }
   unset dirs
}

This is the contents of a special pkgIndex.tcl file. Put it into top-level directories within lib (or that place Tcl looks for packages). The script recursively searches sub-directories for packages and source their pkgIndex.tcl. It stops diving deeper into a directory branch as soon as a pkgIndex.tcl has been found. This is an example:

 lib
 lib/gui/pkgIndex.tcl (*)
 lib/gui/<package_1>/pkgIndex.tcl
 lib/gui/<package_2>/pkgIndex.tcl
 ...
 lib/util/pkgIndex.tcl (*)
 lib/util/string/<package_1>/pkgIndex.tcl
 lib/util/string/<package_2>/pkgIndex.tcl
 lib/util/list/<package_1>/pkgIndex.tcl
 lib/util/list/<package_2>/pkgIndex.tcl
 ...

(*) Put the special pkgIndex.tcl there