Morgan Herrington's Blog Adventures in Porting and Tuning

Thursday Sep 28, 2006

Solaris provides stable API's which are consistent across hardware platforms, so a port from Solaris on SPARC to Solaris on x86 should mostly reduce to a recompile. Right?

Obviously there are some details which might get in the way: (un)availability of x86 versions of the third-party libraries, SPARC assembly code, architecture-specific compiler options in the Makefiles, and low-level data endian-ness.

However, on a project I was recently involved with, the problems of byte order and assembly code had already been solved because the product had been ported to Linux/x86. It might seem that the Solaris/x86 porting work would just require a little tweaking of the existing #ifdef'd code. [Then again, doing anything manually across several million lines of code is more than "just a little tweaking".]

One problem that I hadn't really expected was that we had to manually inspect a large number of #ifdef sequences which were sprinkled throughout the source. Consider the following:

#if defined(SOLARIS)
  ...
#else
  ...
#endif
This code sequence appears to be specific to Solaris, but because "Solaris" and "Sun" have been so intimately associated with SPARC for so long, this conditional (as well as a couple of dozen variations) was also used for protecting big-endian vs. little-endian data accesses, some SPARC specific details, and even occasionally, Sun Studio vs. GNU compiler differences. Similarly, variations of "Linux" could also be used for checking endianness and x86 details.

My first preference would have been to define preprocessor symbols to differentiate OS, platform, and maybe compiler (and to install them consistently throughout the project). However, for this port we chose a "short cut" by using pre-defined symbols provided by the compilers.

As you might expect, there were some differences in what the different compilers provided (for example, the GNU C/C++ compilers define "__sun__", but the Sun compilers do not). However, all compilers define both "sun" and "__sun", so either could be used to recognize when building on "Solaris". I wasn't able to find an argument for using one versus the other, although I'd be interested if anyone has an opinion. Because of some existing uses, we decided to use the pre-defined symbol "sun".

Similarly, all of the SPARC compilers define the symbols "sparc" and "__sparc", and for 32-bit, the x86 compilers define "i386" and "__i386". For 64-bit compiles, the single commonly defined symbol is "__x86_64__".

In retrospect it seems obvious that there should have been distinct discriminants for hardware architecture vs. operating system, however, maybe that was less clear when the code was originally written (when Solaris meant SPARC, HP/UX meant Precision, and AIX meant the Power architecture). That model has changed with Linux running on many platforms (including SPARC), Solaris running on x86, and even Sun Studio tools running on Linux.

For a more in-depth discussion of this topic, see: Lessons Drawn from a Non-trivial Solaris x86 Port

Comments:

When we started to port our compilers to Linux we realized we didn't have a good set of macros for finding OS versus chip etc. Sun compilers have always defined __SunOS_5_10 (for example) for Solaris 10. But you had to use __sun if you wanted to test for generic Solaris. Not really the most clearly named token for that purpose. In the next release of Sun Studio we'll have __SunOS defined whenever we're running on Solaris. Perhaps gcc will pick it up too eventually.

Posted by Chris Quenelle on March 09, 2007 at 03:46 PM PST #

Post a Comment:
  • HTML Syntax: NOT allowed