ObjectStore Building C++ Interface Applications

Chapter 5

Building Applications for Use on Multiple Platforms

You can build an ObjectStore application on multiple platforms and then use it to store and update data interchangeably on any of these platforms. Applications that run on more than one platform are considered to be heterogeneous.

This chapter provides instructions for building heterogeneous applications. This chapter does not provide information about how to make your application portable.

It covers the following topics:

General Instructions

You can build an ObjectStore application on multiple platforms and then use it to store and update data interchangeably on any of these platforms. This is referred to as heterogeneity. Applications that allow heterogeneity are considered to be heterogeneous.

To make an application heterogeneous, you must neutralize its schema for all platforms and then build the application on each platform. Neutralization is the process of modifying a schema so that it has identical data formats on each platform that runs the application. This is necessary because different compilers lay out data in different ways.

When building a heterogeneous application, consider address space limitations on all platforms. Database access patterns might work on some platforms but not on others.

You can start with an application that runs on one platform or you can create a new application. If you are building a new application, see the limitations in Restrictions before you design your application.

When you have a working application, follow these steps to make it heterogeneous. As always, you can use the command-line interface or a makefile.

  1. Run the schema generator to determine what you must do to neutralize your application.

    1. Specify the -architecture setn (or -arch setn) option for the set of compilers on which the application must run.
    2. You can also specify other ossg options. A description of the schema generator neutralization options is on page 140.

  2. Modify your application source files according to the instructions you receive from the schema generator. Some instructions require you to insert macros in your source code. Be sure to enter the exact name specified by the schema generator.

  3. Repeat steps 1 and 2 until the schema generator no longer displays instructions to change your source files.

    If you follow the neutralization instructions correctly, you should need to repeat step 1 only once and step 2 not at all.

  4. Recompile your application source files.

  5. Compile the application schema source file generated by ossg. Be sure to do this after the schema generator has successfully produced the application schema database.

    When you use Visual C++, the schema generator creates the application schema object file directly. On all other platforms, you must compile the application schema source file yourself.

  6. Link the application object files and the application schema object file and any required libraries to create a neutralized executable.

  7. When your neutralized application works on the first platform, copy the source files to each additional platform.

  8. Build the application on each platform:

    1. Run ossg. Always specify the -arch set n option. You should not receive additional instructions to modify your source files, but this catches any changes that affect neutralization.
    2. Compile.
        1. Link.
The following figure illustrates the workflow for neutralizing an application and then building it on multiple platforms.



Which Platforms Can Be Heterogeneous?

You can build an application that runs under all operating systems listed. The compilers you can use are also shown. See the ObjectStore C++ Interface Release Notes for ObjectStore Release 5.1 for the latest versions of supported compilers.

Normally, you cannot build an application that can run on both 32-bit and 64-bit platforms. The only exception to this rule is that Digital UNIX can operate heterogeneously with 32-bit platforms. The compiler on this 64-bit platform allows you to mix 32-bit and 64-bit pointers through pragma statements in the source code. When all pointers in persistent classes are forced to be of the 32-bit variety, you can share these classes with 32-bit platforms. The following table includes the supported compilers.
Platform Operating SystemCompiler
AXP (Alpha)

Digital UNIX

DEC C++

HP 700 and
HP 800

HP-UX

HP C++

IBM RS/6000

AIX

IBM C Set ++

Intel

OS/2 Warp 3.0

Windows NT 3.5 and Windows 95

Solaris 2

VisualAge C++

Visual C++


Sun ProCompiler C++

SGI MIPS

IRIX

SGI C++

Sun SPARC

Solaris 2 (includes SunOS 5)

Sun SPARCompiler C++

When Is a Schema Neutral?

When an application is heterogeneous, its persistent objects are laid out in memory in identical formats for all platforms accessing the objects. The sizes and offsets of all data elements must be identical in both the creating architecture and the accessing architecture.

What Causes Data Formats to Vary?

Compilers on different platforms can use different rules for laying out objects. Machine architectures might have differing requirements for alignment of data types. This can cause differing object layouts. For example, the following class might have a different layout in memory if the required alignment of the int data type is two-byte alignment instead of four-byte alignment:

struct X {
      char status; 
      int value;
};
Layout incompatibilities are related to

Additionally, even when a class is defined so that it is identically laid out on all platforms, the fundamental nature of the processor can result in differing formats of the data values themselves. For example, the standard SPARC architecture uses a byte order different from the Intel microprocessor line. If an integer is written on one platform, its format might need to be converted for it to be readable on another platform.

Other features that can cause data formats to vary are

How Can You Create Identical Data Formats?

