nscl_logo_small.gif (2463 bytes)

Guide to SpecTcl Plugins

HH00706_.wmf (6530 bytes)

SpecTcl Home  General Information User Guide Programmer's Guide Obtaining and Installing

This guide describes:

What is a SpecTcl Plugin

A SpecTcl plugin is compiled code that can be dynamically incorporated into SpecTcl. SpecTcl plugins depend on tow bits of technology;

Plugins allow you dynamically add software to SpecTcl that is distributed in binary form. This can be useful either for intellectual property reasons or for ensuring that users's are actually running the code that was distributed.

Plugins are capable of doing anything any other bits of SpecTcl application code can do including:

The examples and recipes in this document are all relevant to plugins development on linux. On other systems, the same principles should apply although other linker flags may be needed to coerce the linker to build your plugin libraries as shared libraries, and the file type of the plugin may vary as well (e.g. while it is .so on many linux like systems it will be .dylib on OS-X and .dll on Windows/Cygwin).

A plugin is installed in SpecTcl using the Tcl

load
  
command.

The form of this command is:

load pluginfile
  
Where pluginfile is the full path to the plugin shared library.

Top Programmer's Guide

Supported Plugins

This section contains a list of supported plugins and pointers to their documentation. Supported plugins will generally be installed in $SpecTclHome/lib

Top Programmer's Guide

How to write a SpecTcl Plugin

This section describes how to produce a plugin. Of course, prior to writing the plugin you need to have a clear idea of what the plugin should do, and what, if anything, it should offer the user.

As plugins are hard to debug it is a good idea to first test your plugin code as a statically linked application extension to SpecTcl. Once you are confident that your static extension works, you would:

Coding the plugin initialization function

The Tcl load command invokes an initialization function when loading a plugin. The signature of this plugin is:

extern "C" {
   int Pluginname_Init(Tcl_Interp*);
}

Four important notes about this call signature:

  1. The extern "C" {} means that the function is called according to the C, not C++ calling conventions. If your plugin is written in C++, you must define the function in that way.
  2. The Pluginname must be related to the library name as follows; First strip the lib off the library name. Second capitalize the first letter of all that remains. Then strip the file type off the end. For example, the Radware spectrum interchange package is in a library file named libradwareio.so; the full name of its initialization function is therefore: Radwareio_Init
  3. The parameter is a pointer to the raw interpreter handle in the base Tcl programming interface. it is not a pointer to a CTCLInterpreter
  4. The function should return TCL_OK if successful and TCL_ERROR in the event an error is detected by the initialization function.

The body of the initialization function should perform whatever setup is required to make the plugin usable and activate it. This could include registering new Tcl commands, adding event processors to the SpecTcl event processing pipeline, executing scripts in the interpreter to bring up a GUI or augment an existing one, or any other functions you want.

We conclude this section by showing a simplified initialization function for the Radware Spectrum Interchange plugin. This plugin adds two commands: rwwrite, and rwread which write and read spectra in Radware format respectively.

extern "C" {
  int Radwareio_Init(Tcl_Interp* pInterp) 
  {

    cerr << "\n\nradwareio incorporates software that is part of the Radware package\n";
    cerr << "written by David Radford at Oak Ridge National Laboratories\n";
    cerr << "This software is incorporated with permission and thanks\n";

    // Wrap the interpreter in an interpreter object and 
    // create the commands.

    CTCLInterpreter& interp(*(new CTCLInterpreter(pInterp)));
    CRWWrite*  pWrite = new CRWWrite(interp);
    CRWRead*   pRead  = new CRWRead(interp);

    return TCL_OK;

  }
}

First the function takes care of acknowledging the author of Radware and thanking him for providing permission to redistribute the spectrum I/O functions from the radware package.

Next, since this is a C++ plugin, we wrap the interpreter pointer passed in a CTCLInterpreter so that we can use the object oriented Tcl interfaces. Reference information about that library is available in the Web "big blue book" and the Printable "big blue book" which contain comprehensive documentation about the NSCL data acquisition and SpecTcl packages.

Next, instances of the two command processors are created (they register themselves with the interpreter their constructors reeceieve). This adds the two commands to the Tcl interpreter used by SpecTcl. Finally, the initialization function returns TCL_OK indicating the plugin is ready for use.

Building the plugin

Plugins must be built as shared object libraries. The following Linux Makefile accomplishes that for the Radware Spectrum interchange plugin:

INSTDIR=/usr/opt/spectcl/3.2
LIBDIR=$(INSTDIR)/lib
INCDIR=$(INSTDIR)/include -I/usr/include/tcl8.4

CXXFLAGS=-I$(INCDIR)
LDFLAGS=-L$(LIBDIR)  -shared -Wl,"-rpath=$(LIBDIR)"
LIBS= 

pluginName = libradwareio.so

OBJECTS = radwareioPackage.o CRWRead.o CRWWrite.o

$(pluginName): $(OBJECTS)
	$(CXX) --version
	$(CXX) -o $(pluginName)  $(LDFLAGS) $(OBJECTS)  $(LIBS)

clean:
	rm -f $(OBJECTS) $(pluginName)  

Simply replaced the definitions of pluginName with the name of the library you are creating, replace the definition of OBJECTS with the objects that need to be created to make up the plugin library.

If, when loading the plugin you get undefined references, you can add the libraries you need to the definition of LIBS. Note that you don't need to add any of the SpecTcl libraries as they are already linked into SpecTcl and symbols required from them will be resolved when the plugin is loaded.

Installing a plugin

A plugin can be installed anywhere. The important thing is that users who must use the plugin must be have:

  1. Execute access to all directories leading to the plugin
  2. Read and execute access to the plugin library itself
Normally plugins should be installed in some central, shared location so that updates and defect fixes can be applied centrally.

Contributing a plugin

Contributing a plugin involves some support responsibility. In exchange for taking on that responsibility, your plugin is:

You have two options for getting your plugin distributed with SpecTcl:

  1. You can incorporate your plugin into the SpecTcl build system.
  2. You can distribute your plugin on the SpecTcl sourceforge page as a separate release tarball

Now for the responsibilities:

If you do not meet these responsibilities, we reserve the right to stop distributing your plugin with SpecTcl.

To get your plugin distributed with SpecTcl Send an e-mail to fox@nscl.msu.edu. The e-mail should include:

Naturally you may modify your plugin as time goes on. You may fix defects, or enhance the original functionality of the plugin. If you do, Send an email containing:

Note that unless you choose to have your plugin distributed and built separately from SpecTcl, your plugin's release and updates may be delayed to coincide with SpecTcl releases (normally 2-3 times per year).

Note that there may be cases where we determine that for practical reasons we cannot distribute your plugin with SpecTcl. Examples may be failures to get your software to build with the SpecTcl build system in a way that allows it to be bundled into the SpecTcl tarballs. In this case we will let you know about this. This is not a personal decision, but just a support decision on our part. You are still welcome to contribute the plugin as a separately released plugin or as a bundled plugin at a later date.

Top Programmer's Guide
fox@nscl.msu.edu
Last modified: Sun Apr 8 19:39:00 EDT 2007