C++ 使用GCC在可执行文件中嵌入资源
我正在寻找一种方法,可以轻松地将任何外部二进制数据嵌入由GCC编译的C/C++应用程序中 我想做的一个很好的例子就是处理着色器代码——我可以将其保存在源文件中,比如C++ 使用GCC在可执行文件中嵌入资源,c++,c,gcc,resources,embedded-resource,C++,C,Gcc,Resources,Embedded Resource,我正在寻找一种方法,可以轻松地将任何外部二进制数据嵌入由GCC编译的C/C++应用程序中 我想做的一个很好的例子就是处理着色器代码——我可以将其保存在源文件中,比如const char*shader=“source here”但这是非常不切实际的 我希望编译器为我做这件事:在编译(链接阶段)时,读取文件“foo.bar”并将其内容链接到我的程序,这样我就能够从代码中以二进制数据的形式访问内容 对于我想作为单个.exe文件分发的小型应用程序可能很有用 GCC是否支持类似的内容?您可以在头文件中执行
const char*shader=“source here”代码>但这是非常不切实际的
我希望编译器为我做这件事:在编译(链接阶段)时,读取文件“foo.bar”并将其内容链接到我的程序,这样我就能够从代码中以二进制数据的形式访问内容
对于我想作为单个.exe文件分发的小型应用程序可能很有用
GCC是否支持类似的内容?您可以在头文件中执行此操作:
#ifndef SHADER_SRC_HPP
#define SHADER_SRC_HPP
const char* shader= "
//source
";
#endif
把它包括在内
另一种方法是读取着色器文件。有两种可能:
- 使用ld的功能将任何文件转换为对象():
- 使用
bin2c
/bin2h
实用程序将任何文件转换为字节数组()
更新:下面是一个更完整的示例,说明如何使用ld-r-b binary
将数据绑定到可执行文件中:
#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;
}
这是一个解决办法,但它工作良好,也不太难看。以及前面提到的建议,在linux下,您可以使用十六进制转储工具xxd,它具有生成C头文件的功能:
xxd -i mybinary > myheader.h
可以将用于此任务。这是一个完全免费的许可证库:
重述。incbin方法是这样的。您有一个thing.s汇编文件,可以使用gcc-c thing.s编译
.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
在您的c或cpp代码中,您可以使用以下代码引用它:
extern const char thing[];
extern const char* thing_end;
extern int thing_size;
然后将生成的.o与其他编译单元链接起来。
这里的答案应归功于@John Ripley:
但是上面所说的并不像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);
}
@VJo:然后将blob视为文本。如果需要这样终止,您可能需要做一些工作,以确保文本末尾有一个'\0'
。一些实验可能是正确的。@VJo:text是二进制的。计算机上的所有内容都是二进制的。@MSalters re:“文本是二进制的”。是的,但是。。。在文本中,EOL可在不同系统上进行不同处理。显式地将其称为二进制可以防止这种缺点。@atlaste:您描述的是可写(“数据”)和可执行(“代码”)之间的区别。只读数据不需要任何方法。你能告诉ld
为数据生成哪个符号名吗?我认为Kos希望能够维护着色器源,而不必担心转义特殊字符(以及其他可能的问题)。@Michael你显然从未使用过一个着色器。@VJo:nope-从未使用过着色器。我将这个问题理解为将驻留在外部文件中的任意数据嵌入到程序中。我当然可以接受,对于着色器来说,这可能是一个更好的解决方案。定义(而不是声明)全局变量的文件不应该是头文件,而应该是源模块。而且你的类型效率极低。使其const char shader[]=“source”另外,我相信C++不允许你以多个方式使用多行字符串文字,而不是在每个行中分别打开和关闭<代码>“引号”或在每行末尾都有反斜杠。更不用说在开发过程中将着色器作为独立文件提供的其他好处(至少是语法着色?),我认为这个解决方案是最好的。它还支持跨平台和跨编译器。这是事实,但它确实有一个缺点-生成的头文件比原始二进制文件大得多。这对最终编译的结果没有影响,但作为构建过程的一部分,这可能是不可取的。这个问题可以通过使用预编译头来解决。我喜欢这个方法,因为它允许控制符号名。可能会重复
extern const char thing[];
extern const char* thing_end;
extern int thing_size;
#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);
}