Changes between Initial Version and Version 1 of Develop/PlatformDependantCode


Ignore:
Timestamp:
Oct 8, 2016, 1:31:46 PM (8 years ago)
Author:
pulkomandy
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Develop/PlatformDependantCode

    v1 v1  
     1= Introduction =
     2How to code in GrafX2 for one platform without breaking the others.
     3
     4= List of platforms =
     5  * Amiga OS3 and 4, AROS, MorphOS
     6  * BeOS and Haiku
     7  * gp2x
     8  * Linux
     9  * MacOSX
     10  * Win32 refers to versions of Windows : 98, NT, 2000, XP, Vista.
     11
     12= Symbols table for detection =
     13
     14||#ifdef||Linux||Win32 (MinGW)||Win32 (Watcom)||MacOSX||Amiga OS4||Beos||Haiku||AROS||MorphOS||FreeBSD||GP2X||Wiz||Caanoo||AmigaOS 3||
     15||`__WIN32__`   || ||X|| X ||  ||  ||  ||  || ||  || ||   || || || ||
     16||`__MINGW32__` || ||X||   ||  ||  ||  ||  || ||  || ||   || || || ||
     17||`__WATCOMC__` || || || X ||  ||  ||  ||  || ||  || ||   || || || ||
     18||`__linux__`   ||X|| ||   || X||  ||  ||  || ||  || || X ||X||X|| ||
     19||`__macosx__`  || || ||   || X||  ||  ||  || ||  || ||   || || || ||
     20||`__amigaos4__`|| || ||   ||  || X||  ||  || ||  || ||   || || || ||
     21||`__BEOS__`    || || ||   ||  ||  || X||  || ||  || ||   || || || ||
     22||`__HAIKU__`   || || ||   ||  ||  ||  || X|| ||  || ||   || || || ||
     23||`__AROS__`    || || ||   ||  ||  ||  ||  ||X||  || ||   || || || ||
     24||`__MORPHOS__` || || ||   ||  ||  ||  ||  || ||X || ||   || || || ||
     25||`__FreeBSD__` || || ||   ||  ||  ||  ||  || ||  ||X||   || || || ||
     26||`__GP2X__`    || || ||   ||  ||  ||  ||  || ||  || || X || || || ||
     27||`__WIZ__`     || || ||   ||  ||  ||  ||  || ||  || ||   ||X|| || ||
     28||`__CAANOO__`  || || ||   ||  ||  ||  ||  || ||  || ||   || ||X|| ||
     29||`__amigaos__` || || ||   ||  ||  ||  ||  || ||  || ||   || || ||X||
     30
     31Generally, you should assume a globally "unix" platform, and only put code in #ifdef block when you need to do something different for one platform.
     32
     33Be careful that {{{__linux__}}} applies to MacOSX as well.
     34
     35If you need to code a complicated kind of "switch", the cleanest way to write it would be:
     36{{{#!c
     37#if defined(__BEOS__)||defined(__HAIKU__)
     38  // put BeOS/Haiku-specific code here
     39#elif defined(__amigaos4__)
     40  // put OS4-specific code
     41#else
     42  // put default alternative code here
     43#endif
     44}}}
     45
     46= System-specific =
     47== Windows ==
     48Environment variable: *COMSPEC*. This holds the path to the command interpreter (ex: C:\CMD.COM) The Makefile uses this variable to detect Windows build. Hopefully nobody sets it in an other system.
     49
     50Environment variable: *WINDIR*. This holds the path to the windows drive and directory (ex: C:\WINDOWS). Used to find fonts.
     51Directory separator: Windows filesystems traditionally use the character \ as a separator between directories, however / is also supported in *almost* all file i/o functions, and must be expected too.
     52
     53Drives: An absolute file name begins with a drive name, from "A:" to "Z:". It is followed by a path separator, ex: "C:\GrafX2\gfx2.ini"
     54
     55== Amiga-like systems (AmigaOS 3 and 4, AROS, MorphOS ==
     56Drives: AmigaOS filesystem has volume/drive name. It can be a "technical" name like "df0:" for Disk Floppy drive 0, or a user-set name like "games:". The volume or drive is *not* followed by a path separator, ex: "mp3:Switchblade Symphony/Clown.mp3". This means that a directory name can be "something:", with no trailing slash. The parent directory is /, not .. like on other systems.
     57
     58Compiler: The compiler is VBCC, it doesn't support GNU extensions like {{{__attribute__}}}
     59
     60= Caanoo specifics =
     61
     62It seems the build will be little-endian.
     63Be careful to pick *signed* chars by default. If you make a mistake, some compiler warnings about "comparison always true" may be a sign.
     64
     65= Endianness =
     66
     67SDL already provides reliable macros to determine the host system's endianness (Big-Endian like PowerPC, or Little-Endian like Intel)
     68The syntax is
     69{{{#!c
     70#if SDL_BYTEORDER == SDL_LIL_ENDIAN
     71
     72#if SDL_BYTEORDER == SDL_BIG_ENDIAN
     73}}}
     74In general you shouldn't use them anyway. The most frequent reason you need to know endianness is when you read or write data to disk, and all the necessary functions have been coded in io.c, in two forms : big-endian (_`Read_word_be()`_) and little-endian (_`Read_word_le()`_). Just choose the functions that have the right endianness for the *file format* (ex:GIF is little-endian, LBM is big-endian), and the functions will perform swapping as necessary.
     75
     76= Struct packing =
     77
     78Structs in C are not guaranteed to be contiguous in memory, the compiler can insert dummy bytes between struct members in order to align the members on 2-byte, 4-byte or 8-byte addresses. In some cases it makes the program run faster (x86). In some other cases it's *mandatory* to access the members at all (Sparc, and ARM-based machines like the Caanoo).
     79
     80The default behavior of Watcom C was to pack structures (Original code from 1996)
     81*The default behavior of gcc on x86 is to pad them*, so 2-byte data is on address multiple of 2, 4-byte data is on addresses multiple of 4, and the total structure has a final padding at the end, according to its biggest member.
     82
     83As you can guess, when porting grafx2 we ran right into this one. An early fix was to pack a lot of structures by marking them with an GCC extension attribute: `__attribute__((__packed__))` or the `#pragma pack` (Which *is* supported on all versions of GCC that are currently in use).
     84Since then, to support big-endian cpus, all datatypes of more than one byte had to be handled individually for endianness anyway, the code now loads/saves them as individuel fread() and fwrite(), and thus the program no longer relies on having the structures packed.
     85
     86As of 11/2010, only two structures remain forcibly packed: the RGB triplet T_Components, and (as a consequence) the array of 256 of them: T_Palette. This struct is only made of 8-bit types, so it can be packed on all platforms:
     87sizeof(T_Components) == 3 and sizeof(T_Palette) == 768.
     88The guideline now is to never write another structure that require packing. *Don't expect specific sizeof() values. Don't rely on sizeof() to automatically count the "file size" of a structure, even a packed one.* It just doesn't *always* work.
     89(You can still rely on sizeof() for memory allocation)
     90
     91= Memory alignment =
     92
     93On the Caanoo with its ARM architecture, you can't read a 2-byte number at an address that isn't a multiple of 2, and you can't read a 4-byte number at an address that isn't a multiple of 4. This has consequences on struct packing (see above), so for example the compiler will sometimes add padding *even if you use attribute or pragma to disable it*, without any compilation warning.
     94
     95Also, you can trigger this problem if you try to cast a void pointer to a `word*` or `dword*` : The address will be rounded, or maybe the bytes will be shuffled (not clear at this moment).
     96
     97The typical pitfall is trying to read a RGB triplet in a 24bit bitmap as a single dword fetch. *On all platforms, don't do that*. It breaks the Caanoo port.
     98
     99= Zero-sized arrays =
     100
     101Zero-sized array at the end of a struct, in order to support dynamic-allocated array: Use {{{elem[0]}}} on GCC v2 or earlier, {{{elem[]}}} on GCC >= 3 and any other compiler (including VBCC):
     102
     103{{{#!c
     104#if __GNUC__ < 3
     105  // gcc2 doesn't suport [], but supports [0] which does the same thing.
     106  T_Image    Image[0];  ///< Pixel data for the (first layer of) image.
     107#else
     108  T_Image    Image[];  ///< Pixel data for the (first layer of) image.
     109#endif
     110}}}
     111
     112= Unused arguments =
     113
     114The GCC-ism `__attribute__((unused))` breaks the compilation on Amiga-like platforms that use the VBCC compiler.
     115`__attribute__` should only be used when `__GNUC__` is defined. For unused arguments, in order to avoid a compilation warning, the following syntax works on all known platforms:
     116{{{#!c
     117  (void)color; // unused
     118}}}
     119It can be surrounded by #ifdef in order to isolate the specific case when this argument is unused.
     120
     121= Make dependencies =
     122
     123In release source packages, the dependency file (Makefile.dep) is packed with the sources, and may be used on a different platform than the one where it was generated.
     124When this file is not up-to-date, you can get strange compilation or run-time time errors, that disappear only when you `make clean` and then `make`.
     125To keep everybody happy, running *make depend* should generate an identical file on all platforms. It's not difficult, you only have to avoid including some grafx2 headers conditionally:
     126{{{#!c
     127#ifdef __WIN32__
     128#include "gfx2win.h" // bad
     129#endif
     130}}}
     131If you have such situation where there is source file that is not needed for all platforms ("gfx2win.c"), include the header always, and _in the header file itself_, enclose all the declarations in a conditional #if.
     132
     133= 32bit vs 64bit =
     134Size of native types for C compiler:
     135
     136*32bit compiler*
     137|| *Type* || *Size* ||
     138|| short int || 16bit ||
     139|| int || 32bit ||
     140|| long || 32bit ||
     141
     142*64bit compiler*
     143|| *Type* || *Size* ||
     144|| short || 16bit ||
     145|| int || 32bit ||
     146|| long || 64bit ||