These module-level events are called on all Components, but are generally handled by the Component Bindings, so the Component developer will not have to handle them.

Information Exchange

Here, we summarise the information exchange that takes place between the framework and the module as the various events are fired. This documentation will be useful for the developers of bindings, in particular, but also clarifies the relationships for framework maintainers. It will not be of great interest to component developers (users), who will usually be protected by the bindings (which take approach 1, below, by default).


Each release of BRAHMS is stamped with a revision number, a 32-bit unsigned integer. This number uniquely identifies the release, and also uniquely indentifies the interfaces provided by that engine. The interfaces will not usually change from one release to the next but, nonetheless, each engine release defines a new interface revision, even if there are no changes from the previous revision. Most documented features (structure fields, events) are not marked with a revision - this means that they are available in all interfaces. Features that have been added since the first revision-stamped interface release (BRAHMS 0.7.4), i.e. extensions, are marked in the documentation with a revision number; they are available in the indicated revision, and later revisions.

ExecutionInfo is passed from the framework to the module. This structure is valid for the lifetime of the module, and contains information about the running engine and execution. ModuleInfo is passed from the module to the framework. This structure must be valid for the lifetime of the module, and contains information about the module. ExecutionInfo includes a field revisionEngine, which indicates the revision of the run-time engine and implies the interface revision provided by the engine (these two things are equal, as explained above). ModuleInfo includes a field componentInterfaceRevisionCompiled, which indicates the engine revision against which the component was compiled, and a field componentInterfaceRevisionRequired, which indicates the engine revision the component was written for (if the component is recompiled against a later engine release, the former value changes but the latter does not, so the latter value should be hardcoded, whilst the former should be set equal to BRAHMS_COMPONENT_INTERFACE_REVISION).

The Module author can take three approaches to the use of interface functionality, in order of complexity.

  1. The simplest way for a Module author to proceed is to hardcode componentInterfaceRevisionRequired equal to the value of BRAHMS_COMPONENT_INTERFACE_REVISION (not the symbol, the value!). Such a Component will only run on that revision of BRAHMS or later revisions and, if recompiled, will retain the same behaviour. The Module author can take advantage of all interface functionality available at design time.
  2. The downside of the first approach is that the Component will not run on earlier versions of BRAHMS, even if it does not need the interface extensions that have since become available. A Module author may, then, hardcode componentInterfaceRevisionRequired instead to an earlier interface, but must then take responsibility for not using any of the extensions that became available inbetween (which might lead to segfaulting on earlier engines).
  3. Finally, the really brave Module author can take the second approach, but check the value of revisionEngine offered by the run-time engine, and provide additional functionality only if it is available. This is probably not worth the bother - easier to require the later interface revision and expect your users to update their installation of BRAHMS to use your Module.

The Framework has the following responsibilities, which mirror those of the Module author.

  • Check the value of componentInterfaceRevisionRequired offered by the Module, and raise an error if it is greater than the run-time engine revision.
  • Ideally, interface extensions will always be backwards-compatible; that is, the new interface can be called on an earlier Module without causing problems. However, shit happens; if it emerges that a later interface has to be changed so that an earlier interface will no longer work, the framework can check the value of componentInterfaceRevisionCompiled offered by the Module to establish whether to use the changed (later) version of the interface or the unchanged (earlier) version. Such subtleties can only cause performance hits, so this is to be avoided, but the field is included just in case.






No information exchange.