Can't find package from application written in Tcl

社会主义新天地 提交于 2020-05-17 06:22:06

问题


Thanks to the comments, better understand the problem a bit. The variables:

thufir@dur:~/tcl/packages$ 
thufir@dur:~/tcl/packages$ echo 'puts $auto_path' | tclsh
/usr/share/tcltk/tcl8.6 /usr/share/tcltk /usr/lib /usr/local/lib/tcltk /usr/local/share/tcltk /usr/lib/tcltk/x86_64-linux-gnu /usr/lib/tcltk /usr/lib/tcltk/tcl8.6
thufir@dur:~/tcl/packages$ 
thufir@dur:~/tcl/packages$ echo 'puts $tcl_pkgPath' | tclsh
/usr/local/lib/tcltk /usr/local/share/tcltk           /usr/lib/tcltk/x86_64-linux-gnu /usr/lib/tcltk /usr/share/tcltk         /usr/lib/tcltk/tcl8.6 /usr/lib
thufir@dur:~/tcl/packages$ 

code:

thufir@dur:~/tcl/packages$ 
thufir@dur:~/tcl/packages$ ll
total 16
drwxrwxr-x 2 thufir thufir 4096 May  4 02:22 ./
drwxrwxr-x 6 thufir thufir 4096 May  4 02:22 ../
-rw-rw-r-- 1 thufir thufir  215 May  4 02:21 foo.tcl
-rw-rw-r-- 1 thufir thufir 1207 May  4 02:20 tutstack.tcl
thufir@dur:~/tcl/packages$ 
thufir@dur:~/tcl/packages$ cat foo.tcl 
package require tutstack 1.0

set stack [tutstack::create]
foreach num {1 2 3 4 5} { tutstack::push $stack $num }

while { ![tutstack::empty $stack] } {
    puts "[tutstack::pop $stack]"
}

tutstack::destroy $stack
thufir@dur:~/tcl/packages$ 
thufir@dur:~/tcl/packages$ cat tutstack.tcl 
# Register the package
package provide tutstack 1.0
package require Tcl      8.5

# Create the namespace
namespace eval ::tutstack {
    # Export commands
    namespace export create destroy push pop peek empty

    # Set up state
    variable stack
    variable id 0
}

# Create a new stack
proc ::tutstack::create {} {
    variable stack
    variable id

    set token "stack[incr id]"
    set stack($token) [list]
    return $token
}

# Destroy a stack
proc ::tutstack::destroy {token} {
    variable stack

    unset stack($token)
}

# Push an element onto a stack
proc ::tutstack::push {token elem} {
    variable stack

    lappend stack($token) $elem
}

# Check if stack is empty
proc ::tutstack::empty {token} {
    variable stack

    set num [llength $stack($token)]
    return [expr {$num == 0}]
}

# See what is on top of the stack without removing it
proc ::tutstack::peek {token} {
    variable stack

    if {[empty $token]} {
    error "stack empty"
    }

    return [lindex $stack($token) end]
}

# Remove an element from the top of the stack
proc ::tutstack::pop {token} {
    variable stack

    set ret [peek $token]
    set stack($token) [lrange $stack($token) 0 end-1]
    return $ret
}
thufir@dur:~/tcl/packages$ 
thufir@dur:~/tcl/packages$ tclsh foo.tcl 
can't find package tutstack 1.0
    while executing
"package require tutstack 1.0"
    (file "foo.tcl" line 1)
thufir@dur:~/tcl/packages$ 

to my understanding, I need to compile a list or map of where packages are.


回答1:


The problem is that Tcl is not finding the index file (which should be called pkgIndex.tcl) for your package. If you had implemented the weather 1.0 package as a file weather.tcl, then you'd probably be looking to have an index file something like this in the same directory:

package ifneeded weather 1.0 [list source [file join $dir weather.tcl]]

That says “to load version 1.0 of the weather package, run this script” where the script is generated at runtime and binds $dir in (which is a variable always defined in the context where package index loader runs package ifneeded).

Once that's there, you need to allow Tcl to find the index file. This can be done by putting that directory or its immediate parent on the Tcl global auto_path list; either do that inside your script before you load any packages (very useful for applications that have internal packages) or you can initialise that from outside of Tcl too by setting the TCLLIBPATH environment variable. Note that the value of that variable is a Tcl list of directories, not a system path like env(PATH). This matters if you have backslashes or spaces in directory names, or if you want to have multiple elements on the list. Fortunately, you can usually avoid all of these issues in the case of adding a single directory as an environment variable, even on Windows, by using / instead of \ and by following usual installation practice and not putting a space in names. When adding a path during application launch it's easier: you just use lappend, perhaps like this (very early in your main script):

lappend auto_path [file join [file dirname [info script]] my_app_pacakges]
# If the script is in foo/bar.tcl then packages are in or below foo/my_app_packages



回答2:


result which runs:

thufir@dur:~/tcl/foo$ 
thufir@dur:~/tcl/foo$ tree
.
├── api
│   ├── pkgIndex.tcl
│   └── tutstack.tcl
└── main.tcl

1 directory, 3 files
thufir@dur:~/tcl/foo$ 
thufir@dur:~/tcl/foo$ cat main.tcl 
lappend auto_path /home/thufir/tcl/foo/api
package require tutstack 1.0


set stack [tutstack::create]
foreach num {1 2 3 4 5} { tutstack::push $stack $num }

while { ![tutstack::empty $stack] } {
    puts "[tutstack::pop $stack]"
}

tutstack::destroy $stack
thufir@dur:~/tcl/foo$ 
thufir@dur:~/tcl/foo$ cat api/pkgIndex.tcl 
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

package ifneeded tutstack 1.0 [list source [file join $dir tutstack.tcl]]
thufir@dur:~/tcl/foo$ 
thufir@dur:~/tcl/foo$ cat api/tutstack.tcl 
# Register the package
package provide tutstack 1.0
package require Tcl      8.5

# Create the namespace
namespace eval ::tutstack {
    # Export commands
    namespace export create destroy push pop peek empty

    # Set up state
    variable stack
    variable id 0
}

# Create a new stack
proc ::tutstack::create {} {
    variable stack
    variable id

    set token "stack[incr id]"
    set stack($token) [list]
    return $token
}

# Destroy a stack
proc ::tutstack::destroy {token} {
    variable stack

    unset stack($token)
}

# Push an element onto a stack
proc ::tutstack::push {token elem} {
    variable stack

    lappend stack($token) $elem
}

# Check if stack is empty
proc ::tutstack::empty {token} {
    variable stack

    set num [llength $stack($token)]
    return [expr {$num == 0}]
}

# See what is on top of the stack without removing it
proc ::tutstack::peek {token} {
    variable stack

    if {[empty $token]} {
    error "stack empty"
    }

    return [lindex $stack($token) end]
}

# Remove an element from the top of the stack
proc ::tutstack::pop {token} {
    variable stack

    set ret [peek $token]
    set stack($token) [lrange $stack($token) 0 end-1]
    return $ret
}
thufir@dur:~/tcl/foo$ 
thufir@dur:~/tcl/foo$ tclsh main.tcl 
5
4
3
2
1
thufir@dur:~/tcl/foo$ 

generating the config file:

thufir@dur:~/tcl/foo/api$ 
thufir@dur:~/tcl/foo/api$ tclsh
% 
%                                             
% pkg_mkIndex . *.tcl
% 
% exit
thufir@dur:~/tcl/foo/api$ 


来源:https://stackoverflow.com/questions/61587687/cant-find-package-from-application-written-in-tcl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!