C++ 使用GCC在可执行文件中嵌入资源

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是否支持类似的内容?您可以在头文件中执行

我正在寻找一种方法,可以轻松地将任何外部二进制数据嵌入由GCC编译的C/C++应用程序中

我想做的一个很好的例子就是处理着色器代码——我可以将其保存在源文件中,比如
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”“引号”或在每行末尾都有反斜杠。更不用说在开发过程中将着色器作为独立文件提供的其他好处(至少是语法着色?),我认为这个解决方案是最好的。它还支持跨平台和跨编译器。这是事实,但它确实有一个缺点-生成的头文件比原始二进制文件大得多。这对最终编译的结果没有影响,但作为构建过程的一部分,这可能是不可取的。这个问题可以通过使用预编译头来解决。我喜欢这个方法,因为它允许控制符号名。可能会重复
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);   
}