ooc  1.3c
Object Oriented tollkit fo ANSI C
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Porting ooc.

The ooc was designed to be easily portable.

Creating ooc the main goal was to establish an OOP environment that is easily portable onto special systems as well, like small microcumputers, microcontrollers and DSPs that has at least an ANSI compatible C compiler.

Porting headers.

All portability issues are collected into separated header files, that I call porting headers. Each port has its own porting header in the directory named libs/port in the source tree, and include/ooc/port in the installed system.

Modifying any of the porting headers you must rebuild and reinstall ooc! Modifying porting headers on an installed system may not behave as required!

In the main header file (ooc.h) there is an include tree, that decides which porting header should be included.
Currently the following porting headers are available:

Porting header Description
anyc.h Uses ANSI-C only, should be able to be compiled by any C compiler.
There is no multithreading support in this port!
gnuc.h Linux 32 bit x86 port with GNU GCC compilation.
Pthread or OpenMP multithreading is supported as well as single threading.
msvc.h Microsoft Windows 32 bit x86 port with MS Visual C++ compilation.
Windows threads and OpenMP multithreading is supported as well as single threading.
mcc18.h MPLAB C18 compiler support for 8 bit Microchip controllers.
There is no dynamic memory allocation and multithreading support in this port.
Supports the large data + large code configuration only.
mcc30.h MPLAB C30 compiler support for 16 bit Microchip controllers.
There is no multithreading support in this port.
mcc32.h MPLAB C32 compiler support for 32 bit Microchip controllers.
There is no multithreading support in this port.

For special comments on the existing ports see the following descriptions:

How to create a new port?

To create a new port you must do the followings:

  1. Create a porting header file in the libs/port directory in the source tree.
    The content of the porting header file is described in the next section.
  2. Modify the include tree at the beginning of the main header file (ooc.h) to include your porting header properly.
  3. Build and install ooc.

What must contain a porting header?

When you create a new porting header it is advisable to start out from the closest existing header, worst case from anyc.h. Copy it into the libs/port directory with a new name.
The porting header must contain the followings parts:

Include the standard libraries.

Include the necessary standard libraries in your system. See standard includes for details.

/* Inlcude standard headers */
#include <stdlib.h>
#include <assert.h>
#include <stddef.h>
#include <string.h>
#endif /* COMPILING_OOC_C */

If your system does not support these standard headers or functions, you must implement them, and modify this section accordingly.

Longjump primitives.

Longjump primitives are used for exception handling. You must define how your system handles longjumps, or you must implement a longjump mechanism on your own.

/* Longjump functions */
#include <setjmp.h>
#define JMP_BUF jmp_buf
#define SETJMP setjmp
#define LONGJMP longjmp

on some systems the signaling must be considered as well! (sigsetjmp, siglongjmp)

Inline control.

If your compiler allows, you can set some functions inline for better performance. To achive this define the STIN macro as the prefix for static inline functions, and undefine NO_INLINE macro.
If your compiler does not support function inlining, leave this section as follows.

/* implementing static inline */
#define STIN static
#define NO_INLINE

Threading primitives.

You must define the threading primitives for the given port.
Define the appropriate prefix for thread local storage variables, or leave the TLS macro as follows:

/* Threadless implementation */
#define TLS static

Define the mutex and locking primitives for the current system. For a threadless implementation this looks like:

#define ooc_Mutex void
#define ooc_mutex_init( x )
#define ooc_mutex_release( x )
#define ooc_lock( x )
#define ooc_unlock( x )
#define ooc_try_lock( x ) TRUE

See Also
Multithreading support.

Atomic pointer exchange.

Define an atomic pointer exchange (read while nulling) operation as a macro called OOC_IMPLEMENT_PTR_READ_AND_NULL. This is very important for threadsafe pointer manipulation. It is used for nulling a pointer while reading its content into a temporary variable.
If your implementation is threadless, this operatin must be reentrance safe. The reentrance safe default implementation is the following:

/* Helper: pointer read-out while nulling
void * tmp = * ptr_ptr; \
* ptr_ptr = NULL; \
return tmp;
#endif /* COMPILING_OOC_C */

