MAKEIT_OPTIONS := purifyThe definition of the MAKEIT_OPTIONS variable must be included in the initialisation section of the makefile.
The first form of support does not effect the standard process for generating a program executable. When you run:
makeit onewhere `one' is listed in the PROGRAMS variable, a normal program executable will be created, however, if you run:
makeit one.purea variant of the program is created called `one.pure', which has been processed by Purify. As with a normal program executable, the program is placed into the makeit subdirectory. To run the Purify'd program you would need to type:
SUN4_dbg/one.pureIn addition to being able to generate individual programs, all programs can be generated in their Purify'd form in one operation. To have makeit do this you should use the target `programs.pure'.
makeit programs.pureWhen makeit is invoked by the user to generate any program in its Purify'd form, the program will always be recompiled and linked, even if the program is up to date with respect to the programs dependencies. This approach has been taken to simplify the handling of dependencies for programs processed by Purify.
When a program needs to link with an object file, generated from a code file listed in the variable NONLIBSRC, it is necessary to provide a dependency of the form:
$(MK)/one : $(MK)/six.oat the end of your makefile. If Purify is being used in the form described above, it is necessary to modify the dependency to show that the Purify'd version of the program is also dependent on the object file.
$(MK)/one $(MK)/one.pure : $(MK)/six.o
MAKEIT_OPTIONS := purify_allWhen this form of support for Purify is enabled, all programs in a directory will be processed by Purify as the default. Thus invoking:
makeit onewill result in Purify being run. The name of the program executable generated in this case will still be `one', and as before, will be placed into the makeit subdirectory.
When the `purify_all' option is being used, a program executable will only be rebuilt if they are out of date with respect to their dependencies. If a program needs to link with an object file generated from a code file listed in NONLIBSRC, it is not necessary to modify the dependency rule, which shows the program to be dependent upon that object file.
The names of the environment variables differ between version 1.0 and 2.0 of Purify. If you are using version 1.0 of Purify, you can set the following variables:
PURIFYALWAYSUSECACHEDIR := yesIf you are using version 2.0 of Purify, customisation of Purify is performed using the single variable PURIFYOPTIONS. For example:
PURIFYOPTIONS := -always-use-cache-dirAgain, consult your Purify documentation as to the exact options which may be listed in the PURIFYOPTIONS variable.
MAKEIT_OPTIONS := quantifyThe definition of the MAKEIT_OPTIONS variable must be included in the initialisation section of the makefile.
The first form of support does not effect the standard process for generating a program executable. When you run:
makeit onewhere `one' is listed in the PROGRAMS variable, a normal program executable will be created, however, if you run:
makeit onewhere `one' is listed in the PROGRAMS variable, a normal program executable will be created, however, if you run:
makeit one.purea variant of the program is created called `one.pure', which has been processed by Quantify. As with a normal program executable, the program is placed into the makeit subdirectory. To run the Quantify'd program you would need to type:
SUN4_dbg/one.pureIn addition to being able to generate individual programs, all programs can be generated in their Quantify'd form in one operation. To have makeit do this you should use the target `programs.pure'.
makeit programs.pureWhen makeit is invoked by the user to generate any program in its Quantify'd form, the program will always be recompiled and linked, even if the program is up to date with respect to the programs dependencies. This approach has been taken to simplify the handling of dependencies for programs processed by Quantify.
When a program needs to link with an object file, generated from a code file listed in the variable NONLIBSRC, it is necessary to provide a dependency of the form:
$(MK)/one : $(MK)/six.oat the end of your makefile. If Quantify is being used in the form described above, it is necessary to modify the dependency to show that the Quantify'd version of the program is also dependent on the object file.
$(MK)/one $(MK)/one.pure : $(MK)/six.o
MAKEIT_OPTIONS := quantify_allWhen this form of support for Quantify is enabled, all programs in a directory will be processed by Quantify as the default. Thus invoking:
makeit onewill result in Quantify being run. The name of the program executable generated in this case will still be `one', and as before, will be placed into the makeit subdirectory.
When the `quantify_all' option is being used, a program executable will only be rebuilt if they are out of date with respect to their dependencies. If a program needs to link with an object file generated from a code file listed in NONLIBSRC, it is not necessary to modify the dependency rule, which shows the program to be dependent upon that object file.
MAKEIT_OPTIONS := purelink_allInvoking:
makeit onewill thus result in Purelink being run. The name of the program executable generated in this case will still be `one', and usual will be placed into the makeit subdirectory.
When the `purelink_all' option is being used, a program executable will only be rebuilt if they are out of date with respect to their dependencies.
Customisation of Purelink is performed using the single variable PURIFYOPTIONS. Consult your Purelink documentation as to the exact options which may be listed in the PURELINKOPTIONS variable.
MAKEIT_OPTIONS := sentinelThe definition of the MAKEIT_OPTIONS variable must be included in the initialisation section of the makefile.
The first form of support does not effect the standard process for generating a program executable. When you run:
makeit onewhere `one' is listed in the PROGRAMS variable, a normal program executable will be created, however, if you run:
makeit one.senta variant of the program is created called `one.sent', which has been processed by Sentinel. As with a normal program executable, the program is placed into the makeit subdirectory. To run the Sentinel'd program you would need to type:
SUN4_dbg/one.sentIn addition to being able to generate individual programs, all programs can be generated in their Sentinel'd form in one operation. To have makeit do this you should use the target `programs.sent'.
makeit programs.sentWhen makeit is invoked by the user to generate any program in its Sentinel'd form, the program will always be recompiled and linked, even if the program is up to date with respect to the programs dependencies. This approach has been taken to simplify the handling of dependencies for programs processed by Sentinel.
When a program needs to link with an object file, generated from a code file listed in the variable NONLIBSRC, it is necessary to provide a dependency of the form:
$(MK)/one : $(MK)/six.oat the end of your makefile. If Sentinel is being used in the form described above, it is necessary to modify the dependency to show that the Sentinel'd version of the program is also dependent on the object file.
$(MK)/one $(MK)/one.sent : $(MK)/six.o
MAKEIT_OPTIONS := sentinel_allWhen this form of support for Sentinel is enabled, all programs in a directory will be processed by Sentinel as the default. Thus invoking:
makeit onewill result in Sentinel being run. The name of the program executable generated in this case will still be `one', and as before, will be placed into the makeit subdirectory.
When the `sentinel_all' option is being used, a program executable will only be rebuilt if they are out of date with respect to their dependencies. If a program needs to link with an object file generated from a code file listed in NONLIBSRC, it is not necessary to modify the dependency rule, which shows the program to be dependent upon that object file.
If you want your code to be portable to any C++ compiler supporting templates, the extension you use on the template files is important. The first letter in the extension of the template header file should be `h'. The extension of the template code file should be the single character `c'. Whether you use an upper or lower case character for the template header file is not important. Whichever case you use for the extension of the template header file, you should use the same case for the extension of the template code file.
Both of the template files are in essence, header files, as they will be included into other files either by you or the C++ compiler. As the template code file will have an extension of either `c' or `C' though, the danger exists, that makeit will attempt to compile the file directly. To prevent this, you should list the names of the template code files in the EXCLUDE variable. For example:
EXCLUDE := vector.cIf you are writing a number of template classes, a better solution would be to place all header files, standard header files, and template files, into a separate directory. If this is done, you will need to remember to pass the location of that directory onto the C preprocessor using the CPPFLAGS variable. For example, if you placed all header files in the adjacent directory `include', you would need to add the following to your makefile.
CPPFLAGS := -I../includeDue to template code files being treated as header files, it is important to guard against multiple inclusion of the file. The standard technique of using `#ifndef' guards around a file is used to prevent multiple inclusion. For example:
#ifndef VECTOR_CThe final requirement of the organisational structure being recommended is that the template code file be included, using the C preprocessor `#include' directive, at the end of the template header file. Inclusion of the template code file into the template header file should only be carried out when the C preprocessor symbol EXPAND_TEMPLATES is defined. Your template header file would thus look something like this:
#define VECTOR_C
// Place member function templates here.
#endif /* VECTOR_C */
#ifndef VECTOR_HHWhen makeit is run, it will define the symbol EXPAND_TEMPLATES when compiling C++ program code files. This will result in both the class templates and member function templates being seen by the C++ compiler, when compiling the program code file. The C++ compiler is then able to expand any templates required, directly into the program object file. In order for this to be successful, the program code file must include the header files of any classes being used by the program which make use of template classes.
#define VECTOR_HH
template<class T>
class vector
{
...
};
#if defined(EXPAND_TEMPLATES)
#include "vector.c"
#endif
#endif /* VECTOR_HH */
In some situations a template class may be used in the implementation of a member function of a class. The problem is though, that there is no evidence in the header file for that class, that the template class is being used. So that the C++ compiler can detect that the template class is being used, the template header file for the template class must be included into the header file of the class which uses it, and a dummy typedef added to the class header file. This is illustrated below.
#include "vector.hh"Expansion of templates directly into a program object file typically results in the shortest compilation times. Other methods for expanding templates are supported by the various C++ compilers supporting templates. If you organise your code as described above, and do not rely on features particular to a C++ compiler, you should be able to move your code more easily from one compiler to another.
// vector<int> used in implementation, include dummy
// typedef here to force expansion of template into
// program object file
typedef vector<int> myclass_typedef1;
class MyClass
{
...
};
Adding the pragmas to the above example, you would get:
#ifndef VECTOR_HH
#define VECTOR_HH
#ifdef __GNUG__
#if defined(EXPAND_TEMPLATES)
#pragma implementation "vector.hh"
#endif
#if (__GNUC__ >= 3 || __GNUC_MINOR__ >= 6)
#pragma interface "vector.hh"
#else
#pragma interface
#endif
#endif
template<class T>
class vector
{
...
};
#if defined(EXPAND_TEMPLATES)
#include "vector.c"
#endif
#endif /* VECTOR_HH */
The template preprocessor supplied with OSE is a modified version of the COOL template preprocessor. The major changes which have been made to the COOL preprocessor include modification to support the correct template syntax for class and member function templates, and the addition of support for static class member variable initialisers. The template instantiation mechanism has also been extended and improved.
Note though, that the template preprocessor, does not support the complete template syntax as described in the Annotated \cxx{C++} Reference Manual. In particular, the template preprocessor does not support function templates. Other subtle aspects of templates are probably also not supported.
#ifndef VECTOR_HHIf you are not using the OSE C++ class libraries, firstly you will have to let the C preprocessor know where to search for the OSE C++ library header files. To achieve this, add the following to your makefile.
#define VECTOR_HH
#include <OTC/OTC.h>
template<class T>
class vector
{
...
};
#if defined(EXPAND_TEMPLATES)
#include "vector.c"
#endif
#endif /* VECTOR_HH */
CPPFLAGS := -I$(OSE_HOME)/includeWhen the OSE C++ class libraries are not being used, you will not be able to use the include file `OTC/OTC.h' to initialise the template preprocessor. This is because that file includes definitions which will require your programs to link with the OSE C++ class library. If the header file were included and you are not linking with the library, the compiler will fail to link your program due to undefined symbols. In this case, you should include the file `OTC/ansi/template.hh'. This file only contains code to initialise the template preprocessor and will not result in the OSE C++ class library having to be linked with your program.
#include "vector.hh"This must be at file scope and appear before the point that you first use vector<int> in that file. The template header file for the class template must also be included into your file. The template header file must be included before the OSE_TEMPLATE declaration.
#ifdef __OSE_TEMPLATES__
OSE_TEMPLATE vector<int>;
#endif
If you wish to be able to compile your code using a C++ compiler supporting templates, you must surround the OSE_TEMPLATE declaration with the check for the preprocessor symbol `__OSE_TEMPLATES__'. The symbol `__OSE_TEMPLATES__' is defined explicitly by the template preprocessor, the check allows the OSE_TEMPLATE declaration to be excluded, when using a true template compiler.
The semicolon at the end of the OSE_TEMPLATE declaration is not mandatory, however it is recommended that it be included. The reason for this is that C++ code browsers that use fuzzy parsing techniques will trip up on the OSE_TEMPLATE declaration. By including the semicolon, those C++ code browsers are able to recover and continue parsing the remainder of the file. C++ code browsers, for which this has been found to be necessary, include sniff and xcoral.
In order to use the template preprocessor correctly, it is important to understand how the instantiation of templates actually works. To illustrate more clearly what is occurring, you can rewrite the above example as:
#include "vector.hh"The inclusion of the OSE_TEMPLATE declaration results in the expansion of both the class template declaration, via OSE_DECLARE, and the member function implementation for the template listed, via OSE_IMPLEMENT. If the template class has been expanded for that set of template arguments previously, it will not be expanded again. Although OSE_IMPLEMENT will always be encountered by the template preprocessor, it does not result in the template member functions being expanded into every object file that includes the OSE_TEMPLATE declaration.
#ifdef __OSE_TEMPLATES__
OSE_DECLARE vector<int>;
OSE_IMPLEMENT vector<int>;
#endif
The reason that the template member functions are not expanded into every object file is that the template preprocessor can only expand the template member functions, if the code implementing them has been seen by it. If you have followed the structure for organising your template header files as described above, the template member functions will only be seen by the template preprocessor when the symbol EXPAND_TEMPLATES is defined. When you run makeit, it generally only defines the symbol EXPAND_TEMPLATES when compiling a program code file. This means that the template member functions will only be expanded into the program object file.
Since the implementation of any templates being used are only expanded into the program object file, the program code file must include any header files that contain an OSE_TEMPLATE declaration. If you use a class template in a code file then you must include an OSE_TEMPLATE declaration in a header file which is seen by the template preprocessor when compiling the program. This is similar to the requirement of providing a typedef in the header file for true template compilers. Specifically you would need to have:
#include "vector.hh"
// vector<int> used in implementation, include dummy
// typedef here to force expansion of template into
// program object file
#ifdef __OSE_TEMPLATES__
OSE_TEMPLATE vector<int>
#endif
typedef vector<int> myclass_typedef1;
class MyClass
{
...
};
class MyClassIf a OSE_TEMPLATE declaration for vector<MyClass*> were added just before the class, the C++ compiler would complain about MyClass being an unknown type. The situation thus requires that a forward declaration of MyClass be provided, as shown below.
{
private:
vector<MyClass*> myVec;
};
#ifdef __OSE_TEMPLATES__The above, will not work if any member functions of the template class vector attempt to access a data member or call a member function of the type MyClass. This is because the implementation of the member functions for vector will be expanded into the code at the point of the OSE_TEMPLATE declaration, which is before class MyClass has been fully defined. In this situation, you will need to take explicit control of the expansion of the declaration and implementation of a template class. To do this, you will need to use the OSE_DECLARE and OSE_IMPLEMENT macros directly. The above example can be rewritten as:
class MyClass;
OSE_TEMPLATE vector<MyClass*>;
#endif
class MyClass
{
private:
vector<MyClass*> myVec;
};
#ifdef __OSE_TEMPLATES__If the member function which was trying to access or use MyClass was an inline function, this will still fail. To avoid failure, any inline member functions of the template class, which try to access or use the class must be converted into normal member functions and not be made inline.
class MyClass;
OSE_DECLARE vector<MyClass*>;
#endif
class MyClass
{
private:
vector<MyClass*> myVec;
};
#ifdef __OSE_TEMPLATES__
OSE_IMPLEMENT vector<MyClass*>;
#endif
template<class T>User override template classes allow you to provide an alternative implementation of the template class which is tailored to the type of the template argument. If you provide a user override template class you should place it in the same header file as one of the types given as argument to the template. If the override template class is not placed in the same header file, some template compilers will not find it and will still use the default template version, not your version.
class vector
{
...
};
class MyClass
{
...
};
class vector<MyClass*>
{
...
};
If you are using the template preprocessor, you must tell the preprocessor that you have overridden the template class for a specific set of arguments. If you do not, when OSE_TEMPLATE is used for that template class, with that set of arguments, it will still expand the original template. This will result in the C++ compiler complaining that two versions of the class exist.
To let the template preprocessor know that you have overridden a template, you must use the macro OSE_MARK_TEMPLATE. A declaration using this macro must be included in the same file as your version of the template. For example:
template<class T>
class vector
{
...
};
class MyClass
{
...
};
#ifdef __OSE_TEMPLATES__
OSE_MARK_TEMPLATE vector<MyClass*>;
#endif
class vector<MyClass*>
{
...
};
To delay the expansion of the base class template till the time that the derived class template is expanded, a special syntax, only understood by the template preprocessor, must be used. This special syntax is given below.
template<class T> TemplateClassNameIn this statement `TemplateClassName' should be replaced with the name of the derived template class. The template argument list should match the argument list for the derived template class. You should then add an OSE_DECLARE statement in the body of the statement to expand the base class. Note that since this syntax is only understood by the template preprocessor, you should enclose it in an `#ifndef'. For example:
{
...
};
template<class T>It is important that the OSE_DECLARE be included in one of these statements, just before the declaration of the derived class template. The statement being before the template class declaration, will ensure that the base class template will be expanded before the derived class template.
class MyTemplate1
{
...
};
#ifdef __OSE_TEMPLATES__
template<class T> MyTemplate2
{
OSE_DECLARE MyTemplate1<T>;
};
#endif
template<class T>
class MyTemplate2 : public MyTemplate1<T>
{
...
};
To expand the implementation of the base class template, a similar statement is included at the beginning of the template code file. In this case, you should use an OSE_IMPLEMENT declaration.
#ifdef __OSE_TEMPLATES__As this will be seen by the template preprocessor after it has seen the declaration for the derived class template, it will only be expanded when the implementation of the derived class template is expanded.
template<class T> MyTemplate2
{
OSE_IMPLEMENT MyTemplate1<T>;
};
#endif
It is important that you use OSE_DECLARE and OSE_IMPLEMENT in two separate statements, instead of just OSE_TEMPLATE in one statement, before the template class declaration. If you did just use OSE_TEMPLATE and you needed to take control of when the declaration and implementation were expanded, (as was described in the previous section), the compiler could generate errors. This will be because the implementation of the base class template will be expanded, when you asked for the derived class template declaration to be expanded. If the base class template member functions tried to use some feature of the class being used as argument to the template, it would fail as that class would not yet have been defined.
template<class T>Again, it is best to have the OSE_IMPLEMENT declaration separate.
class MyTemplate1
{
...
};
#ifdef __OSE_TEMPLATES__
template<class T> MyTemplate2
{
OSE_DECLARE MyTemplate1<int>;
};
#endif
template<class T>
class MyTemplate2
{
MyTemplate1<int> myData;
};
The file into which all the templates will be expanded is a template instantiation file. In addition to the template preprocessor supporting this feature, some true C++ template compilers also support this feature. These compilers include the ObjectStore C++ compiler, DEC C++ compiler and IBM XL C++ compiler.
To use this feature you should create a template instantiation file and add a definition to your makefile which lists the name of the file in the TEMPLATES variable. For example, if you named your file `templates.cc' you would need to include the following in your makefile.
TEMPLATES := templates.ccIn this file, you should now include the header files of all the classes which are used in your program. Instead of defining the preprocessor symbol EXPAND_TEMPLATES when compiling your program code files, makeit will define it only when compiling the template instantiation file. For C++ compilers such as DEC C++, makeit also defines any compiler options necessary to force expansion of templates. In the case of DEC C++ this is the `-define_templates' option. If you are using a compiler which does not support template instantiation files, the fact that you have defined the TEMPLATES variable will be ignored.
When using makeit the name of this repository is defined by the variable MKPTR. By default the MKPTR variable is defined to be `$(MK).ptr', where `$(MK)' is the name used for the standard makeit subdirectory. If the C++ compiler has to expand template classes individually into the repository, compilation times will typically be longer. It is therefore encouraged that you include all header files for classes used by a program into the program code file. If you also include the special macros required by the template preprocessor it will allow you to compile your code using either the template preprocessor or a true C++ template compiler.
When using a cfront based C++ compiler, if you want the compiler to only use the template repository and not instantiate templates into program code files, the `use_repository_only' option should be listed in the MAKEIT_OPTIONS variable. This option is equivalent to supplying the `-ptn' to the compiler.
When expanding templates into the template repository, cfront based C++ compilers must know which header file, and for templates, which code file to include. Normally the compiler will collect this information while compiling your code files and put that information into the repository directory so that it can use it when expanding the templates. If however, you are using a C++ library that internally uses class templates, and you do not include any header files which show they are being used, where the templates are found, or where the classes used as arguments to the templates are found, the compiler will not know where to find the header files and template code files.
When the compiler doesn't know which files to use, it will use a default strategy to find those files. The strategy used is to expect that the header and code files have the same basename as the name of the class. In addition, the compiler expects that the files are not in a subdirectory of those directories searched for include files. For example, if a class EX_Example is used as an argument to a template class, it will try to include the file `EX_Example.h'. If the name of the header file is not the same as the class name, you have used a different extension, or the file is in a subdirectory, the compiler will fail.
To avoid this, a library provider can provide a map file, which indicates those files that contain classes. For example, such a file may include the following for the EX_Example class.
@dec EX_ExampleIf a library provider has made a map file available, makeit can direct cfront based C++ compilers to consult that file when expanding templates into the repository. For this to be done, you should add a definition to your makefile which lists the location of any map files into the PTMAPS variable. For example:
<mylib/example.hh>
PTMAPS := ../mylib/PTMAPIf a library provider has not created a map file, you could always create one yourself, placing it in your directory and setting PTMAPS appropriately.
MODULES := c ccThe process involved in creating a shared library is not that different to a static library. To create a shared library, makeit will compile each library code file, directing the compiler to produce a PIC object, and then link the PIC objects together to form the shared library.
MAKEIT_OPTIONS := shlib
Creation of the shared library is initiated by invoking makeit with `shlib' as target.
makeit shlibIndividual library code files can also be compiled. To compile the library code file `one.c' into a PIC object, the target `one.so' is used. For example:
makeit one.soMultiple shared library PIC objects may be listed as targets for a single invocation of makeit. Creation of the individual PIC objects will not result in the shared library being generated. The shared library is only created when the target `shlib' is used. The target `shlib' is automatically built when the target `all' is built. Thus, invoking
makeit allwill also create the shared library.
The shared library produced by makeit is called `lib.so' and is placed in the makeit subdirectory. Makeit does not provide support for applications in the same directory linking with the shared library. Shared libraries can only be used after they have been installed in a common area.
Using makeit, any library code file which contains initialised static data must have its full name listed in the STATIC variable. For example, if the file `one.c' contained initialised static data, you would need to include the following in the definitions section of your makefile.
STATIC := one.cThis will force makeit to deal with this file as described above. The name of the static portion of the shared library which makeit creates, is called `lib.sa'. The library `lib.sa' will be placed into the makeit subdirectory after being created.
If you need to enable different code if a file is compiled as a PIC object, the preprocessor symbol `PIC' can be checked. The symbol is only defined when compiling a file into a PIC object.
WARNING: Implementations of shared libraries differ between platforms. For this reason the manual does not go into more detail on this topic. Instead, consult the documentation for your system, on how to deal with initialised static data. If code must be portable, initialised static data should be avoided.
Two techniques exist to ensure that static objects are initialised. The first technique requires the static objects only to be accessed through a global function or static member function. Instead of having a static object, a static pointer to the type of the object is declared. The pointer will be initialised to zero at program startup. The first time the function is called to access the object, an instance of the object is created. The address of this object is assigned to the static pointer.
static Object* theObject = 0;Using this technique, the object is only created if an attempt is made to access the object. If the object is never accessed it is never created. If the object is created, it is never destroyed.
Object& object() {
if (theObject == 0)
theObject = new Object;
return *theObject;
}
The second technique uses the nifty counter method of initialisation. In this approach, a helper class is created, which keeps a count of how many instances of the helper class exist. The first time an instance of the helper class is created, the static object is initialised. When the last instance of the helper class is destroyed, the static object is destroyed.
An implementation of the helper class is:
class ObjectInitA definition for a static instance of ObjectInit class should be added into a header file. The header file containing the definition must be included in any code using the static instance of the Object. At least one of the code files including the header file must be compiled as a static object and not as a PIC object.
{
public:
ObjectInit()
{
if (count++ == 0)
theObject = new Object;
}
~ObjectInit()
{
if (--count == 0)
{
delete theObject;
theObject = 0;
}
}
private:
static int count;
};
int ObjectInit::count = 0;
The form of the definition in the header file should be:
static ObjectInit _ObjectInit;If it is not possible to change your code, such that a pointer to a global object is used, a variation of the ObjectInit class can be used. The modification entails using the placement syntax for operator new() to initialise the static object. An explicit call to the destructor is used to destroy the object.
As initialisation of the static object will correctly occur in a static library, the call to operator new() should only be carried out when the code is compiled to a PIC object.
static Object theObject;Using this approach, the constructor and destructor for ObjectInit must not be inline.
ObjectInit::ObjectInit()
{
#if defined(PIC)
if (count++ == 0)
new (&theObject) Object;
#endif
}
ObjectInit::~ObjectInit()
{
#if defined(PIC)
if (--count == 0)
theObject.~Object();
#endif
}
The second technique described, has the benefit that the object will always be created. Creation of the object will even occur if the object isn't accessed. In addition, the destructor for the object is always called.
Support for the ObjectStore database is automatically enabled if you are using the ObjectStore C++ compiler. For instance, if you have the variable C++COMPILER defined to be:
C++COMPILER := OS2.0If the option `+OSTD' is not listed in the variable C++FLAGS, makeit assumes that you are using the ObjectStore DML extensions. If `+OSTD' is listed in the variable C++FLAGS, makeit assumes that you are using the C++ library interface to access the ObjectStore database.
Support for ObjectStore will also be enabled if you are using a C++ compiler other than the ObjectStore compiler if you add `OSTORE-' before the name of the C++ compiler. For example, instead of listing your C++ compiler as:
C++COMPILER := SUN3.0.1you would list it as:
C++COMPILER := OSTORE-SUN3.0.1Only the C++ library interface is available, when using a C++ compiler other than that provided with ObjectStore. To identify that you are using a C++ compiler other than the ObjectStore C++ compiler with ObjectStore, makeit will define the preprocessor symbol ENV_OSTORE. Makeit will also define this symbol, if you are using the ObjectStore C++ compiler with `+OSTD' as an option to the compiler, ie., with the C++ library interface. As the ObjectStore C++ compiler defines the symbol `__OS_DML' when the DML extensions are being used, you can write your code to cope with all cases. For example:
template<class T>The OTC_TypeSpec class in the above example is a special template class provided with the OSE C++ class libraries. This template class may be used to obtain a typespec for a builtin type, object, or pointer to a builtin type or object. If the template argument type is not a builtin type then you must mark the type in the schema file.
OTC_Vector<T>::OTC_Vector(u_int theSize)
: mySize(theSize)
{
#if defined(CXX_OS) && defined(__OS_DML)
myVector = new (os_segment::of(this)) T[theSize];
#else
#if defined(ENV_OSTORE)
myVector = new (os_segment::of(this),
OTC_TypeSpec<T>::typespec(),theSize) T[theSize];
#else
myVector = new T[theSize];
#endif
#endif
OTCLIB_ASSERT(myVector != 0);
}
The two databases are the compilation and application schema databases. To define the locations of the databases you should define the following variables appropriately in the definitions section of your makefile.
C++COMPILER := SUN3.0.1To enable the use of the Versant compiler front end for this compiler, change this to:
C++COMPILER := VERSANT-SUN3.0.1When the Versant compiler front ends are being used, makeit forces the symbol `ENV_VERSANT' to be defined by the preprocessor. This allows different code to be used in applications or libraries, depending on whether Versant is being used.
By default, the version of the `-lcxxcls' library linked with programs built by makeit, will be the version containing debugger information. To link with the optimised version of this library, the option `production_library' should be listed in the VERSANT_OPTIONS variable.
VERSANT_OPTIONS := production_libraryIn addition, a single process client will be created by default. if a dual process client is required, the option `dual_processes' should be listed in the VERSANT_OPTIONS variable.
VERSANT_OPTIONS := dual_processesIn either case, the VERSANT_OPTIONS definition must appear in the initialisation section of your makefile.
C++COMPILER := ODE-SUN2.1When the ODE front end is being used, the preprocessor symbol `ENV_ODE' is defined by makeit. You should however check for the preprocessor symbol `__oplusplus' if you need to compile different code into your application. The `__oplusplus' symbol is defined by the ODE front end.
MODULES := cc c ose ocenterBefore ObjectCenter can be used, it must be initialised. Initialisation is performed by running the following commands from within ObjectCenter, once it has started.
setopt make_prog makeitIt may be necessary to include the full pathname to the makeit program when setting the `make_prog' variable. Instead of setting `make_prog' each time you run ObjectCenter, you could add the command to the `.ocenterinit' file in your home directory.
make ocenter_init
These commands have the effect of loading information about the location of header files, libraries, compiler flags and preprocessor definitions, stored in the makefile for makeit, into ObjectCenter. This avoids duplicating the information. The initialisation also initialises ObjectCenter to use makeit to build object files which are not present when a request is made to load them. Once initialised, ObjectCenter commands such as `load' and `swap' may be used as normal.
Note that when the ObjectCenter `link' command is used, it will expand any missing templates into the repository directory. To ensure that the repository directory is already populated with the required template expansions, the option `use_repository_only' should be listed in the MAKEIT_OPTIONS variable. This will cause makeit to also use the repository for all template expansions when building programs.