0

i have many package requires which is used inside the tcl code as below:

package require tlautils 1.0
package require profilemanager
package require tla::log 1.2
package require res_mgr 1.1
package require resource 1.2
package require sysexits
package require utils 1.5
package require testutil 1.0
package require profilemgr
package require leakChecker
package require testutil

what is the alternative to use instead of using so many package requires? this is taking time and i am in search of any other alternatives for package require whcih increases the time in seconds/miliseconds

Peter Lewerin
  • 13,140
  • 1
  • 24
  • 27
vinay
  • 53
  • 1
  • 8
  • I once built a rather big itcl application. I wrote a source file whose only purpose was to source or load whatever files may be needed, before using the application. This avoids to use `pkgIndex.tcl` files which load packages only when needed and can cause delays, but of course the application was less modular. I don't remember if this had a true positive impact on performance. The main motivation was to avoid package errors during runtime. – b2vincent Dec 20 '16 at 14:54

1 Answers1

3

The package require lines don't really take much longer than the load and source calls that they delegate to (all the packages are doing is stopping you from having to hard-code paths to everything, taking care of all the details of versions and so on). However, when you do package require of a package whose name is not already known, Tcl has to actually search for the pkgIndex.tcl files that describe how to actually load the packages. It does this by calling the code that you can look up (or replace if necessary) using package unknown, and that's actually really quite slow. Depending on the TCLLIBPATH environment variable's contents, it could be extremely slow.

But we can “compile” that so that we will be able to source a single file and be able to load these specific packages on this machine quickly.

To do that, we need the above package requires and a bit of extra wrapping code:

package require tlautils 1.0
package require profilemanager
package require tla::log 1.2
package require res_mgr 1.1
package require resource 1.2
package require sysexits
package require utils 1.5
package require testutil 1.0
package require profilemgr
package require leakChecker
package require testutil

set f [open "pkgdefs.tcl" w]
foreach pkg [package names] {
    # Skip the packages built directly into Tcl 8.6
    if {$pkg in {zlib TclOO tcl::tommath Tcl}} continue

    # Get the actual loaded version; known but absent would be an error
    if {[catch {package present $pkg} version]} continue

    # Get the actual script that we'd run to load the package.
    set script [package ifneeded $pkg $version]

    # Add to the file
    puts $f [list package ifneeded $pkg $version $script]
}
close $f

Once you've run that, you'll have a script in pkgdefs.tcl that you can source. If in future runs you source it before doing any of those package require calls that you listed, those package require calls will be fast. (This also includes any packages that are dependencies of the ones you list.) However, if you ever install new packages to use in the list, or update the versions of the packages, or move them around, you'll need to rebuild the list: it makes your code quite a lot more inflexible, which is why we don't do it by default.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215