IBM Support

Implementing a C/C++ "NoFramework" adaptor for IBM Rational Rhapsody

White Papers


Abstract

Author: Chris Sutton This document and the attached project files illustrate how the Object Execution Framework (OXF) can be either a) completely removed or b) removed with minimal behavioural functionality. This is beneficial for users seeking to reduce the footprint of their executable or do not require the OXF.

Content

Table of Contents:  



Introduction

The goals of this paper are to i) remove the auto-generated Object Execution Framework (OXF) code/dependencies from your project, whilst ii) retaining minimal behavioural functionality.

These two goals are achieved respectively by:
 

  • A NoFramework profile: This contains the property modifications to remove the OXF code/dependencies.
  • Component files definitions.h and definitions.c. These contain small portions of the OXF that we wish to retain.
 


Limitations

Removing the OXF framework comes at a cost to feature availability. This includes the following limitations:
 
  • No Triggered operations
  • No asynchronous events
  • No Event arguments or event generalization
  • No Event Timeouts
  • No Null-triggered transitions
  • No Instrumentation (Animation/Tracing)
  • No Active objects (Multi-threading)
  • No Protected Operations (Mutex)
  • No Memory Management
  • No OM/OMU containers



The NoFramework profile and stereotype

This stereotype contains the properties that remove OXF framework references from your project. These can be divided into three categories:
 
  • Framework Properties (disabled to exclude the above Limitations)
 
 
  • Compiler switches Properties (removed references to the OXF headers)
 
C_CG::MSVC::CompileSwitches
Default: /I . /I $OMDefaultSpecificationDirectory /I $(OMROOT)\LangC /I $(OMROOT)\LangC\oxf /nologo /W3 $(ENABLE_EH) $(CRT_FLAGS) $OMCPPCompileCommandSet /D "_AFXDLL"
/D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" $(INST_FLAGS) $(INCLUDE_PATH) $(INST_INCLUDES) /c
Modified: /I . /I $OMDefaultSpecificationDirectory /I /nologo /W3 $(ENABLE_EH) $(CRT_FLAGS) $OMCPPCompileCommandSet /D "_AFXDLL"
/D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" $(INST_FLAGS) $(INCLUDE_PATH) $(INST_INCLUDES) /c
CPP_CG::Microsoft::CompileSwitches
Default: /I . /I $OMDefaultSpecificationDirectory /I $(OMROOT)\LangCpp /I $(OMROOT)\LangCpp\oxf /nologo /W3 /GX $OMCPPCompileCommandSet /D "_AFXDLL"
/D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" $(INST_FLAGS) $(INCLUDE_PATH) $(INST_INCLUDES) /c
Modified: /I . /I $OMDefaultSpecificationDirectory /I /nologo /W3 /GX $OMCPPCompileCommandSet /D "_AFXDLL"
/D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" $(INCLUDE_PATH) /c
 
  • Makefile contents (removed references to the OXF headers)
 
  • See CPP_CG::MSVC::MakeFileContent properties in attached projects for modifications




  •  
 
  • Statechart and Event support

  • There is one additional step that is optional; This allows you to fully disable the OXF. This will add further limitations to your project: No Statechart/Event support.
    You can do this by setting CG::Class::ImplementStatechart and CG::Event::Generate to false. This will fully disable the OXF.

    However, in this paper we will retain a minimum statechart functionality.



Synchronous Event and Minimal Statechart support for Rhapsody In C

This section below explains how to provide minimal behavioural functionality (Statecharts/Events) along with the NoFramework profile.

Once the NoFramework profile is applied, some auto-generated framework code will still remain in any reactive classes. We can re-use this code to provide minimal behavioural functionality. Our main focus will be on two member operations in particular:
  • static void rootState_entDef(void * const void_me)
  • static RiCTakeEventStatus rootState_dispatchEvent(void * const void_me, short id)

The first is called to enter the default state of the statechart, the second is called to trigger an event.
In order to continue the use of these operations we need to account for any return or parameter types they may be using. Since we have removed all OXF dependencies from the project, the compiler will no longer recognise these types.

The me pointer is purely used as a reference to the calling class, so we do not need to be concerned with that.
This leaves the RiCTakeEventStatus and RiCEvent structures. Note that the latter contains the id of the event seen in the rootState_dispatchEvent operation. These structs are from the OXF so we must provide a local definition for the compiler. These are added into the definitions.h component file. See appendix.
 


Synchronous Event and Minimal Statechart support for Rhapsody In C++

This section below explains how to provide minimal behavioural functionality (Statecharts/Events) along with the NoFramework profile.

Once the NoFramework profile is applied, some auto-generated framework code will still remain in any reactive classes. We can re-use this code to provide minimal behavioural functionality. Our main focus will be on two member operations in particular:
 
  • virtual void rootState_entDef()
  • virtual IOxfReactive::TakeEventStatus rootState_processEvent();

The first is called to enter the default state of the statechart, the second is called to trigger an event.
In order to continue the use of these operations we need to account for any return types they may be using. Since the references to the IOxfReactive::TakeEventStatus interface and event status identifiers were removed along with the rest of the OXF so we must provide a local definition for the compiler. These are added into the definitions.h component file. See appendix.
 


Using the NoFramework Profile with Rhapsody In C
 
  • rootState_entDef() Operation
  • This function is used to transition the startchart execution into the default state. This needs to be called by all reactive classes when they are initialised. For example:

  • rootState_dispatchEvent() Operation
  • You use this operation to dispatch an event. You identify the event using the event_id. You create a class function for each call to an event in its statechart. In this case we have called the class: call_evPing(). Additionally we created a macro to ease the ability to dispatch an event:

    #define SEND_EVENT(me, identifier) rootState_dispatchEvent(me, identifier);


You can now use the operations to trigger synchronous events in the statechart.
 


Using the NoFramework Profile with Rhapsody In C++
 
  • Operation: rootState_entDef()
  • This function is used to transition the startchart execution into the default state. This needs to be called by all reactive classes when they are initialised. For example:

 
  • Operation: rootState_process_Event()
  • You use this operation to dispatch an event. You identify the event using the event_id. You create a class function for each call to an event in its statechart. In this case we have called the class: callEvPing(). Additionally we created a macro to ease the ability to dispatch an event:

    #define SEND_EVENT(identifier) rootState_processEvent();


You can now use the operations to trigger synchronous events in the statechart.
 


Appendix - C Local definition files.
  • Variables.h

  • #ifndef _OMINSTRUMENT

    int OM_CURRENT_EVENT_ID;

    #endif




  •  
  • Definitions.h

  • #ifndef _OMINSTRUMENT

    typedef int OMBoolean;
    typedef int intnum;
    #define DECLARE_MEMORY_ALLOCATOR(class,int)
    #define IMPLEMENT_MEMORY_ALLOCATOR(class,int,intnum,OMBoolean)

    #ifndef NULL
    #define NULL 0
    #endif

    #ifndef TRUE
    #define TRUE 1
    #endif

    #ifndef FALSE
    #define FALSE 0
    #endif

    #define eventNotConsumed 0
    #define eventConsumed 1
    #define instanceUnderDestruction 2
    #define instanceReachTerminate 3
    class IOxfReactive {
    public:
    // Event dispatching result
    typedef int TakeEventStatus;
    };

    extern int OM_CURRENT_EVENT_ID;
    //extern void setId(int identifier);

    inline void setId(int identifier) {
    OM_CURRENT_EVENT_ID = identifier;
    }

    #define SEND_EVENT(identifier) setId(identifier); \
    rootState_processEvent();

    #endif




  •  



Appendix B - C++ Local definition files.
  • Definitions.h

  • /*********************************************************************
    Rhapsody in C : 8.1
    Component : DefaultComponent
    Configuration : DefaultConfig
    Model Element : definitions
    //! Generated Date : Fri, 25, Jul 2014
    File Path : DefaultComponent\DefaultConfig\definitions.h
    *********************************************************************/

    #ifndef definitions_H
    #define definitions_H

    typedef int RiCBoolean;
    typedef short RiCEventId;

    #define RIC_EMPTY_STRUCT RiCBoolean dummy;

    #ifndef TRUE
    #define TRUE ((RiCBoolean)1)
    #endif

    #ifndef FALSE
    #define FALSE ((RiCBoolean)0)
    #endif

    #ifndef NULL
    #define NULL 0
    #endif

    typedef enum RiCTakeEventStatus_t
    {
    eventNotConsumed = 0,
    RiCTakeEventError = 0,
    eventConsumed = 1,
    RiCTakeEventCompleted = 1,
    RiCTakeEventInCleanup = 2,
    RiCTakeEventReachTerminate = 3
    } RiCTakeEventStatus;

    typedef struct RiCEvent_t
    {
    RiCEventId lId;
    } RiCEvent;

    typedef struct RiCReactive_t {
    RIC_EMPTY_STRUCT

    } RiCReactive;

    /* Creation and Destruction methods */
    RiCBoolean RiCEvent_init( RiCEvent *const me, const RiCEventId eventId,
    const struct RiCReactive_t *dest );
    void RiCEvent_cleanup( RiCEvent *const me );

    #define SEND_EVENT(me, identifier) rootState_dispatchEvent(me, identifier);

    #endif




  •  
  • Definitions.c

  • /*********************************************************************
    Rhapsody in C : 8.1
    Component : DefaultComponent
    Configuration : DefaultConfig
    Model Element : definitions
    //! Generated Date : Fri, 25, Jul 2014
    File Path : DefaultComponent\DefaultConfig\definitions.c
    *********************************************************************/

    #include "definitions.h"


    RiCBoolean RiCEvent_init( RiCEvent *const me,
    const RiCEventId eventId,
    const RiCReactive *dest )
    {
    RiCBoolean result = FALSE;

    if( me != NULL )
    {
    me->lId = eventId;
    result = TRUE;
    }

    return result;
    }

    void RiCEvent_cleanup( RiCEvent *const me )
    {
    if( me != NULL )
    {
    me->lId = NULL;

    }
    }
    /*********************************************************************
    File Path : DefaultComponent\DefaultConfig\definitions.c
    *********************************************************************/




  •  


Document information

More support for: Rational Rhapsody

Component: General Information

Software version: 8.1

Operating system(s): Windows

Reference #: 7043154

Modified date: 28 January 2019