Intégration des ressources dans l'exécutable en utilisant GCC

je cherche un moyen d'intégrer facilement des données binaires externes dans une application C/C++ compilée par GCC.

un bon exemple de ce que je voudrais faire est de gérer le code shader - je peux juste le garder dans les fichiers source comme const char* shader = "source here"; , mais c'est extrêmement impraticable.

j'aimerais que le compilateur le fasse pour moi: lors de la compilation (étape de lien), lire le fichier" foo.bar" et lier son contenu à mon programme, de sorte que je serais en mesure d'accéder au contenu comme données binaires à partir du code.

pourrait être utile pour les petites applications que je voudrais distribuer en un seul exemplaire .EXE.

est-ce que GCC soutient quelque chose comme ça?

42
demandé sur jww 2010-11-11 23:21:30

4 réponses

Il y a deux possibilités:


mise à jour: voici un exemple plus complet de la façon d'utiliser les données liées dans l'exécutable en utilisant 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;
}

mise à Jour 2 - Obtenir la ressource de la taille: je ne pouvais pas lire _binary_foo_bar_size correctement. A l'exécution, gdb me montre la bonne taille de la ressource texte en utilisant display (unsigned int)&_binary_foo_bar_size . Mais attribuer cela à une variable donnait toujours une mauvaise valeur. J'ai pu résoudre ce numéro de la façon suivante:

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

c'est un contournement, mais il fonctionne bien et n'est pas trop laid.

43
répondu Michael Burr 2017-05-23 10:30:52

ainsi que les suggestions déjà mentionnées, sous linux vous pouvez utiliser l'outil de dump hexadécimal xxd, qui a une fonction pour générer un fichier d'en-tête C:

xxd -i mybinary > myheader.h
18
répondu Riot 2014-02-06 14:08:19

pas exactement une nouvelle voie, mais certainement très commode. Je suis tombé sur cette bibliothèque totalement libre licence basée sur la méthode assembleur incbin pas mentionné parmi les réponses ici.

https://github.com/graphitemaster/incbin

à récapituler. La méthode incbin est comme ceci. Vous avez une chose.S fichier d'assemblage que vous compilez avec gcc-C.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

dans votre code C ou RPC vous peut faire référence à:

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

alors vous liez le résultat .o avec le reste des unités de compilation. Le crédit est dû à @John Ripley avec sa réponse ici: C/C++ avec GCC: Statically ajouter des fichiers de ressources à l'exécutable / bibliothèque

mais ce qui précède n'est pas aussi commode que ce que incbin peut vous donner. Pour y parvenir avec incbin vous n'avez pas besoin d'écrire de l'assembleur. Juste ce qui suit fera l'affaire:

#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
répondu Matt 2017-05-23 12:34:54

vous pouvez faire ceci dans un fichier d'en-tête:

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

//source

";
#endif

et incluez ça.

L'autre façon est de lire le fichier shader.

1
répondu BЈовић 2010-11-11 21:47:12