The COMPILING_OOC_C macro ensures, that this definition is available in the ooc core implementation only.

What compiler controls do I have?

You can use several macros that alter the behavior of the code according to the actual needs of your port.

Macro name Behavior
ROM In case of a microcontroller, the const data could be located in Read Only Memory.
For those targets define ROM macro as the appropriate storage specifier.
ROM is used when dereferencing a ROM based variable. For allocation purposes see the ROM_ALLOC macro! If not specified it is defined automatically as:
#define ROM const
ROM_ALLOC In case of a microcontroller, the const data could be located in Read Only Memory.
Define the ROM_ALLOC macro as it is required for allocating a variable in the read only memory.
ROM_ALLOC is used only for the allocation of a ROM based variable. For other purposes see the ROM macro! If not specified it is defined automatically as:
GEN_PTR General pointer type for memory and string manipulation libraries (<mem.h>, <string.h>).
In ANSI-C the general pointer type in theese standard libraries is char*.
However e.g MPLAB C18 uses void* in these libraries, causing compiler warnings.
Define GEN_PTR according to your actual target's needs.
If not specified it is defined automatically as:
#define GEN_PTR char *
NO_RELATIVE_INCLUDE Most compiler treats the include path relative to the actual file invoking the include command for local includes, regardless if it is a source or a header file.
Some others always use the source file location as the base path for all local includes (e.g. MPLAB C18).
This macro is not defined normally, define it if your compiler requires.
NDEBUG The usual way to distinguish between debug and release versions is defining the NDEBUG macro for the release version. Ooc uses this approach internally. However some compilers or IDEs use other macros for this purpose.
Define NDEBUG macro according to your compiler / IDE, letting ooc be consistent.
OOC_NO_THREADS If defined then a single threaded version is built.
You must define dummy threading primitives in case of a single threaded version, as well! See Threading primitives.
NO_INLINE If defined then it indicates that the comlpiler does not support function inlining.
See Inline control.
OOC_NO_DYNAMIC_MEM On some microcontroller targets the dynamic memory allocation is not available. On those targets every Object must be statically allocated, and thus the ooc_new() and ooc_delete() is nonsence.
Defining OOC_NO_DYNAMIC_MEM ooc is compiled without the need for dynamic memory handling, and thus has some limitations as well: any function related to dynamic memories is unavailable.
OOC_NO_FINALIZE On microcontroller targets there is usually no normal shutdown or program exit: those programs are running continuously and never exit. In such environments the class finalization is more than meaningless: defining this macro will save three pointers per class definitions and remove the ooc_finalize_class() and ooc_finalize_all() functions from the build. (A good optimizing compiler should remove your class finalizing routines as well, since they are never reached.)
_OOC_VTAB_INITIALIZER On some microcontroller targets it is important to place the virtual table into the initialized data section. We van force this behaviour by defining this macro. (Se mcc18.h port file!)
Although ANSI-C says that all uninitialized data is set to 0 at program start, this macro could be necessary on small microcomputers, since they do not clean their uninitialized data section at start up or restrat.

The TestCase class converts some Unix signals (SIGSEGV, SIGFPE) into ooc Exceptions letting us to do unit test checks way much easier. This macro indicates that there are unix signals implemented in the operation system.

Requirements against the standard C library.

The standard C library on the host must support the following minimal set compatible with ANSI-C:
The following headers must be available:

  • stddef.h (for size_t )
  • string.h (for memcpy() )
  • stdlib.h (for the functions below )
  • assert.h (for the assert macro )
  • setjmp.h (for jmp_buf, setjmp, longjmp or equivalents)

The following memory handling functions must be available:

  • void * malloc( size_t size )
  • void * calloc( size_t num, size_t size )
  • void * realloc( void *ptr, size_t size )
  • void free( const void * mem )
  • void memcpy( void * dest, const void * src, size_t size )
  • void memmove( void * dest, const void * src, size_t size )
  • void memset( void * dest, int c, size_t size )
  • void abort( void )

(This is not an extra requirement :-) If your host does not support these functions then you must implement them.)