C/C++ with GCC: Statically add resource files to executable/library
With imagemagick:
convert file.png data.h
Gives something like:
/*
data.h (PNM).
*/
static unsigned char
MagickImage[] =
{
0x50, 0x36, 0x0A, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4D, 0x50, 0x0A, 0x32, 0x37,
0x37, 0x20, 0x31, 0x36, 0x32, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
....
For compatibility with other code you can then use either fmemopen
to get a "regular" FILE *
object, or alternatively std::stringstream
to make an iostream
. std::stringstream
is not great for this though and you can of course just use a pointer anywhere you can use an iterator.
If you're using this with automake don't forget to set BUILT_SOURCES appropriately.
The nice thing about doing it this way is:
- You get text out, so it can be in version control and patches sensibly
- It is portable and well defined on every platform
You can embed binary files in executable using ld
linker.
For example, if you have file foo.bar
then you can embed it in executable adding the following commands to ld
--format=binary foo.bar --format=default
If you are invoking ld
thru gcc
then you will need to add -Wl
-Wl,--format=binary -Wl,foo.bar -Wl,--format=default
Here --format=binary
tells the linker that the following file is binary and --format=default
switches back to default input format (this is usefull if you will specify other input files after foo.bar
).
Then you can access content of your file from code:
extern uint8_t data[] asm("_binary_foo_bar_start");
extern uint8_t data_end[] asm("_binary_foo_bar_end");
There is also symbol named "_binary_foo_bar_size"
. I think it is of type uintptr_t
but i didn't check it.
Update I have grown to prefer the control John Ripley's assembly .incbin
based solution offers and now use a variant on that.
I have used objcopy (GNU binutils) to link the binary data from a file foo-data.bin into the data section of the executable:
objcopy -B i386 -I binary -O elf32-i386 foo-data.bin foo-data.o
This gives you a foo-data.o
object file which you can link into your executable. The C interface looks something like
/** created from binary via objcopy */
extern uint8_t foo_data[] asm("_binary_foo_data_bin_start");
extern uint8_t foo_data_size[] asm("_binary_foo_data_bin_size");
extern uint8_t foo_data_end[] asm("_binary_foo_data_bin_end");
so you can do stuff like
for (uint8_t *byte=foo_data; byte<foo_data_end; ++byte) {
transmit_single_byte(*byte);
}
or
size_t foo_size = (size_t)((void *)foo_data_size);
void *foo_copy = malloc(foo_size);
assert(foo_copy);
memcpy(foo_copy, foo_data, foo_size);
If your target architecture has special constraints as to where constant and variable data is stored, or you want to store that data in the .text
segment to make it fit into the same memory type as your program code, you can play with the objcopy
parameters some more.