I'm probably missing something obvious here but maybe you can help me.
I have a tcl script. Here it is in its entirety:
puts [encodeSDR 25]
proc encodeSDR {input} {
set sdr "test"
return $sdr
}
when I run this script I get an error:
c:\temp>tclsh testenviro.tcl
invalid command name "encodeSDR"
while executing
"encodeSDR"
invoke from within
"puts [encodeSDR 25]"
(file "testenviro.tcl" line 1)
What am I missing? Seems like this should work perfectly.
PS. Found possible reason:
There when I put the puts call below the proc it worked - so does it not load the entire script first? seems weird if that's the case but maybe thats it.
You are correct in that the entire script is not loaded before any execution takes place. A TCL script is interpreted one command at a time, and then will move to the next one only once it is finished. There is no compiling beforehand to check for procedures you may be referencing down below.
In your case, it first tried to interpret the puts command, which involved calling encodeSDR. Since that had not been defined in memory as of yet, the interpreter had no idea what you were trying to do.
One thing to watch out for is if you define the procedure by itself (say during testing/debug), and then later add it into a script in a way like your example. It will work just fine until you close out of the session, and TCL's memory gets released. The next time you load the script, however, it will fail because the procedure was never loaded for that session.
Related
I worked on a TCL script that takes a bit of time to execute. In order to to run it faster, I would like to use multi-threading using the Thread package. The problem is that I execute my TCL script in an engineering software called Hypermesh. It supports TCL scripting quite well since everything that can be done in the software has an associated TCL command.
For example if the user was to use Hypermesh to create a node at coordinate (x, y, z) then the same result can be obtained using the command *createnode $x $y $z.
Back to the multi-thread problem: I can create threads just fine but inside the thread, I cannot use the command *createnode because it is not recognized. I am guessing it is because some packages are not loaded inside the thread. I would like to load those missing packages with "package require" but no matter how I tried, it could not find any package.
I found out that inside a thread, the auto_path variable does not exist. I tried to create it, but it still would not work.
It looks like my thread can execute basic TCL buit-in commands and nothing else.
On the other hand, when I created a Thread using wish, I did not have this problem at all. All the packages "outside" the thread were also directly loaded "inside".
Here is how my code looks like:
package require Thread
package require Ttrace
set scriptToSend {
package require Trf
return 0
}
set t1 [thread::create]
thread::send -async $t1 $scriptToSend result
puts $result
Trf is just a random package that can be loaded just fine when "package require" is called outside of t1
Is there any way I could setup the thread to have all the commands that exist outside the thread? For example by making the use of package require possible?
EDIT:
I spent some more time on this problem and tried to use tpool instead of thread. The threads created in tpool seem "better". Unlike with thread, they do have an auto_path variable and I am able to use it to successfully load packages when using threads. However now I have more of an Hypermesh issue since it does not let me load all the necessary packages to use procs such as *createnode.
I will try to go around the problem by making my threads do as much as they can without using any Hypermesh function. It will still speed up the script quite a bit.
Tcl uses a limited version of the auto_path global in threads by default because it doesn't set it up in quite the same way (e.g., it doesn't evaluate your ~/.tclshrc). To use the same packages as in the main thread, you'll need to transfer a copy of that variable over.
thread::send $otherThread [list set ::auto_path $::auto_path]
Do that before sending other scripts to the subthread in order to synch things up.
On my system I'd see this sort of thing too:
bash$ tclsh8.6
% puts $::auto_path
/opt/local/lib/tcl8.6 /opt/local/lib /opt/local/lib/tcllib1.19
% package require Thread
2.8.4
% set otherThread [thread::create]
tid0x7000053ab000
% puts [thread::send $otherThread {set ::auto_path}]
/opt/local/lib/tcl8.6 /opt/local/lib
There's also the module path (controllable via the tcl::tm::path command) but that's the same for me in the subthread as in the main thread.
I have scripts which were used without Tk. When I added Tk one line is treated as path to window and I don't understand why.
Error infor is like:
bad window path name "* Log directory: D:/tests/log/2016_10_13_17_30_29"
It is when this line is executed:
message "* Log directory: ${dirname}"
dirname is resolved as path to directory, for example:
D:/tests/log/2016_10_13_17_30_29
message is a simple procedure for logging to file:
proc message {text} {
global test_log_filename
puts -nonewline $test_log_filename "[timestamp] "
puts $test_log_filename $text
}
When I do not use Tk it is working correctly. As I understand it takes message procedure argument as path to Tk window, but I don't know why. Of course such a window doesn't exist.
I also tried to invoke something like message test to confirm that it is argument problem. It gives error bad window path name "test"
Could you please help with it?
Tk also defines a command called message (it's a widget similar to a label, but with a somewhat different word-wrapping algorithm; it's not recommended for new code) and for some reason, that's winning out. While you could probably force yours to be used instead by directly sourceing your code after the package require Tk, it's unlikely to be a good idea as you may find some other code breaks because of it. (I can't remember if it is currently used in the standard dialogs, but that's the sort of thing which might go wrong.)
The easiest thing is to change the name of your logging procedure. Perhaps to Message (with the capital letter). That shouldn't take long as it's effectively not much more than a global search-and-replace.
I have a C extension to Tcl where command mytest is defined. The extension is compiled correctly (I am on Linux, extension is *.so). For example, I can start tclsh and use it like this:
$ tclsh
% load /path/extension.so
% mytest abc
...
But, if I create a file myscript.tcl with the following content:
load /path/extension.so
mytest abc
then I get error:
$ tclsh myscript.tcl
invalid command name "mytest"
while executing
"mytest abc"
(file "myscript.tcl" line 2)
I am using bash on Ubuntu 14.04. Tcl 8.6.
EDIT 1: My question/problem is that I want to use tclsh with a script as an argument - this script should properly load extensions in such a way that mytest and other implemented functions are working without error.
EDIT 2: Uhh, If I use command "source myscript.tcl" inside tcl shell the result is the same. If I use absolute path for myscript.tcl the error is still the same --- "load" executes without warning but I am not sure about it because I get invalid command name "mytest". Maybe the problem is with scope, but it is working correctly when tclsh is used interactively.
If you are using the full path of the extension library in both cases, that part should work identically. It probably is doing though; if it couldn't load it, it would generate an error (which might or might not be helpful, as some of the ways that things fail give very little information; Tcl reports what it has got, but that's sometimes not enough, as it is dependent on the OS to tell it some things). Instead, the problem is probably elsewhere.
The main difference between interactive use and scripted use is that in interactive use, the unknown command will expand unknown command names to Tcl commands that the thing you typed is an unambiguous prefix of. This is convenient, but when converting to a script, you should always use the full command name. OK, not the full full command name — you mostly don't want or need the :: namespace on the front — but without abbreviation, so don't use lappe for lappend. (In interactive use, Tcl will also exec things as external programs without requiring you to type the exec explicitly; again, that's turned off in scripts as it is rather fragile.)
Could it be that this is what is going on? You can check by setting the global variable tcl_interactive to 0 before typing in your code (I recommend using cut-n-paste for that typing, so that you know exactly what is going in). If that fails, it's the interactive-mode helpfulness that is tripping you up. Check what commands you might have as an expansion for a prefix with info commands (after the load, of course):
info commands mytest*
If that just reports mytest, my theory is wrong. (Well, if it does that and the length of that string is 6; there could theoretically be extra invisible characters have been put on the command name, which would be legal Tcl but very nasty and DON'T DO THAT!)
I'm using IDL 8.3 on Mac 10.9.3
I am running a script that calls in a procedure. The procedure I am calling in is contained in a directory that I included in IDL's path (I did this by going under IDL->preferences->IDL->paths and adding the directory). However, when I attempt to run the script, I get the error message: "% Attempt to call undefined procedure/function: 'procedure.pro'. % Execution halted at: $MAIN$". The weird thing is is that it still lists all the syntax errors in the procedure that is supposedly 'undefined'. Also, when I type the procedure.pro name into the IDL prompt, it lights up teal/blue color (meaning it recognizes the procedure).
I tried making a very simple simple.pro, put it into the same directory I mentioned before, typed it into the IDL prompt (it turned teal/blue), and it ran perfectly with no errors.
I am unsure why the procedure.pro file is 'undefined' since it is contained it its path, and I proved with simple.pro that .pro files in this path will run correctly.
A couple of things to check:
Is the routine called as a procedure and defined as a procedure (or called/defined as a function)?
Does the name of the file match the name of the routine?
well, the procedure I was attempting to call in contained other procedures/functions that weren't included in IDL's original library. I just had to download these separate procedures/functions, and the syntax errors went away, along with the 'unidentified procedure' error message.
In my PowerShell script I'm calling some command line tools (not cmdlets) that may output error text and set errorlevel nonzero on error conditions. I'd like any error from any of these tools to abort my script.
What's the best way to do this?
Is there a way to have PowerShell automatically check $? and stderr after every command and throw an exception? I was thinking something along the lines of "on error" that 4NT or VBScript has - a global watch. Not very object-orienty, so I was hoping PowerShell had something better.
[Edit: last couple questions moved to here.]
You will need to either write a function to do this or within the script constantly check for the errorlevel.
Some information on a function to do this is at:
http://www.eggheadcafe.com/conversation.aspx?messageid=31829234&threadid=31829225
and other useful information can be found on the windows powershell blog.