Overview

This chapter covers how to compile and link basic programs, and programs that use C++ classes generated from EXPRESS schemas.

The generated EXPRESS C++ classes provide strong compile-time type checking and convenient member functions but programs do not need a C++ class for each type in an EXPRESS schema. When reading data that does not exactly match a C++ class, the ROSE library can use the closest available class and access information using an EXPRESS data dictionary.

Compiling

This section describes how to build ST-Developer C++ applications. We have specific instructions for setting up Visual Studio projects and UNIX makefiles, but the walkthrough below will help you understand basic process in case you would like to adapt it to a different build system.

This discussion uses environment variables set as part of the ST-Developer installation, specifically $ROSE, $ROSE_INCLUDE, and $ROSE_LIB. These point to directories where the C++ header and library files are located. The following example compiles and links a simple program. All ROSE applications link against -lrose or rose.lib, or alternately DLL versions of the libraries on Windows.

    On UNIX and MacOS
    % CC -I$ROSE_INCLUDE  simple.cxx -L$ROSE_LIB -lrose 
    
    On Windows
    > cl /I"%ROSE_INCLUDE%"  simple.cxx /LIBPATH:"%ROSE_LIB%" rose.lib

ST-Developer has class libraries for STEP APs and other models. These have sample programs that you can use as a starting point. They also have code for creating STEP units, measure values, contexts, and other common data that you can reuse.

When using an AP class library, you add another library and include search to your build. The example below uses the AP203 class library. The documentation page for each AP lists the extra library and include directory names.

    On UNIX and MacOS
    % CC -c -I$ROSE_INCLUDE -I$ROSE_INCLUDE/ap203lib  simple.cxx

    On Windows
    > cl /c /I"%ROSE_INCLUDE%" /I"%ROSE_INCLUDE%\ap203lib"  simple.cxx

The linker sometimes omits EXPRESS classes if instances are only created indirectly by reading a STEP file. A call to the force-load function in your main() will make sure that all classes are present.

Each class has a static RoseType object with C++ runtime type information, so it also is important that static constructors are called or the ROSE library will not be properly initialized. This used to be an issue when linking with different languages now static initialization is handled directly in the object file format.

EXPRESS C++ Classes

ROSE applications can use C++ classes created from EXPRESS for strong type-checking and simple access/update functions. The STEP Merged AP and IFC BIM libraries contain ready-to-use classes for the most widely used schemas. You can use the ST-Developer EXPRESS compiler to generate C++ classes from your own schemas. This section describes how the C++ classes are structured.

Each generated definition includes a <class>.h declaration file and a <class>.cxx definition file. A definition is generated for each entity, select, aggregate and enumeration in a schema. The compiler also generates the <schema>.h master header file, which includes the definitions of all classes.

These class files usually have the same name as the entity or type, and the naming conventions are discussed in the following sections. Class or file names can also be overridden on an individual basis using a "workingset" control file.

The EXPRESS compiler usually writes the source files to the "./classes" directory, although the location can be changed with -o compiler option.

Naming Conventions

The C++ language is is case sensitive but the EXPRESS language is not. For example, "SAMPLE" and "sample" are the same in EXPRESS but different in C++. The generated C++ classes use a naming convention to consistently map EXPRESS names to C++ symbols. The examples below use the following EXPRESS definitions:

SCHEMA config_control_design;
    ENTITY representation_item 
	name : STRING; 
    END_ENTITY;
END_SCHEMA;

The compiler supports three three conventions. The first one, "rose", is used by all of the STEP and IFC libraries included with ST-Developer. In addition, STEP APs are also given the "stp_" prefix as described in Adding a Prefix to Class Names so definitions like "product" and "cartesian_point" become classes named stp_product and stp_cartesian_point.

The other two conventions, "sdai" and "fullsdai", exist for SDAI C++ compatibility, but are not widely used.

Simple Types

The EXPRESS compiler uses the following C++ types when generating access or update functions for simple EXPRESS types. The simple types include integers and floating point values, booleans, strings and binary values. These types are also used where an EXPRESS schema defines an alias for a simple type, such as a length_measure defined as a REAL.

