Drektz
Drektz

Reputation: 95

How to develop tool in C/C++ whose command interface is Tcl shell?

Suppose a tool X need to developed which are written in C/C++ and having Tcl commanline interface, what will the steps or way?

I know about Tcl C API which can be used to extend Tcl by writing C extension for it.

Upvotes: 1

Views: 825

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137567

What you're looking to do is embedding Tcl (totally a supported use case; Tcl remembers that it is a C library) but still making something tclsh-like. The simplest way of doing this is:

Grab a copy of tclAppInit.c (e.g., this is the current one in the Tcl 8.6 source tree as I write this) and adapt it, probably by putting the code to register your extra commands, linked variables, etc. in the Tcl_AppInit() function; you can probably trim a bunch of stuff out simply enough. Then build and link directly against the Tcl library (without stubs) to get effectively your own custom tclsh with your extra functionality.

You can use Tcl's API more extensively than that if you're not interested in interactive use. The core for non-interactive use is:

// IMPORTANT: Initialises the Tcl library internals!
Tcl_FindExecutable(argv[0]);

Tcl_Interp *interp = Tcl_CreateInterp();
// Register your custom stuff here

int code = Tcl_Eval(interp, "your script");
// Or Tcl_EvalFile(interp, "yourScriptFile.tcl");

const char *result = Tcl_GetStringResult(interp);
if (code == TCL_ERROR) {
    // Really good idea to print out error messages
    fprintf(stderr, "ERROR: %s\n", result);
    // Probably a good idea to print error traces too; easier from in Tcl
    Tcl_Eval(interp, "puts stderr $errorInfo");
    exit(1);
}

// Print a non-empty result
if (result[0]) {
    printf("%s\n", result);
}

That's about all you need unless you're doing interactive use, and that's when Tcl_Main() becomes really useful (it handles quite a few extra fiddly details), which the sample tclAppInit.c (mentioned above) shows how to use.

Upvotes: 5

ItayBenHaim
ItayBenHaim

Reputation: 183

Usually, SWIG (Simplified Wrapper and Interface Generator) is the way to go. SWIG HOMEPAGE

This way, you can write code in C/C++ and define which interface you want to expose.

suppose you have some C functions you want added to Tcl:

/* File : example.c */

 #include <time.h>
 double My_variable = 3.0;

 int fact(int n) {
     if (n <= 1) return 1;
     else return n*fact(n-1);
 }

 int my_mod(int x, int y) {
     return (x%y);
 }

 char *get_time()
 {
     time_t ltime;
     time(&ltime);
     return ctime(&ltime);
 }

Now, in order to add these files to your favorite language, you need to write an "interface file" which is the input to SWIG. An interface file for these C functions might look like this :

 /* example.i */
 %module example
 %{
 /* Put header files here or function declarations like below */
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();
 %}

 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();

At the UNIX prompt, type the following:

 unix % swig -tcl example.i
 unix % gcc -fpic -c example.c example_wrap.c \
        -I/usr/local/include 
 unix % gcc -shared example.o example_wrap.o -o example.so
 unix % tclsh
 % load ./example.so example
 % puts $My_variable
 3.0
 % fact 5
 120
 % my_mod 7 3
 1
 % get_time
 Sun Feb 11 23:01:07 2018

The swig command produces a file example_wrap.c that should be compiled and linked with the rest of the program. In this case, we have built a dynamically loadable extension that can be loaded into the Tcl interpreter using the 'load' command.

Taken from http://www.swig.org/tutorial.html

Upvotes: 4

Related Questions