An Introduction To Embedded Tk (page 16 of 32)

[Previous Page][Next Page][Table of Contents]

8 Including External Tcl/Tk Scripts In A C Program

In the sample programs seen so far in this article, Tcl/Tk code in an ET() function was used to construct the main window. This works fine for the examples, since their windows are uncomplicated and can be constructed with a few lines code. But in a real application, or even a more complex example, the amount of Tcl/Tk code needed to initialize the program's windows can quickly grow to hundreds or thousands of lines. It is impractical and irksome to put this much code into an ET() statement, so the ET system provides another way to get the job done: the ET_INCLUDE() statement.

The ET_INCLUDE() statement is similar in concept to the #include statement in the C preprocessor. Both take a filename as their argument, and both read the named file into the original source program. The ET_INCLUDE() statement expects its file to be pure Tcl/Tk code, though. Its job is to turn the Tcl/Tk source into a form that the C compiler can understand, and to arrange for the Tcl/Tk to be executed when control reaches the ET_INCLUDE() statement.

An example may help to clarify this idea. In the decimal clock program (way back at the beginning of section 6), there are 7 lines of Tcl/Tk in an ET() function used to create the application's main window. Now suppose we move those 7 lines of Tcl/Tk into a separate file named dclock.tcl. Then we could replace the ET() function with an ET_INCLUDE() statement that references the new file like this:

  void main(int argc, char **argv){
    Et_Init(&argc, argv);
    ET_INSTALL_COMMANDS;
    ET_INCLUDE( dclock.tcl );
    Et_MainLoop();
  }
When the et2c preprocessor sees the ET_INCLUDE() statement, it locates the specified file, reads that file into the C program, and makes arrangements for the text of the file to be executed as if it had all appeared within an ET() function.

Well, almost like an ET() function. There are a couple of minor differences. The ET_INCLUDE() does not understand the various %s(...) substitutions as ET() does. Also, ET_INCLUDE() is a true procedure, not a function. It doesn't return a value like ET() so you can't use an ET_INCLUDE() in an expression.

It is important to understand the difference between an ET_INCLUDE() statement like this

    ET_INCLUDE( dclock.tcl );
and the source command of Tcl/Tk, used as follows:
    ET( source dclock.tcl );
The ET_INCLUDE() statement reads the Tcl/Tk into the program at compile-time, effectively making the Tcl/Tk code part of the executable. The Tcl source command, on the other hand, opens and reads the file at run-time, as the application executes. This makes the executable a little smaller, but it also means that the file containing the Tcl/Tk must be available to the executable whenever it runs. If you move just the executable, but not the Tcl/Tk file, to another computer, or even another directory, then it will no longer work because it won't be able to locate and read the Tcl/Tk file.

The ability to read an external Tcl/Tk script and make it part of the executable program is an important feature of ET. But while you are developing and testing a program, it is sometimes convenient to turn this feature off and to have the application read its scripts at run-time instead of compile-time. That way, you can make changes to the Tcl/Tk script and rerun your program with the changes, but without having to recompile. You can do this using the -dynamic option to the et2c proprocessor. Whenever you run et2c with the -dynamic command-line option, it effective turns instances of the statement

    ET_INCLUDE( filename.tcl );
into the statement
    ET( source filename.tcl );
This feature has proven very helpful during development. But be careful to turn it off before doing your final build, or else you won't be able to move your executable to other machines!

There is just one other feature of the ET_INCLUDE() statement that we need to discuss before moving on, and that is the algorithm it uses to locate the Tcl/Tk source code files. Just like the C preprocessor's #include statement, the ET_INCLUDE() mechanism can include files found in other directories.

The et2c preprocessor always looks first in the working directory for files named by an ET_INCLUDE() statement. If the file is found there, no further search is made. But if the file is not found, then et2c will also look in all directories named in -I command line options. For example, if you run et2c like this:

    et2c -I../tcl -I/usr/local/lib/tcl app.c >app_.c
and the app.c file contains a line of the form:
    ET_INCLUDE( setup.tcl );
then et2c will search for the setup.tcl first in the ``.'' directory, then in ../tcl and in /usr/local/lib/tcl. It will use the first instance of setup.tcl that it finds.

[Next Page][Table of Contents]