EXPRESS		C++
-------		---
INTEGER		int
NUMBER		double
REAL		double

BOOLEAN		RoseBoolean  ==> typedef char, values ROSE_TRUE, ROSE_FALSE
LOGICAL		RoseLogical  ==> typedef char, values ROSE_TRUE, ROSE_FALSE, and ROSE_UNKNOWN

STRING		RoseSTR        ==> typedef char*
BINARY		RoseBinarySTR  ==> typedef char*

ENUM		enum, see below
ENTITY		object pointer, see below
SELECT		object pointer, see below
AGGREGATE	object pointer, see below

The RoseBoolean and RoseLogical types are interchangable. The ROSE_TRUE value is defined to be one, while ROSE_FALSE is zero. ROSE_UNKNOWN is a nonzero value, so it tests as "not false" which matches EXPRESS semantics.

Strings are stored as UTF-8 encoded, null-terminated C strings. The compiler uses the RoseSTR typedef for char* in function prototypes and instance variables. The "put" functions for string attributes make a copy of the string value. The string value returned by a "get" function should be treated as read-only.

The ROSE library fully supports international characters in STEP data. All functions that take or return char* values expect UTF-8 encoded Unicode characters. When reading or writing data files, the library converts between UTF-8 strings in memory and the \X2\ or \X4\ hexadecimal format used for Unicode data in Part 21 files. It can also read Part 21 files with strings containing ISO 8859 \S\ notation characters and convert them to the UTF-8 strings. Similarly, functions that take filenames also expect UTF-8 strings for wide character filenames.

Unix applications should already be using UTF-8 strings when international characters are needed. On Windows, programs can use MultiByteToWideChar() and WideCharToMultiByte() with the CP_UTF8 flag to convert between wchar_t and UTF-8 strings where needed.

BINARY is handled using the C++ type RoseBinarySTR. This is also a typedef for char* and values are stored in the string encoding used by the Part 21 file format. We provide the RoseBinaryObject helper class to handle bit and byte level access to the data.

The null values for each of these primitive types are described in NULL Attribute Values

Enumerations

The compiler generates a C++ enum for each EXPRESS ENUMERATION. Each EXPRESS enumeration is a separate name space, while C++ uses one name space for all enumerators. To avoid conflicts, the compiler prepends the name of the enum to each enumerator separated by an underscore. Consider the EXPRESS:

SCHEMA example_schema;
    TYPE colorType = ENUMERATION OF (red, green, blue);
    END_TYPE;
END_SCHEMA;

The generated C++ enum will be:

enum colorType {
	colorType_NULL = NULL_ENUM,
	colorType_red = 0,
	colorType_green,
	colorType_blue
};

The compiler also generates a null value for each enum, which is equivalent to the NULL_ENUM constant, but strongly-typed.

The SDAI C++ name styles separate the value and the type name by two underscores. The NULL value is <typename>_unset. If you use a SDAI style, the definition will look like the following:

// full SDAI name style
enum Example_schema_Colortype {
	Example_schema_Colortype_unset = NULL_ENUM,
	Example_schema_Colortype__red = 0,
	Example_schema_Colortype__green,
	Example_schema_Colortype__blue
};

// terse SDAI name style
enum Colortype {
	Colortype_unset = NULL_ENUM,
	Colortype__red = 0,
	Colortype__green,
	Colortype__blue
};

Entities

EXPRESS ENTITY definitions become C++ subclasses of RoseStructure. Consider the following EXPRESS definition:

ENTITY Point;
	x : REAL;
	y : REAL;
END_ENTITY;

This definition becomes the following class definition:

class Point : virtual public RoseStructure {

    /* x Access functions */
    double x();
    void x (double ax);

    /* y Access functions */
    double y();
    void y (double ay);

    Point ();
};

The C++ inheritance follows the EXPRESS as closely as possible. If an entity has no supertypes, the C++ class is an immediate subclass of RoseStructure. If an entity has multiple supertypes, the C++ class has multiple superclasses. The C++ classes are generated with virtual base classes to accommodate multiple inheritance.

