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 commonstd.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.
6
Design in general is always “the art to balance contradicting goals”.
Here, you have these goals:
- 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.
- 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 3string.h
header files. - Dependencies are bad, so you want to reduce them to the smallest amount possible
- Reading huge (amounts of) header files is slow
- 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.
Having all headers in one single is great and better, it’s easier for others to include one single header than including different headers.
One issue of this sort of design, in big headers such as windows.h
, gtk.h
still small comparing to window.h
, the building process can get slow. In windows.h
we get around this issue by defining WIN32_LEAN_AND_MEAN
to exclude some uncommon headers such as windows sockets and cryptography API to speed up building process, read more here Using the Windows Headers.
Also by the time when your library grow, there are many headers and it can be hard to work with it, you will have to make a lot of macros, lots, and endup with complex header to not break backward compatibility.
Even though, I personally prefer single header design.