Global variable in Tcl - tcl

I am trying to use a global variable (gpio_out_set_3) by declaring it outside a function (because the variable might be used in other functions too in future). Inside the function, I have declared the same variable as 'global' and trying to access it through '$gpio_out_set_3'.
I am getting an error "can't read "gpio_out_set_3": no such variable"
set gpio_out_set_3 0x03
proc port2phy { device } {
global gpio_out_set_3
erf_wr devcpu_gcb $gpio_out_set_3 $phy_mdc_gate_en
}
Please help.

Declare all of your global variable at the beginning of your main file using variable command.
variable gpio_out_set_3 0x03
TIP: I dont like the global command. I always forget to use, and hard to see which variable is global and which variable is local. I prefer the $::<varname>, which points to the global namespace.
proc port2phy { device } {
erf_wr devcpu_gcb $::gpio_out_set_3 $phy_mdc_gate_en
}

My guess is that when you're creating variable gpio_out_set_3 you're not at top level. You are in some other procedure. So the gpio_out_set_3 in not really global, but instead local in some proc.

Your global variable is named gpio_out_set_0 (not the same as gpio_out_set_3).

Although newer versions of tcl allow for executable code to exist almost anywhere in your program, a good habit to form is to be sure that where you set the variable initially is in the main section of your program code. In order for your code to run properly on any version of tcl, there should be no executable code prior to, or in-between your procs (including set commands). All of your procs should go at the beginning of the program followed by your main code. Things that can/should go before your procs are comment lines and any necessary "package require ..." commands.

Related

Use of "trace add variable read" in tcl

New to tcl and trying to understand the "trace add variable" command.
I understand the need to invoke a callback function when a variable is "written" to.
But what is the use of the "read" option? For debugging?
One example use might be a global counter:
proc init { } {
set ::globalcounter 0
trace add variable ::globalcounter read ::gcountUpdate
}
proc gcountUpdate { } {
incr ::globalcounter
}
proc main { } {
init
puts $::globalcounter
puts $::globalcounter
}
main
I'm sure there are other uses. As you pointed out, debugging.
It could be used for enforcement of variable access by specific procedures.
One of the uses for read callbacks (which are indeed quite a bit less common than write callbacks) is in linking a Tcl variable to a C variable; the read callback is used to enforce the reading of the C variable and synchronizing the Tcl variable to it. (The write callback would ensure that the update of the Tcl variable gets reflected to the C variable.) Tcl's got a built-in C API that uses this mechanism, though it's using the underlying C API for variable traces rather than the Tcl API that is built on top of it.
You could also use a read callback to make an apparently read-only variable:
trace add variable foo read {apply {args {
upvar "#0" foo v
set v "definitely this"
}}}
puts $foo
set foo "that"
puts $foo
I don't recommend using variable traces on local variables. They have a lot more overhead (and internal complexity) than for global/namespace variables.

Manipulation of variables inside a proc with bind

