I'm looking for a way to easily embed any external binary data in a C/C++ application compiled by GCC.
我正在寻找一种在GCC编译的C/ c++应用程序中轻松嵌入任何外部二进制数据的方法。
A good example of what I'd like to do is handling shader code - I can just keep it in source files like const char* shader = "source here";
but that's extremely impractical.
我想做的一个很好的例子是处理着色代码——我可以把它保存在源文件中,比如const char* shader = "source here";但这是非常不切实际的。
I'd like the compiler to do it for me: upon compilation (linking stage), read file "foo.bar" and link its content to my program, so that I'd be able to access the contents as binary data from the code.
我希望编译器替我做:在编译(链接阶段)时,读取文件“foo”。并将其内容链接到我的程序中,这样我就可以从代码中以二进制数据的形式访问内容。
Could be useful for small applications which I'd like to distribute as a single .exe file.
对于我想作为一个.exe文件分发的小型应用程序来说可能很有用。
Does GCC support something like this?
GCC支持这样的东西吗?
4 个解决方案
#1
42
There are a couple possibilities:
有几个可能性:
-
use ld's capability to turn any file into an object (Embedding binary blobs using gcc mingw):
使用ld的功能将任何文件转换为对象(使用gcc mingw嵌入二进制blob):
ld -r -b binary -o binary.o foo.bar # then link in binary.o
-
use a
bin2c
/bin2h
utility to turn any file into an array of bytes (Embed image in code, without using resource section or external images)使用bin2c/bin2h实用工具将任何文件转换成字节数组(在代码中嵌入图像,不使用资源部分或外部图像)
Update: Here's a more complete example of how to use data bound into the executable using ld -r -b binary
:
更新:这里有一个更完整的示例,说明如何使用ld -r -b二进制文件将数据绑定到可执行文件中:
#include <stdio.h>
// a file named foo.bar with some example text is 'imported' into
// an object file using the following command:
//
// ld -r -b binary -o foo.bar.o foo.bar
//
// That creates an bject file named "foo.bar.o" with the following
// symbols:
//
// _binary_foo_bar_start
// _binary_foo_bar_end
// _binary_foo_bar_size
//
// Note that the symbols are addresses (so for example, to get the
// size value, you have to get the address of the _binary_foo_bar_size
// symbol).
//
// In my example, foo.bar is a simple text file, and this program will
// dump the contents of that file which has been linked in by specifying
// foo.bar.o as an object file input to the linker when the progrma is built
extern char _binary_foo_bar_start[];
extern char _binary_foo_bar_end[];
int main(void)
{
printf( "address of start: %p\n", &_binary_foo_bar_start);
printf( "address of end: %p\n", &_binary_foo_bar_end);
for (char* p = _binary_foo_bar_start; p != _binary_foo_bar_end; ++p) {
putchar( *p);
}
return 0;
}
Update 2 - Getting the resource size: I could not read the _binary_foo_bar_size correctly. At runtime, gdb shows me the right size of the text resource by using display (unsigned int)&_binary_foo_bar_size
. But assigning this to a variable gave always a wrong value. I could solve this issue the following way:
更新2 -获取资源大小:我无法正确读取_binary_foo_bar_size。在运行时,gdb通过使用display (unsigned int)和_binary_foo_bar_size向我显示文本资源的正确大小。但是给变量赋值总是错误的。我可以用以下方法来解决这个问题:
unsigned int iSize = (unsigned int)(&_binary_foo_bar_end - &_binary_foo_bar_start)
It is a workaround, but it works good and is not too ugly.
这是一种变通方法,但效果不错,也不太难看。
#2
16
As well as the suggestions already mentioned, under linux you can use the hex dump tool xxd, which has a feature to generate a C header file:
除了前面提到的建议之外,在linux下,您还可以使用十六进制转储工具xxd,它具有生成C头文件的特性:
xxd -i mybinary > myheader.h
#3
3
Not exactly a new way, but certainly very convenient. I stumbled upon this totally free licenced library based on the incbin assembler method not mentioned among the answers here.
不完全是一种新方法,但肯定非常方便。我偶然发现了这个完全免费的许可库,它基于incbin汇编器方法,这里的答案中没有提到。
https://github.com/graphitemaster/incbin
https://github.com/graphitemaster/incbin
To recap. The incbin method is like this. You have a thing.s assembly file that you compile with gcc -c thing.s
回顾一下。incbin方法是这样的。你有一个东西。用gcc -c东西编译的汇编文件
.section .rodata
.global thing
.type thing, @object
.align 4
thing:
.incbin "meh.bin"
thing_end:
.global thing_size
.type thing_size, @object
.align 4
thing_size:
.int thing_end - thing
In your c or cpp code you can reference it with:
在你的c或cpp代码中,你可以参考以下内容:
extern const char thing[];
extern const char* thing_end;
extern int thing_size;
So then you link the resulting .o with the rest of the compilation units. Credit where due is to @John Ripley with his answer here: C/C++ with GCC: Statically add resource files to executable/library
然后将结果的.o与编译单元的其余部分连接起来。归功于@John Ripley的回答:C/ c++和GCC:静态地向可执行/库添加资源文件
But the above is not as convenient as what incbin can give you. To accomplish the above with incbin you don't need to write any assembler. Just the following will do:
但是上面的内容并不像incbin提供的那样方便。要使用incbin实现上述目标,您不需要编写任何汇编程序。只要以下几点就可以了:
#include "incbin.h"
INCBIN(thing, "meh.bin");
int main(int argc, char* argv[])
{
// Now use thing
printf("thing=%p\n", gThingData);
printf("thing len=%d\n", gThingSize);
}
#4
1
You could do this in a header file :
你可以在头文件中这样做:
#ifndef SHADER_SRC_HPP
#define SHADER_SRC_HPP
const char* shader= "
//source
";
#endif
and just include that.
包括。
Other way is to read the shader file.
另一种方法是读取着色文件。
#1
42
There are a couple possibilities:
有几个可能性:
-
use ld's capability to turn any file into an object (Embedding binary blobs using gcc mingw):
使用ld的功能将任何文件转换为对象(使用gcc mingw嵌入二进制blob):
ld -r -b binary -o binary.o foo.bar # then link in binary.o
-
use a
bin2c
/bin2h
utility to turn any file into an array of bytes (Embed image in code, without using resource section or external images)使用bin2c/bin2h实用工具将任何文件转换成字节数组(在代码中嵌入图像,不使用资源部分或外部图像)
Update: Here's a more complete example of how to use data bound into the executable using ld -r -b binary
:
更新:这里有一个更完整的示例,说明如何使用ld -r -b二进制文件将数据绑定到可执行文件中:
#include <stdio.h>
// a file named foo.bar with some example text is 'imported' into
// an object file using the following command:
//
// ld -r -b binary -o foo.bar.o foo.bar
//
// That creates an bject file named "foo.bar.o" with the following
// symbols:
//
// _binary_foo_bar_start
// _binary_foo_bar_end
// _binary_foo_bar_size
//
// Note that the symbols are addresses (so for example, to get the
// size value, you have to get the address of the _binary_foo_bar_size
// symbol).
//
// In my example, foo.bar is a simple text file, and this program will
// dump the contents of that file which has been linked in by specifying
// foo.bar.o as an object file input to the linker when the progrma is built
extern char _binary_foo_bar_start[];
extern char _binary_foo_bar_end[];
int main(void)
{
printf( "address of start: %p\n", &_binary_foo_bar_start);
printf( "address of end: %p\n", &_binary_foo_bar_end);
for (char* p = _binary_foo_bar_start; p != _binary_foo_bar_end; ++p) {
putchar( *p);
}
return 0;
}
Update 2 - Getting the resource size: I could not read the _binary_foo_bar_size correctly. At runtime, gdb shows me the right size of the text resource by using display (unsigned int)&_binary_foo_bar_size
. But assigning this to a variable gave always a wrong value. I could solve this issue the following way:
更新2 -获取资源大小:我无法正确读取_binary_foo_bar_size。在运行时,gdb通过使用display (unsigned int)和_binary_foo_bar_size向我显示文本资源的正确大小。但是给变量赋值总是错误的。我可以用以下方法来解决这个问题:
unsigned int iSize = (unsigned int)(&_binary_foo_bar_end - &_binary_foo_bar_start)
It is a workaround, but it works good and is not too ugly.
这是一种变通方法,但效果不错,也不太难看。
#2
16
As well as the suggestions already mentioned, under linux you can use the hex dump tool xxd, which has a feature to generate a C header file:
除了前面提到的建议之外,在linux下,您还可以使用十六进制转储工具xxd,它具有生成C头文件的特性:
xxd -i mybinary > myheader.h
#3
3
Not exactly a new way, but certainly very convenient. I stumbled upon this totally free licenced library based on the incbin assembler method not mentioned among the answers here.
不完全是一种新方法,但肯定非常方便。我偶然发现了这个完全免费的许可库,它基于incbin汇编器方法,这里的答案中没有提到。
https://github.com/graphitemaster/incbin
https://github.com/graphitemaster/incbin
To recap. The incbin method is like this. You have a thing.s assembly file that you compile with gcc -c thing.s
回顾一下。incbin方法是这样的。你有一个东西。用gcc -c东西编译的汇编文件
.section .rodata
.global thing
.type thing, @object
.align 4
thing:
.incbin "meh.bin"
thing_end:
.global thing_size
.type thing_size, @object
.align 4
thing_size:
.int thing_end - thing
In your c or cpp code you can reference it with:
在你的c或cpp代码中,你可以参考以下内容:
extern const char thing[];
extern const char* thing_end;
extern int thing_size;
So then you link the resulting .o with the rest of the compilation units. Credit where due is to @John Ripley with his answer here: C/C++ with GCC: Statically add resource files to executable/library
然后将结果的.o与编译单元的其余部分连接起来。归功于@John Ripley的回答:C/ c++和GCC:静态地向可执行/库添加资源文件
But the above is not as convenient as what incbin can give you. To accomplish the above with incbin you don't need to write any assembler. Just the following will do:
但是上面的内容并不像incbin提供的那样方便。要使用incbin实现上述目标,您不需要编写任何汇编程序。只要以下几点就可以了:
#include "incbin.h"
INCBIN(thing, "meh.bin");
int main(int argc, char* argv[])
{
// Now use thing
printf("thing=%p\n", gThingData);
printf("thing len=%d\n", gThingSize);
}
#4
1
You could do this in a header file :
你可以在头文件中这样做:
#ifndef SHADER_SRC_HPP
#define SHADER_SRC_HPP
const char* shader= "
//source
";
#endif
and just include that.
包括。
Other way is to read the shader file.
另一种方法是读取着色文件。