I would like to introduce my single header libraries. For now there is only one, but I have some others on the shelf I will eventually clean up and post.
These are my single header libraries, which is a way of bundling code popularized by STB.
All of my libraries are licensed under the MIT license.
DataBundle.h
This library creates object files from arbitrary files, which then can be linked into any program and referenced at runtime. This is useful to e.g. embed fonts or other files in your executable, making it easier to distribute and more convenient for the user (no installation or zip extraction necessary).
It supports both PE/COFF (Windows MSVC) and ELF (Linux).
It can be used either as a standalone executable or as a pair of functions embedded in your build system.
Building standalone
On Linux with e.g. GCC:
cp DataBundle.h DataBundle.c && gcc -DDATABUNDLE_STANDALONE DataBundle.c -o data-bundle
./data-bundle
We rename the file because the compiler will get confused trying to just
compile a .h
rather than a .c
.
On Windows with MSVC (install Visual Studio and then run in a "x64 Native Tools Command Prompt", which you can find from the Start menu):
copy /Y DataBundle.h DataBundle.c && cl -DDATABUNDLE_STANDALONE DataBundle.c -link -out:DataBundle.exe
DataBundle.exe
Using as a library
In exactly one source file in your project, do the following:
#define db_memcpy memcpy #define db_memset memset // Or use your custom ones; these will be forward declared with the following signatures: // void* db_memcpy(void* destination, const void* source, size_t size); // void* db_memset(void* s, int c, size_t n); #define DATABUNDLE_IMPLEMENTATION #include "DataBundle.h"
The two functions writeElfDataObject
and writeCoffDataObject
call a
writeBytes
callback with the constructed object. It is your job to
provide this callback to e.g. write out a file. It is done this way to
make DataBundle.h have literally zero dependencies. See the "Standalone
executable implementation" section in DataBundle.h
for example usage.
Explanation
No one should ever be generating C source code which is just long arrays of data to do this, unless they are e.g. making an embedded font for a single header lib and don't want the library user to have to worry about it. This library does things the right way: using object files to hold data, and then letting the linker put the data in the executable where we want it. No compiler ever needs to traverse your data.
I previously wrote a post on how to embed data with Resource Compiler on Windows, but it has various drawbacks like requiring Resource Compiler, writing an RC script, and needing to call a runtime function to set up the resource variables.
This header makes the interfaces 100% compatible. In fact, one can generate object files for Windows or Linux on either Windows or Linux, which makes it easy to e.g. use tcc on Windows, which likes consuming ELF objects even when building Windows executables.