tcl - how to find the path of package loaded? - tcl

In tcl how does one find out the path of the package loaded?
% tclsh
% package require csv
I want to find out the path from which csv was loaded.
In python, one can find the path of a module using
>>> import os
>>> print os.__file__
'/a/b/python2.2.1/linux26_x86_64/lib/python2.2/os.pyc'
I am looking for a similar command in tcl

It's not that simple: a package in Tcl appears to be a more abstract thing than that in Python.
First, there are two kinds of packages: "classic" and "modules" which have different underlying mechanisms for finding what to load in response to the package require ... command.
Next, both kinds of packages are able to do whatever they wish to provide their functionality. It means they can be (but not limited to):
Pure Tcl packages, source'ing just one Tcl file or any number of files.
Packages implemented in C or another compiled language, which are in the form of dynamic library which gets loaded when the package is required.
A combination of the above, when there's a C library and a layer of Tcl code around it (usually providing helper/convenience commands).
Hence the question per se has little sense as only modules are represented by exactly one self-contained file but "classic" packages are free to implement themselves as they see fit.
On the other hand, each package normally provides (using one way or another) certain information to the package subsystem which can be retreived (and parsed) using the package ifneeded command. For instance, on my Windows system with ActiveState Tcl 8.5.x, I have:
% package require csv
0.7.2
% package ifneeded csv 0.7.2
package provide csv 0.7.2;source -encoding utf-8 {C:/Program Files/Tcl/lib/teapot/package/tcl/teapot/tcl8/8.3/csv-0.7.2.tm}
Note that what package ifneeded returns is just a Tcl script which is meant to be evaluated to get the package loaded, so parsing of this information is bound to be inherently ad-hoc and fragile.

For Tcl packages you can view list of all loadedable path dirs by command:
join $::auto_path \n

This manual addresses auto_path and other loadable library variables: https://www.systutorials.com/docs/linux/man/n-auto_path/
New or missing loadable package search directory can be added within tclsh:
lappend auto_path /new_directoty

Related

Mapping libraries modelsim

I am trying to map libraries using a do file in ModelSim PE 10.4a and am having trouble making them local to the project. E.g. I don't want to hard-code the commands for changing directories to compile sources into a working directory there, but I would be okay with providing a path to the .do/.tcl file that would define a static library or something. For Xilinx core libs, the compiled sources don't move and I don't need to recompile so I can just have a hard mapping. However, I am developing some stuff for a project and want a nice way to map libraries and compile them. For unit tests, I don't mind using this hard-coded method. However, for projects where these locations may change or the directories apart from my libs may be far, what is a better way of doing what I have done below?
Below is how I compile my library (do_map_lfsr.do)
# 0) Create work directory for modelsim
vlib LFSR_lib
# 2) Compile files in use order
#vcom -93 -work work src/*.vhd
vcom -93 -work LFSR_lib GaloisLfsrBody.vhd
vcom -93 -work LFSR_lib LfsrPack.vhd
Below is the method I use to run this do file from the location of my testbench
# 1a) map/compile libs
# trying to find better way to do this
cd ../
do do_map_lfsr.do
cd unit_test/
vmap -modelsim_quiet LFSR_lib ../LFSR_lib
Is there a fancy way of finding and recompiling my libraries using .do/.tcl files and then mapping them for my development outside unit tests? Is there a way of defining a static library or something that doesn't disappear when I change directories?
For finding the files, the Tcllib find command (in the fileutil package) should be very useful.
package require fileutil
proc needsRecompiling {name} {
return [expr {[file extension $name] in {.do .tcl}}]
}
foreach filename [fileutil::find . needsRecompiling] {
if {[file extension $filename] eq ".do"} {
# Process the .do file here
} else {
# Process the .tcl file here
}
}
Of course, that assumes that you can just process each file independently; the order of listing isn't guaranteed (and likely depends on the order in the underlying directory node in the filesystem and things like that). If you need to do more complex things like matching files with different extensions, you'll need to write more code.

How to use ceylon js (also with google closure compiler)

Calling a file resulting from the concatenation (bash: cat ... >> app.js) of the following three files:
/usr/share/ceylon/1.2.0/repo/ceylon/language/1.2.0/ceylon.language-1.2.0.js
modules/com/example/helloworld/1.0.0/com.example.helloworld-1.0.0-model.js
modules/com/example/helloworld/1.0.0/com.example.helloworld-1.0.0.js
with the command nodejs app.js does nothing. The same when used in a web page. How do have I to call that javascript program so that it runs without using require.js ?
Please give the rules how ceylon modules and the run function and other functions contained within translate to javascript and are to be called.
How can I get one javascript file from compilation of several ceylon modules without concatenating them manually or with require.js?
The above is without using google closure compiler.
Given the size of 1.6 MB of the language module, it makes no sense to run ceylon-js without using google closure compiler.
Compiling "ceylon.language-1.2.0.js" alone with google closure compiler results in a lot of warnings.
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js /usr/share/ceylon/1.2.0/repo/ceylon/language/1.2.0/ceylon.language-1.2.0.js --js_output_file lib-compiled.js
How can I get rid of those warnings?
In what order do I have to chain together files resulting from ceylon-js with the model file and the language file to compile them in advanced mode with google closure compiler for dead code elimination.
These are 3 questions, really.
A Ceylon module is compiled to a CommonJS module. Concatenating the resulting files won't work because each file is on CommonJS format, which is a big function that returns an object with the exported declarations.
You can compile the modules with the --no-module option to get just the generated code, without it being wrapped in CommonJS format. For the language module, you can copy the file and just delete the first line and the last 5 lines.
I do not yet know how to get rid of the warnings you mention in the second question.
And as for the third question, I would recommend putting the language module first, then the rest of the files. If you have any toplevel declarations with the same name in different modules, you'll have conflicts (only the last declaration will remain), even if they're not shared, since they're all in the same module/unit.
Well, I think require.js can run the compilation of the modules to one file and then run the google-closure-compiler, see: http://www.requirejs.org/docs/optimization.html

