X-Ray Jam. June 9-15, 2025. See the results.

Single header library: Data Bundle

Macoy Madson

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.

Does this work for compiling to wasm, e.g. with Emscripten?

2025-06-17 16:53:15

It does not, though it looks like Emscripten has built-in file embedding. It probably makes sense to use that instead, but there isn't anything stopping you from adding support for outputting WASM objects.

It seems we need a login and password to see the files ?

EDIT: I didn't see the error page contains a public login.

EDIT2: The public login doesn't work, it times out.

That makes sense. I'm not using the Emscripten filesystem api as that requires loading that part of Emscripten at run time. Since that might be troublesome when using non-browser wasm runtimes, I'm only relying on the bare minimum api functions, e.g. malloc/free, add/remove js function. I'll look into forming wasm objects programmatically.

2025-06-17 19:48:29

Btw instead of this:

copy /Y DataBundle.h DataBundle.c && cl -DDATABUNDLE_STANDALONE DataBundle.c -link -out:DataBundle.exe

you can simply do:

cl -TC -DDATABUNDLE_STANDALONE DataBundle.h -link -out:DataBundle.exe

I also cannot login to see the source. Connection just times out for me. Am I an AI?

Sorry guys, the username is human and the password is noai. You can also clone the repo directly:

git clone https://macoy.me/code/macoy/single-header-libs.git

Sorry for the login inconvenience, but I'm just not okay with all the AI scraping nowadays.