Tcl - how to load Memchan linked statically? - tcl

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.

Related

Is there a Tcl package init procedure?

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).

How to access unexported functions in the same package but from different file

I am trying to build godoc.org source code in my local to make some changes. My working directory is /Users/Dany/go/src/github.com/golang/gddo. In gddo-server package there several files. One of the go file uses a function from another file which is in the same package but unexported. It is throwing Undefined: <function-name> exception.
Folder is structure is,
golang/gddo/
gddo-server
main.go
crawl.go
How do we use unexported function from the same package in a different file? Could anyone help me with this. Also if anyone has any idea about how to build godoc.org code?
Source files of the same package can refer to identifiers defined in any of the source files without any effort. If they are in the same folder and if they have the same package declaration, you can refer all package-level exported and unexported identifiers as if all would have been defined in one file.
See Spec: Packages:
A package in turn is constructed from one or more source files that together declare constants, types, variables and functions belonging to the package and which are accessible in all files of the same package.
And Spec: Package clause:
A set of files sharing the same PackageName form the implementation of a package. An implementation may require that all source files for a package inhabit the same directory.
One thing to note: your example seems to be the special main package. If you want to run it with go run, you have to enumerate all the source files.
To run your example with go run, navigate to the gddo-server folder and type:
go run background.go browse.go client.go crawl.go graph.go main.go play.go template.go
Or simpler if you first build it. Navigate to the gddo-server folder and type:
go build
This will generate a native executable binary in the same folder. To run it type: gddo-server (on Windows) or ./gddo-server (on Linux).
Or you can install it with go install which will place the result executable binary in your $GOPATH/bin folder.

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 find the path of package loaded?

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

SWIG TCL Static Linking

I am trying to use SWIG to generate wrappers for some of my C++ function calls.
Also, I am trying to do build my own TCL shell so I need to static link the generated SWIG libraries. I have my own main function with a Tcl_AppInit call where I do some prior setup.
To do this what function should I include in my program's Tcl_AppInit call? I found that SWIG_init is not the right function. I even tried Cell_Init where cell is the name of the class in my code, but that doesn't help either.
How do I static link SWIG object files with my own main function and Tcl_Appinit call?
Currently when I use the following command to link my executabel I get the following error:
g++ -o bin/icde src/core/*.o src/read/*.o src/swig/*.o src/icde/*.o -ltk -ltcl
I get the following error:
src/icde/main.o: In function `AppInit(Tcl_Interp*)':
main.cpp:(.text+0xa9): undefined reference to `Cell_Init(Tcl_Interp*)'
collect2: ld returned 1 exit status
I checked the src/swig/cell.o file which has the Cell_Init function or not using objdump:
~> objdump -d src/swig/cell.o | grep Cell_Init
00006461 <Cell_Init>:
646c: 75 0a jne 6478 <Cell_Init+0x17>
I am not sure if I am doing something wrong while linking.
------------------- UPDATE ----------------------------
I found that including the swig/swig.cxx file directly in the main file which calls the Tcl_AppInit function resolves the linking issue. Is there a reason for this.
Isn't it possible to create and seprately link the swig file and the file with the main function?
In general, with SWIG you'll end up with a bunch of generated source files that you compile. The normal thing you do then is package them up into a shared library (with appropriate bound dependencies on other shared libraries) that can be imported into a Tcl runtime with the load command.
But you don't want that this time. Instead, you want the object files that you would use to make that shared lib, and you want to include them in the instructions to build an executable along with the object file that holds your main and Tcl_AppInit. You also need to make sure that when linking your main executable that you make it dependent on those external shared libraries; executable building requires that you satisfy all dependencies and make all symbols be bound to their definitions. (You can use a static library to make this easier: it combines a bunch of object files into one file. There's very little difference to just using the object files from it though; in particular, static libraries aren't bound to their dependencies.)
Finally, you do want to include a call to Cell_Init in your Tcl_AppInit. That's the right place to put it (well, as long as you're not arranging for the package to be loaded into sub-interpreters). If it was failing before, that was because you'd got your linking wrong. (Tip: linkers work best when objects and libraries on the link line only depend on things later on the link line. Getting the link order right is a bit of a black art when you've got a complex build!)