Recently I found that if package require is evaluated with not existing package name and one of pkgIndex files in auto_path again contains package require with not existing package then tclPkgUnknown enters infinite recursion.
I wonder is it not allowed to eval package require from pkgIndex or this is a hidden bug?
A pkgIndex.tcl file should never run package require itself. It should just call package ifneeded to tell the package management system how to load a particular version of a particular package. This is because the index scripts are loaded at times that are rather different — during package discovery — and not necessarily at the point when that version of the package is really wanted. If you stick to this rule, you won't have any problems.
Here's the sort of thing that ought to be in there.
# Maybe some comments here?
package ifneeded Foo 1.2.3 [list source [file join $dir foo.1-2-3.tcl]]
The $dir? That's just the name of the directory containing the index file, for convenience sake. (It's actually a local variable too; the index files are evaluated inside a procedure context.)
Related
It will be easier to explain using an example in C. When you build an application in C(or C++, etc) you can build a "release" one that would not include some code that you would have in an none release one. Ex: test code, etc.
I'm trying to do similar in TCL. We have some tracing functions that I would like to be empty shell when in "release".
So I thought I could use two different package to do that and use one in release and one in designer so designer could use a "define" or something similar.
I know I could also "replace" each functions using "rename" and "alias" but my application start many threads(and there is one interpreter per thread) so I would have to replace multiple functions in multiple threads and that make things more complicated, I think. I thought that instead using two different package would do a "one shot solve them all" kind of solution.
Thanks
One of the simplest techniques is to put some extra magic in the pkgIndex.tcl script for the package. Usually it looks something like (cookiejar is a little package I wrote that's in 8.7):
package ifneeded cookiejar 0.1 [list source [file join $dir cookiejar.tcl]]
But if you want to make things more conditional, you can do instead:
if {[info exist ::developermode]} { # Or however you want to detect it!
package ifneeded cookiejar 0.1 [list source [file join $dir cookiejar-dev.tcl]]
} else {
package ifneeded cookiejar 0.1 [list source [file join $dir cookiejar-release.tcl]]
}
You can then have two implementations, one a version for development and another for release; in your case, the release version should probably be just some empty stand in functions that provide the same API but do nothing. (You could not provide any commands at all, or make things inconsistent, but that's likely to cause code that works in development to fail in prod.)
If it helps, note that if you define a procedure like this:
proc someCommand {args} {}
(That is, it just takes args as its formal argument and has an empty body.) then Tcl will make that procedure be removed entirely from the runtime bytecode of your procedures that use it. This is probably going to be very useful to you; it lets your production code refer to your debugging helpers, yet have no (meaningful) cost for doing so.
I loaded a package first:
package require Tktable
then i wanted to unload this package. I searched some info, and used "package ifneeded" to get the library path. I tried as below:
unload $path Tktable
but i got error message "cannot be unloaded under a trusted interpreter". How to unload a package?
Most packages do not support unloading at all. (Specifically, Tktable does not; it doesn't define either a Tktable_Unload function or a Tktable_SafeUnload function in its public C API.) Unloading is rare as it requires the author of the C code to take special care to ensure that it is possible at all, and most of the time programmers have other higher-priority concerns.
Unloading is disabled in safe interpreters, as it is considered to be an insecure operation. (load is also not supported, but is often profiled in restricted fashion by the parent master interpreter, such as via package require doing clever things behind the scenes.)
If the problem is that some package is interfering with your code (as seems to be the case from your comments), put your code in a namespace. There's often an easy way to pick the namespace name, typically the name of your application or library works fine. If you're wanting to call your code the same thing as someone else's and their code is more well-known than yours, that's going to cause you trouble anyway.
I have a strange problem I am using fedora 20 and installed tcllib on my system.
But if I use package require uri in example I got an package not found in response.
Does anyone know what the issue here is or how to determine if the tcllib is added in the package index?
Tcl looks up packages in two ways: with auto_path and with tcl::tm::path.
1. The auto_path — the traditional mechanism.
When you do package require, the package manager looks to see if the package is already present, or if instructions for obtaining the package from the filesystem are present. If neither of these is true, it asks the package unknown handler to load it (strictly, it's the handler installed using the package unknown command). The default implementation of that handler loads packages by looking for pkgIndex.tcl files in the directories on your auto_path, and their immediate subdirectories.
auto_path is a global variable holding a Tcl list of directories to search. You can probably just lappend the right place to it. pkgIndex.tcl is a Tcl script that describes how to make the package available, which it does by calling an appropriate package ifneeded command. The actual loading of the
Once a package is required that isn't present but its instructions for obtaining are, Tcl will simply eval those instructions: they're just a plain old script (that usually just calls source and/or load to do the grunt work).
2. Tcl modules — the new (in 8.5) mechanism.
The Tcl module system uses a different search system managed with the tcl::tm::path command. The tcl::tm::path list subcommand will tell you where it looks (a huge list, to be honest) and you can use the tcl::tm::path add subcommand to extend the path with extra locations to search. Tcl modules have the entire package placed into a single file (with the extension .tm) and have a structured name so that they can avoid having a separate pkgIndex.tcl file; the TM loader can synthesise the package ifneeded calls from the filename itself (in all cases, this is done with source; there are some clever ways to package binary code inside files so they can be loaded, but they're far outside the scope of this answer).
At that point, you're back to the source of the file when the package is actually required; that part is the same whether you're using a module or a traditional package.
The module system is much faster than the traditional search mechanism since it doesn't need to open any files to figure out what to do: it just uses glob with the right options. It is, however, less flexible in how things can be packaged: multi-file packages (e.g., almost anything you make yourself) can't be made into modules (well, not without extra work).
I want to know about modular programming in tcl and how we can achieve that .
In some tcl tutorials mention like source command having some drawbacks in achieving "modularity" so that we came to the "package" after that "package" is having some more drawbacks so that we came with the combination of package and namespaces .
I want to know what are the drawbacks and proper hierarchy of 3 concepts . Can Anyone help me ?
I'm not sure if I understand your question correctly, so I'll try to explain the 3 commands you throwed in your question:
source: Evaluates a file as a Tcl script. -
It simply opens the file, reads until the EOF character (^Z on both windows and *nix) and evaluates it.
It does not keep track of sourced files, so you can source the same file again (great for hotpatching), but this is the drawback: It will source the file again.
package: Manages packages. It basically keeps track of the provided packages and tries to figure out which file it has to source to load a new package.
namespace: They provide context for commands and variables, so you don't have to worry about unique names for your commands. Just the namespace has to be unique. Has nothing to do with loading packages or other modules, it just provides namespaces.
I suggest that you use packages, each package in it's own file, each package with a namespace equal to the package name where all commands reside.
You should export the public commands with namespace export.
I have a problem with changing tcl version from 8.4 to 8.5.12 on RHEL machine. Our product uses TclDevKit components like Tcldom, Tclxml, etc. Also we are using Incr Tcl (Itcl). I am trying to create pkgIndex.tcl file in Itcl in order to find Itcl when that package is required as follown:
package ifneeded Itcl 3.4 [list load [file join $dir "libitcl-O.a"] Itcl ]
but when I use
package require Itcl
Getting report: couldn't load file "/somepath/itcl/lib/libitcl-O.a": /somepath/lib/libitcl-O.a: invalid ELF header
It seems I can't load files with .a extention, but the same is done with previous version of tcl (8.4) and it works fine. I googled a lot, read a lot of documentation, but it doesn't help to go further.
Please help.
Thanks in advance
Libraries come in two general sorts, static libraries and shared libraries. On Linux, static libraries have the extension .a by default, and shared libraries have the extension .so (plus optionally some numbers to indicate the version). Only shared libraries will work with Tcl's load command and even then they have to be designed to work that way (with an appropriate Foobar_Init function, as documented).
When dealing with stub-exporting extensions (fairly rare) or Tcl and Tk themselves, the linking is done in two parts. There's a stub library, normally called somethingstub.a, and there's a main shared library. The main shared library contains the implementation of the code; all that is in the stub library is an ABI/API adaptor so that you can avoid binding your code to an explicit version of the implementation library. By building an extension stub-enabled and linking against the stub library, you gain the ability to have your extension loaded into future versions of Tcl/Tk without any recompilation or relinking steps at all. (You also become able to put the extension inside a starkit for deployment, as those use a rather unusual way of managing shared libraries that the stub mechanism conceals from you.)