Access Functions

The class has an access and update functions are generated for every explicit attribute. Derived attributes and WHERE, UNIQUE, and INVERSE clauses are not mapped into C++.

<type> <attribute_name>();    /* Access Value */

void   <attribute_name>(      /* Update Value */
	<type> value
	);

For example, our cartesian point entity has "x" and "y" attributes and the following access functions. The C++ double type is used for EXPRESS REAL values as described in Simple Types.

/* x Access Functions */
double x();
void x (double ax);

/* y Access Functions */
double y();
void y (double ay);

Consult Early-bound Functions for Entities for more information on the access and update functions for entity types.

Constructors

The compiler generates a default constructor for each C++ class. The default constructor takes no arguments and is used for the pnewInstance() function and also for a static prototype instance. This constructor sets each instance variable to null. Integer and real attributes are set to zero, booleans and logicals are set to false, and strings and binaries are set to null strings.

Point();                       /* default constructor */

AND/OR Complex Classes

EXPRESS AND/OR entity types are handled as C++ classes that inherit from each of the multiple types in the complex entity. They have no new attributes, and are specified in the working set files as described by Working Sets and Best-Fit Classes.

Selects

Each EXPRESS SELECT definition is translated into a subclass of RoseUnion. This class acts as a strongly-typed union, which stores a single value from a range of possible types, and remembers the type of value stored in the union.

This compiler generates an access, an update, and a query function for each possible type that can be stored in the select. Each instance can only hold one value at a time. Calling any of the update functions will replace the previous value.

<type> _<type>();                 /* access value */

void   _<type>(                   /* update value */
	<typname> value
	);

RoseBoolean is_<type>();          /* query value */

The functions are named based on each type in the select. The access and update functions have an underscore prefix to avoid conflict with the C++ type name. The query function determines whether the value stored in the select matches the type. Consider the following EXPRESS definition.

TYPE shape = SELECT (Point, Circle, Text);
END_TYPE;

The corresponding C++ class is as follows:

class shape : public RoseUnion  {
public:
    ROSE_DECLARE_MEMBERS(shape);

    /* Access and Update Functions */
    RoseBoolean is_Point();
    Point *  _Point();
    void _Point (Point *  a_Point);

    RoseBoolean is_Circle();
    Circle *  _Circle();
    void _Circle (Circle *  a_Circle);

    RoseBoolean is_Text();
    Text *  _Text();
    void _Text (Text *  a_Text);

    /* constructor */
    shape () {}
};

The Early-bound Functions for Selects section has more on access and update functions for select types. The rose_get_nested_object() and rose_put_nested_object() functions are also useful when working with deeply nested selects in STEP models.

Aggregates

Each EXPRESS aggregates becomes a subclasses of RoseAggregate. Lists translate into subclasses of RoseList, arrays to subclasses of RoseArray, etc.

A class named <agg>Of<type> is generated for entities, selects, enumerations, and nested aggregates. Aggregates for the various primitive types are already present in the ROSE library. For example, the LIST OF LIST OF LIST OF XYZ construct will produce three new classes:

ListOfListOfListOfXYZ
ListOfListOfXYZ
ListOfXYZ

Any EXPRESS bounds specifications on the aggregate is ignored. The C++ aggregate classes are declared and implemented using macros. Refer to Early-bound Functions for Aggregates, Parameterized Aggregate Classes, and RoseAggregate for more information about declaring and using the C++ aggregate classes.

Working Sets and Best-Fit Classes

A working set file controls the EXPRESS compiler C++ class generation. This small text file is mostly used to force extra classes for EXPRESS AND/OR type combinations, but it can also generate a subset of definitions, change the naming of classes, or extra aggregates. The documentation for each EXPRESS model contain a sample workinset files for each of the pre-installed schemas.

