One reason that I haven't really put much thought or effort into POSH as a cross-platform application tool is that most people writing cross-platform apps are already depending on or leverage third party libraries. Very few non-trivial cross-platform applications are completely dependency free. Because of this, many applications already use POSH-like facilities provided by their libraries (for example, LibSDL, Qt and GTK+ all provide features similar to POSH's, however they are aimed squarely at the application, not library, developer.
#include the former and, if you're using POSH's utility functions, compile and link to the latter. That's it.If you do things right, an application that uses your library won't have to know you're using POSH at all.
POSH provides type definitions for 8-bit, 16-bit, 32-bit and 64-bit (if available) signed and unsigned integer types. These are in the form posh_u16_t, posh_s32_t, etc. POSH also provides a byte (unsigned 8-bit) type: posh_byte_t. For a full list, look at Basic Types.
If you use these types, you are guaranteed to get native types of the exact given size, not "at least" the given size. This is to ensure that serialization and deserialization works, since you need to be able to count on sizeof(x) to remain constant across platforms.
The posh data types are fairly verbose. For this reason (and to avoid user confusion), you may want to create your own type definitions and simply alias them to the POSH ones:
typedef posh_u16_t my_u16;
POSH_PUBLIC_API() ensures that the appropriate DLL import/export directives are used if your library is built or used as a Windows DLL.
Of course, all this magic requires some effort on the part of the library author, but thankfully not that much. In fact, on most systems you don't have to configure anything if you don't care about disabling floating point or being built/used as a Windows DLL.
The only three symbosl a POSH user is responsible for defining are POSH_BUILDING_LIB, POSH_DLL and POSH_NO_FLOAT.
When building a library you should define the preprocessor symbol POSH_BUILDING_LIB before including posh.h. Do this in your source files, not in your public header files!. You do not want this defined inadvertently when a user is trying to link to your library, since this may cause linkage failures on Windows if your library is a DLL.
For example, if your library is called "MyLib", make sure all your source (not header) files define this before including posh.h, for example:
Alternatively, if you distribute a project or makefile you can ensure that the appropriate compiler option (e.g. -DPOSH_BUILDING_LIB=1) is set correctly instead of modifying your source code this way.
POSH checks the POSH_DLL symbol to determine if the __declspec(dllexport) or the __declspec(dllimport) directive should be part of the POSH_PUBLIC_API() macro. This is a moot issue on operating systems other than Windows, but under Windows this is very important if you're building a DLL.
The typical way to handle this, especially if you want the ability to build optionally as a statically linked or dynamically linked library, is to have your own preprocessor symbol that the user can define to enable/disable building-as-a-DLL.
For example, if your library is called "MyLib", you might have your own symbol called MYLIB_DLL. A user of your library would define this if they are building your library as a DLL and/or using it as a DLL. Then in your own code you key off this symbol as such:
However, it may be desirable or necessary to disable this feature, for example on platforms that lack native floating point support or which do not have IEEE compliant floating point bit representations. Or you may just find that linking without floating support gives you a marginally smaller executable.
If you want to disable floating point support in POSH, simply define the symbol POSH_NO_FLOAT, either at the top of posh.h or, preferably, in your makefile/project file.
Probably the single most common topic that comes up regarding cross-platform programming is that of endianess assumptions and conversion. For a complete discussion on processor endianess, um, search the Web, because I'm not going to get into the details here.
POSH provides a set of Byte Order Conversion Macros, such as POSH_LittleU16() and POSH_BigS32(), along with 64-bit (if available) and floating point versions, that convert a value in a specific endianess to host-endian format.
NOTE: If you use the endianess macros, you will have to link with posh.c if byte swapping is actually necessary.
During compilation POSH looks at the local environment (via examining predefined symbols) and tries to figure out what's what. Once it figures things out, it defines numerous constants to give your code chance to react during the build phase.
The constants potentially defined include:
POSH_BIG_ENDIAN POSH_LITTLE_ENDIAN, POSH_64BIT_INTEGER, POSH_64BIT_POINTER, along with a host of CPU and Operating System Symbols.
Just do the appropriate thing in your code based on the above, for example:
Note that POSH does not define any compiler macros, since unlike CPU and OS target macros, these are (hopefully) going to be consistent and unique. In addition, if you have code that is compiler specific, the expectation is that you already know how to detect that compiler.
In support of the endianess macros, POSH provides a set of Byte Swapping Functions that byte swap 16, 32 and 64-bit (if available) values.
POSH does not have floating point byte swapping functions, since this could theoretically lead to floating-point exceptions on some systems.
The proper way to handle cross-platform floating point is to convert floating point values to integer form and byte swap that value before serialization. For deserialization, simply do the reverse -- read an integer form, byte swap, then load a floating point value from the converted integers. Doing a direct load to a floating point variable then swapping will potentially result in an invalid floating point variable either before or after the swap, depending on the conversion. For more information, see floating point functions.
Directly related to the issue of cross-platform endianess is the ability to serialize and deserialize native data in a portable form. This is typically done by arbitrarily choosing a data file endianess then converting all data from host-to-data endianess at serialization time.
POSH provides a set of In Memory Serialization/Deserialization Functions, along with 64-bit (if available) and floating point versions, that will automatically write native data types to memory and read them back in properly. For floating point values, you must convert to/from integer representation first.
POSH provides a cross-platform compile time assertion macro. You don't have to use it, but it's there if you want to. POSH itself uses it fairly liberally in posh.h to sanity check the environment. An example of its use might be something like:
That's pretty much it -- follow the above and you're on the way to cross-platform nirvana. Or something.
1.3.7