Easy-to-use CMake utility to generate C/C++ code containing binary data from files. Useful when you want to avoid shipping extra files, but you want to still have them separately during development.
- Generates C/C++ source files with arrays containing binary data
- Single CMake file with no dependencies except CMake >=3.17.5. Copy the file to your project and start using it!
- Generated source files are updated at build-time whenever the original assets get modified (CMake's
add_custom_command
is used) - Platform-independent, since all of the implementation is written in CMake
- Can optionally generate a
constexpr
array for compile-time manipulation in C++
embed_binaries(<generated-target-name>
[ASSET
NAME <name>
PATH <path>
[BYTE_TYPE <c-cpp-type>]
[CONSTEXPR]
[NULL_TERMINATE]
]...)
NAME
: name of the asset (the name of the generated file and variable)PATH
: path to the asset file (absolute of relative toCMAKE_CURRENT_SOURCE_DIR
)BYTE_TYPE
: type of the elements of the generated array. Defaults to:"unsigned char"
. Useful when embedding ascii string data (useBYTE_TYPE "char"
)CONSTEXPR
: by default, anextern const
array will be declared in the header, with the contents in a corresponding .c file, which makes the header as short as possible, improving compile time, especially when embedding larger assets. If you specify this option, aconstexpr
array will be generated instead (which must go in the header)NULL_TERMINATE
: append a null-terminator (0
byte) at the end of the embedded data. Useful when embedding string data that will be used with APIs expecting null-terminated strings
Having the implementation written in CMake makes this utility easy-to-use and portable, but that also makes it rather slow. This is not really noticeable for small assets (<1MB), but you will notice it as you have more and more data. During my tests, generating the code for an ~8MB big file took ~17 seconds in my machine (and generated a ~40MB big .c file!). Therefore, this utility is intended for projects where ease of use is important (e.g. personal projects) or for projects that will only have a few assets to embed. If you have different plans, I would suggest investing some time on a different solution
NOTE: see the example/
directory for a full example project
include("path/to/embed-binaries.cmake")
embed_binaries(my-embedded-binaries
ASSET
NAME "application_logo"
PATH "assets/application_logo.png"
ASSET
NAME "vertex_shader"
PATH "shaders/dummy_shader.vert"
BYTE_TYPE "char"
CONSTEXPR # The data will be placed in the header
# OpenGL does not require null-terminated strings for shaders, this is not a good example
NULL_TERMINATE
# ASSET ...
)
add_executable(my-executable
# files...
)
target_link_libraries(my-executable PRIVATE my-embedded-binaries)
With CONSTEXPR
and DATA_TYPE "char"
:
fragment_shader.h
#pragma once
#ifndef __cplusplus
#error "'constexpr' is a C++ feature"
#endif
constexpr char embedded_fragment_shader[226] = {
0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0d,0x0a,0x0d,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x5f,
0x63,0x6f,0x6f,0x72,0x64,0x69,0x6e,0x61,0x74,0x65,0x73,0x3b,0x0d,0x0a,0x0d,0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x6d,0x6f,0x64,
0x75,0x6c,0x61,0x74,0x69,0x6f,0x6e,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0d,0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,
0x44,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x3b,0x0d,0x0a,0x0d,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,
0x72,0x3b,0x0d,0x0a,0x0d,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0d,0x0a,0x7b,0x0d,0x0a,0x09,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,
0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x5f,0x63,0x6f,0x6f,
0x72,0x64,0x69,0x6e,0x61,0x74,0x65,0x73,0x29,0x20,0x2a,0x20,0x6d,0x6f,0x64,0x75,0x6c,0x61,0x74,0x69,0x6f,0x6e,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0d,0x0a,0x7d,
0x0d,0x0a,
};
Normal mode:
application_logo.h
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
extern const unsigned char embedded_application_logo[212253];
#ifdef __cplusplus
}
#endif
application_logo.c
#include "application_logo.h"
#ifdef __cplusplus
extern "C" {
#endif
const unsigned char embedded_application_logo[212253] = {
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,0x00,0x00,0x02,0x64,0x00,0x00,0x01,0x99,0x08,0x02,0x00,0x00,0x00,0xa8,0x97,0xba,
/* 6632 more lines... */
};
#ifdef __cplusplus
}
#endif