The GNU classpath native layer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To enable GNU classpath to run on a diverse array of different hardware platforms, a new native software layer has been added. This layer hide all machine and hardware dependent issues except common available definitions, which are ANSI C functions. For each targets system where the GNU classpath library is to be used, a specific set of native layer functions have to be provided. A generic set of functions is provided for Unix like systems (currently tested only with Linux). For a new target system, some or all native layer functions have to be rewritten. The following scheme illustrate the native layer. Java API ---------------------- | Java classes | | -------------------- | | C native functions | | -------------------- | >> | C native layer | << | -------------------- | | operating system | | -------------------- | | hardware | ---------------------- The C native layer is implemented as a set of C pre-processor native macros. These macros expand to the appropriated native code. Macros are used instead function calls to give optimal performance and small code size. Of course in special cases, a macro can also expand to a function call if this is needed. This approach provide a flexible and efficient implementation of the native layer. The naming pattern for native macros is like follows: TARGET_NATIVE__ where is a name of a module, e. g. FILE; is the name of the specific native macro, e. g. OPEN_READ. The parameters for the macro use in general (with a few exceptions) the scheme ,,..., where is input/output parameter and is the result code TARGET_NATIVE_OK or TARGET_NATIVE_ERROR. Specific error codes and error strings can be gotten with TARGET_NATIVE_LAST_ERROR and TARGET_NATIVE_LAST_ERROR_STRING (see also file target_generic.h). For a single target system there exists two sets of native macros in the files a) /target_native_.h b) generic/target_generic_.h The macros in "a" are target specific implementations of native functions, the macros in "b" are generic implementations (for Unix) of the same native functions. If a native macro is not defined in the file "a", then the definition in file "b" is used (there is a check to see if a native macros is already defined elsewhere). This technique enables "a" to 'overwrite' single generic native macros with specific native macros for a specific target. In the default case, where only the generic implementation of the native macros is used, the files in the directory '' are empty except for the mandatory include of the generic header file in the directory 'generic' at the end. Please look at the existing Linux target specific files. The directory and file structure is as follows. native ... | |--- target | | | |--- Linux | | |--- target_native_.h | | |--- ... | | ... | |--- ... | |--- generic | | |--- target_generic_.h | | |--- ... ... ... ... Include hierarchy is as follows. native file --> include 'target_native_.h' ... ... --> include 'target_generic_.h' ... ... When writing native code, please take care with the following. - Use _only_ ANSI C specific functions directly which are available on all target systems with the same parameters, e. g. strdup() is not an ANSI C function, thus is is not available on all systems; mkdir() expect on some systems different parameters. !!!Do NOT use this functions in your native code!!! Instead * if a function is not available, create a native macro in the file /target_native_.h * if it is a generic function, include a generic implementation in generic/target_generic_.h * Then use this macro in your native code. - Avoid _all_ OS specific data types and constants, e. g. structures or error numbers. Instead, wrap them in a native macro and convert the values to basic scalar types like char, int, double or long. - Take care with 64 bit values; the are machine dependent. Not all target system support 64 bit operations. The macros in target_generic_math_int.h give a set of macros implementing 64 bit operations and constants. - Avoid - if possible - non-reentrant functions. Non-reentrant functions cause strange problems on some multitasking systems. - Avoid - if possible - dynamic data types created by malloc() and similar functions. Instead use (local) static variables to avoid stack usage. On some target systems, dynamic memory management is either slow or even dangerous. Moreover malloc()-calls can cause fragmentation of the system memory, which could result in a system crash or an application failure. For some examples, please look in the current implementation for Linux in the directory 'target/Linux' and the generic implementation in the directory 'target/generic'. aicas GmbH, February 2003