Go to the first, previous, next, last section, table of contents.

New Tools, Targets, or Hosts

The most common ways to extend the DejaGnu framework are: adding a suite of tests for a new tool to be tested; adding support for testing on a new target; and porting runtest to a new host.

Writing tests for a new tool

In general, the best way to learn how to write (code or even prose) is to read something similar. This principle applies to test cases and to test suites. Unfortunately, well-established test suites have a way of developing their own conventions: as test writers become more experienced with DejaGnu and with Tcl, they accumulate more utilities, and take advantage of more and more features of expect and Tcl in general.

Inspecting such established test suites may make the prospect of creating an entirely new test suite appear overwhelming. Nevertheless, it is quite straightforward to get a new test suite going.

There is one test suite that is guaranteed not to grow more elaborate over time: both it and the tool it tests were created expressly to illustrate what it takes to get started with DejaGnu. The `example/' directory of the DejaGnu distribution contains both an interactive tool called calc, and a test suite for it. Reading this test suite, and experimenting with it, is a good way to supplement the information in this section. (Thanks to Robert Lupton for creating calc and its test suite--and also the first version of this section of the manual!)

To help orient you further in this task, here is an outline of the steps to begin building a test suite for a program example.

  1. Create or select a directory to contain your new collection of tests. Change to that directory (shown here as testsuite):
    eg$ cd testsuite/
  2. Create a `configure.in' file in this directory, to control configuration-dependent choices for your tests. So far as DejaGnu is concerned, the important thing is to set a value for the variable target_abbrev; this value is the link to the init file you will write soon. (For simplicity, we assume the environment is Unix, and use `unix' as the value.) What else is needed in `configure.in' depends on the requirements of your tool, your intended test environments, and which configure system you use. This example is a minimal configure.in for use with Cygnus Configure. (For an alternative based on the FSF autoconf system, see the calc example distributed with DejaGnu.) Replace example with the name of your program:
    # This file is a shell script fragment
    # for use with Cygnus configure.
    srcname="The DejaGnu example tests"
    # per-host:
    # per-target:
    # everything defaults to unix for a target
    # post-target:
  3. Create `Makefile.in', the source file used by configure to build your `Makefile'. Its leading section should as usual contain the values that configure may override:
    srcdir = .
    prefix = /usr/local
    exec_prefix = $(prefix)
    bindir = $(exec_prefix)/bin
    libdir = $(exec_prefix)/lib
    tooldir = $(libdir)/$(target_alias)
    datadir = $(exec_prefix)/lib/dejagnu
    RUNTEST = runtest
    #### host, target, site specific Makefile frags come in here.
    This should be followed by the standard targets at your site. To begin with, they need not do anything--for example, these definitions will do:
            -rm -f *~ core *.info*
    It is also a good idea to make sure your `Makefile' can rebuild itself if `Makefile.in' changes, with a target like this (which works for either Cygnus or FSF Configure):
    Makefile : $(srcdir)/Makefile.in $(host_makefile_frag) \
            $(SHELL) ./config.status
    You also need to include two targets important to DejaGnu: check, to run the tests, and site.exp, to set up the Tcl copies of configuration-dependent values. The check target must run `runtest --tool example':
    check: site.exp all
                --tool example --srcdir $(srcdir) 
    The site.exp target should usually set up (among other things!) a Tcl variable for the name of your program:
    site.exp: ./config.status Makefile
            @echo "Making a new config file..."
            -@rm -f ./tmp?
            @touch site.exp
            -@mv site.exp site.bak
            @echo "## these variables are automatically\
     generated by make ##" > ./tmp0
            @echo "# Do not edit here. If you wish to\
     override these values" >> ./tmp0
            @echo "# add them to the last section" >> ./tmp0
            @echo "set host_os ${host_os}" >> ./tmp0
            @echo "set host_alias ${host_alias}" >> ./tmp0
            @echo "set host_cpu ${host_cpu}" >> ./tmp0
            @echo "set host_vendor ${host_vendor}" >> ./tmp0
            @echo "set target_os ${target_os}" >> ./tmp0
            @echo "set target_alias ${target_alias}" >> ./tmp0
            @echo "set target_cpu ${target_cpu}" >> ./tmp0
            @echo "set target_vendor ${target_vendor}" >> ./tmp0
            @echo "set host_triplet ${host_canonical}" >> ./tmp0
            @echo "set target_triplet ${target_canonical}">>./tmp0
            @echo "set tool binutils" >> ./tmp0
            @echo "set srcdir ${srcdir}" >> ./tmp0
            @echo "set objdir `pwd`" >> ./tmp0
            @echo "set examplename example" >> ./tmp0
            @echo "## All variables above are generated by\
     configure. Do Not Edit ##" >> ./tmp0
                    @cat ./tmp0 > site.exp
            @sed < site.bak \
                   -e '1,/^## All variables above are.*##/ d' \
                   >> site.exp
            -@rm -f ./tmp?
  4. Create a directory (in `testsuite/') called `config/':
    eg$ mkdir config
  5. Make an init file in this directory; its name must start with the target_abbrev value, so call it `config/unix.exp'. This is the file that contains the target-dependent procedures; fortunately, most of them do not have to do very much in order for runtest to run. If example is not interactive, you can get away with this minimal `unix.exp' to begin with:
    proc foo_exit {} {}
    proc foo_version {} {}
    If example is interactive, however, you might as well define a start routine and invoke it by using an init file like this:
    proc foo_exit {} {}
    proc foo_version {} {}
    proc foo_start {} {
      global examplename
      spawn $examplename
      expect {
        -re "" {}
  6. Create a directory whose name begins with your tool's name, to contain tests:
    eg$ mkdir example.0
  7. Create a sample test file in `example.0'. Its name must end with `.exp'; you can use `first-try.exp' To begin with, just write there a line of Tcl code to issue a message:
    send_user "Testing: one, two...\n"
  8. Back in the `testsuite/' (top level) directory, run
    eg$ configure
    (You may have to specify more of a path, if a suitable configure is not available in your execution path.)
  9. You are now ready to triumphantly type `make check' or `runtest --tool example'. You should see something like this:
    Test Run By rhl on Fri Jan 29 16:25:44 EST 1993
                    === example tests ===
    Running ./example.0/first-try.exp ...
    Testing: one, two...
                    === example Summary ===
    There is no output in the summary, because so far the example does not call any of the procedures that establish a test outcome.
  10. Begin writing some real tests. For an interactive tool, you should probably write a real exit routine in fairly short order; in any case, you should also write a real version routine soon.

Adding a target

DejaGnu has some additional requirements for target support, beyond the general-purpose provisions of Cygnus configure. runtest must actively communicate with the target, rather than simply generating or managing code for the target architecture. Therefore, each tool requires an initialization module for each target. For new targets, you must supply a few Tcl procedures to adapt DejaGnu to the target. This permits DejaGnu itself to remain target independent. See section Initialization module, for a discussion of the naming conventions that enable DejaGnu to locate and use init files.

Usually the best way to write a new initialization module is to edit an existing initialization module; some trial and error will be required. If necessary, you can use the `--debug' option to see what is really going on.

When you code an initialization module, be generous in printing information controlled by the verbose procedure (see section DejaGnu procedures).

Most of the work is in getting the communications right. Communications code (for several situations involving IP networks or serial lines) is available in a DejaGnu library file, `lib/remote.exp'. See section Library procedures.

If you suspect a communication problem, try running the connection interactively from expect. (There are three ways of running expect as an interactive interpreter. You can run expect with no arguments, and control it completely interactively; or you can use `expect -i' together with other command-line options and arguments; or you can run the command interpreter from any expect procedure. Use return to get back to the calling procedure (if any), or return -tcl to make the calling procedure itself return to its caller; use exit or end-of-file to leave expect altogether.) Run the program whose name is recorded in `$connectmode', with the arguments in `$targetname', to establish a connection. You should at least be able to get a prompt from any target that is physically connected.

Porting to a new host

The task of porting DejaGnu is basically that of porting Tcl and expect. Tcl and expect, as distributed with DejaGnu, both use autoconf; they should port automatically to most Unix systems.

Once Tcl and expect are ported, DejaGnu should run. Most system dependencies are taken care of by using expect as the main command shell.

Go to the first, previous, next, last section, table of contents.