When you run ossg with neutralization options, the schema generator determines where padding is needed to create identical data formats. The schema generator examines the schema for a set of compilers that you specify. It then displays instructions for you to insert padding macros in your source files. After you modify your source files, you run ossg again. If you followed the instructions correctly, the schema is now neutralized for the compilers in the specified set.

The schema generator always proposes adding explicit padding to your classes to achieve neutralization. In many cases, however, you can reduce the size of the end result by reordering the members of a class to eliminate some or all padding. For example:

class X {
      char a;
      int i;
      char b;
      int j;
};
The best way to neutralize this code is to reorder the members:

class X {
      int i;
      int j;
      char a;
      char b;
};
Because some applications depend on the order of members within a class, it is up to you to decide whether or not this method is appropriate for each case.

After you neutralize a schema, a class in the schema is the same size on each platform on which you run the application. If you run the ossize utility, the returned value is the actual size of the object in the database. Objects belonging to a particular class are the same size on each platform on which they exist.

Restrictions

When designing applications, it is important to be familiar with the restrictions on heterogeneity.

Virtual Base Classes

When you are using several types of compilers, the use of virtual base classes makes neutralization particularly complex because of differences among the compilers in the way they lay out objects.

You cannot use virtual base classes when some but not all of your compilers use a cfront or SGI layout.

Applications compiled with Sun ProCompiler C++, AIX C Set ++, DEC C++, VisualAge C++, and Visual C++ can use virtual base classes in a heterogeneous environment.

Primitive Data Types

The compilers OS/2 VisualAge C++ (icc), Sun C++, and AIX C Set ++ (xlC) each support a long double data type that has no counterpart on any other platform. If you use the long double type, you cannot neutralize your application. Use the double data type instead.

If you expect to run a heterogeneous application on a Digital UNIX platform, avoid using the long data type. On the Alpha platform, long data types are 64 bits, rather than the usual 32 bits. Types can only be neutralized for architectures that use the same size for the type.

In general, you should use 32-bit integers and floating-point formats that are four or eight bytes.

64-Bit Pointers

You cannot neutralize a schema containing 64-bit pointers so that it works on a 32-bit platform. See DEC C++ 64-Bit Pointer Considerations for detailed information about mixing pointer size.

Floating-Point Data Conversion

During database access, it is not known whether or not the data might have been written by an application running on another platform. ObjectStore automatically converts data if necessary so that data is in the correct format for your application. There is, however, an exception to this rule.

ObjectStore does not convert floating-point data formats. To do so would introduce inaccuracies in your data. When floating-point formats are different but the data size is the same, ObjectStore only swaps bytes, which causes the result to be meaningless.

Pointers to Members

On some platforms, you cannot use pointers to members in persistent classes.

DEC C++ does not allow pointer-to-data-members (PTODMs) or pointer-to-member-functions (PTOMFs) to be persistently maintained. Visual C++ PTOMFs cannot be persistently maintained.

On other platforms, you can store PTODMs persistently and use them heterogeneously, with this exception: cfront and Sun C++ PTODM formats do not support PTODMs that refer to a member of a virtual base class.

Base Class Initialization Order

Occasionally, you might receive neutralization instructions from ossg that involve the reordering of base classes. Following these instructions might disturb dependencies in your source files. If this occurs, you might need to modify your source code to accommodate changes in the base class initialization order as well as to accommodate neutralization.

Parameterized Classes

The schema generator instructs you to neutralize class instantiations rather than the template class itself. This is because you can create a template specialization with different parameters that produces a different layout. This can present a problem. For example:

template <class T> class Y
{ 
public:
      char a;
      T b; 
};
Y<char> y_char; 
Y<double> y_double;
The Y<char> template requires no additional padding to be neutral. However, the Y<double> template does require padding. To define the schema as neutral, you can follow the neutralizer instructions and define a template specialization for Y<double>.

Template specialization
A template specialization is a special kind of replacement class. In certain cases, you might want to specify that for a template with a particular set of template arguments, the instantiation generated from the template not be used. Instead, a replacement class that you specify should be used. These replacement classes are known as template specializations. Here is an example of where one might be useful:

/* a simple template class that holds a data item */
template<class T> class Data {
public:
      Data(T& the_data) : data(the_data) {}
      T data;
};
/* a specialization that knows to strdup string data */
class Data<char*> {
public:
      Data(char* the_data) : data (the_data ? strdup(the_data) : 0) {}
      ~Data() { if (data) free(data); }
      char* data;
};
Here is the template specialization you would define for the example:

class Y<double>
{ 
public: 
      char a; 
      char_os_pad_1[7]
      double b; 
};
You might find that the schema generator instructs you to specialize each class instantiation in the same way. In this case, it is easier for you to change the template itself. Since the schema generator does not provide instructions for modifying class templates, it is up to you to decide when this is appropriate. For example:
Original template definition

template <class T> class linked_list
{
public:
      T* data;
      char flag;
      linked_lists<T*> next;
};

Used by this type

linked_list<int>


Template specialization based on schema generator instructions. This provides a neutral storage format.

class linked_list <int> {
public:
      T* data;
      char flag;
      char _os_pad_1[3];
      linked_lists<T*> next;
};

Alternatively, you can modify the template this way. Instantiations of this template would be neutral.

template <class T> class linked_list
{
public:
      T* data;
      char flag;
      char _os_pad_1[3];
      linked_lists<T*> next;
};

Sizes for Data Types

A neutralized schema requires that a data type be the same size on all platforms. When the types involved are classes, the schema generator can determine how to achieve the same size. But when the types involved are primitive types, the schema generator cannot provide instructions for padding to achieve the same size. In this case, ossg displays messages similar to the ones following. You might receive multiple versions of the second message.

<err-0013-0006>The following neutralization problems occurred during 
the compilation of file m.cc:
failures for class E:
<err-0013-0011>Components of the class have differing sizes:
Data member e
In general, you must do one of the following:

An example of nonstandard type sizes is when you use enum types and your architecture set includes OS/2. On OS/2, use the /Su4 option to force enums to have a size of four bytes.

General Restriction

Occasionally, there are classes that require a special alignment that the schema generator cannot provide. Generally this refers to certain special cases of classes with virtual bases (usually multiple virtual bases) where at least one base class requires double alignment (usually with set3 heterogeneous).

If you carefully followed the neutralization instructions and you still receive the Neutralization failure message, it might mean that your schema includes such a class. In this situation, contact Object Design Technical Support for assistance in neutralizing your schema.

An example of when this might occur is when you are using virtual base classes that contain doubles. Even with a single compiler (cfront is the most likely one), there might be cases where the schema generator cannot adequately align the virtual base classes for all platforms.

ossg Neutralization Options

You neutralize a schema by running ossg with neutralization options. The -arch set n option is required; the other options are not. The table describes the neutralization options
-arch set n

The schema that is generated or updated will be neutralized to be compatible with the architectures in the specified set. Applications running on these architectures can then access a database associated with the schema.

Required when you are neutralizing schema. No default.

You can specify one of the following sets.

.
set1 Some 32-bit architectures



HP-UX HP C++





IBM VisualAge C++ for OS/2





Intel Solaris 2 Sun C++





Intel Windows NT and Windows 95





RS/6000 AIX C Set ++





SGI IRIX SGI C++





SPARC 2 Sun C++



set2 set1 without cfront architectures



IBM VisualAge C++ for OS/2





Intel Solaris 2 Sun C++





Intel Windows NT Visual C++





Intel Windows 95 Visual C++





RS/6000 AIX C Set ++





SPARC Solaris 2 Sun C++



set3 cfront architecture



HP-UX HP C++





RS/6000 AIX C Set ++





SPARC 2 Sun C++



set4 Some IBM architectures



IBM VisualAge C++ for OS/2





RS/6000 AIX C Set ++



set5

set1 plus Digital UNIX DEC C++

Restriction: Your schema cannot contain a data member of type long.

set6

set2 plus Digital UNIX DEC C++

Restriction: Your schema cannot contain a data member of type long.

set7

set1 with Windows NT Alpha



set8

set2 with Windows NT Alpha



set9

set5 with Windows NT Alpha



set10

set6 with Windows NT Alpha



set11

set6 with SGI and HP-UX support



-neutral_info_output filename
or -nout filename

Indicates the name of the file to which neutralization instructions are directed.

Optional. Default is that the schema generator sends output to stderr.

-noreorg or -nor

Prevents the schema generator from instructing you to reorganize your code as part of neutralization. This is useful for minimizing changes outside your header file, working with unfamiliar classes, or simply padding formats.

When you include -noreorg, your application might not make the best use of its space. In fact, it is seldom possible to neutralize a schema without reorganizing classes.

When you use virtual base classes, it is very unlikely that you can neutralize your schema when you include this option.

Optional. The default is that the schema generator provides reorganization instructions.

-pad_maximal or -padm
-pad_consistent or -padc

Indicates the type of padding requested.

-pad_maximal or -padm indicates that maximal padding should be done for any ObjectStore-supported architecture. This means all padding, even padding that the various compilers would add implicitly.

-pad_consistent or -padc indicates that padding should be done only if required to generate a consistent layout for the specified architectures.