Working set files normally contain a list of entity or type names. Each is listed on a separate line, with possible modifiers after them. Use backslashes ("\") to break an entry over several lines. Use the hash character ("#") to mark comment lines.

# This is a comment line
# The entry for type2 is split across multiple lines
#
type1
type2  -option1 foo \
       -option2 bar

EXPRESS AND/OR Entities

EXPRESS allows a form of multiple inheritance on a per instance level, which is called an AND/OR or complex entity. A particular data instance has a set of types rather than one EXPRESS type for the combination. These appear as a complex instance in a Part 21 file, with each entity type enclosed in parenthesis. They are commonly used by STEP for "mix-in" combinations of types for units and contexts.

/* A complex instance from a Part21 file.  This is a combination of
 * length_unit and si_unit.   Both are subtypes of named_unit.
 */
#16=(
   LENGTH_UNIT()
   NAMED_UNIT(*)
   SI_UNIT(.MILLI.,.METRE.)
   );

When generating C++, we must add extra classes for these complex instance combinations. A limited number of combinations are generally used, so we list them in the working set description and the EXPRESS compiler generates a C++ class for each. We specify a combination with the ANDOR keyword, then a list of type names. e.g.:

ANDOR (type1 type2 type3 ...)

This creates dictionary data and a C++ class. The ROSE library automatically creates dictionary information for new combinations as it finds them in a data file, but the workingset file is the only way to get new classes. The name is built from the type concatenated together with "_and_". The constructed name uses the types in alphabetical order.

# A complex class length_unit_and_si_unit is used for the Part21
# sample data shown above.

ANDOR( si_unit  length_unit )

If the working set contains only AND/OR entries, it will generate all classes. Below is a sample working set file with some common AND/OR combinations for STEP schemas. The ST-Developer documentation has complete workingset files for each pre-installed application protocol or other model.

    # The AP units for area, length, mass, plane_angle, solid_angle, and
    # volume. Create SI and conversion unit combinations for most.  Just
    # SI for solid angle, because only steradians are ever used.
    
    ANDOR( si_unit  length_unit )
    ANDOR( si_unit  mass_unit )
    ANDOR( si_unit  plane_angle_unit )
    ANDOR( si_unit  solid_angle_unit )
    
    ANDOR( conversion_based_unit    mass_unit )
    ANDOR( conversion_based_unit    length_unit )
    ANDOR( conversion_based_unit    plane_angle_unit )
    
    #  
    # Spline curves and surfaces (nurbs)
    #
    ANDOR(  rational_b_spline_curve         b_spline_curve_with_knots )
    ANDOR(  rational_b_spline_curve         bezier_curve )
    ANDOR(  rational_b_spline_curve         quasi_uniform_curve )
    ANDOR(  rational_b_spline_curve         uniform_curve )
    
    ANDOR(  rational_b_spline_surface       b_spline_surface_with_knots )
    ANDOR(  rational_b_spline_surface       bezier_surface )
    ANDOR(  rational_b_spline_surface       quasi_uniform_surface )
    ANDOR(  rational_b_spline_surface       uniform_surface )

When the compiler generates a C++ class for and AND/OR entry, it concatenates the entity names to produce a name for the class. If you use the default rose name style, the names are concatenated with "_and_" between them. If you use the sdai or fullsdai style, the names are capitalized before concatenating them.

    ANDOR ( si_unit plane_angle_unit  )
    
    plane_angle_unit_and_si_unit                    -- ROSE
    Config_control_design_Plane_angle_unitSi_unit   -- full SDAI
    Plane_angle_unitSi_unit                         -- terse SDAI

Some of these names can get absurdly long, so you may want to specify your own using the -name option. If you are using the -prefix option, note that the prefix will only be applied to the final concatenated name, not to each element of the name.

    ANDOR( measure_representation_item length_measure_with_unit ) \
           -name stp_length_measure_representation_item

Best-Fit Classes

The ROSE library keeps runtime C++ type information and matches each EXPRESS definition to the most appropriate C++ class. When an application is built with a subset of classes using a working set, or when a data file contains new AND/OR combinations, there may be instances for which there is no exact C++ type.

Missing Polygon Class

Missing Polygon Class

