Skip to content

GNU Smalltalk with C Callouts

June 4, 2013

Chances are that if you’re using GNU Smalltalk you’re going to want to call out to a C program or some C libraries.

First off, the docs are here: http://www.gnu.org/software/smalltalk/manual/html_node/C-and-Smalltalk.html#C-and-Smalltalk. For C callouts, there are two links which are most helpful, being “C Callout” and “C Data Types”. The rest of the links are mostly related to going the other way, i.e. calling from C into Smalltalk.

This post is an introductory example of how to access a shared library from Smalltalk. To get a feel for what is going on, we’ll make our own shared library and then call it from Smalltalk. There are four files to copy as follows:

  • a shared library with a single numeric function that adds 10 to an argument and returns the sum (tutcall1.h and tutcall1.c)
  • a C test program to use the library (tutcall1test.c)
  • a GNU Smalltalk script to use the library (tutcall.st)

—> tutccall1.h


extern unsigned int addTen(unsigned int aNum);

—> tutccall1.c

#include
#include "tutccall1.h"
unsigned int addTen(unsigned int aNum) {
printf("\n Inside addTen()\n");
return (aNum+10);
}

—> tutccall1test.c

#include
#include "tutccall1.h"

int main(void)
{
unsigned int aNum = 5;
unsigned int result = 0;
result = addTen(aNum);
printf("Test addTen: Passed [%u] and the result is [%u]\n",aNum,result);
return 0;
}

—> tutccall1.st

#!/usr/bin/gst -f    "set to the path of your gst binary"

"Simple call from GNU Smalltalk to a C library"
CObject subclass: ClassCall [
"demonstrating a class method callout"

ClassCall class >> addTen: aNum [
  <cCall: 'addTen' returning: #uint args: #(#uint)>
] ]

CObject subclass: InstanceCall [
"To demonstrate an instance method callout."
addTen: aNum [
  <cCall: 'addTen' returning: #uint args: #(#uint)>
] ]

"mainline"
| result callout |
Transcript showCr: '.started'.

"Link GNU Smalltalk with the Library we created"
DLD addLibrary: 'libtutccall1'.

"Callout using a class method"
result := ClassCall addTen: 5.
Transcript show: 'ClassCall: Result is: %1' % {result asString}; nl.
Transcript show: 'Result: '. result inspect.
Transcript showCr: '---'.

"Callout again, but this time using an instance method"
callout := InstanceCall new.
result := callout addTen: 5. "or, InstanceCall new addTen: 5."
Transcript show: 'InstanceCall: Result is: %1' % {result asString}; nl.
Transcript showCr: ''.

Compilation

To keep things simple, I put all the files in the same directory, say, /opt/gst/ccall1. Set the environment variable LD_LIBRARY_PATH so that programs can find the shared library:-

export LD_LIBRARY_PATH=/opt/gst/ccall1

Here is a Makefile to build the shared library and test program.

CC=gcc

all: libtutccall1.so tutccall1test.o
        $(CC) -o tutccall1test tutccall1test.o -L. -ltutccall1 

libtutccall1.so: tutccall1.c
        $(CC) -fPIC -c tutccall1.c -o  tutccall1.o
        $(CC) -shared -Wl,-soname,libtutccall1.so -o libtutccall1.so tutccall1.o

clean:
        rm *.o *.so

“make” and you should find it has created the shared library “libtutccall1.so”, as well as a test executable “tutccall1test”.

Testing the Library

Run the tutccall1test program to check that the library is working. You should get the following output

 Inside addTen()
Test addTen: Passed [5] and the result is [15]

If ever the test program shows an error on loading the shared library, use the ldd utility to check that the library is available. For example:

$> ldd ./tutccall1test
linux-vdso.so.1 =>  (0x00007fff35fff000)
libtutccall1.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcfe8728000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcfe8ac5000)

And set the LD_LIBRARY_PATH environment variable (as mentioned earlier)

$> export LD_LIBRARY_PATH=/opt/gst/libs/
$> ldd ./tutccall1test
linux-vdso.so.1 =>  (0x00007fff2e7ff000)
  libtutccall1.so => /opt/gst/libs/libtutccall1.so (0x00007fc6c83c3000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc6c8028000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc6c85c6000)

$> ./tutccall1test
Inside addTen()
Test addTen: Passed [5] and the result is [15]

Running the Smalltalk script

And here is the output you can expect.

$> ./tutccall1.st

 Inside addTen()
ClassCall: Result is: 15
Result: An instance of SmallInteger

---

 Inside addTen()
InstanceCall: Result is: 15

Regarding the Smalltalk script:-

  • the DLD command references the library we created, i.e. libtutccall1.so, omitting the “.so” suffix.
  • cCall is used to define a C function. As you can see, the Smalltalk method name doesn’t have to be the same as the C function name although it is good practice to keep them similar.
  • The C function addTen accepts and returns an unsigned int, which is mapped to #uint. Available C return types and argument types are listed on this page: http://www.gnu.org/software/smalltalk/manual/html_node/C-callout.html#C-callout
Advertisements

From → GNU Smalltalk

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: