64

Assumptions

  1. One of the advantages of header-only libraries for C++ is that they do not need to be compiled separately.

  2. In C and C++ inline makes sense only if the function is defined in a header file*.

  3. Traditionally, in C, .c/.h layout has been used, where the header represents the minimal public interface of the translation unit. Similarly, .cpp/hpp.

Question

Are header-only libraries generally more efficient code- and execution time wise than the traditional layout? If so, is this because of extensive inlining or other optimizations?

* - defining the function in a header allows the compiler to see the implementation during compilation of any translation unit and practically makes inlining code possible

3
  • 3
    You'd be surprised how well a lot of modern C++ linkers (GCC, MSVC, ICC, etc) can inline code across separate translation units. I would say "generally no" on the efficiency perspective given the number of times optimizing linkers defied my expectations and managed to inline anyway (that's excluding dylib contexts where inlining in a header or providing the implementation in a separate statically-linked library can help). Yet header-only libraries, provided that they are stable in both interface and implementation, can be sexy because of how easily they can be deployed in new projects.
    – user204677
    Commented Dec 22, 2015 at 18:19
  • 1
    I don't know that this deserves a full answer, but one huge benefit of header only libs is the ease of installation and usage: Download, #include "lib.h(pp)", done.
    – WeRelic
    Commented Feb 10, 2016 at 5:27
  • 1
    Related: stackoverflow.com/questions/2174657/… Commented May 13, 2020 at 17:06

3 Answers 3

56

One of the advantages of header-only libraries for C++ is that they do not need to be compiled separately

No, that is not an advantage, quite the opposite - the main part of the library has to be compiled as often as it gets included, not just once. That will typically increase compile times. However, if you are referring to the advantages listed here in Wikipedia: that article is talking about decreased administrative overhead concerning the whole build, packaging and deployment process.

In C and C++ inline makes sense only if the function is defined in a header file*

This depends on the compiler/linker system, but I guess for most existing C and C++ compilers this is true.

Traditionally, in C, .c/.h layout has been used, where the header represents the minimal public interface of the translation unit. Similarly, .cpp/hpp.

That is mostly correct. C++ class headers often contain more than the minimal public interface - they typically contain also a lot of private stuff. To mitigate this, things like the PIMPL idiom are used. This is something like "the opposite" of a header-only library, it tries to minimize the necessary header content.

But to answer your main question: this is a trade-off. The more library code one puts into the header files, the more the compiler has a chance for optimizing the code for speed (if this really happens, or if the increasement is noteable, is a completely different question). On the other hand, too much code in headers increases the compile time. Especially in large C++ projects this can become a serious problem, see "Large Scale C++ Software Design" by John Lakos - though the book is a little bit outdated and some of the problems described in there are addressed by modern compilers, the general ideas/solutions are still valid.

In particular, when you are not using a stable (third party) library, but you are developing your own libs during your project, the compile times become apparent. Everytime you change something in the lib, you must change a header file, which will cause a recompile and linkage of all dependent units.

IMHO the popularity of header-only libs is caused by the popularity of template meta programming. For most compilers, templated libs must be header-only because the compiler can only start the main compile process when the type parameters are provided, and for full compilation and optimization the compiler must see "both at once" - the library code plus the template parameter values. That makes it impossible (or at least hard) to produce any "precompiled" compilation units for such a library.

11
  • 10
    So in short, header-only libraries are more convenient rather than more efficient; and since C++ does not have any standard package manager, this helps driving adoption. Commented Dec 22, 2015 at 13:38
  • 8
    @MatthieuM: no, the compiled code may indeed sometimes be more efficient, and for template libs the header-only design is typically not a question of convenience. And increased compiled times are definitely not more convenient.
    – Doc Brown
    Commented Dec 22, 2015 at 13:49
  • 2
    It is convenient that you don't have to worry what compile flags were used for the library.
    – Vorac
    Commented Dec 23, 2015 at 7:41
  • 2
    @Vorac: don't play with words. Surely there are things that are more convenient in header-only libraries. Other's things are clearly less convenient (like compile times or that one must open-source such a library in full). But Matthieu's comment was saying "header-only libs are more convenient" (in general!) than other libs, and his statement about efficiency is wrong in this generality, too. That's what the comments above are about.
    – Doc Brown
    Commented Dec 23, 2015 at 8:26
  • 3
    I worked on a large embedded project on top of a slimmed-down, older OS for my previous employer, and in those cases I can attest to the pain of long compile times. Anyone caught stuffing too much into header files would be dealt with mercilessly. Commented Dec 28, 2015 at 2:20
17

Well, let's first demolish some of your assumptions:

  1. One of the advantages of header-only libraries for C++ is that they do not need to be compiled separately.

Compiling things separately means potentially not having to recompile everything if only a part changes.
So, a disadvantage instead of an advantage.

  1. In C and C++ inline makes sense only if the function is defined in a header file*.

Yes, the only effect inline has left is the exception to the one-definition-rule.
Woe unto you if those definitions are different in any way though.

So, if a function is internal to a compilation-unit, mark it static. That also makes inlining more likely, as the function needs to be available in order to inline it.
Still, take a look at link-time-optimization, as supported by at least MSVC++, gcc and clang.

  1. Traditionally, in C, .c/.h layout has been used, where the header represents the minimal public interface of the translation unit. Similarly, .cpp/hpp.

Well, only presenting the minimal interface is certainly one of the goals, to achieve higher API and ABI stability, and to minimize compilation times.

Especially C++ classes aren't really geared to that though, as all the private bits leak into the header, as do the protected ones whether you want to derive from it or not.

The design-pattern PIMPL is for reducing such details.

The part where separating interface and implementation completely fails in C++ is templates though.
The committee tried to do something with exported templates, but that has been abandoned as too complicated and not really working.

Now, they are working on a proper module system, though it's slow going. That severely reduce compile-times, and should also increase API and ABI stability by decreasing their surface.

Are header-only libraries generally more efficient code- and execution time wise than the traditional layout? If so, is this because of extensive inlining or other optimizations?

Header-only libraries can be more efficient in code-size and execution-time, though that depends on whether the library is shared, how much of it is used, in what ways, and whether inlining proves a decisive win in that specific case.

And the reason inlining is so important for optimization isn't because inlining itself is such a great boost, but due to the opportunities for constant-propagation and further optimization it opens.

0

Inlining can be done by Link Time Optimization (LTO)

I'd like to highlight this since it decreases the value of this commonly cited advantage of header only libraries ("you need definitions on a header to inline").

A minimal concrete example of this is shown at: https://stackoverflow.com/questions/7046547/link-time-optimization-and-inline/61367211#61367211

So you just pass a flag, and inlining can be done across object files without any refactoring work, no need to keep definitions in headers for that anymore.

LTO might have its own downsides too however: https://stackoverflow.com/questions/23736507/is-there-a-reason-why-not-to-use-link-time-optimization-lto

Not the answer you're looking for? Browse other questions tagged or ask your own question.