Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

This repo contains libbce and bce. Both of these are independent programs for embedding binary files directly into C programs.

libbce

libbce (LIB Binary C Embed) is a single-header library for generating C headers/sources with embedded constants/variables. It's intended for performing compile-time computations and then saving them in headers/sources. An example of this may be decoding images and then embedding them into a program.

To use libbce, create a source file with the following contents:

#defineLIBBCE_IMPL#include"libbce.h"

To generate a simple 3-variable file with libbce, you can just do:

#include"libbce.h"#defineARRAY_LENGTH(arr) (sizeof(arr)/sizeof((arr)[0]))
intmain(void) {
// variables to writeconstchar*hello_world="hello world!";
constunsigned charnums[] = {8, 64, 11, 92, 129, 2, 2, 55};
constintnumber=69;
bce_file*file=bce_create("output.c");
bce_printf(file, "const char *hello_world=");
bce_print_string(file, hello_world, strlen(hello_world));
bce_printf(file, ";\n");
bce_printf(file, "const char *nums=");
bce_print_string(file, (constchar*) &nums[0], ARRAY_LENGTH(nums));
bce_printf(file, ";\n");
bce_printf(file, "const int number=%d;\n", number);
bce_close(file);
}

This will output the following to output_file.c:

constchar*hello_world="hello world!";
constunsigned charnums[]="\b@\v\\\201\2\0027";
constintnumber=69;

This example does not do any error handling, but most falliable libbce functions will return false and set errno upon error.

Additionally, If all of the file-writing logic is put into a bool-returning function, the bce_printfh macro can be used which will automatically pass on any errors returned by bce_printf.

bce

bce (Binary C Embed) is a simple program for converting a file to a C byte array. This can be used with build systems like Meson or Make to embed binary files directly into a C program. bce is meant to be a lightweight replacement for vim's xxd -i command, but bce's output is simpler.

Installing

bce was designed so that its bce.c file can be symlinked or copied directly into your project. This way, your project can architecture-independently ship bce around with it and not require it as an external dependency. To do this with Meson, see the Using with Meson section.

bce can also be compiled and used as a standalone application. Since bce has only one file and no dependencies, it can be directly compiled with:

gcc bce.c -o bce

For easier development, some Nix, Meson, and Bash files have been provided. To compile using these (assuming you have Nix installed), you can do

nix-shell --pure
source envsetup.sh
b

Usage

bce <input_file> <output_file>

To read from stdin or output to stdout, - can be used as an input or output file name.

bce does not have any flags due to its simplified output.

Differences from xxd -i

bce has different output compared to xxd -i. Say the user runs bce foo.bin foo.h. If foo.bin contains two null bytes, the generated foo.h will contain:

{0,0,};

Unlike xxd -i, the user must create a variable to store the data themselves, and they must find the length of the data themselves.

This can be done with the following C code:

constcharFOO[] =#include"foo.h"constsize_tFOO_LEN=sizeof(FOO) / sizeof(FOO[0]);

Using with Meson

The following examples assume that the bce.c file has been copied into the same directory as your project's build.meson file.

Simple example

build.meson:

bce_prog =executable('bce', 'bce.c')
bce =generator(bce_prog,
output : '@BASENAME@.h',
arguments : ['@INPUT@', '@OUTPUT@'])
embedded_files = [
'foo_icon.png',
'bar_icon.png'
]
project_source_files = [
# Omitted... #
]
embed_headers = bce.process(embedded_files)
exe =executable('my_project', project_source_files + embed_headers,
install : false)

C code:

constunsigned charFOO_ICON[] =#include"foo_icon.h"constunsignedcharBAR_ICON[] =#include"bar_icon.h"

Real use case: compiling and embedding GLSL shaders

When writing C applications with Vulkan, you will need SPIR-V shaders. With the following code, Meson will automatically recompile your shaders into SPIR-V and embed them into your project whenever their source code is updated.

build.meson:

glslc_prog =find_program('glslc')
bce_prog =executable('bce', 'bce.c')
glslc =generator(glslc_prog,
output : '@BASENAME@.spv',
arguments : ['@INPUT@', '-o', '@OUTPUT@'])
bce =generator(bce_prog,
output : '@BASENAME@.h',
arguments : ['@INPUT@', '@OUTPUT@'])
shader_source_files = [
'src/vertex_shader.vert',
'src/fragment_shader.frag'
]
project_source_files = [
# Omitted... #
]
compiled_shaders = glslc.process(shader_source_files)
shader_headers = bce.process(compiled_shaders)
exe =executable('my_vulkan_project', project_source_files + shader_headers,
install : false, dependencies : [vulkan, glfw3])

C code:

// Vulkan requires that shaders are 32-bit aligned //
__attribute__( ( aligned ( 4 ) ) )
constunsigned charVERTEX_SHADER[] =#include"vertex_shader.h"
__attribute__( ( aligned ( 4 ) ) )
constunsigned charFRAGMENT_SHADER[] =#include"fragment_shader.h"

About

bce (Binary C Embed) is a lightweight alternative to vim's xxd -i command

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages