Tue, 14 Nov 2006

Autoconf and #ifdef Considered Harmful.

I recently got an email from someone suggesting that my example for detecting the presence of libsamplerate was somewhat problematic. The crux of the complaint is that my configure.ac snippet ends up setting the HAVE_SAMPLERATE variable to 0 or 1 and that most people tend to use something like this in their C or C++ code:


    #ifdef  HAVE_SAMPLERATE
         /* Some code which uses libsamplerate here. */
    #endif

Obviously with HAVE_SAMPLERATE defined to 0 or 1, this code is not going to work as the developer expected. Instead, they should be using something like:


    #if  HAVE_SAMPLERATE
         /* Some code which uses libsamplerate here. */
    #endif

I know that the former idiom is more common, but I chose the second method for a reason; I believe that it is more robust. The problem of course is that autoconf and its related tools are fragile, but the standard idiom certainly doesn't help.

Consider the following code (from a bug I found in XMMS ):


    #ifndef  WORDS_BIGENDIAN
         /* Some little endian machine specific code. */
    #endif

The bug resulted from an error in configure.ac where the author had forgotten to invoke the autoconf macro which sets the WORDS_BIGENDIAN variable. The result was that this code compiled perfectly and ran perfectly on little endian machines. On big endian machines, it compiled perfectly and under certain circumstances failed badly causing really horrible noises to come out of my headphones.

Now consider my version where WORDS_BIGENDIAN gets set to either 0 or 1. In this case, if the author forgot to invoke the autoconf macro, WORDS_BIGENDIAN would have been undefined and this code:


    #if  (WORDS_BIGENDIAN == 0)
         /* Some little endian machine specific code. */
    #endif

would have failed to compile on both big and little endian machines.

It also doesn't take a genius to see that this is a symptom of a larger and much more common problem. In fact my solution is a classic example of moving something up Rusty's spectrum of interface simplicity. The original code was at position 11 on the scale (follow common convention and you'll get it wrong) and my alternative is at position 1 on the scale (compiler/linker won't let you get it wrong).

Posted at: 20:27 | Category: CodeHacking | Permalink