Optional. Default is -padc.

-schema_options option_file
or -sopt option_file

Specifies a file in which you list compiler options being used on platforms other than the current platform. The options in this file usually override the default layout of objects, so it is important for the schema generator to take them into account. See page 157 for details about the content of the option file.

Optional. No default.

-show_difference or -showd
-show_whole or -showw

Indicates the description level of the schema neutralization instructions. Optional. Default is -show_whole.

Neutralizing the Schema

Follow these instructions to generate a neutral application schema.

  1. Run the schema generator with neutralizer options to determine what changes in your source files (usually header files) allow your application to be heterogeneous.

    When you initiate the schema generator, you specify the set of platforms for which you want to neutralize. The schema generator examines the classes in the schema to ensure that the interpretation of the class definitions yields identical layout results on all platforms in the specified set.

    When there are layout discrepancies, the schema generator determines the changes needed to produce a neutral layout, and provides instructions for modifying your source files.

    To invoke ossg, use the same format you use to generate an application, library, or compilation schema. The only difference is the addition of neutralizer options. The following format shows the addition of neutralization options when generating an application schema. You can also add neutralization options when you generate a library or compilation schema. For an explanation of the ossg command line, see Generating an Application or Component Schema. (Portions of the command line are on different lines only for clarity.)

          ossg [ compilation_options]  neutralizer_options 
    
          [ other_schema_generator_options] 
    
          {-assf  app_schema_source_file | -asof  app_schema_object_file} 
    
          -asdb  app_schema_database    schema_source_file 
    
    
          [ lib_schema.ldb ... ] 
    
  2. Change your source files according to the instructions from the schema generator.

  3. Run ossg again.

    If you followed the neutralization instructions correctly, you should now have a neutralized schema and you can skip step 4.

  4. Continue to modify your source files according to ossg instructions and then run ossg until the schema generator successfully produces your application schema.

  5. Recompile your source files.

When you run the schema generator with neutralization options, neutralization is limited to the classes defined in the schema source file and any classes defined in an include file that is directly or indirectly included in the schema source file. This means that when ossg generates an application schema, the schema generator does not examine class definitions that are in existing schemas. This limitation has no meaning when ossg generates a library or compilation schema because an existing schema is not involved.

When to Use Neutralization Options

After you neutralize your application, you should continue to include the -arch set n option whenever you run ossg. This ensures that changes do not cause platform conflicts.

Specifying the -arch set n option creates internal information needed by the relocation subsystem. This information ensures access to the correct virtual function tables.

If you remove the -arch set n option, you might add data that is not properly aligned for a particular platform. The schema generator normally selects the most restrictive alignment. Without the -arch set n option, the schema generator cannot determine that the alignment must be larger on certain platforms.

Additional Neutralization Considerations

Be sure to generate an application schema that is neutral for each platform on which you plan to run the application. When a schema is not explicitly neutralized for a platform, you might receive run-time schema validation errors when you invoke the application on that platform.

Be sure to mark all required data types in the schema source file. When you fail to mark a required type, the schema generator cannot detect incompatibilities.

The schema generator might require neutralization to prevent straddling pointers (pointers that span pages). This might be necessary

Updating a Database Schema to Be Neutral

Suppose you have an existing application on one platform that already stores information in a database. Now you want to neutralize the application schema to create a heterogeneous application. In this case, you must also update the database schema and the data so it matches the neutralized application schema. To do this, use the ossevol utility or a custom evolution application using the schema evolution library.

Benefits of Compiler Groups

There are several reasons to group the cfront platforms separately.

The more platforms for which you neutralize your schema, the more space you use. If you neutralize for fewer platforms, you decrease the amount of space you use but you cannot run your application on as many types of platforms.

Command Line and Neutralization Examples

Here is a sample ossg command line on a Sun SPARC system:

ossg command line
ossg -arch set1 -padm -assf proj_schema.cc \
-asdb progschema.adb \
proj_schema_source.cc $(OS_ROOTDIR)/lib/liboscol.ldb \
$(OS_ROOTDIR)/lib/libosqry.ldb
The schema will be neutralized for use on platforms belonging to set1. Maximal padding will be done. Since this is not being invoked on a Windows platform, the schema generator produces an application schema source file (prog_schema.cc) that you must compile. The application schema will include the type information from the two library schemas specified.

Neutralization example
Here is a schema source file:

#include <ostore/ostore.hh>
#include <ostore/manschem.hh>
class A {
public:
      virtual void fun1();
      double d;
      A();
};
OS_MARK_SCHEMA_TYPE(A);
First, try running the schema generator and specifying -arch set1 for schema neutralization. These examples assume that you are running ossg on a UNIX platform. To try these examples on a Windows NT platform, you would specify -asof instead of -assf. Also, on Windows and OS/2 platforms, the specification of the path for ObjectStore header files would be -I%OS_ROOTDIR%\include instead of the way it is in the examples.

ossg -assf hetero.cc -asdb hetero.adb -arch set1 \
-I$OS_ROOTDIR/include hetero.cc
Schema generator output
<err-0013-0002>The schema must be neutralized in order to operate 
heterogeneously with the architectures specified:
The following schema modifications must occur:
class A :
      public os_virtual_behavior /* New */
{
      public:
      char _os_pad_0[4]; /* New */
      double d;
};
In the output, the schema generator does not display the member functions. It displays only the data members and nested types in the class definitions.

Also, the /* New */ comment in the output flags the changes you need to make. You must edit the schema source file to have this content:

Modified schema source file
#include <ostore/ostore.hh>
#include <ostore/manschem.hh>
class A : public os_virtual_behavior {
public:
      virtual void fun1();
      double d;
      char _os_pad_0[4];
      A();
};
OS_MARK_SCHEMA_TYPE(A);
Now the previous ossg command line generates the schema with no error messages.

Use of -noreorg
Suppose that the first run of the schema generator also had the -noreorg switch specified:

ossg -assf hetero.assf -asdb hetero.adb -noreorg -arch set1 \
-I$OS_ROOTDIR/include hetero.cc
<err-0013-0002>The schema must be neutralized in order to operate 
heterogeneously with the architectures specified:
The following schema modifications must occur:
class A
{
      public:
      os_pad_vftbl_start /* New */
      char _os_pad_0[4]; /* New */
      double d;
      char _os_pad_1[4]; /* New */
      os_pad_vftbl_end /* New */
};
Working from this output, edit the original class description as follows:

Modified class description
class A {
public:
      virtual void fun1();
      os_pad_vftbl_start
      char _os_pad_0[4];
      double d;
      char _os_pad_1[4];
      os_pad_vftbl_end
      A();
};
Next, modify the original ossg command line by adding the -show_difference option. The only effect that this has is on the way that the changes are presented:

Use of
-show_difference
ossg -assf hetero.assf -asdb hetero.adb -arch set1 -show_
difference\
-I$OS_ROOTDIR/include hetero.cc
<err-0013-0002>The schema must be neutralized in order to operate 
heterogeneously with the architectures specified:
The following schema modifications must occur:
Changes for class A:
      Add os_virtual_behavior as the first base class
Add a padding member as the first member: char _os_pad_0[4];
As you can see, the output in this case is simpler. For complex classes, the difference mode of display might be more easily understood.

For most classes, the default (-show_whole) display behavior is probably simplest.

Virtual base example
Here is a more complicated class involving virtual bases:

#include <ostore/ostore.hh>
#include <ostore/manschem.hh>
class A {
public:
      virtual void fun1(int);
      A();
};
class B {
public:
      virtual void fun2(char);
      B();
};
class C {
public:
      virtual void fun3(void*);
      C();
};
class D : public virtual A, public virtual B, public C
{
public:
      D();
      virtual void fun1(int);
};
OS_MARK_SCHEMA_TYPE(D);
In this case, neutralize with the set2 architecture group because heterogeneity of classes with virtual bases between cfront and non-cfront-type platforms is not supported.

Schema generator command line
ossg -assf hetero.assf -asdb hetero2.adb -arch set2 \
-I$OS_ROOTDIR/include hetero2.cc
<err-0013-0002>The schema must be neutralized in order to operate 
heterogeneously with the architectures specified:
The following schema modifications must occur:
class/* file: m.cc line: 19 */
class D :
      public os_vb_fbsc<0,A> /* New */,
      public C,
      public os_vb_fbs<0,B> /* New */
{
};
Nonvirtual template instantiations
In this example, you can see that the schema generator replaces the virtual bases with nonvirtual template instantiations. These instantiations virtually inherit from classes A and B in a way that ensures layout compatibility. Note that the two virtual base introducing templates are named slightly differently.

The particular template that the schema generator chooses for a given virtual base depends on the characteristics of the virtual base and the derived class.

Caution
When you modify files according to neutralization instructions be sure to follow the instructions exactly. In particular, when a class inherits from other classes the order of inheritance must be specified in the exact way expected by the schema neutralizer.

Using a Makefile to Obtain Neutralization Instructions

You can use a single makefile to invoke ossg and compile and link your code. The schema generator sends a nonzero return code when source changes are required for neutralization. This nonzero return causes make to stop processing. The schema generator displays neutralization instructions for changes to your source code.

