C API – Library Design: Common Header File vs Multiple Headers

apic

There are essentially two camps of library designers concerning the design of the final header file inclusion:

  • Provide a single header file that includes every other header file that makes up the public API. For example, GTK+ dictates that only gtk.h shall be included. This does not mean that everything is explicitly written into that common header file.
  • Have the user include the header file whose functionality he is most interested in. The most prominent example would be the standard library where he has to include stdio.h for I/O, string.h for string manipulation etc., instead of a common std.h

Is there a preferred way? libabc gives no advice on that matter, whereas an answer to a similar question suggests to keep them separated but does not specifies why.

Best Answer

Design in general is always "the art to balance contradicting goals".

Here, you have these goals:

  1. The framework should be simple to use. If your API is 15 header files, then users will always struggle which ones to include and which ones to omit.
  2. All common functionality should be in a single header file. So file I/O shouldn't be in string.h but you also don't want 3 string.h header files.
  3. Dependencies are bad, so you want to reduce them to the smallest amount possible
  4. Reading huge (amounts of) header files is slow
  5. Each feature in your header file will raise the risk that you need to include another header file to make it compile.

gtk.h makes sense since you want to build a user interface for your application (point #2). You could argue that people should include each widget individually but then, your framework will become slightly harder to use (point #1).

If you look at old X11/Motif code, you will see dozens of #include statements at the top of each C source file. It compiles a little bit faster but it takes hours of manual work to maintain these lists.

OTOH, if you put too many features in your header files, you will have too many dependencies in there and one of them might kill you (for example, when this dependency requires another framework with a certain version -> dependency hell).

I hope you understand by now that there is no solution; the problem is too complex and needs to be addressed again every time a new framework is started.

EDIT

But then there must be a pretty good reason that GTK+ actively prevents including single headers via macro checks. – matthias

For GTK, the #include statements are part of the public API. With these macros, they are free to rearrange the header files, their content, names and include order, in any way they like at any time without breaking a single existing project.

Related Topic