Overview
Large information models, such as those in the STEP standard, can contain hundreds of entity definitions. When compiled, these information models will translate into a corresponding number of C++ classes. We have provided several additional tools to make the management of these classes somewhat easier.
- The extclass and extall tools place hooks in your generated C++ classes so that you may extend them in a safe manner.
- The mkmakefile tool creates a makefile for C++ files, such as the classes generated by the EXPRESS compiler. This can be used for command line builds on UNIX or Windows. We also have instructions for configuring Visual Studio.
- The stepmunch tool can generate calls to the C++ static constructors. This is helpful when linking the C++ classes with code written in other languages, like C, FORTRAN or PL/1. This is not needed on Windows or recent UNIX systems because of improvements in linker/loaders.
extclass
The extclass tool puts #include directives into C++ class files generated by the EXPRESS compiler. These include directives are used to extend the classes by placing member variable or member functions into the class declaration.
extclass [options] <class>...
The options recognized by this utility are:
- -help
- Print usage information and exit.
- -d <dir>
- Look in directory <dir> for C++ source and header files to extend. The default is the current directory.
- -c / -cx
- Extend the class definition file <class>.cxx. Add an include statement for <class>.cx for new function definitions and constructor extensions.
- -h
- This option is equivalent to -hi -hx
- -hi
- Extend the class definition file <class>.h. Add an include statement for <class>.hi for bringing in other #include files and ordinary (non-member) function declarations.
- -hx
- Extend the class definition file <class>.h. Add an include statement for <class>.hx for declaring class member functions and variables.
With no options, extclass adds include directives for all extensions.
Description
Code generation is an effective software development technique. Properly used, it reduces development time and maintenance load. However, if the generated code is ever extended, the modifications might be lost if the code is ever regenerated.
The extclass tool makes it possible to add extensions to a generated C++ class in such a way that you can regenerate them without losing your changes. The tool adds preprocessor #include statements to the class files so that your extensions can be kept in auxiliary files. The auxiliary files are kept under source control and you can regenerate your C++ classes without concern.
Extending the Declaration File (.h)
Declarations for new functions and non-persistent instance variables need be inserted into the class declaration file <class>.h. We do this by placing the declarations into auxiliary files. The files we will be working with are:
- <class>.h
- Class declaration file. Generated automatically
- <class>.hi
- Your extensions. Contains new include statements and ordinary function declarations.
- <class>.hx
- Your extensions. Contains new member function declarations and non-persistent instance variables.
As an example, let us examine how we would go about extending a Point C++ class to include some new instance variables and member functions. Given the following EXPRESS definition, we generate a C++ class using the expfront tool.
ENTITY Point; --------------------------------------- -- Example Entity declaration: --------------------------------------- x : REAL; y : REAL; END_ENTITY;
We want to extend the C++ class with some graphics routines from our application program. These routines might require some 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 we see the Point declaration file. The additions made by the extclass tool have been highlighted.
#ifndef Point_h #define Point_h #include "rose.h" /* CLASS INCLUDE-FILE EXTENSIONS */ #include "Point.hi" #define PointOffsets(subClass) \ RoseStructureOffsets(subClass) \ ROSE_SUPERCLASS_OFFSET(subClass,Point) ROSE_DECLARE (Point) : virtual public RoseStructure { private: float PERSISTENT_x; float PERSISTENT_y; public: ROSE_DECLARE_MEMBERS(Point); /* Access and Update Methods */ /* x Access Methods */float x() { return ROSE_GET_PRIM (float,PERSISTENT_x); } void x (float ax) { ROSE_PUT_PRIM (float,PERSISTENT_x,ax); } /* y Access Methods */ float y() { return ROSE_GET_PRIM (float,PERSISTENT_y); } void y (float ay) { ROSE_PUT_PRIM (float,PERSISTENT_y,ay); } /* Constructors */ Point (); Point (float ax, float ay ); /* CLASS DECLARATION EXTENSIONS */ #include "Point.hx" }; #endif
As we can see, the 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 * Application-specific include-files and * ordinary (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.
/* File: Point.hx * Application-specific member functions and * non-persistent instance variables for the * Point class. */ BOOL NP_redraw_state; /* non-persistent data */ Window NP_drawing_window; void draw(); /* new member function */
Remember that the Point.hx file will be included in the middle of the Point class declaration. Any #include statements should be placed in the Point.hi file and not in the Point.hx file.
Extending Definition File (.cxx)
Now that we have extended our class declaration, we must finish the job by extending the class definition. The files we will be working with are:
- <class>.cxx
- Class definition file. Generated automatically
- <class>.cx
- Your extensions. Contains new member function definitions and constructor extensions.
In the previous section, we used the extclass tool to add hooks to the Point.h and Point.cxx files. Here we see the Point definition file. The additions made by the extclass tool have been highlighted.
#ifndef Point_c #define Point_c /* Class Point */ #include "Point.h" /* CLASS IMPLEMENTATION EXTENSIONS */ #include "Point.cx" ROSE_BEGIN_MEMBERS ("Point",Point,PointOffsets) ROSE_SCHEMA_NAME ("all_types") ROSE_VIRTUALSUPERCLASS (RoseStructure) ROSE_VARIABLE (float,PERSISTENT_x,"x") ROSE_VARIABLE (float,PERSISTENT_y,"y") ROSE_END_MEMBERS; /* 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 (float ax, float ay ) { x (ax); y (ay); ROSE_CTOR_EXTENSIONS; } #endif
We will put the member function definitions and constructor extensions in the file Point.cx. Since we have added non-persistent instance variables to the class, we must extend the constructors so that these new fields are initialized. We can do this by defining the symbol ROSE_CTOR_EXTENSIONS to be the initialization statements for our new variables. The resulting file is as follows:
/* File: Point.cx * Member function definitions and constructor * extensions for the Point class. */ #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 the newlines so that it all looks like one line to the C preprocessor. If you examine the generated code for the constructors, you will see that they each refer to the ROSE_CTOR_EXTENSIONS macro. This allows us to easily add new code to the generated constructors without physically editing the files.
Additional Situations
Depending on your extensions, you may not need to use all of the extension files. For example, if all of your new member functions are defined in-line, you may not use a <class>.cx file. If your extensions do not require any new header files or typedefs, you may not use a <class>.hi file. The extclass tool has options to control which hooks are placed in a file. These options are described at the beginning of this section.
Consider the case where your new member functions are all defined in-line. Your extensions may be completely contained in the header files, and so you would not need a <class>.cx file. In this case you would use the extclass tool to extend just the header files:
% extclass -h <class>
This adds include statements for <class>.hi and <class>.hx to the <class>.h file, but leaves the <class>.cxx file unchanged.
If your extensions do not require any new header files or typedefs, you might not use a <class>.hi file. In this case you would use:
% extclass -hx -cx <class>
This would add an include statement for <class>.hx to the <class>.h file, and an include statement for <class>.cx to the <class>.cxx file.
extall
The extall tool extends all of the class files in a directory, as needed. The tool examines all files in a directory and calls the extclass tool as needed when extension files (.hi/.hx/.cx) exist for a class. This tool is quite useful in makefile targets for generating and preparing C++ classes.
extall [options] [<class_dir> ... ]
The options recognized by this tool are:
- -help
- Print usage information and exit.
- -I<dir>
- Adds <dir> to the search path for extension files. Behaves just like the C or C++ compiler option. By default, the tool just looks in the current directory for extension files.
- -d <dir>
- Look in directory <dir> for source files. This is the same as adding the directory to the end of the command line.
The tool goes through each class file in <class_dir> and searches for any extension files that match it. If an extension file is found, the extclass tool is called to patch in the extension file. By default, the tool searches the current directory for extension files. Additional directories can be specified with the -I option. If no directory is specified for class files, the tool looks for a classes directory. Given a generated directory of classes (classes) and a directory of extension files (exts):
exts/ classes/ foo.hi foo.h foo.hx foo.cxx
We could automatically extend all of the class files with:
% extall -Iexts classes
This would find the hi and hx files in exts and extend the foo.h file in classes. There are no cx extension files, so foo.cxx will not be changed.
mkmakefile
The mkmakefile tool creates a makefile for C++ source files such as the classes generated by the EXPRESS compiler.
mkmakefile [libname]
The options recognized by this tool are:
- -help
- Print usage information and exit.
- -cflags <str>
- Set the value of the $(CFLAGS) macro. All files are given <str> as arguments to the compiler.
- -d <dir>
- Look in directory <dir> for source files, and generate the makefile there as well. Default is the current directory.
- -dll <str>
- Generate rules to build release and debug Windows DLLs for EXPRESS C++ classes. The import library is named <str>dll and the DLL is called <str>_<ver> where <ver> comes from $(ROSE_DLLVER). The output is linked with the DLL version of the ROSE library.
- -dllinst <str>
- Create install-dll and install-dlld targets that moves plain and debug DLLs to <str>.
- -includes <str>
- Set the value of the $(INCLUDE) macro. All files are given <str> as arguments to the compiler.
- -incinst <str>
- Create an install-includes target that copies all generated header files to <str>.
- -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.
- -libinst <str>
- Create an install-library target that moves the library to <str> and installs includes if -incinst is also present.
- -o <file>
- Save makefile to <file> rather than Makefile/win32.mak.
- -shared
- Generate rules to build and install a Unix shared library for EXPRESS C++ classes. The library is named lib<str>.so or lib<str>.dylib, using the name and install directory from the -lib and -libinst flags. The output is linked with the shared version of the ROSE library.
- -unix
- Generate a UNIX-style makefile called Makefile. This is the default when mkmakefile is run on a UNIX machine.
- -win32
- Generate a Windows-style makefile called win32.mak suitable for use with NMAKE and other Windows tools. This is the default when mkmakefile is run on a Windows machine.
The tool normally generates a makefile appropriate for the platform it is run on, although the -macos/-unix/-win32 flags can be used to force one or another. On UNIX and MacOS, the generated makefile is called Makefile. On Windows, the makefile is called win32.mak and can be run using "nmake /fwin32.mak".
The generated makefile compiles all C++ source files in a directory and places them into a library. The library will be called "Classes" (libClasses.a on UNIX or Classes.lib on Windows) unless a different name is given on the command line.
This tool is normally used with the EXPRESS compiler expfront. The following example shows how to go from EXPRESS schema to a C++ library:
% expfront -classes geometry_schema.exp % cd classes % mkmakefile geometry % make
This example generates C++ classes using the EXPRESS compiler and then generates a makefile that will compile all of them. Once this is in place, we call make which will compile the classes and collect them into a library called libgeometry.a.
The following templates show how to use this within another makefile to generate classes, apply extensions, and build a sub-makefile. Extensions go under source control in a directory called exts, so we need to make sure that the compiler can find them. We also construct the makefiles for both platforms so that you can see how to quote everything so that the correct values pass through.
The following is an example of how to do this in a UNIX makefile. Note the use of double quotes in the -win32 use of ROSE_INCLUDE. This is necessary because of the spaces in directory names.
generated_on_unix: expfront -writenone -classes schema.exp mkmakefile -unix -d classes \ -includes '-I../exts -I$$(ROSE_INCLUDE)' mkmakefile -win32 -d classes \ -includes '-I../exts -I"$$(ROSE_INCLUDE)"' extall -d classes -Iexts
The following is an example of how to do this in a Windows NMAKE makefile.
generated_on_windows: expfront -writenone -classes schema.exp mkmakefile -unix -d classes \ -includes "-I../exts -I$$(ROSE_INCLUDE)" mkmakefile -win32 -d classes \ -includes "-I../exts -I\"$$(ROSE_INCLUDE)\"" extall -d classes -Iexts
stepmunch
stepmunch [function_name] > ctors.c
This utility is useful only in situations when you must link your ROSE C++ application with the something other than the C++ compiler. This might happen when working with code written in other languages, like C, FORTRAN or PL/1. In addition, it is only useful on platforms that do not have "smart" linkers. Windows and some UNIX platforms have linkers that know about initialization functions, and will make sure that they get called regardless of any other factors.
Normally, the C++ compiler puts in code to call the constructors for static objects, but if you are not going to link your application with CC, you may need to generate the calls to these static constructors yourself.
The stepmunch utility scans the output of the nm command for static constructors, and then generates a C function to call them This utility should work with code compiled under either C++ or G++.
The following example scans a library and creates a function called call_ctors(), that calls all of the static constructors in the library. Your application should call this function when it first starts up.
% nm -g libclasses.a | stepmunch call_ctors > ctors.c % cc -c ctors.c
The file ctors.o should then be linked in with your application.