Incrustar recursos en ejecutable usando GCC

Estoy buscando una manera de incrustar fácilmente cualquier información binaria externa en una aplicación C / C ++ comstackda por GCC.

Un buen ejemplo de lo que me gustaría hacer es manejar el código del sombreador; puedo guardarlo en archivos fuente como const char* shader = "source here"; pero eso es extremadamente poco práctico.

Me gustaría que el comstackdor lo hiciera por mí: en la comstackción (etapa de vinculación), lea el archivo “foo.bar” y vincule su contenido a mi progtwig, de modo que pueda acceder a los contenidos como datos binarios del código.

Podría ser útil para pequeñas aplicaciones que me gustaría distribuir como un solo archivo .exe.

¿GCC es compatible con algo como esto?

Hay un par de posibilidades:

  • use la capacidad de ld para convertir cualquier archivo en un objeto ( Incrustar blobs binarios usando gcc mingw ):

     ld -r -b binary -o binary.o foo.bar # then link in binary.o 
  • use una utilidad bin2c / bin2h para convertir cualquier archivo en una matriz de bytes ( Incruste la imagen en el código, sin usar la sección de recursos o las imágenes externas )


Actualización: Aquí hay un ejemplo más completo de cómo usar datos enlazados al ejecutable usando ld -r -b binary :

 #include  // 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; } 

Actualización 2 – Obtener el tamaño del recurso: no pude leer el _binary_foo_bar_size correctamente. En tiempo de ejecución, gdb me muestra el tamaño correcto del recurso de texto usando display (unsigned int)&_binary_foo_bar_size . Pero asignar esto a una variable siempre daba un valor incorrecto. Podría resolver este problema de la siguiente manera:

 unsigned int iSize = (unsigned int)(&_binary_foo_bar_end - &_binary_foo_bar_start) 

Es una solución alternativa, pero funciona bien y no es demasiado fea.

Además de las sugerencias ya mencionadas, bajo Linux puede usar la herramienta de volcado hexadecimal xxd, que tiene una función para generar un archivo de encabezado C:

 xxd -i mybinary > myheader.h 

No es exactamente una nueva forma, pero ciertamente muy conveniente. Me encontré con esta biblioteca con licencia totalmente gratuita basada en el método de ensamblador incbin no mencionado entre las respuestas aquí.

https://github.com/graphitemaster/incbin

Recordar. El método incbin es así. Tiene un archivo de ensamblaje de cosa que comstack con 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 

En su código c o cpp puede referenciarlo con:

 extern const char thing[]; extern const char* thing_end; extern int thing_size; 

Entonces, vincula el .o resultante con el rest de las unidades de comstackción. El crédito es debido a @John Ripley con su respuesta aquí: C / C ++ con GCC: Agregue estáticamente archivos de recursos a ejecutable / biblioteca

Pero lo anterior no es tan conveniente como lo que incbin puede darte. Para lograr lo anterior con incbin no necesita escribir ningún ensamblador. Solo lo siguiente hará:

 #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); } 

Puedes hacer esto en un archivo de encabezado:

 #ifndef SHADER_SRC_HPP #define SHADER_SRC_HPP const char* shader= " //source "; #endif 

y solo incluye eso.

Otra forma es leer el archivo de sombreado.