UNIX makefile example
all: my_exec
my_exec: main.o os_schema.o foo.o bar.o
      CC -o my_exec main.o os_schema.o foo.o bar.o -los -loscol
      $(OS_POSTLINK) my_exec
os_schema.cc: schema_source.o
# os_schema.cc must depend on all headers that
# schema_source.cc depends on.
# You must also set up default rules so that schema_source.cc
# compiles to schema_source.o.
      ossg -arch set2 -showd -mrscp -asdb my_exec.adb \
      -assf os_schema.cc $(CPPFLAGS) schema_source.cc \
      $(OS_ROOTDIR)/lib/os_col.ldb

Building a Heterogeneous Application from a Neutral Schema

After you neutralize a schema, there are two more steps before you have a heterogeneous application:

  1. Finish building your application on the original platform.

  2. After your application works on the first platform, build it on each platform on which you want it to work.

Neutralizing enums

OS/2 is the only platform on which you can specify multiple enum sizes. All other platforms use four bytes for an enum.

If you are neutralizing for any architecture set except set3 (which does not include OS/2), the schema generator assumes that the schema is to be used on OS/2. Consequently, unless you specify otherwise, the schema generator expects OS/2 to use one byte for small-valued enums. This causes a neutralization error.

Regardless of whether or not you intend to use the schema on OS/2, you must do one of the following:

      enum embedd_enum { enum_val1, enum_val2, enum_val3, 
      enum_val4 = 100000  };

Listing Nondefault Object Layout Compiler Options

When building C++ applications, you might encounter circumstances where compiler options or pragma statements are needed to alter default object layout rules. When you are building heterogeneous applications, this is usually true because each compiler has its own layout rules that might be incompatible in some way with the other compilers to be used. For nonheterogeneous applications, all that is required is that you specify any such compiler command options when invoking ossg. For heterogeneous applications the problem is more complicated, because ossg needs to know about all options or pragma statements that are used on any of the platforms in the heterogeneity set. You must provide this information to ossg by using a schema options file.

In the options file, you maintain a list of any compiler options and pragma statements that alter default object layout required on all platforms in the application's heterogeneity set. The schema generator uses the compiler option file when determining what changes are necessary for schema neutralization. You tell ossg what schema options file to use by the -schema_options options_file command-line argument.

See Compiler Option Files for Architecture Sets for information about the contents of basic compiler option files for specific platform architectures. These describe what you should use as an absolute minimum for each architecture set.

If there are compiler options that you use on the current platform, specify them on the ossg command line as well as in the schema options file.

Compiler Option File Format

The compiler options file has the following structure:

      {  compiler_spec |  architecture_spec } [ ( class_list) ]  option 
The compiler_spec variable indicates the compiler with which you are using the specified option.

The architecture_spec indicates both the compiler and the platform that you are using. The possible values are in the following table.
Architecture architecture_spec
Digital UNIX DEC C++

axp_unix_dec

IBM VisualAge C++ for OS/2

intel_os2_visualage

Intel Windows NT Visual C++
Intel Windows 95 Visual C++

intel_win32_msoft or visualc++

RS/6000 AIX C Set ++

rs6000_visualage

The class_list variable lists one or more classes that the specified compiler option or pragma operates on. Classes in the list can be all application classes included in the schema. If you do not specify a class, the option applies to all possible classes.

Enclose the class list in parentheses and insert a space between two class names.

The option variable can be a compiler switch or a pragma statement.

Compiler switches
When the option variable is a compiler switch, it has one of the following forms:

      switch  compiler_switch 
      switch  compiler_switch compiler_switch_value 
      switch  compiler_switch '=' compiler_switch_value 
The compiler switches you can specify appear in the following table. See your compiler documentation for an explanation of each switch. These switches apply to an entire compilation rather than to a specific class.
compiler_spec or architecture_spec compiler_switch compiler_switch_value
axp_unix_dec

-nomember_alignment

-vptr_size_short

-xtaso_short

-Zpn

Not applicable

intel_os2_visualage

/Sp

/Sp1 (default)

/Sp2

/Sp4

/Sp+

/Sp-

/Su+ (default)

/Su-

/Su1

/Su2

/Su4

Not applicable

rs6000_visualage

-qalign=

full

packed

power



-qenum=

int (default)

small

visualc++ or
intel_win32_msoft

/vmb
/vmg 

/vms

/vmm

/vmv

/Zpn

Not applicable

Pragma statements
When the option variable is a pragma statement, it has the following form:

