Category Archives: Cross-Platform

Universal Software Principles

Universal Software is software that can be used natively on any device and guarantees universal reuse, extension, and maintenance.

The four fundamental principles of universal software are:

  1. The software must run natively on any hardware, Operating System, and network (Environment Independence Principle).
  2. The software must allow reuse of complete or part functionality as modules to create new applications (Modular Reuse Principle).
  3. The software must allow extension of its functionality by addition, enhancement, or replacement of its functionality by new modules or plugins (Inject and Extend Principle).
  4. The software must use a single set of source code that is permissive for maintenance by software engineers other than its original authors (Open Maintenance Principle).


These principles can be further understood by the following guidelines:

Environment Independence Principle

Universal software must run natively on any hardware, Operating System, and network.

This should be understood to mean the software:

  1. Must run natively on any device to which it is deployed.
  2. Must not require particular hardware to operate.
  3. Must not require a particular Operating System (OS) to operate.
  4. Must work in both stateful and stateless environments.
  5. Must not require a network or internet connection to perform non network tasks.

Whenever possible the software:

  1. Should also be available for use within a web browser (separate to the native applications).
  2. Should make use of specific hardware capabilities of the device it is running on where it helps achieve the software’s purpose.
  3. Should follow applicable guidelines and recommendations of an OS when running within that OS.
  4. Should cache non-senstative data to allow continued use of the software in environments without network or internet access.
  5. Should include platform independent version of any platform dependent code to allow the software to be executed on new platforms that were not available at the point of release.

Modular Reuse Principle

The software must allow reuse of complete or part functionality as modules to create new applications.

This should be understood to mean the software:

  1. Must provide all its functionality as a reusable dynamic link library or package.
  2. Must self initialise its data store and other dependencies on first use.
  3. Must provide complete functionality including CRUD operations and user interface.

Whenever possible the software:

  1. Should use the Mvpc Command pattern to allow a containing application to display its functionality alongside that of other modules.
  2. Should be suitable for use as a plugin at run time in environments that allow plugins.

Inject and Extend Principle

The software must allow extension of its functionality by addition, enhancement, or replacement of its functionality by new modules or plugins.

This should be understood to mean the software:

  1. Must allow any service it provides to be extended or replaced by another module.
  2. Must allow any service it invokes to be extended or replaced by another module.
  3. Must allow any user interface screen to be extended or replaced by another module.
  4. Must allow the replacement of a single service or interface screen without requiring related services or interface screens to be replaced as a result.

Whenever possible the software:

  1. Should allow functionality to be disabled at runtime through configuration.

Open Maintenance Principle

The software must use a single set of source code that is permissive for maintenance by software engineers other than its original authors.

This should be understood to mean the software:

  1. Must use a single source code for all functionality across all platforms except those files or classes that directly interact with the hardware or Operating System.
  2. Must provide documented APIs for all public classes and members.
  3. Must not directly create or require software patents.
  4. Must be written in a programming language with a formal ECMA and/or ISO standard that makes it free to implement and has an open source compiler available.

Whenever possible the software:

  1. Should only use version controlled standardised APIs between packages.
  2. Should be extendible in a programming language different to its original language.
  3. Should be made available under a permissive open-source license.


17 Years of Porting Software… Finally Solved

A History of Porting Software

I’ve been involved in creating and maintaining commercial and open source software for as long as I can remember, reaching back to 1996 when the world wide web was in its infancy, and Java wasn’t even a year old.

I was attracted to the NetBSD project because of its focus on having its software run on as many hardware platforms as possible.  Its slogan was, and remains “Of course it runs NetBSD”.

Although the NetBSD team worked tirelessly for its operating system to work across every imaginable hardware platform; much of the new open-source software development was talking place in for the i386 focused GNU/Linux operating system, not to mention the huge volume of Windows-only software that Wine tried, and mostly failed, to make available to people on non-Windows operating systems.

Advocates of cross-platform software like me were then constantly choosing between recreating or porting this software depending on its licenses terms and source availability just so we can use it on our platform of choice.

Some of the early of my open source contributions that are still available to download demonstrate this really well such as: adding NetBSD/OpenBSD support to Afterstep asmem in early 2000.  Or allowing CDs to be turned into MP3s on *BSD platforms with MP3c in the same year.

In 2002 when the large and ambitious KDE and GNOME desktops started to dominate the Linux desktop environments, I worked on changes to the 72 separate packages needed bring GNOME 2 and to NetBSD and became the primary package maintainer for a number of years.

As an early adopter of C# and the Microsoft .NET Framework I also worked through 2002 and 2003 to make early versions of the Mono project execute C# code to FreeBSD, NetBSD, and OpenBSD too.

The #ifdef solution

How was software ported between platforms back in those days?  Well to be honest, we cheated.

We would find the parts of the code that were platform specific and add #ifdef and #ifndef statements around them with conditions instructing the compiler to compile, or omit, different sections of code depending on the target platform.