How to access user-supplied command-line options in Tcl?

in the command line i m giving input as
filename option
here option starting with hyphen.
how to pass command line arguments starts with -
The list of all the arguments passed to the process hosting your Tcl interpreter can be accessed using the global variable argv, which you can iterate over and inspect.
Special packages implementing ready-made solutions for "declarative" parsing of command-line arguments exist, with cmdline being one example. Also search the wiki for alternatives.
I think, you need the cmdline package from tcllib.
Documentation is here
http://tcllib.sourceforge.net/doc/cmdline.html
Joachim

Need some explanation about package in TCL

I am having a little problem understanding the following command:
package ifneeded HelloWorld 1.0 [list source [file join $dir helloworld.tcl]]
in the pkgIndex.tcl,
I understand that when the pkgIndex.tcl is sourced and for example, we package require HelloWorld 1.0 , the helloworld.tcl will be sourced. I dont understand the list command...
The package ifneeded command is used to register (or query) how to make a package actually become present in a Tcl interpreter. This is done by evaluating a script, which is the argument generated with list in your example. Let's deconstruct it.
package ifneeded HelloWorld 1.0 [list source [file join $dir helloworld.tcl]]
---------------- ========== --- =============================================
command name package ver how to make it present,
name result of [list ...]
So far, so good. Now, a little aside: the list command is not just used for making lists, but it also makes guaranteed-substitution-free commands. That is, its result is a scrip that consists of an invocation of the command with its arguments, exactly as they were when they went into the list command.
This means that we're producing a script that is source somefilename, where somefilename is the result of the file join. In other words, you're getting almost the same thing as:
package ifneeded HelloWorld 1.0 "source $dir/helloworld.tcl"
Except that there is no assumption that the filename separator is / (that's formally a feature of the OS, not of Tcl, and file join knows about the difference) and it is safe if $dir happens to contain a space or other metacharacters (rather more common than you might hope).
What is $dir? Well, it's a special feature of pkgIndex.tcl scripts that they are (normally) evaluated in a context that sets the dir variable to the absolute name of the directory that contains the pkgIndex.tcl script. (You mustn't make assumptions about the current directory at this point; that belongs to the user of the main Tcl program, not to the package author.) This makes it enormously easier to relocate a package, as you can place all its component files relative to the one script and just move the whole lot in one chunk.
The package ifneeded command expects the following inputs:
package ifneeded package version ?script?
You can see that in your case, the package is HelloWorld, and the version is 1.0. Finally, the script is [list source [file join $dir helloworld.tcl]]. The reason list is used is that the script parameter expects a list.
The package ifneeded command expects a script as its last argument. A script is expected (in a common sense) to be well-formed, that is, to be parsable by the Tcl parser.
In this case of a rather standard pkgIndex.tcl, the thing to ensure is: no matter what the "dir" variable contains at the time the code from that pkgIndex.tcl is processed, the script should be constructed in such a way, that later the Tcl parser sees in it the source command with exactly one argument — no matter if $dir expanded to contain whitespace or funky characters like { etc.
Enter the list command. Here, it's used to construct a list of two elements: the string "source" and a string containing a file name (to serve as the sole argument to that source command). Now, when that list is interpreted as a script (a string), Tcl ensures that string representation contains all the needed quoting to remove any ambiguity about whitespace etc.
This ensures when the parser later interprets our constructed script, the source command in it will receive exactly one argument.
You can read much more of better written information on using list to prevent quoting issues here.

Tcl - how to load Memchan linked statically?

I am trying to use Memchan package in my application. I was able to compile and link it statically. But unfortunately I don't know how to load this package in my application.
% rs
Internal error detected during start: can't find package Memchan
can't find package Memchan
while executing
"package require Memchan"
I traced this to the pkgIndex.tcl in Memchan2.3 directory:
% cat pkgIndex.tcl
package ifneeded Memchan 2.3 [list load [file join $dir libMemchan2.3.so]]
I have two questions:
How do I load the statically linked version libMemchan2.3.a ?
Is there a special syntax for calling package require Memchan when one calls a statically linked library?
You've got a statically linked memchan package? Well, that means you need a different package index, whose contents should be this:
package ifneeded Memchan 2.3 {load {} Memchan}
The load has an empty first argument so that statically-linked libraries are considered, but without the filename, a second argument is needed in order to locate the initialization function (which will be Memchan_Init with the above value).
Alternatively, just do this at the start of your script:
load {} Memchan
That will cause the internal package provide to be done anyway, so that any future package require Memchans will just succeed immediately on the grounds that the package is already in use.
[Background info]: As you can see, a package index file is actually very simple: it just provides some instructions to say that if you need a particular package of a particular version, here's a script to make it available. The only real nuance is that the $dir variable describes the location of the package index file while the file is being loaded.