SourceForge.net LogoThe Eiffel Compiler / Interpreter (tecomp)

doc/tecomp/ace

Options and ace-file format

Assembly of compilation units

ACE is an abbreviation which stands for Assembly of Classes in Eiffel. An Eiffel compilation unit is an assembly an must be described by an ace section.

A compilation unit is either a program or a library. Each program and each library must have a describing ace section. A library has to be described by an ace file and a program can be described by either an ace file or an ace section within the main file.

An ace file (or section) specifies:

From simple to more complex programs

The simplest Eiffel program

The simplest Eiffel program can be written within a file

   do
       print("Hello world.%N")
   end
 

This file specifies implicitly a nameless root class with a nameless root procedure (and no other features). The block between `do' and `end' is the body of the root procedure.

It is not necessary to specify the used library "eiffel/lang", because it will be included implicitely by the compiler.

By the way: On any unix system you can add

  #! /usr/bin/env tecomp

as the first line, make the file executable and call it simply by its name from the shell.

A more complex program in one file

The main file can grow and contain various classes and a feature block of the nameless root class and the body of the nameless root procedure in any order. If it contains an ace section, it has to be the first part of the file.

A more complex one file Eiffel program might look like

   -- ace section of the program
   default
      assertion(no)                     -- assertion monitoring off
   option
      assertion(all): SIMPLE_CLASS_1, 
                      SIMPLE_CLASS_2    -- but on for these classes
   cluster
      "eiffel/container"                -- library "eiffel/container" used
   end
 
   -- program section
   class SIMPLE_CLASS_1  ... end
 
   class SIMPLE_CLASS_2  ... end
 
   class SIMPLE_CLASS_3  ... end
   ...
 
   -- features of the root class
   feature            
      f1(a:INTEGER)                    do ... end
      f2(b:CHARACTER): BOOLEAN         do ... end
   end
 
   -- body of the root procedure
   local              
      c1: SIMPLE_CLASS_1
   do
      create c1.make
      f1(100)
      if f2('A') then
        c1.do_some_thing
      else
        c1.do_some_thing_else
      end
   end
 

Splitting out the Eiffel classes

If the program grows further one file will become too big. It is therefore better to put each Eiffel class into one file and put all *.e files into the same directory as the ace file. The directory will look like

   % ls
   my_program.ace  my_program.e  class_1.e  class_2.e  class_3.e  class_4.e

and the ace file will have the content

   {MY_PROGRAM}.make
   default
      assertion(no)
   cluster
      "."                   -- the "current" cluster
         option
            assertion(all): CLASS_1, CLASS_2
         end
      "eiffel/container"
   end
 

Splitting out clusters

If the program reaches a certain size, you will want to group the classes into clusters. Let's say you want to group them into the subclusters `main', `basic', `file_io'.

   % ls
   my_program.ace  main  basic  file_io
   % ls main
   my_program.e  class_1.e class_2.e
   % ls basic
   basic_1.e  basic_2.e
   ...

If you just put the classes into different subdirectories, there is no need to change the ace file. All the classes of your program are still contained within the cluster ".", because clusters are scanned recursively. You would still have one application cluster.

But there is also the possibility to treat the subclusters `main', `basic' and `file_io' as separate clusters. This gives us the possibility to set different defaults for each cluster (e.g. if the cluster have different maturity). We could e.g. use the ace file

   {MY_PROGRAM}.make           -- root class and root procedure
   default
      assertion(no)
   cluster
      "main"
         default
            assertion(all)
         end
      "basic"
      "file_io"
      "eiffel/container"
   end
 

Splitting out libraries

You might discover that the classes within the cluster `basic' can be used by other programs as well. Then you want to convert the cluster into a library. If you want to do that, you have to create a directory "my/eiffel/libs" where you will put all your libraries.

  % ls my/eiffel/libs
  basic
  % ls my/eiffel/libs/basic
  lib.ace  basic_1.e basic_2.e ...

In order to find the library by the name `basic', you have to include the path `my/eiffel/libs" into the search path for libraries (e.g. via the environment variable `EIFFEL_LIBRARY_PATH' or via the command line option `-Imy/eiffel/libs' for the eiffel compiler).

In order to convert your cluster `basic' into a library you only have to add a file named `lib.ace' to the toplevel directory of the cluster, e.g.

  default
     assertion(no)                 -- the library has already been well tested
  option
     assertion(all): X, Y          -- but there are still some less mature
                                   -- classes
  cluster
     "eiffel/container"
        option
           assertion(all): LIST    -- and you don't trust the class LIST
        end
  end
 

The following rules apply:

How to override and merge defaults and options

Since a library can be used by other libraries or programs, the different users of that library can specify different defaults and options for that library (cluster).

If there is only one user of a library the rule is simple: The user can override the defaults and the options if he decides to do so. E.g. the ace file `my_program.ace'

   {MY_PROGRAM}.make
   default
      assertion(no)
   cluster
      "main"
         default
            assertion(all)
         end
      "basic"
         default
            assertion(all)
         option
            assertion(no): X
         end
      "file_io"
      "eiffel/container"
   end
 

decides to override the defaults and the specific option for the class `X'.

If there is more than one user, the overrides might be in conflict. In order to resolve the conflicts we introduce the rules:

Merge schema:

  ace_file_1:
    assertion(all)  debug(yes)  debug("net")
  ace_file_2:
    assertion(no)   debug(no)   debug("io")
  merged:
    assertion(all)  debug(yes)  debug("net")  debug("io")

The above merge scheme applies for defaults and for options of specific classes.

 Local Variables: 
 mode: outline
 coding: iso-latin-1
 outline-regexp: "=\\(=\\)*"
 End:
Table of contents

- Assembly of compilation units

- From simple to more complex programs

- The simplest Eiffel program

- A more complex program in one file

- Splitting out the Eiffel classes

- Splitting out clusters

- Splitting out libraries

- How to override and merge defaults and options


ip-location