Sorry for the title couldn't think of anything better.
Heres my question:
Im trying to change a variable inside a proc only when the user hits space. the proc loops itself with after so if the user wish to hit space more then once the variable will increment.
Heres what I know:
There are many ways to go about this. You can pass variable inside the proc, you can link the variable with global or upvar and/or if your in a namespace then you can use variable. but the only one that seem to work with my is global. I'm getting a feeling it's because global makes a link but if thats true then variable should work too, right?
Here my test code:
proc test1 {} {
global testing
bind . <Key-a> {incr testing}
puts $testing
puts "test2"
after 100 test2
}
namespace eval test2 {
variable testing 0
namespace export {[a-z]*}
proc of1 {} {
variable testing
bind . <Key-a> {incr testing}
puts $testing
after 100 test3::of1
}
}
proc test3 {testing} {
bind . <Key-a> {incr testing}
puts $testing
puts "test4"
after 100 test4 $testing
}
set testing 0
#test1
test2::of1
#test3 0
grid .c
side question:
Why is it that in the global namespace we use set and global while in namespace we use variable (that seem to set and do global in one command). they seem to do the same job in different namespaces?
Variables in Callbacks
The scripts registered by the bind command — also in things like after events and fileevent callbacks — are evaluated in the global scope because they may be called long after the procedure that defined them returns; Tcl does not do scope capture (and that's actually a really complicated feature, so it isn't likely to come soon unless someone writes lots of code). This means that the variable that you want your procedure to notice changes to must also have global scope.
However, namespaced variables count just fine as global variables for the purpose of this discussion as they're nameable from a global context (real local variables are not). That means that we can do several ways to build a script that accesses a namespace variable from a bind-defined callback. Here's one of the nicer ones:
bind . <Key-a> [namespace code {incr testing}]
That's effectively the same as this:
bind . <Key-a> [list namespace eval [namespace current] {incr testing}]
(There are some strict differences that don't matter in this example.)
Another way to do the callback is this:
bind . <Key-a> [list incr [namespace which -variable testing]]
Which in this case is going to be much like:
bind . <Key-a> [list incr [namespace current]::testing]
If things are getting any more complicated than this toy example, it's time to stop updating variables directly in a binding script and instead write a helper procedure. That always simplifies things a lot. Or to use a class/object to encapsulate the details.
The variable Command: Why and Where to Use It
Why is it that in the global namespace we use set and global while in namespace we use variable (that seem to set and do global in one command). they seem to do the same job in different namespaces?
That's a good question. In fact, what global does is very much like upvar #0 (with the variable names doubled up), and set is a fundamental variable access command. They're commands that you can use regularly wherever you want their behaviour.
The variable command is rather stranger. What it does is three-fold:
If called in a namespace context and the variable does not exist in that namespace, it creates that variable in a present-but-unset state.
If called in a context with local variables, it links a local variable with the name (after stripping everything up to the last namespace separator) to a namespace variable with the name (using the whole supplied name if there are qualifiers, and resolving non-absolute names with respect to the current context namespace). This also forces the namespace variable to exist in the present-but-unset state.
If a value is given, the namespace variable is set to the value. This gets rid of the present-but-unset-ness.
The important behaviour is actually the creating of that present-but-unset state, since otherwise you can end up with a set (or array set) in the namespace escaping that namespace and instead working with a global variable, but not always. It all depends on the exact behaviour of the code that resolves variables, and that's deeply tricky. This is hard to explain properly, and ridiculously hard to justify. It's been the cause of quite a few outright bugs, and is definitely no better than a horrible misfeature.
The setting of the initial value is little more than a lollipop; you could instead put set straight afterwards without ill-effect. What's more, it inhibits using variable to pull in multiple variables from a namespace except in the case where you're setting them to a known value; great for initialisation, but sucky for other uses. (In case you hadn't guessed, I think this is an area of Tcl where the interface was got rather badly wrong back when it was introduced, back in Tcl 8.0. Not one bit of this is nice.)
The key take-away is this though:
Always use variable in your namespaces to declare variables as this is the only way you can be sure that the semantics is predictable. You can then initialise them any way you want. (You have to do it this way if you're creating arrays.)
Fully-qualified variable names have no craziness associated with them. Tcl always knows exactly how to look up the thing you're naming in that case.

Tcl info exists

I have a curious case of Tcl that perhaps I just don't understand.
The following code is done at the top level (not inside of any procedure):
if {![info exists g_log_file_name]} {
set g_log_file_name "default.txt"
}
What I hope it would do is to declare a global variable with some value if it wasn't declared yet (which can be done at some other script or C application). However, the if statement always false. I ran on Tcl 7.4.
What may be the problem?
Thank you so much.
% info level
0
% info exists g_log_file_name
0
% set g_log_file_name whatever
whatever
% info exists g_log_file_name
1
Hence the reason you observe is probably because the variable is really always unset at the time your if command is executed.
Possible reasons for this I can imagine are:
It's just not set: literally, no code attempt to do this;
The external code sets some other variable: name mismatch;
The external code sets a variable in some other interpreter: in a C code embedding Tcl, there can be any number of Tcl interpreters active at any moment (and those are free to create child interpreters as well);
I'm not sure abot the long forgotten version of Tcl you have at hand, but 8.x has the trace command which can be used to log accesses to a particular variable—you could try to use it to see what happens.

the usage of global keyword in TCL

I have a question about global in TCL.
In one tcl file tclone.tcl, I have a global variable: global SIGNAL
in another tcl file called tcltwo.tcl, I set the variable SIGNAL as: set SIGNAL 10
In tclone.tcl, I improted the tcltwo.tcl as following" package require tcltwo.tcl
will the variable SIGNAL in tclone.tcl will be set as 10 when I execute it? and what is the usage of gloable variable?
As stated in its manual page, the global command only has meaning inside proc bodies:
This command has no effect unless executed in the context of a proc body.
So the whole question is unclear. If you meant that you have a proc in the first file setting a global variable and another proc (in the second file) reading it, then the question makes sense and the answer is yes, the code from the second file will see the change made by the code from the first file provided the "setting" procedure runs before the "getting" one. To possibly make it more clear, a global variable is global with regard to an interpreter the code operating that variable runs. Hence no matter which way do you use to fetch the code into an interpreter (package require vs source vs eval etc), all that code will see the same set of globals.
But in any case you should probably abstrain from using globals and use namespaced variables: they are also global but you greatly reduce the risk of introducing some other code later which will inadvertently mess with that global variable it should not touch. Of course, as usually this depends on how complicated your application is expected to be.

How to resolve naming conflicts when multiply instantiating a program in VxWorks

I need to run multiple instances of a C program in VxWorks (VxWorks has a global namespace). The problem is that the C program defines global variables (which are intended for use by a specific instance of that program) which conflict in the global namespace. I would like to make minimal changes to the program in order to make this work. All ideas welcomed!
Regards
By the way ... This isn't a good time to mention that global variables are not best practice!
The easiest thing to do would be to use task Variables (see taskVarLib documentation).
When using task variables, the variable is specific to the task now in context. On a context switch, the current variable is stored and the variable for the new task is loaded.
The caveat is that a task variable can only be a 32-bit number.
Each global variable must also be added independently (via its own call to taskVarAdd?) and it also adds time to the context switch.
Also, you would NOT be able to share the global variable with other tasks.
You can't use task variables with ISRs.
Another Possibility:
If you are using Vxworks 6.x, you can make a Real Time Process application.
This follows a process model (similar to Unix/Windows) where each instance of your program has it's own global memory space, independent of any other instance.
I had to solve this when integrating two third-party libraries from the same vendor. Both libraries used some of the same symbol names, but they were not compatible with each other. Because these were coming from a vendor, we couldn't afford to search & replace. And task variables were not applicable either since (a) the two libs might be called from the same task and (b) some of the dupe symbols were functions.
Assume we have app1 and app2, linked, respectively, to lib1 and lib2. Both libs define the same symbols so must be hidden from each other.
Fortunately (if you're using GNU tools) objcopy allows you to change the type of a variable after linking.
Here's a sketch of the solution, you'll have to modify it for your needs.
First, perform a partial link for app1 to bind it to lib1. Here, I'm assuming that you've already partially linked *.o in app1 into app1_tmp1.o.
$(LD_PARTIAL) $(LDFLAGS) -Wl,-i -o app1_tmp2.o app1_tmp1.o $(APP1_LIBS)
Then, hide all of the symbols from lib1 in the tmp2 object you just created to generate the "real" object for app1.
objcopymips `nmmips $(APP1_LIBS) | grep ' [DRT] ' | sed -e's/^[0-9A-Fa-f]* [DRT] /-L /'` app1_tmp2.o app1.o
Repeat this for app2. Now you have app1.o and app2.o ready to link into your final application without any conflicts.
The drawback of this solution is that you don't have access to any of these symbols from the host shell. To get around this, you can temporarily turn off the symbol hiding for one or the other of the libraries for debugging.
Another possible solution would be to put your application's global variables in a static structure. For example:
From:
int global1;
int global2;
int someApp()
{
global2 = global1 + 3;
...
}
TO:
typedef struct appGlobStruct {
int global1;
int global2;
} appGlob;
int someApp()
{
appGlob.global2 = appGlob.global1 + 3;
}
This simply turns into a search & replace in your application code. No change to the structure of the code.