Tcl namespaces in code executing from C - tcl

I have a Tcl code that is being sourced from a C application using:
Tcl_Eval(tcl_interp, "source nmsp.tcl")
Everything runs fine.
However, the namespace scope isn't preserved. For example, the following file:
#!/bin/sh
# namespace evaluation
namespace eval bob {
namespace eval joe {
proc proc1 {} {}
}
proc proc2 {} {
puts "proc2"
}
proc ::proc3 {} {
puts "proc3"
}
proc joe::proc4 {} {
puts "proc4"
}
}
puts "Namespace calling [info procs ::bob\::*]"
when run by itself will produce this output:
Namespace calling ::bob::proc2
But when sourcing from Tcl_Eval will not print anything. In fact, the proc2 procedure can be called by itself fine without any namespace designation.
Anyone knows what may be causing it? I really like the encapsulation that namespaces provide.

Seems fine to me.
I created the following Tcl extension to perform your Tcl_Eval:
#include <tcl.h>
static int
DotestCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[])
{
return Tcl_Eval(interp, "source test_namespace.tcl");
}
int DLLEXPORT
Testnamespace_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, "8.4", 0) == NULL) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "dotest", DotestCmd, NULL, NULL);
return Tcl_PkgProvide(interp, "testnamespace", "1.0");
}
Being on windows, I compiled this using:
cl -nologo -W3 -O2 -MD -DNDEBUG -DUSE_TCL_STUBS -I\opt\tcl\include -c test_namespace.c
link -dll -release -out:testnamespace.dll test_namespace.obj \opt\tcl\lib\tclstub85.lib
and then created a test_namespace.tcl file with the content you posted above. Running this produces the following:
C:\opt\tcl\src>tclsh
% load testnamespace.dll Testnamespace
% dotest
Namespace calling ::bob::proc2
%
and further introspection shows things are as I would expect from that script:
% namespace children ::
::platform ::activestate ::bob ::tcl
% namespace children ::bob
::bob::joe
%
You probably are doing something weird in your C code first if this is really not working for you.
Update
The above example is for extending tcl with a compiled package. Apparently the OP is embedding Tcl into some other application. A trivial example of doing this is provided here which also runs the same command to the same effect as above. In reality when embedding Tcl into an application the code should use the tclAppInit.c file and provide its own Tcl_AppInit function. By running the usual Tcl_Main you get the full capabilities for processing events (needed for fileevents or after commands) and the interactive shell. An example of that follows the trivial version:
/* trivial embedding Tcl example */
#include <tcl.h>
#include <locale.h>
int
main(int argc, char *argv[])
{
Tcl_Interp *interp = NULL;
int r = TCL_ERROR;
setlocale(LC_ALL, "C");
interp = Tcl_CreateInterp();
if (interp != NULL) {
Tcl_FindExecutable(argv[0]);
r = Tcl_Eval(interp, "source test_namespace.tcl");
if (TCL_OK == r)
r = Tcl_Eval(interp, "puts [namespace children ::bob]");
Tcl_DeleteInterp(interp);
}
return r;
}
Running the above:
C:\opt\tcl\src>cl -nologo -W3 -O2 -MD -I\opt\tcl\include test_namesp_embed.c -link -subsystem:console -release -libpath:\opt\tcl\lib tcl85.lib
test_namesp_embed.c
C:\opt\tcl\src>test_namesp_embed.exe test_namespace.tcl
Namespace calling ::bob::proc2
::bob::joe
A better embedding scheme that uses tclAppInit to extend a stock Tcl interpreter:
#include <tcl.h>
#include <locale.h>
#define TCL_LOCAL_APPINIT Custom_AppInit
int
Custom_AppInit(Tcl_Interp *interp)
{
return Tcl_Eval(interp, "source test_namespace.tcl");
}
#include "/opt/tcl/src/tcl.git/win/tclAppInit.c"
Building and running this also produces the same output as previous versions:
C:\opt\tcl\src>cl -nologo -W3 -O2 -MD -I\opt\tcl\include test_namesp_embed.c -link -subsystem:console -release -libpath:\opt\tcl\lib tcl85.lib
C:\opt\tcl\src>test_namesp_embed.exe
Namespace calling ::bob::proc2
% namespace children ::bob
::bob::joe
% exit

