If you’ve ever had to write a portable application in C, you’ve likely run into the same problem faced by countless other programmers: no matter how much you try to stick to a well-defined application programming interface (API), the program just doesn’t work the same on every platform.
While POSIX does a passable job of providing a portable API for most Unix and Unix-like platforms, POSIX either doesn’t exist on other operating systems or is so full of bugs as to be unusable. Moreover, POSIX isn’t always the best choice. Non-Unix platforms, such as Microsoft Windows, have their own APIs that are better mantained and perform better on that platform.
So, to make something portable, you could write, rewrite, and tweak your code several times — at least so the code compiles on several platforms. Or, you can use the Apache Portable Runtime (http://apr.apache.org/) the same library that makes the ubiquitous Apache HTTP server portable. If it’s good enough for Apache, well, enough said.
If you’ve ever had to write a portable application in C, you’ve likely run into the same problem faced by countless other programmers: no matter how much you try to stick to a well-defined application programming interface (API), the program just doesn’t work the same on every platform.
While POSIX does a passable job of providing a portable API for most Unix and Unix-like platforms, POSIX either doesn’t exist on other operating systems or is so full of bugs as to be unusable. Moreover, POSIX isn’t always the best choice. Non-Unix platforms, such as Microsoft Windows, have their own APIs that are better mantained and perform better on that platform.
So, to make something portable, you could write, rewrite, and tweak your code several times — at least so the code compiles on several platforms. Or, you can use the Apache Portable Runtime (http://apr.apache.org/) the same library that makes the ubiquitous Apache HTTP server portable. If it’s good enough for Apache, well, enough said.
Apache 1.3 was ported to a variety of platforms, including many that weren’t POSIX based, such as Windows, OS/2, and BeOS. On those platforms, Apache 1.3 often relied on #ifdef blocks to acheive portability, effectively forking the source into mainline code and platform-specific code, making the code harder to read, debug, and maintain.
When development started on Apache 2.0, the developers knew that they needed a better solution. Initially, two existing solutions were considered. One was the Adaptive Communication Environment (ACE), and the other was the Netscape Portability Runtime (NSPR). However, both were rejected.
ACE was implausible because Apache requires that all code be written strictly in C, and ACE is a combination of C and C++. And while NSPR looked like a good fit, it’s license was incompatible with Apache’s. (The licensing issues were eventually resolved, but by that time, APR was already in development.)
Nonetheless, writing APR from scratch has worked well for the Apache community — and others. (See the sidebar, “Who’s Using the Apache Runtime?” for more details.) It’s a portability layer specifically written with servers in mind.
Let’s see how to write applications with APR. And to appreciate APR’s power, let’s start with code that looks portable, but’s not. As you’ll see, there are devils in the details.
Almost Portable
Some code is inherently portable, because it uses very well documented APIs
that are implemented everywhere. For example, the code…
char *var = getenv(”SHELL”);
… compiles and runs on all platforms, but there are…
Please log in to view this content.
Not Yet a Member?
Register with LinuxMagazine.com and get free access to the entire archive, including: