What is the most efficient way of writing portable applications (eg. apps that runs on Windows, Linux and MacOS)?
The general techniques are
Keep platform-specific code in modules separate from the cross-platform code, for ease of porting.
Write code in a popular high-level language (that is, not in assembly language nor a platform-specific language)
Use standardized widely available APIs (e.g., POSIX, OpenGL, X)
Use cross-platform network APIs, protocols, and data representations (e.g., CORBA, ASN.1, XML, UniCode). Pay attention to byte-ordering, structure-packing, and native character set issues.
Use cross-platform libraries. OpenSource libraries have the advantage that you can port them to new platforms yourself if necessary.
Establish a platform-abstraction layer, and build the rest of the application on top of that.
Use a preprocessor to modify the code according to platform-specific dependencies
Take advantage of tools that detect platform dependencies and alter build options accordingly (e.g., AutoConf)
Use a cross-platform virtual machine or interpreter (e.g., Java, Smalltalk, Python, Perl)
There are costs associated with portability. Take these into account when deciding what level of portability you really need:
Writing, testing, and supporting portable code usually involves a lot more work than does developing for one specific target platform.
Achieving portability often requires a "least common denominator" approach to feature selection and design, restricting one to only those features that can be implemented efficiently on all platforms.
Portable applications are often not well integrated into their runtime environments, and do not conform to the common conventions nor look-and-feel of those platforms.
Once you provide support for a particular platform, there is enormous pressure to continue supporting that platform in all subsequent versions.
Portable code is often "bloated" with extra abstraction layers and format-translation code.
Cross-platform libraries, interpreters, virtual machines, and other runtime portability support components must be distributed and installed along with the application. And you'll need to manage versioning issues with all those components and your application.