pragma  directive directive_value 
The pragma statements you can specify appear in the following table. See your compiler documentation for an explanation of these pragma statements.
compiler_spec or architecture_spec directive directive_value
axp_unix_dec

member_alignment

Not applicable



nomember_alignment

Not applicable



pack

Not applicable



pointer_size

long

short

32

64



required_pointer_size

long

short

32

64



required_vptr_size

long

short

32

64

intel_os2_visualage

pack

(n) 
rs6000_visualage

options

ldbl128



options align=

power

full

packed



options enum=

smallest

int

visualc++ or
intel_win32_msoft

pack

(n) 


pointers_to_members



best_case

full_generality,single_inheritance

full_generality,multiple_inheritance

full_generality,virtual_inheritance

Overriding Options Within the Compiler Option File

You can specify compiler options and pragmas at various levels. Specifications for a specific platform or compiler can override a specification that applies to all platforms or a set of platforms. Specifications for specific classes can override a specification for all classes. The order of the options in the compiler option file is not significant. For example:

intel_os2_visualage switch /Sp
intel_os2_visualage (classA classB classC) switch /Sp2
For all classes, ossg assumes that the compiler uses the /Sp switch. Except for classA, classB, and classC, ossg assumes the /Sp2 switch.

Sample Compiler Option File

visualc++      switch /Zpn
intel_os2_visualage                  switch /Sp4
intel_win32_msoft                  pragma pointers_to_members best_case
visualc++             (ClassX)                  pragma pack (1)
rs6000_cset                        pragma options align=full

Compiler Option File Example

Suppose you want to use the following class in an application that runs on several platforms:

class A {
public:
      enum { X,Y,Z} id;
};
The platforms you intend to use are OS/2, Windows NT, and Solaris 2. This class will not be neutral unless you specify the /Su4 option on OS/2. (This option forces enums to be of size int.) You need a schema option file that contains the line

intel_os2_visualage option /Su4
In this example, the name of the schema option file is schm.opt. When you generate the schema on OS/2, specify the /Su4 option. When you run ossg on the other platforms, specify schm.opt. Specifying the schema option file indicates to the schema generator exactly how objects are laid out on all platforms.

Compiler Options That Aid Neutralization

Certain platforms have default behavior in their compilers that causes problems in neutralization. The schema generator normally reports these problems as members of different sizes. In this situation, you might need to specify compiler options that force the compiler to yield a compatible object layout.

OS/2
On OS/2 with the VisualAge C++ compiler, enum types default to the smallest size that can contain all values of the enumeration. Because of this, you must do one of the following:

DEC AXP
On DEC AXP systems that run Digital UNIX, pointers default to 64 bits. For this platform to operate heterogeneously with 32-bit platforms, you must build applications with compiler switches or pragmas that force the compiler to use 32-bit pointers at the appropriate time. To do this, use -xtaso or -xtaso_short on the compiler command line, as described in DEC C++ 64-Bit Pointer Considerations.

Compiler option file
When you use one of these compiler options, remember to include it in the compiler option file. In fact, if you specify -arch set1 for neutralization but you do not intend to use OS/2, you still need to specify compiler options that would be needed on OS/2.

Compiler Option Files for Architecture Sets

This section provides basic compiler option files that are a minimum starting point for each of the architecture sets. Note that file contents are listed for set1 through set6. In the event that you are using any set beyond set6 (set7 through set11), be aware that these sets are based on the first six. See ossg Neutralization Options to clarify the relationship between the sets.
SetCompiler Option File Contents
set1

# force enums to be 4 bytes on OS/2

intel_os2_visualage switch /Su4

set2

# force enums to be 4 bytes on OS/2

intel_os2_visualage switch /Su4

set3

# no options needed

set4

# force enums to be 4 bytes on OS/2

intel_os2_visualage switch /Su4

set5

# force enums to be 4 bytes on OS/2

intel_os2_visualage switch /Su4

# force pointers to be 4 bytes on AXP under DEC UNIX

axp_unix_dec switch -xtaso_short

axp_unix_dec switch -vptr_short

set6

# force enums to be 4 bytes on OS/2

intel_os2_visualage switch /Su4

# force pointers to be 4 bytes on AXP under DEC UNIX

axp_unix_dec switch -xtaso_short

axp_unix_dec switch -vptr_short

Description of Schema Generator Instructions

When run with neutralization options, the schema generator instructs you to insert ObjectStore padding macros and make other changes in your source files. The neutralization instructions are explicit. Be sure to use the exact macro name the schema generator provides.

This section provides a description of the macros that the schema generator instructs you to use. An explanation of changes to virtual base templates is also included.

