NHollmann

English | German

Hi, I'm Nicolas Hollmann and this is my personal site and blog.
Happy reading! 📖

Single Header Libraries

August 14, 20196 min read
Tags:

This article is targeted towards beginners. It should clarify what a single header library (SHL) is and how you could create our own. When I use or create single header libraries in later articles I can just link to this article for clarification.

This article is about a concept in C and C++, the most other languages don’t even have header files so you can’t create a single header library.

To understand what a single header library (SHL) is, first we look at the single parts of this name one by one. We start with the last one, because it has the most meaning.

Library

Almost every langauge have some sort of libraries. In general one could say, a software library is a collection of functions and datatypes, that can’t normaly run directly. Instead it provides it’s features to other software (programs and other libraries). This allows you to use the same code in different projects easily. A user of a library only needs to know the public interface, not the internal workings. Examples for libraries are the C++ STL or libSDL.

If you ever used C or C++, you should know what a header file is. But for the sake of completeness:

In C/C++ a function must be deklared befor its name can be used in any way. This not only holds for functions in the same source file (conventionally .c or .cpp) but also applies to functions from different source files or external libraries. To declare them, it is enough to write down the function header with the parameters and return type:

// Declaration
int add(int, int);

int main()
{
    // Usage
    printf("%d", add(1, 2));
    return 0;
}

// Definition / Implementation
int add(int a, int b) {
    return a + b;
}

As you may have spotted, it is even enough to just write down the types of the parameters, their names are optional in the declaration. Still you normaly write them down too, so the function documents itself.

Declaring the function header for all functions you want to use, especially if they come from libraries, would be really cumbersome. For this reason C and C++ use so called header files (conventionally .h or .hpp). They include normaly no code to run (although that would be very possible), instead they include the function headers of alle functions that are part of the public interface of some software module. These header files can then be included in own source files by using #include.

Single

The “single” just means in this context that our complete library is contained in a single file so it can be easily embedded in different projects.

And now everything together!

Going by these parts of the name a SHL is nothing more than a software library which consist of a single header file. That’s it.

Why are single header libraries useful?

Libraries are part of the daily life of a developer. But often it can be cumbersome to embed them in new projects (at least in C and C++). First, you need to compile it for all your target platforms by yourself. The build processes may differ from library to library and often the setup and compilation takes a lot time and don’t even work on the first try. Some libraries even need other dependencies to work properly. In general, many C and C++ libraries have a somewhat difficult setup which may need to be done more than once for each platform.

SHLs have a solution for that: They consist of a single file that can be copied easily in any project. There is no big setup, they just use the build process of your own project to compile themselves. They can also be included in the version control system so they are available for everyone trying to build your project.

This a big plus for open source projects which will be used by many people around the world.

In which situation are they not useful?

But even SHLs have their limits. One big problem is that you need to recompile the whole library for every computer in every project. This takes time. Classic static or dynamic libraries can be compiled once for each target platform and then the build products (.lib, .so, .dll, .dylib, etc.) can be copied between computers.

In my opinion, the scope of a library is the strongest criteria to decide if a SHL or a classic library should be the way to go. Where the limit is, however, must be determined individually for each project.

How do you include/use a SHL?

The exact usage naturally differs from SHL to SHL but there are some similar patterns.

You decide on a source file in your project which is going to include the implementation of the whole SHL and there you define a preprocessor constant before including the SHL. If other source files in your project want to use the library they just need to include it without defining the constant.

Let’s look at an example: The SHL ”stb_image” allows to read many image formats in a C/C++ program.

First we need to implement the library in a C/C++ source file:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

In this file the stb_img.h header will expand all the implementations of the reading functions. Every other source file, which also want to read images can just include this header again but without setting STB_IMAGE_IMPLEMENTATION:

#include "stb_image.h"

Often you will observe that the file which includes the implementation will take a lot longer in the compilation step. This is logical because even if we don’t see it, the SHL injects a lot of functionality in this file. For this reason you should use a build system like make which onle recompiles source files if their contents changed since the last compilation. Additionally you should choose a source file for the implementaiton that doesn’t change that often, maybe even a special file just for this SHL.

How do you create your own SHL?

First, we need some code which can be used usefully in different projects. For this article, we expect that we already have something like that.

After that you must decide if your library should work with C and C++ or just for one of these languages. If you use C++ only features like classes your library definitely won’t work with C code. A library written in C can be used in C++, but it often feels not nativ. The usage of such a library just don’t feel “C++ly”. With the help of the preprocessor it is possible to write a SHL wich works behves for C and C++ like anyone would expect but this may increases the effort a lot.

Beside that, writing a SHL is really easy thanks to the preprocessor. Let’s look at a example with a useless fictional math library:

#ifndef MINI_MATH_H
#define MINI_MATH_H

/* Public Interface */

int add(int a, int b);
int sub(int a, int b);

#ifdef MINI_MATH_IMPLEMENTATION_H

/* Implementation */

int add(int a, int b)
{
    return a + b;
}

int sub(int a, int b)
{
    return a - b;
}

#endif /* MINI_MATH_IMPLEMENTATION_H */

#endif /* MINI_MATH_H */

Thats all to create your very own SHL. It’s important that only on .c/.cpp file defines MINI_MATH_IMPLEMENTATION_H, otherwise you get linker conflicts when building your project.

If you want to use utility functions in the implementation that should not be part of the public interface place them in the MINI_MATH_IMPLEMENTATION_H part. THis also holds for external headers which are not needed for the interface.

There are some different approaches in the development of a SHL. For example you could use a program that bundles many files into a single header file. This allows you to split your library code in meaningful submodules without loosing the comfort of a SHL after the bundling.

This is the end of this first small article.



© 2022, Nicolas Hollmann