The figure above shows a Polygon instance with no matching C++ type. This is represented in memory as an instance of a more general C++ type, such as RoseObject. The RoseObject class has no special access or update functions for Polygon attributes, but the late-bound RoseObject::get<name>()/put<name>() functions can be used to manipulate the values.

The ROSE library can do sophisticated class matching. When reading an instance, the library will search the C++ type information for a "best-fit" class. The best-fit class is the closest match to the EXPRESS definition. For example, consider the figure below. Our application program contains only the Point class, but we are reading instances of both Point and Extended_Point types.

Best Fit Classes

Best Fit Classes

The Point instance has an exact match to the Point class. The Extended_Point instance has no exact match, but the Point class is the closest fit. All attributes inherited from Point have generated access and update functions, while any extra attributes defined by Extended_Point can be accessed through late-bound functions. It is an instance of the Point C++ class, but the object is still an EXPRESS Extended_Point and will be written as such if the file is saved.

If a type inherits from several supertypes (multiple inheritance) there might be more than one potential "best fit" class. The library will choose the class that covers the most attributes or subtypes.

Best-fit matching is also used when reading a complex entity instance, that does not contain a matching ANDOR class. For complex instances, the library will look for a class that has a a complex instance combination for a subset of types if the full combination is not available. It finds a combination with a supertype if one with a subtype is not available.

Best Fit AND/OR

Best Fit AND/OR Classes

At the other extreme, the figure below shows an application that contains no generated classes. In this situation, every instance will be matched with the built-in RoseObject types. In fact, entity instances will be matched to RoseStructure, selects to RoseUnion, and aggregates to one of the built-in RoseAggregate subtypes such as RosePtrList, RosePtrSet, RosePtrBag, or RosePtrArray.

Completely Late-Bound

Completely Late-Bound

Generating a Subset of Definitions

STEP schemas can be large, but some have conformance classes with well-defined subsets of definitions. If you list the subset in a working set file, the EXPRESS compiler can generate classes for just these entities. References to anything outside of the working set appear as the generic type RoseObject.

When you read a data set into memory, objects in your working set are instantiated as the appropriate C++ class, while others are instantiated as RoseObjects. No data is lost. Attributes of the RoseObject instances are accessed through late-bound functions as in Late-bound Functions for All Objects.

The following example compiles the EXPRESS file schema.exp and generates C++ only for entities listed in the file myents:

    % expfront -classes -ws myents schema.exp 

where the myents file contains:

    % cat myents
    ent_one
    ent_two
    ent_three
    ent_four
    %

In this case, the compiler generates C++ classes for ent_one through ent_four, but not for any other entities. If ent_one contained a attribute called some_att of some type ent_five, the compiler would generate an access and update function for it, but it would be of type RoseObject.

Changing Class and File Names

A workingset file can also control the file or class name used for a definition. The C++ class name or source file name can be changed as needed, but will still correspond to the original EXPRESS type.

As we have seen, the simplest workingset entry is just the name of a definition. The following will generate a C++ class Automobile for the EXPRESS type of the same name. The class definitions are put in the files Automobile.h/cxx

    Automobile

The -file option changes the file name, but not the class name. The example below will generates a C++ class Automobile in the files auto.h/cxx. Use this option to make file names conform to special naming conventions such as 8.3 filesystems.

    Automobile -file car

The -name option changes the file name and the class name. The example below generates a C++ class auto for the EXPRESS type named Automobile, and puts the class definition into auto.h/cxx.

    Automobile -name auto

Adding a Prefix to Class Names

STEP application protocols define entites with common names (point, line, address, vertex). If you are use other packages, you may see name clashes because some other package contains a "point" or "line" class. (For example, one geometry kernel has conflicts with bounded_curve, curve, ellipse, pcurve, plane, surface, and vector)

The -name option will rename individual classes, but to rename them all, you can specify a prefix for all generated type names (entities, selects, and enumerations). You can give the prefix either on the command line or in a workingset file.

On the command line, just call the EXPRESS compiler with the -prefix option. In a workingset file, add -prefix to the SCHEMA entry. The following examples will prepend "stp_" to all definitions in the AP203 schema.

    On the command line:
    > expfront -classes -prefix stp_ ap203.exp
    
    In a workingset file:
    SCHEMA config_control_design -prefix stp_

