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.
Related
Is there a way to define an initialization procedure that's automatically called when a Tcl package is loaded?
In this case, I need to parse a configuration file and set a namespace variable.
I originally had the code in the namespace, outside of a proc, but pkg_mkIndex tried to execute the code when it sourced the file and tossed an error "while sourcing". The package file sources just fine from tclsh, and I'm not sure why it wouldn't do so within pkg_mkIndex.
I can comment out the init routine for pkg_mkIndex's sake, if that's the proper way to do this, but I wondered if there's a built-in way to have init procedures executed automatically, a la C's main().
but I wondered if there's a built-in way to have init procedures
executed automatically
It is common practise to provide an initialisation script as part of your package ifneeded script, e.g.:
package ifneeded mypkg 1.0.0 "source [list [file join $dir mypkg.tcl]]; source [list [file join $dir myinit.tcl]]"
Using pkg_mkIndex turns out not particularly helpful in anything non-trivial, as it attempts to (partially) evaluate the source files with all their dependencies. Better handicraft the pkgIndex.tcl script and separate the concerns (pkg definition, pkg initialisation; see above).
I have a tcl script named main.tcl in a folder called App. One of the lines in the script uses a command from the twapi module (that line is actually in a proc and I'm trying to minimize the app to system tray when a user closes the app through the 'X' window button):
package require twapi
# ... code here
set hand [twapi::load_icon_from_file tclkit.ico]
# ... code here
The file tclkit.ico is in the same directory as the script (i.e. in the folder App).
When main.tcl is run through wish, the script works without any issues, but after wrapping it into an executable through command line,
> tclkit sdx.kit wrap App -runtime tclsh863.exe
the executable raises an error, notably that the icon file could not be found:
The system cannot find the file specified.
The system cannot find the file specified.
while executing
"LoadImage $hmod $path $type $opts(width) $opts(height) $flags"
(procedure "twapi::_load_image" line 18)
invoked from within
"twapi::load_icon_from_file tclkit.ico"
(procedure "min_to_tray" line 2)
invoked from within
"min_to_tray"
(command for "WM_DELETE_WINDOW" window manager protocol)
The current workaround right now is to have a copy of the tclkit.ico file in the same directory as the .exe but I want to avoid that as much as possible and only have the standalone .exe file. I tried using the full path with:
set hand [twapi::load_icon_from_file [file join [pwd] App.exe tclkit.ico]]
which normally works when I want to read a file (.txt, .png files, etc.) within the .exe, without success.
So basically, is there a way to enable the .exe to load the .ico file from within itself or another workaround that will not require some dependence on a file outside the .exe app?
The core issue is that the relevant Windows API actually takes a filename, and not something that it's more easy to wrap loading-from-archive around (such as a buffer). This means that you have to copy the file out of the archive somewhere and then pass that name to the system call. This is in fact what Tcl does internally for load when it's pulling the DLL from a source that isn't directly visible to the OS; it doesn't do it automatically for TWAPI though, as that library takes the philosophical position of being just a thin wrapper and letting the caller handle the consequences (which does mean you can easily do more tricks, provided you're inventive).
I suggest copying the file to a temporary file somewhere (i.e., the standard location for these things; Tcl 8.6 has file tempfile to help with this sort of trick) and then passing the full filename into the TWAPI call. I think everywhere in the Windows API that you could pass a simple filename in, you can also pass a full filename. (That's actually very convenient…)
I'm new to Tcl and I have a script that is wrapped using freewrapTCLSH.exe
At first, when started, the program complained about not finding a package
I edited the line the seems to "include" it to
lappend auto_path ../../lib/crc
This worked fine and the .exe started without issues. But then I moved the exe to another folder and it started complaining again. I thought that once the exe was created everything would be done. But it doesn't seem to handle this very well.
At first the entire path to the lib was hard coded into the script and then everything worked fine. But since we can't rely on the exe always being built in the same folder this had to be changed.
Any ideas on how to get around this annoying problem?
../../lib/crc is interpreted using the current working directory each time a package is searched. Having this thing it your ::auto_path is almost always not what you want.
I use [file dirname [info script]] to get a directory of currently sourced Tcl file, adding a relative path to some lib/crc with file join, ensuring to get a full pathname with file normalize. The result of file normalize is what I add to ::auto_path (or remember for future use in some other way):
lappend ::auto_path [file normalize [file join [file dirname [info script]] ../mylib]]
It might be obvious, but still: info script returns the path to file currently being sources, not the path somehow remembered when the file containing a call to it was sourced. If you want to get the current script location, ensure it happens at right time (e.g. do it at top level).
You should deliver the required package (and the dependencies of that package) into your exe.
usually this only involves copying the directory of the required packages to the lib folder in your vfs.
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
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.