Incrustar recursos en ejecutables mediante GCC


Estoy buscando una manera de incrustar fácilmente cualquier dato binario externo en una aplicación C/C++ compilada por GCC.

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

Me gustaría que el compilador lo hiciera por mí: después de la compilación (etapa de enlace), lea el archivo "foo.bar " y enlazar su contenido a mi programa, para poder acceder a los contenidos como datos binarios del código.

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

¿El CCG admite algo como esto?

Author: jww, 2010-11-11

4 answers

Hay un par de posibilidades:


Actualización: Aquí hay un ejemplo más completo de cómo usar datos enlazados al ejecutable usando 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;
}

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 dio 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 feo.

 43
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:30:52

Además de las sugerencias ya mencionadas, en Linux puede utilizar la herramienta de volcado hexadecimal xxd, que tiene una característica para generar un archivo de encabezado C:

xxd -i mybinary > myheader.h
 18
Author: Riot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-06 14:08:19

No es exactamente una forma nueva, pero ciertamente muy conveniente. Me topé 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

Para recapitular. El método incbin es así. Tienes algo.s fichero ensamblador que se compila con gcc-c cosa.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 tu código c o cpp puedes referenciarlo con:

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

Entonces se enlaza el resultado.o con el resto de las unidades de compilación. El crédito es para @John Ripley con su respuesta aquí: C / C++ con GCC: Estáticamente agregar archivos de recursos al 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 servirá:

#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);   
}
 5
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:54

Puedes hacer esto en un archivo de encabezado:

#ifndef SHADER_SRC_HPP
#define SHADER_SRC_HPP
const char* shader= "

//source

";
#endif

Y solo incluya eso.

Otra forma es leer el archivo de sombreado.

 1
Author: BЈовић,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-11 21:47:12