Portability to as many systems as possible is one of the primary design goals of ScummVM. We strive all the time to ensure our code compiles and runs on as many systems as possible. To this end, it's important that our developers are aware of certain typical portability problems and pitfalls. On this page we try to collect some of them.
Work in progress: This page is incomplete. We should probably also link on some good & relevant web pages on the net, and only focus on the most frequent or maybe unusual (ScummVM specific) issues.
ScummVM is written in a subset of C++. Due to limitations of the C++ run-times on various platforms, the following features cannot be used:
- C++ exceptions (throw/catch): Not all C++ compilers support these correctly (esp. on embedded systems), and exception support incurs a noticeable overhead in binary size.
- C++ RTTI (run-time type information, as in dynamic_cast<>): This incurs a severe overhead in binary size and memory usage, as every C++ object is enlarged by RTTI information
- Global C++ objects: Their constructors / destructors will not be called on certain targets, causing all kinds of bad problems and requiring ugly workarounds. (The GCC option -Wglobal-constructors helps finding code doing this.)
Furthermore, the standard C++ library is a big no-no. Besides usually heavily relying on the above mentioned features, it also sucks up rather more resources than we would like to, so we have our own replacements for various container classes etc.
We are reviewing these decisions from time to time, but so far, in our estimation the drawbacks of using any of these outweigh the hypothetical advantages.
If you don't know what "Endianess issues" refers to, read up here: http://en.wikipedia.org/wiki/Endianess
ScummVM engine authors have to keep endianess issues in mind for two reasons:
- ScummVM runs on both little endian (Windows, x86 Mac OS X, x86 Linux...) and big endian hosts (PowerPC Mac OS X, PlayStation 3 Linux...). So when writing data (think savegames) to files and reading it back again, you need to compensate for this. This is easily done by using the READ_ and WRITE_ macros from common/endian.h (like READ_LE_UINT32 or WRITE_BE_UINT16.) respectively the corresponding Stream class methods (like readUint32LE or writeUint16BE).
- Furthermore, some games existed in multiple versions, e.g. one for Windows and one for Mac OS. In that case, you may have to detect and distinguish these versions and employ different reading calls, to compensate for endian differences in the game data files.
Do *not* assume that structs are stored in a certain way in memory -- the layout of a struct in memory can vary a lot between platforms, and on most modern systems it will almost never be "packed". If you absolutely must use packed structs, do not just use some #pragma or __attribute__ (as that is not portable either). Instead, do the following:
- Before the struct(s) you need to be packed, insert
#include "common/pack-start.h" // START STRUCT PACKING
- After the struct(s) you need to be packed, insert
#include "common/pack-end.h" // END STRUCT PACKING
- At the "end" of each struct you need to be packed, insert the following between the closing } and the ; after it:
You may want to look at some files which already do that, e.g. look at
In a nutshell, you must not use fopen(), fread(), fwrite(), etc., nor open(), close(), etc. in your code (unless you are developing a backend, that is). Instead you must use the APIs for reading and writing files provided by ScummVM. Please consult the HOWTO Open Files page for details.