Instead of C++ classes like product and cartesian_point, you will get classes named stp_product and stp_cartesian_point. If a workingset file has both a schema prefix and -name for a particular type, the -name will be used for that type.

Other Control Options

Entire schemas can be called out in the working set file using the special SCHEMA keyword, then the name of the schema. You can use the -all and -none directives to control what definitions are generated.

By default, only definitions listed in the control file are generated. If the control file contains only AND/OR entries, all definitions are generated. Putting in a schema entry with the -all directive forces generation of all definitions for the schema. The -none directive stops generation of any definitions for the schema.

    SCHEMA config_control_design -all
    SCHEMA config_control_design -none

There is also an ENTITY keyword to identify entity entries. It is not required, and rarely used, but it might make your working set clearer at times.

Part 28 Namespace

The Part 28 namespace for an AP can be added to the compiled EXPRESS data dictionary by using the -p28ns flag on a SCHEMA entry. If none is provided, XML will be written in the default namespace.

    # Sample workingset file entry
    SCHEMA config_control_design \
        -p28ns urn:oid:1.0.10303.203.1.0.1

Extra Aggregates

The EXPRESS compiler generates classes and data-dictionary entries for all aggregates used by the schema. You can use the -aggs directive to force extra aggregate definitions for a base type.

The -aggs argument indicates the aggregate types using the first letter of the aggregate style. For example "L" indicates a list, "B" indicates a bag, "LL" is a nested list of list of the base type, and so on. The argument is not case sensitive.

For example, suppose a schema had a cartesian_point definition, but never used any aggregates. My application might use a list of cartesian points for some temporary processing. Since the schema doesn't use a list, one would not normally be generated, but I could add the following line to my working set file:

    cartesian_point -aggs l

This would forces the compiler to generate a ListOfcartesian_point class. By default the compiler generates only those classes listed in the working set file. The schema -all option will force the compiler to generate all of the other classes in addition to cartesian point:

    SCHEMA my_schema_name -all     <-- generate all classes in schema
    cartesian_point -aggs l        <-- also generate the extra list

If you need to list several aggregates, separate them with semicolons. The examples below force the generation of list, set, bag, array, and list of lists of cartesian point. All three entries are equivalent.

    cartesian_point -aggs l;s;b;a;ll
    cartesian_point -aggs L;S;B;A;LL
    ENTITY cartesian_point -aggs L;S;B;A;LL

Customizing EXPRESS/C++ Classes

The ROSE library can attach extra data to any object using a general mechanism called managers. Managers are the preferred way to keep extra data since they can be used on any class.

If you generate your own C++ classes instead of using the STEP Merged AP or IFC BIM class libraries, you can add member data and functions using the extclass tool. This tool inserts #include statements at key places in the generated classes so that you can keep your extensions in separate files that will not be lost if the classes are regenerated. There is also an extall tool that scans a directory for extension files and calls extclass as needed.

extclass files

Extclass Files

Extending the Declaration File (.h)

Put the declarations for your new functions and non-persistent instance variables into files called <class>.hi and <class>.hx as described below:

<class>.h
Class declaration file. Generated automatically
<class>.hi
Class extensions. Contains new include statements and ordinary function declarations. The contents of this file are placed before and outside of the scope of the class definition.
<class>.hx
Class extensions. Contains new member function declarations and non-persistent instance variables. The contents of this file are placed inside the scope of the class definition after all other member functions have been declared.

For example, let us extend the Point class to include new instance variables and member functions. Given the following EXPRESS definition, generate a C++ class using the EXPRESS compiler.

ENTITY Point;
    x : REAL;
    y : REAL;
END_ENTITY;

We will extend the C++ class with some graphics routines from our application. These routines might require additional member data and member functions. The first step is to add the hooks into the generated C++ Point class.

% cd classes
% extclass Point

This adds the hooks to the Point.h and Point.cxx files. Here is the Point declaration file. The additions made by the extclass tool have been highlighted.