Here is an example of read_mem.c from asmem release 1.6:

 * Copyright (c) 1999  Albert Dorofeev <>
 * For the updates see
 * This software is distributed under GPL. For details see LICENSE file.

/* kvm/uvm use (BSD port) code:
 * Copyright (c) 2000  Scott Aaron Bamford <>
 * BSD additions for for this code are licensed BSD style.
 * All other code and the project as a whole is under the GPL.
 * For details see LICENSE.
 * BSD systems dont have /proc/meminfo. it is still posible to get the disired
 * information from the uvm/kvm functions. Linux machines shouldn't have
 * <uvm/vum_extern.h> so should use the /proc/meminfo way. BSD machines (NetBSD
 * i use, but maybe others?) dont have /proc/meminfo so we instead get our info
 * using kvm/uvm.

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#include "state.h"

#include "config.h"

/* sab - 2000/01/21
 * this should only happen on *BSD and will use the BSD kvm/uvm interface
 * instead of /proc/meminfo
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>

#include <uvm/uvm_extern.h>
#endif /* HAVE_UVM_UVM_EXTERN_H */

extern struct asmem_state state;

#define BUFFER_LENGTH 400
int fd;
char buf[BUFFER_LENGTH];
#endif /* !HAVE_UVM_UVM_EXTERN */