As far as I'm aware, the only way your code could not produce the message you expect is if the current namespace at the point it was called was other than the global namespace. Suppose the current namespace was ::foo, the first namespace eval would work in ::foo::bob and the inner one in ::foo::bob::joe. Unqualified procedure definitions put their definitions in the current namespace, of course.
To detect if this is really the case, add the output of the namespace current command to your printed message.
If this is the problem, change the outer namespace eval to use a fully-qualified name:
namespace eval ::bob { # <<<<<<< NOTE THIS HERE!
namespace eval joe {
proc proc1 {} {}
}
proc proc2 {} {
puts "proc2"
}
proc ::proc3 {} {
puts "proc3"
}
proc joe::proc4 {} {
puts "proc4"
}
}
If you're writing a Tcl package this is very strongly recommended and it is a good idea even if you're not going all the way to that extent; you can never be quite sure what context a script is going to be sourced in. (The inner namespace eval is OK though; that's running inside a known context, the outer namespace eval.)

Sorry guys for trouble. I found the problem.
The problem is in my code. I had the following procedure which I completely forgot about:
rename proc _proc
_proc proc {name args body} {
global pass_log_trace
set g_log_trace "0"
if {[info exists pass_log_trace]} {
set g_log_trace $pass_log_trace
}
# simple check if we have double declaration of the same procedure
if {[info procs $name] != ""} {
puts "\nERROR: redeclaration of procedure: $name"
}
_proc $name $args $body
if {$g_log_trace != 0} {
trace add execution $name enter trace_report_enter
trace add execution $name leave trace_report_leave
}
}
The purpose of this procedure, mainly, is to add entry and exit point tracers to all the procedures in my code. For some reason, which I'm still investigating, it also removes the namespace scoping.

Related

Meaning of a proc name ending with ::

In the tk code base I found the construct:
proc ::tk::dialog::file::chooseDir:: {args} {
Normally I would expect the procedure name after the last set of :: but here it is empty. Is this some sort of constructor in a namespace?
(Might look like a trivial question but I'm not a tcl programmer and need to know it to, automatically, generate some documentation.
Some more of the code (maybe gives some background, it is the beginning of the file)
namespace eval ::tk::dialog {}
namespace eval ::tk::dialog::file {}
namespace eval ::tk::dialog::file::chooseDir {
namespace import -force ::tk::msgcat::*
}
proc ::tk::dialog::file::chooseDir:: {args} {
variable ::tk::Priv
set dataName __tk_choosedir
upvar ::tk::dialog::file::$dataName data
Config $dataName $args
...
Normally I would expect the procedure name after the last set of ::
but here it is empty
The empty string is a valid name for a procedure in Tcl (as it for variables).
% namespace eval ::tk::dialog::file::chooseDir {}
% proc ::tk::dialog::file::chooseDir:: {args} { return "called!" }
% ::tk::dialog::file::chooseDir::
called!
% namespace eval ::tk::dialog::file::chooseDir { "" }
called!
% info procs ::tk::dialog::file::chooseDir::*
::tk::dialog::file::chooseDir::
I don't know the history behind these Tk internals, but a procedure named using the empty string might be the main procedure for the same-named namespace chooseDir (as a kind of naming convention), rather than just duplicating the name: proc ::tk::dialog::file::chooseDir::chooseDir {args} {;}. Or, it is because the entire directory-picking functionality is auto_loaded, which requires a proc (command) name rather than a namespace name?
automatically, generate some documentation.
Maybe, when harvesting a Tcl interpreter for pieces to document, take the containing namespace name chooseDir as the documented name of such a procedure?

What is a function equivalent of source in Tcl?

I have a series of Tcl scripts which are being executed in an interpreter (Cadence Innovus). I want a way to group commands and execute them with a single call. Functionally I can achieve this by writing each group of commands in a separate file and calling source <group_file_name>. However it is inconvenient to define so many files.
I have tried to do this with:
proc {} {
commands...
}
This doesn't give me the functionality I need though. I believe it executes the commands in a lower namespace and the variables that are set do not remain.
Is there a way to get this functionality (a single file with callable functions), but that execute in the same namespace?
Well, you can always use uplevel or namespace eval inside that procedure to change the current namespace. If you use uplevel, you would do this:
proc foo {} {
uplevel 1 {
TheFirstCommand
TheSecondCommand
TheThirdCommand
}
}
With namespace eval, you might instead do this:
proc foo {} {
namespace eval ::theTargetNamespace {
TheFirstCommand
TheSecondCommand
TheThirdCommand
}
}
Things get a bit more complicated if you're wanting to use local variables with the scope-changers, but the principle for how to manage things is about the same whichever mechanism you use.
proc foo {} {
set a [uplevel 1 { TheFirstCommand }]
set b [uplevel 1 { TheSecondCommand }]
# Dynamically-generate the script to run; it's trivial code generation
uplevel 1 [list TheThirdCommand $a $b]
}
Switching to namespace eval is pretty much a drop-in replacement.

Tcl: How to do a callback accross namespace borders?

Consider a library structured like this:
package provide ::mylib 1.0
namespace eval ::mylib {
namespace export f
proc f { action } {
# pass action around
g $action
}
proc g { action } {
eval $action
}
}
If I try to use it like this, it won't work:
....
namespace eval ::user {
set x 10
::mylib::f { puts $x }
}
The reason is that $x is not known in mylib. I can fix it like this:
namespace eval ::user {
set x 10
::mylib::f { puts $::user::x }
}
This works, but qualifying each variable in the argument to ::mylib::f is awkward. Another possibility is to wrap the code inside another namespace eval:
namespace eval ::user {
set x 10
::mylib::f { namespace eval { puts $x } }
}
Better, but still ugly. If it were Ruby or Perl, I would simply pass a closure to ::mylib::f. What is the best practice in Tcl?
BTW, I'm currently on Tcl 8.3, but hope to have the possibility to upgrade to a newer version soon, so solution in terms of 8.3 AND more recent versions are wellcome.
tl;dr version: namespace code
The namespace code command is intended for this situation. You pass it the script that you want to be encapsulated, and it hands you back a version that has magic in it so that it handles being called from anywhere. Here's how you might use it.
namespace eval ::user {
variable x 10
::mylib::f [namespace code { puts $x }]
}
Internally, it uses namespace inscope to do this. You're recommended to not use that directly; namespace code is the convenient way of doing this.
Note that it even works if the callback site passes arguments to it, so long as that site is doing:
eval $callback [list "the argument is this"]
(In fact, in 8.3 the eval isn't necessary because of a gross hack in unknown, but please do it the way I recommend above because we took that hack out in later versions. It was pretty awful.)

Adding a custom Tcl procedure to a SWIG generated Tcl module?

I'm trying to replace an old Tcl interface to C++ using SWIG. Here is an example class:
class test {
std::string str;
public:
test(const char * s):str(s) {}
void print() const {std::cout << str << std::endl;}
};
and here is the standard way to use it:
load ./example.so example
test s "this is a test string"
s print
But I want to preserve the simplicity of the old interface which does not use the "". I've found that I can do something like:
load ./example.so example
proc TEST {args} { test [lindex $args 0] [lrange $args 1 end] }
TEST s2 this is another test string
s2 print
Which looks simple and works flawlessly, however, of course, I cannot have the proc definition in the user script. I'm not sure where else I could place it. Is there a way to put it in the .i file?
I think you can put this in your .i file:
%init %{
Tcl_Eval(interp, "proc TEST {args} { ... }");
%}
That will insert a call to Tcl_Eval (which will make the procedure) into your module's initialization function, and as long as the interp context is available there (WARNING! Check this!) then you'll get everything nicely packaged.
If you've got lots of code, consider calling Tcl_EvalFile instead, or calling Tcl code that will source the script code (necessary if you've got a need for complex scripting to locate the file to read).

How can I callback Tcl commands from different namespaces without explicitly qualifying?

Basically the problem is to execute Tcl code defined in one namespace, using calls to functions in that namespace, in an eval inside another namespace.
The following code works fine:
namespace eval ::eggs {
namespace export e1 eeval
proc e1 {} { puts pe1 }
proc eeval body { puts "in cb enter"; eval $body; puts "in cb exit" }
}
namespace import ::eggs::*
namespace eval ::spam {
namespace export s1 scall
proc scb {} { puts pscb }
proc scall {} { puts "in call enter"; eeval {::spam::scb}; puts "in call exit" }
e1
scall
}
namespace import ::spam::*
and prints:
% % % % % % pe1
in call enter
in cb enter
pscb
in cb exit
in call exit
Now I want to replace the ::spam::scb with a plain scb. I would trade in a wrapper for eeval.
My use case:
The namespace eggs is a very basic library for regression testing. The namespace spam is a small library implementing nice to have functions. They shall be tested upon reload. For this scall is called and uses a special test function in eggs called eeval.
The eeval is the unit test. For convenience and "do-not-repeat-yourself" reasons I'd like to not have to use the fully qualified namespace name of any function defined in spam.
Ideally scall would look like this:
proc scall {} { puts "in call enter"; eeval {scb}; puts "in call exit" }
However, during execution the eval in ::eggs::eeval does not know where to find scb. Since eggs is just a test library I cannot import the spam namespace.
Is there any way one could e.g. devise a wrapper for e.g. eeval to make it run in the other namespace?
If you're going to pass the code to eval (possibly appending arguments) then the simplest method to generate the callback script is with namespace code:
eeval [namespace code {scb}]
That generates all the wrapping code to ensure that things work correctly, including handling all sorts of cases you've not dealt with:
% namespace eval boo {
puts [namespace code {foo bar}]
}
::namespace inscope ::boo {foo bar}
However, if you're doing the callback immediately then the most common approach is not the above, but rather to use uplevel 1 to do the callback:
proc eeval body {
puts "in cb enter"
uplevel 1 $body
puts "in cb exit"
}
This has the advantage that the called-back code really is in the stack context of the caller, allowing it to do useful things like access local variables. Since the code is running in the same context that you define it[*], it's fine using that for resolving command names.
[*] That's a big fat lie — Tcl's semantics are rather more complex than that — but everything works like what I've said is true.
namespace current is the DRYer you're probably looking for.
namespace eval ::spam {
proc scall {} {
puts {in call 2 enter}
eeval [namespace current]::scb
puts {in call 2 exit}
}
}
Or pass the current namespace to the eeval proc
proc ::eggs::eeval {body {namespace ""}} {
puts "in cb enter"
if {$namespace == ""} {
eval $body
} else {
namespace eval $namespace $body
}
puts "in cb exit"
}
proc ::spam::scall {} {
puts "in call 3 enter"
eeval scb [namespace current]
puts "in call 3 exit"
}