#include <rose.h>

/* CLASS INCLUDE-FILE EXTENSIONS */
#include "Point.hi"

ROSE_DECLARE (Point) : virtual public RoseStructure {
private:
    double PERSISTENT_x;
    double PERSISTENT_y;

public:
    ROSE_DECLARE_MEMBERS(Point);
    /* Access and Update Functions */
    double x();
    void x (double ax);

    double y();
    void y (double ay)

    /* Constructors */
    Point ();
    Point (double ax, double ay );

/* CLASS DECLARATION EXTENSIONS */
#include "Point.hx"
};

The extclass tool has added includes for Point.hi and Point.hx. The Point.hi file will bring in the new include files that we will need for our graphics application.

/* File: Point.hi
 * New include-files and plain (non-member)
 * function declarations for the Point class.
 */

#include <graphics.h>        /* graphics package decls */

The Point.hx file will declare the new member functions and instance variables that we need for our extended class. In this example, we add a couple of new fields and a new member function. The Point.hx file will be included in the middle of the Point class declaration so any #include statements should be placed in the Point.hi file and not in Point.hx.

/* File: Point.hx
 *  New member functions and data for the Point class.
 */
int      NP_redraw_state;      /* non-persistent data */
Window   NP_drawing_window;

void draw();                   /* new member function */

Extending the Implementation File (.cxx)

After extending our class declaration, we must extend the class implementation. The files we use are:

<class>.cxx
Class implementation file. Generated by the compiler.
<class>.cx
Class extensions. Contains new member function definitions and constructor extensions.

The Point implementation file is shown below. The additions made by the extclass tool have been highlighted.

#include "Point.h"

/* CLASS IMPLEMENTATION EXTENSIONS */
#include "Point.cx"

/* Default Constructor - This constructor may be modified,
 *  but *DO NOT* add any calls that would initialize ROSE.
 */

#ifndef ROSE_CTOR_EXTENSIONS
#define ROSE_CTOR_EXTENSIONS /* additional initializations */
#endif
Point::Point () {
	PERSISTENT_x = 0;
	PERSISTENT_y = 0;
	ROSE_CTOR_EXTENSIONS;
}

Point::Point (
	double ax,
	double ay )
{
	x (ax);
	y (ay);
	ROSE_CTOR_EXTENSIONS;
}

We extend the Point constructors to initialize the new member data by defining the macro ROSE_CTOR_EXTENSIONS to expand into initialization code. Our Point.cx contains the following member function definitions and constructor extensions:

/* File: Point.cx
 *  Member function definitions and constructor extensions
 */

#define ROSE_CTOR_EXTENSIONS \
	NP_redraw_state = FALSE; \
	NP_drawing_window = NULL;

void Point::draw()
{
    /* C++ code to draw the point on the screen */
}

The backslashes in the #define statement hide newlines so that it is one line to the C preprocessor. The generated code for the constructors refer to this macro.

Class Library Makefiles

If you generate your own C++ classes, you must compile them. On Windows, it may be easiest to import the source files to a Visual Studio project. For other platforms, the mkmakefile tool can generate a makefile that compiles and assembles a library from all class files in a directory. By default the the library is named libClasses.a or Classes.lib, but there are command line arguments to change that.

The example below generates classes from geometry_schema.exp, then creates a makefile in the classes subdirectory. The makefile compiles all classes and collects them into a library called libgeometry.a.

% expfront -classes geometry_schema.exp
% mkmakefile -d classes -lib geometry
% cd classes
% make

Some of command line options for the makefile generator are shown below. Refer to the ST-Developer Tools Reference Manual for a complete list:

-o <file>
Save makefile to <file> rather than Makefile/win32.mak.
-d <dir>
Look in directory <dir> for source files, and generate the makefile there as well. Default is the current directory.
-cflags <str>
Set the value of the $(CFLAGS) macro. All files are given <str> as arguments to the compiler.
-includes <str>
Set the value of the $(INCLUDE) macro. All files are given <str> as arguments to the compiler.
-lib <str>
Set the library name to <str> rather than "Classes". The name can also be given without any flags as the last argument on the command line.