void error_handle( int place, const char * message )
	int error_num;
	error_num = errno;
	/* if that was an interrupt - quit quietly */
	if (error_num == EINTR) {
		printf("asmem: Interrupted.\n");
	switch ( place )
	case 1: /* opening the /proc/meminfo file */
		switch (error_num)
		case ENOENT :
			printf("asmem: The file %s does not exist. "
			"Weird system it is.\n", state.proc_mem_filename);
		case EACCES :
			printf("asmem: You do not have permissions "
			"to read %s\n", state.proc_mem_filename);
		default :
			printf("asmem: cannot open %s. Error %d: %s\n",
				state.proc_mem_filename, errno,
	default: /* catchall for the rest */
		printf("asmem: %s: Error %d: %s\n",
			message, errno, sys_errlist[errno]);

#ifdef DEBUG
/* sab - 2000/01/21
 * Moved there here so it can be used in both BSD style and /proc/meminfo style
 * without repeating code and alowing us to keep the two main functions seperate
#define verb_debug() { \
       printf("+- Total : %ld, used : %ld, free : %ld \n", \
             , \
       printf("|  Shared : %ld, buffers : %ld, cached : %ld \n",\
       printf("+- Swap total : %ld, used : %ld, free : %ld \n",\
#define verb_debug()
#endif /* DEBUG */

/* using kvm/uvm (BSD systems) ... */

#define pagetok(size) ((size) << pageshift)

int read_meminfo()
      int pagesize, pageshift;
      int mib[2];
      size_t usize;
      struct uvmexp uvm_exp;

      /* get the info */
      mib[0] = CTL_VM;
      mib[1] = VM_UVMEXP;
      usize = sizeof(uvm_exp);
      if (sysctl(mib, 2, &uvm_exp, &usize, NULL, 0) < 0) {
        fprintf(stderr, "asmem: sysctl uvm_exp failed: %s\n",
          return -1;

      /* setup pageshift */
      pagesize = uvm_exp.pagesize;
      pageshift = 0;
      while (pagesize > 1)
              pagesize >>= 1;

      /* update state */ =  pagetok(uvm_exp.npages);
      state.fresh.used = pagetok(; = pagetok(;
      state.fresh.shared = 0;  /* dont know how to get these */
      state.fresh.buffers = 0;
      state.fresh.cached = 0;
      state.fresh.swap_total =  pagetok(uvm_exp.swpages);
      state.fresh.swap_used = pagetok(uvm_exp.swpginuse);
      state.fresh.swap_free = pagetok(uvm_exp.swpages-uvm_exp.swpginuse);
      return 0;

/* default /proc/meminfo (Linux) method ... */

int read_meminfo()
	int result;
	result = lseek(fd, 0, SEEK_SET);
	if ( result < 0 ) {
		error_handle(2, "seek");
		return -1;
	result = read(fd, buf, sizeof buf);
	case 0 : /* Huh? End of file? Pretend this did not happen... */
	case -1 :
		error_handle(2, "read");
		return -1;
	default :
	buf[result-1] = 0;
	result = sscanf(buf, "%*[^\n]%*s %ld %ld %ld %ld %ld %ld\n%*s %ld %ld %ld",
	case 0 :
	case -1 :
		printf("asmem: invalid input character while "
			"reading %s\n", state.proc_mem_filename);
		return -1;
	return 0;

#endif /* (else) HAVE_UVM_UVM_EXTERN_H */

int open_meminfo()
	int result;
	if ((fd = open(state.proc_mem_filename, O_RDONLY)) == -1) {
		error_handle(1, "");
		return -1;
#endif /* !HAVE_UVM_UVM_EXTERN_H */
	return 0;

int close_meminfo()
#endif /* !HAVE_UVM_UVM_EXTERN_H */
	return 0;

It wasn’t neat.  It increased code complexity and maintenance costs, but it worked.  And we all accepted it as the best we had for now.

Hopes of a Brave New World

Like many cross-platform advocates, I had big hopes for Java and C# with the Microsoft .NET Platform.  But sadly we never saw the fulfilment of their “platform independent” coding promises.  Too many times we have to choose between a GUI toolkit for a platform and looking out of place.  Other times we had to P/Invoke to native APIs to get at functionality not exposed or reproduced by the frameworks.  Even now the GUI toolkit Gtk# is recommended over standard Windows’ System.Windows.Forms on Mono when creating C# programs for Linux or *BSD.

Cross Platform Toolkits such as SWING for Java and Qt for C++ sprung up to abstract the user from the platform they were working with.  But they were primarily GUI toolkits and their APIs only went so far, and eventually, like it or not, all but the most simple applications ended up with a native API call or two wrapped in an #ifdef style condition.

How Web Development Made it Worse

With the rapid increase in Web Development many saw this as finally the way to deliver software across multiple platforms.  Users accessed software via a web browser such as Netscape Navigator and didn’t need the code to work on their own PC or operating system.

Of course behind the scenes the CGI programs were still platform specific or littered with #ifdef statements if they needed to work on more than one server OS.  But the experience of the end user was protected from this, and it looked like a solution may be in the pipeline.

But then the Netscape vs Internet Explorer browser wars happened.  Browsers competed for market share by exposing incompatible features and having sites marked as “recommended for Netscape” or “works best in IE”.  People wanting to support multiple browsers started having to litter their code with the JavaScript equivalents of #ifdef statements.  The same happened again CSS as it became popular.  Nothing really changed.

Enter the Mobile

Then along came the iPhone, and made a bad situation even worse.

Those who went for a native implementation had to learn the rarely used Object-C language.  This helped Apple to avoid competition as developers scrambled to be part of the mobile revolution, but deliberately made portability harder rather than easier.  That still remains part of their strategy today.

People turning again to the web for solutions found that accessing web sites carefully formatted to look great on 1024×768 screens, now being viewed on a tiny mobile phone screen in portrait orientation – was ugly at best, but more often unusable!  And it wasn’t just about text size.  Touch and other mobile specific service meant users expected a different way of interacting with their applications, and browser based software felt more out of place than ever. Yes Responsive Web design and HTML 5 go a long way towards solving some of these web specific mobile issues, but it doesn’t take us away from the #ifdef style logic that has become an accepted part of web application development as it did C and C++ development before it.

So What is to be Done?

Most of this article has been about a history of failures to tackle cross-platform software head on.  Each attempt did bring us a little closer to a solution, but throughout we resigned ourselves to the fact that #ifdef style code was still ultimately necessary.

As application designers and developers we had to choose between how native our applications felt and limiting users from using our software in situations we didn’t plan for.

For almost two decades I’ve been involved in trying to overcome this cross-platform problem.  Now the landscape is more complicated than ever.  Can the same software really run without compromise both inside and outside the browser?  Can we really have a native look and feel to an application on a mobile, tablet, and as desktop PC, is wearable computing going to be the next spanner in the works?

All this is why to move forward, we went back to basics.  We thought first about how software was designed, rather than the libraries and languages that we used.  We first made the Mvpc design pattern, and only then did we make there reference libraries and the commercial Ambidect Technology (soon to be known as Ambicore).  Its fair to say that our many years of experience led us to be able to finally learn from the past we had been so involved with, rather than allowing ourselves to repeat our mistakes again and again.

Because Ambicore provides access to the whole .NET Framework gives a complete cross-platform API that’s developers already know.  Use of C# as our first reference language gives us access to the great thinking that went into creating the Java JVM and Microsofts IL environments that really can abstract us from the operating system and help us avoide #ifdef statements.

Providing native GUI interfaces for each platform means applications using the platforms own recommended toolkit helps applications look and feel native everywhere – simply because they are native to each platform.

Providing a design pattern that works equally well in request-response stateless environments and in rich state-full environments allows us from day one to provide a browser based experience for those who want or need it, as well as a native rich client experience for those wanting to get more from their Windows PCs, phones, tablets, Macs, Linux, *BSD, or…

Its taken 17 years of personal involvement, and recognising and listening to visionaries in the industry.  But by standing on the shoulders of others we re-thought the problem, knowing #ifdef statements were as much part of problem as they were a solution.  We redesigned the development pattern to be portable by default, not as an after thought.  And we based our reference libraries on trusted platforms from market leaders such as Microsoft to make our technology available to the largest pool of developers possible in a language, framework, and IDE they already know.

We are stepping into a new chapter of software development where the platform and device is there to enable, not restrict, the end user from the software they want.  And just as we stood on the shoulders of giants to get here – we want you to join us in the new world too.