1

I am looking for a way to reduce compile-time for header-only libraries. If there are only headers, each translation unit must compile all functions it needs, hence there is a lot of duplicate work done in the compilation step. My idea is to move the compilation to a single translation unit, which creates a single object file the other translation units can link to. This allows the header-only library to effectively behave like a static library which is compiled along with the actual productive code.

A typical header of the library looks like this. It includes all the declarations (all inline of course), while the definitions are hidden behind the macro MYUTILS_INLINE.

// MyUtils1.hpp, example utility header
#ifndef MyUtils1_h__
#define MyUtils1_h__

class MyClass1{...};
inline int myfunction1(void);

#ifdef MYUTILS_INLINE
#include MyUtils1.cpp
#endif // MYUTILS_INLINE
#endif // MyUtils1_h__

MyUtils1.cpp can include additional headers required for the implementation and contains the definitions.

// MyUtils1.cpp, example implementation file
#include MyUtils1.hpp
#include "additionalheader.hpp"

MyClass1::MyClass1(void) {...}
inline int myfunction1(void){...}

In my code, the headers of the library can be included normally. There is one additional file MyUtils.cpp or MyUtils.inl, which is the only file which sets MYUTILS_INLINE and hence sees the definitions and compiles them:

// MyUtils.cpp, separate translation unit in my project
// set macro to get the definitions and compile them.
#define MYUTILS_INLINE
// include all headers which are used throughout the project
#include "MyUtils1.hpp"
#include "MyUtils2.hpp"
#include "MyUtils3.hpp"

Advantages:

  • reduced compile-time due to no duplicate work
  • fewer header dependencies, headers needed for definitions can be hidden in MyUtils1.cpp
  • opt-in behavior: If user defines MYUTILS_INLINE globally, he does not need MyUtils.cpp and all works as before

Disadvantages:

  • less optimization potential because functions are no longer inline
  • ship twice as many files (one implementation file for each header)

Now before I restructure my entire library, I want to ask for thoughts about this:

  • Did I just reinvent something?
  • Do I miss some important points? Advantages or disadvantages?
  • Is there a similar or better way?

I noticed that Catch actually does something similar with CATCH_CONFIG_MAIN.

EDIT

I have read some articles about precompiled headers and tried them in one of my projects. While they try to solve the same problem, they have other issues, especially regarding clean dependencies between header files. My suggested approach is considerably different, as each file still manages its own dependencies but has the option to pass work to the translation unit MyUtils.cpp.

Fabian
  • 4,001
  • 4
  • 28
  • 59
  • https://en.wikipedia.org/wiki/Precompiled_header – KamilCuk May 12 '22 at 07:33
  • 2
    What you are making is not a header only library. It is a regular library distributed as source code (unless the user defines MYUTILS_INLINE, in which case it becomes a header only library again). – n. m. could be an AI May 12 '22 at 07:38
  • As a compromise, you could keep small functions - that deserve to be inlined - in the header, and move larger functions to the .cpp file. Software development is hardly ever "single rule". – BoP May 12 '22 at 08:26
  • Precompiled header have several issues (https://qualitycoding.org/precompiled-header/). One big drawback is that they create a big pile of header dependencies which are shared across all project files. The dependencies easily get out of control. – Fabian May 12 '22 at 10:24
  • Are you aware of modules? C++20, so fairly recent. – MSalters May 12 '22 at 12:48
  • It seems to be an extension of https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Inline_Guard_Macro with MYPROJECT_INLINE_ENABLED only defined in one translation unit. – Fabian Nov 21 '22 at 06:03

0 Answers0