Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of HAVE_* macros?

I am reusing some C/C++ source files part of an autotools project within a CMake project and I see many source files littered with lines like:

#ifdef HAVE_UNISTD_H
#include <unistd.h>  // for getpid()
#endif

I would understand the purpose of this construct if getpid() was optional and its call was surrounded by equivalent HAVE_UNISTD_H directives. However, without HAVE_UNISTD_H the source file does not compile, complaining that getpid() is not defined. This feels a lot more cryptic than the compiler letting me know that unistd.h was not found.

Of course, this is only an example. Other popular macros include HAVE_STDINT_H, HAVE_INTTYPES_H, etc. whose presence is mandatory to compile the source file.

Why are HAVE_* guards included at all? I feel they only bring disadvantages:

  • Reusing such source files requires making sure the right header files are present and the right HAVE_* macros are defined.
  • In case of a mistake, the developer gets a more cryptic message, i.e., the compiler does not report the root cause (header not found) but an ancillary error (type/function not found).
  • The source files are a bit longer and a bit more tedious to read, i.e., #includes mixed with #ifdefs.
like image 886
user1202136 Avatar asked Dec 10 '22 10:12

user1202136


1 Answers

Most of the HAVE_xxx_h guards are remnants from an era before POSIX came along and standardized the header files. In early 90s you could easily come across a system that did have getpid(), but without a working unistd.h - the function would simply be declared in another header file, or it wouldn't be declared at all, but it would still work (as long as its return value was int-sized) due to declarations being optional in K&R and C89 C.

There were even stranger issues between the multitude of systems in use at the time. For example there were systems that shipped time.h, those that shipped sys/time.h, and those that shipped both - except that among the last category there was a subset where attempting to actually include both would result in a compilation error! Supporting a vast array of such systems, where possible without listing them all in advance, was one of the explicit design goals of Autoconf, and some of the long-irrelevant hacks are still carefully documented.

In addition to the above concerns, decoupling the header names from support for functions can come in useful when porting the code to non-POSIX systems such as windows. On such systems the posix headers might be missing or broken, and the actual function definition comes from a portability library such as gnulib.

like image 66
user4815162342 Avatar answered Dec 19 '22 22:12

user4815162342