[Up: C++ mapping]
[Previous: Interface inheritance] [Next: Exceptions]

#
Modules

In contrast to other middleware platforms, CORBA does not assign an universal unique identifier (UUID) to an interface. To avoid name clashes, CORBA offers a structured name space, similar to the directory structure of a UNIX file system. Within an IDL a scope is defined by the keyword `module`. For example the following IDL-code excerpt defines two modules called `Mod1` and `Mod2` on the same level:

      module Mod1 {
        //...
        interface foo;
      };

      module Mod2
      {
        //...
      };

Module declarations can be nested which leads to the above mentioned hierarchical namespace. The IDL to C++ mapping offers different alternatives on how to map a module to C++. Those C++ compilers which support the namespace feature of the C++ language, IDL-modules are directly mapped to C++ namespaces. Unfortunately the GNU compiler currently does not support namespaces. In this case the CORBA specification offers two alternatives: either do some name mangling such that a name reflects the absolute name of the IDL-identifier where the names are separated by undersores (e.g. `Mod1_foo`). The second alternative is to map an IDL-module to a C++ `struct`.

The second alternative has two drawbacks: without a proper support for namespaces all names have to be referenced by their absolute names, i.e. there is no C++ keyword `using` (note that this is also true for the first alternative). The second drawback has to do with the possibility to re-open CORBA-modules which allows cyclic definitions:

      module M1 {
        typedef char A;
      };

      module M2
      {
        typedef M1::A B;
      };

      module M1 {  // re-open module M1
      {
        typedef M2::B C;
      };

The declaration of a C++ `struct` has to occur in one location (i.e. a `struct` can not be re-opened). Mapping IDL-modules to C++ structs therefore implies, that re-opening of modules can not be translated to C++. However, if the C++ compiler supports namespaces, MICO's IDL-compiler allows the re-opening of modules. The backend of MICO's IDL-compiler generates a dependency graph to compute the correct ordering of IDL definitions. Figure 5.3 shows the dependency graph for the IDL specification shown above. The correct ordering of IDL definitions is done by doing a left-to-right, depth-first, post-order traversal of the dependency graph starting from `_top`, and omitting previously visited nodes of the graph.

Figure 5.3: Dependency graph.

Sometimes it is necessary to have some control over the top-level modules. This for example is used in `CORBA.h` where some definitions have to be read in one at a time. The IDL-compiler inserts some `#define` in the generated `.h` file. Setting and unsetting these defines allows to read the module definitions one at a time. Given the two modules `Mod1` and `Mod2` as above, the following C++ code fragment demonstrates how to do this:

     1:  // These #includes need to be done manually if
     2:  // MICO_NO_TOPLEVEL_MODULES is defined
     3:  #include <CORBA.h>
     4:  #include <mico/template_impl.h>
     5:
     6:  #define MICO_NO_TOPLEVEL_MODULES
     7:
     8:  // Get module Mod1
     9:  #define MICO_MODULE_Mod1
    10:  struct Mod1 {
    11:    #include "module.h"
    11:  };
    12:  #undef MICO_MODULE_Mod1
    13:
    14:  // Get module Mod2
    15:  #define MICO_MODULE_Mod2
    16:  struct Mod2 {
    17:    #include "module.h"
    18:  };
    19:  #undef MICO_MODULE_Mod2
    20:
    21:  // Get global definitions in module.h
    22:  #define MICO_MODULE__GLOBAL
    23:  #include "module.h"
    24:  #undef MICO_MODULE__GLOBAL
    25:  #undef MICO_NO_TOPLEVEL_MODULES

In this example we assume that the definitions are located in a file called `module.h`. First of all you need to define `MICO_NO_TOPLEVEL_MODULES` which simply means that you wish to read in the definitions yourself (line 6). For each toplevel module `XYZ` in an IDL-file there exists a define called `MICO_MODULE_XYZ`. Setting this define will activate all definitions which belong to module `XYZ` (see lines 9 and 15). Do not forget to undefine these definitions after the definitions are read in (lines 12 and 19). There are some global definitions which do not belong to any module. For these definitions there in a special define called `MICO_MODULE__GLOBAL` (see line 22; the two underscores are no typo). The last thing we need to do is to undefine `MICO_MODULE__GLOBAL` and `MICO_NO_TOPLEVEL_MODULE` (see lines 24 and 25). This example can also be found in the directory `mico/test/idl/10`.

[Previous: Interface inheritance] [Next: Exceptions]
[Up: C++ mapping]