Autoconf, Automake, and Libtool: Error Management

| #### 9.2.1.1 Error Management A good place to start with any project design is the error management facility. In Sic I will use a simple group of functions to display simple error messages. Here is ``sic/error.h'`:
    #ifndef SIC_ERROR_H
    #define SIC_ERROR_H 1

    #include <sic/common.h>

    BEGIN_C_DECLS

    extern const char *program_name;
    extern void set_program_name (const char *argv0);

    extern void sic_warning      (const char *message);
    extern void sic_error        (const char *message);
    extern void sic_fatal        (const char *message);

    END_C_DECLS

    #endif /* !SIC_ERROR_H */
This header file follows the principles set out in 9.1.2 C Header Files. I am storing the `program_name` variable in the library that uses it, so that I can be sure that the library will build on architectures that don't allow undefined symbols in libraries(12). Keeping those preprocessor macro definitions designed to aid code portability together (in a single file), is a good way to maintain the readability of the rest of the code. For this project I will put that code in ``common.h'`:
    #ifndef SIC_COMMON_H
    #define SIC_COMMON_H 1

    #if HAVE_CONFIG_H
    #  include <config.h>
    #endif

    #include <stdio.h>
    #include <sys/types.h>

    #if STDC_HEADERS
    #  include <stdlib.h>
    #  include <string.h>
    #elif HAVE_STRINGS_H
    #  include <strings.h>
    #endif /*STDC_HEADERS*/

    #if HAVE_UNISTD_H
    #  include <unistd.h>
    #endif

    #if HAVE_ERRNO_H
    #  include <errno.h>
    #endif /*HAVE_ERRNO_H*/
    #ifndef errno
    /* Some systems #define this! */
    extern int errno;
    #endif

    #endif /* !SIC_COMMON_H */
You may recognise some snippets of code from the Autoconf manual here--- in particular the inclusion of the project ``config.h'`, which will be generated shortly. Notice that I have been careful to conditionally include any headers which are not guaranteed to exist on every architecture. The rule of thumb here is that only ``stdio.h'` is ubiquitous (though I have never heard of a machine that has no ``sys/types.h'`). You can find more details of some of these in section `Existing Tests' in The GNU Autoconf Manual. Here is a little more code from ``common.h'`:
    #ifndef EXIT_SUCCESS
    #  define EXIT_SUCCESS  0
    #  define EXIT_FAILURE  1
    #endif
The implementation of the error handling functions goes in ``error.c'` and is very straightforward:
    #if HAVE_CONFIG_H
    #  include <config.h>
    #endif

    #include "common.h"
    #include "error.h"

    static void error (int exit_status, const char *mode,
                       const char *message);

    static void
    error (int exit_status, const char *mode, const char *message)
    {
      fprintf (stderr, "%s: %s: %s.\n", program_name, mode, message);

      if (exit_status >= 0)
        exit (exit_status);
    }

    void
    sic_warning (const char *message)
    {
      error (-1, "warning", message);
    }

    void
    sic_error (const char *message)
    {
      error (-1, "ERROR", message);
    }

    void
    sic_fatal (const char *message)
    {
      error (EXIT_FAILURE, "FATAL", message);
    }
I also need a definition of `program_name`; `set_program_name` copies the filename component of `path` into the exported data, `program_name`. The `xstrdup` function just calls `strdup`, but `abort`s if there is not enough memory to make the copy:
    const char *program_name = NULL;

    void
    set_program_name (const char *path)
    {
      if (!program_name)
        program_name = xstrdup (basename (path));
    }

This document was generated by Gary V. Vaughan on February, 8 2006 using texi2html