ROSE Compiled Schemas

Any tool that manipulates EXPRESS-defined data must have access to the EXPRESS schema definitions. The ST-Developer tools use a compiled data dictionary form of the EXPRESS schema. EXPRESS and C++ Data Dictionary describes this compiled form in greater detail.

The STEP Merged AP and IFC BIM libraries have a dictionary in the library, but other applications read a dictionary at startup from the ST-Runtime package. This contains dictionaries for all STEP application protocols, IFC, and CIS/2. If you are using a different schema, you will need to compile and install the data dictionary information yourself.

This is a simple process. Call the EXPRESS compiler with the -rose option to generate a compiled schema definition. The compiled schema files are named after the original EXPRESS schemas (<schema>.rose).

    % expfront -rose my_express.exp 

Copy the <schema>.rose file to the ST-Runtime schemas directory (Program Files\ST-Runtime\schemas or $ROSE/runtime/schemas). For testing you can also put in a local subdirectory "./schemas" as well.

Files with the "_EXPX" suffix (<schema>_EXPX.rose) are contain parse information used by the EXPRESS interpreter to evaluate WHERE clauses and derived attributes. This file may be safely removed and recreated at any time.

Warning

In most cases, you can remove and regenerate compiled schema files without any problems. STEP Part 21 files refer to EXPRESS definitions by name, so removing and regenerating compiled schemas is safe. However, files stored in binary ROSE working form refer to compiled definitions by object identifier (OID) which change if the schema is removed. This would render unreadable any binary ROSE working form files written with those definitions.

Packaging Applications for Distribution

Applications built with the ROSE library require ST-Runtime support files to operate properly. You are allowed to ship the ST-Runtime package with your applications, as long as the application is distributed according to the terms of your license for ST-Developer. Unless otherwise noted, these are the only files in ST-Developer that may be redistributed with applications.

ST-Runtime

ST-Runtime is a redistributable package containing runtime support files required by ST-Developer applications. We provide ST-Runtime as a Windows Installer and a merge module as well as a zip file.

The ST-Runtime Windows Installer can be found in the ST-Developer installation directory as redist/struntime.msi. This package can be installer on a Windows machine by double clicking on it. Once ST-Runtime is installed, you can then run your ST-Developer application on the target machine.

An ST-Runtime merge module is also provided so that it can be incorporated into another msi file. It can be found in redist/struntime.msm

Finally, we also provide ST-Runtime as a zip file in redist/struntime.zip. To install, unzip the file then set the $ROSE_RUNTIME environment variable to the location of the struntime_<ver> directory. For example:

> cd /path/to/extract
> unzip $ROSE/struntime.zip

Then before running an ST-Developer application.

> setenv ROSE_RUNTIME /path/to/extract/struntime_11

Custom Configuration

If you prefer, you can force your application to look elsewhere for runtime support files. Start-up parameters are normally taken from the environment or registry. Applications can query these settings and provide different initial values.

See rose_get/setenv registry_key(), rose_get/setenv search_path() and rose_get/setenv system_schema_path() for examples and more information.

If you prefer to ship your own compiled schema files, rather than use ST-Runtime, you must include the *.rose files for all of the schemas you plan to read or write. You must also include the header_section_schema.rose file, which is needed for the Part 21 HEADER section entries.

Search Details

Most Windows applications find runtime support files using the ST-Runtime registry key, and UNIX / MacOSX applications use the $ROSE_RUNTIME environment variable. For historical reasons, the ROSE library searches other places as well and this section describes the search order.

Windows Search Order

The software looks for registry entries under both HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE. This allows per-user customization if desired. The location of the ST-Runtime registry settings can be set with rose_setenv_registry_key(). The default location is SOFTWARE\STEP Tools, Inc.\ST-Runtime\<version>.

The seach order is as follows:

UNIX Search Order

On UNIX machines, the runtime is found exclusively through the environment. The following search order is used, which is the same as the Windows search order without registry values.