Next: C callout, Up: C and Smalltalk
A nice thing you can do with gnu Smalltalk is enhancing it with your own goodies. If they're written in Smalltalk only, no problem: getting them to work as packages (see Packages), and to fit in with the gnu Smalltalk packaging system, is likely to be a five-minutes task.
If your goodie is mostly written in C and you don't need particular glue
to link it to Smalltalk (for example, there are no callbacks from C code
to Smalltalk code), you can use the dynamic library linking
system. When using this system, you have to link gnu Smalltalk with the
library at run-time using dld; the method to be used here is
DLD class>>#addLibrary:
.
But if you want to provide a more intimate link between C and Smalltalk,
as is the case with Blox, you should use the dynamic module
linking
system. This section explains what to do, taking the Blox
library as a guide.
Modules are searched for in the gnu-smalltalk subdirectory of the
system library path, or in the directory that the
SMALLTALK_MODULES environment variable points to. A module is
distinguished from a standard shared library because it has a function
which Smalltalk calls to initialize the module; the name of this
function must be gst_initModule
. Here is the initialization
function used by Blox:
void gst_initModule(proxy) VMProxy *proxy; { vmProxy = proxy; vmProxy->defineCFunc("Tcl_Eval", Tcl_Eval); vmProxy->defineCFunc("Tcl_GetStringResult", Tcl_GetStringResult); vmProxy->defineCFunc("tclInit", tclInit); vmProxy->defineCFunc("bloxIdle", bloxIdle); }
Note that the defineCFunc
function is called through a function
pointer in gst_initModule
, and that Blox saves the value of its
parameter to be used elsewhere in its code. This is not strictly
necessary on many platforms, namely those where the module is
effectively linked with the Smalltalk virtual machine at
run-time; but since some1 cannot obtain this, for maximum portability you must always
call the virtual machine through the proxy and never refer to any symbol
which the virtual machine exports. For uniformity, even programs that
link with libgst.a should not call these functions directly, but
through a VMProxy
exported by libgst.a and accessible
through the gst_interpreter_proxy
variable.
First of all, you have to build your package as a shared library; using
gnu Automake and libtool
, this is as easy as changing your
Makefile.am file so that it reads like this
pkglib_LTLIBRARIES = libblox.la libblox_la_LDFLAGS = -module -no-undefined ... more flags ... libblox_la_SOURCES = ... your source files ...
instead of reading like this
pkglib_LIBRARIES = libblox.a libblox_a_LDFLAGS = ... more flags ... libblox_a_SOURCES = ... your source files ...
As you see, you only have to change .a extensions to .la,
LIBRARIES
targets to LTLIBRARIES
, and add appropriate
options to LDFLAGS
2. You will also have to run libtoolize
and follow its
instruction, but this is really simpler than it looks.
Note that this example uses pkglib because Blox is installed
together with Smalltalk, but in general this is not necessary. You can
install the library wherever you want; libtool
will even generate
appropriate warnings to the installer if ldconfig
(or an
equivalent program) has to be re-run.
Finally, you will have to add the name of the module in the packages.xml file. In this case, the relevant entry in that file will be
<package> <name>BloxTK</name> <namespace>BLOX</namespace> <filein>BloxBasic.st</filein> <filein>BloxWidgets.st</filein> <filein>BloxText.st</filein> <filein>BloxCanvas.st</filein> <filein>BloxExtend.st</filein> <filein>Blox.st</filein> <module>blox-tk</module> <directory>blox-tk</directory> <file>Blox.st</file> <file>BloxBasic.st</file> <file>BloxWidgets.st</file> <file>BloxText.st</file> <file>BloxCanvas.st</file> <file>BloxExtend.st</file> <file>colors.txt</file> </package>