Some macros have ( x) at the end. The neutralizer provides instructions for replacing the x with a meaningful value.

Base Class Padding Macros

On platforms where the base class produces no padding, the schema generator cannot recognize that the padding macro exists. However, the schema generator can determine that, if the macro were present, the schema would be neutral. This allows the schema generator to both

The message names the specific platforms. Add the padding and run ossg again.
MacroInserts Padding to Compensate for
os_base_pad_vftbl

os_base_pad_vftbl8

Four- or eight-byte vftbls placed at the start of an object

os_base_pad_vbptr( x)

os_base_pad_vbptr8( x)

Four- or eight-byte virtual base pointers placed at the start of an object

os_base_pad_vbtbl

Four-byte vbtbls placed at the start of an object

Dynamically Defined Padding Macros

The schema generator does some dynamic naming of macros when inheritance precludes reusing a macro name. Dynamically named macros all begin with _os_pad_.

Member Padding Macros

Each member padding macro does one of the following:

The following table describes the member padding macros that ObjectStore provides.
MacroInserts Padding to Compensate For
os_pad_vftbl_start
os_pad_vftbl_start8

Four- or eight-byte vtbls placed at the start of an object.

os_pad_vftbl_end
os_pad_vftbl_end8


Four- or eight-byte vtbls placed at the end of an object.

os_pad_vftbl_only8

Eight-byte vtbls in classes containing no data members.

os_pad_vbtbl
os_pad_vbtbl8


Four- or eight-byte virtual base tables placed at the end of an object.

os_pad_vbptr_start( x) os_pad_vbptr_start8( x)

Four- or eight-byte virtual base pointers placed at the start of an object. Takes an integer argument that must be unique for any use of the macro within the class.

os_pad_vbptr_end( x) os_pad_vbptr_end8( x)

Four- or eight-byte virtual base pointers placed at the end of an object. Takes an integer argument that must be unique for any use of the macro within the class.

os_pad_mem_ptr8( x) os_pad_mem_ptr12( x) os_pad_mem_ptr16( x)

Data member pointers that are 8, 12, or 16 bytes long.

Virtual Base Templates

Class layout varies so greatly among compilers that in many cases there is no way to achieve a compatible layout by padding alone. Often, complex inheritance paths that differ from platform to platform are needed.

Rather than require you to maintain multiple parallel class definitions and manually check that the correct neutralizations have been applied, the schema generator instructs you to use standard template base classes to introduce virtual bases. For example, suppose you begin with this class:

class A : public virtual B {}
The schema generator might instruct you to convert this to something like the line following. This varies depending on which platforms are involved.

class A : public os_vb_fbs<0,B> {}
Sometimes, instead of using a particular virtual base class, the schema generator instructs you to use a specific class whose name starts with os_vb_. This class takes two arguments. The first is an int, and you should insert the exact int that the schema generator provides. The second is the name of the virtual base class that you are replacing. Here are the class names:

This technique has the effect of virtually inheriting from class B, but hides all platform-dependent details needed to make the class neutral.

An important effect of this technique is that class B must have a public or protected default constructor. Since it is the responsibility of the most derived class to actually invoke the correct constructor, it should not be difficult to provide a public or protected default constructor.

The virtual base introduction templates have the prefix os_vb_. The schema generator flattens these template instantiations so that your class definitions are retained and the classes have compatible schema representations.

Database Growth Resulting from Padding

Database growth as a result of padding source files is hard to predict. Whether or not there is any growth depends on

For example, the schema databases supplied with ObjectStore hardly grow. Applications that include virtual base classes and applications that do not include the os_virtual_behavior base class will grow more.

One way to try to determine any effect on database size would be to neutralize the schema and then run the osexschm utility on the preneutralized schema and postneutralized schema. Compare class sizes weighted by their relative frequency of occurrence in the database. You can also make a test run of the neutralized application and compare the database size to an equivalent preneutralized database.

Endian Types for ObjectStore Platforms

Endian type specifies whether the high-order byte is first or the low-order byte is first. This information is provided as general information. You do not need to be concerned with endian types when you neutralize schemas.

When you use the schema generator to neutralize for a group of platforms, the schema generator takes into account all platforms you want to use and the endian type for each platform. When the schema generator does this, it helps determine how to lay out objects in a way that can be used by all machines involved.

The following table shows the endian type for ObjectStore platforms. In a big-endian type, the high-order bit is first.
Big-EndiansLittle-Endians
HP

DEC AXP

RS/6000

Intel

SGI



Sun SPARC





[previous] [next]

Copyright © 1998 Object Design, Inc. All rights reserved.

Updated: 03/26/98 20:00:39