Incorporation de ressources dans l’exécutable à l’aide de GCC

Je cherche un moyen d’intégrer facilement des données binarys externes dans une application C / C ++ compilée par GCC.

Un bon exemple de ce que je voudrais faire est de manipuler le code du shader – je peux juste le garder dans des fichiers sources comme const char* shader = "source here"; mais c’est extrêmement peu pratique.

Je voudrais que le compilateur le fasse pour moi: lors de la compilation (étape de liaison), lisez le fichier “foo.bar” et liez son contenu à mon programme, afin que je puisse accéder au contenu en tant que données binarys du code.

Pourrait être utile pour les petites applications que je voudrais dissortingbuer en un seul fichier .exe.

Est-ce que GCC supporte quelque chose comme ça?

Il y a quelques possibilités:

  • Utilisez la capacité de ld à transformer n’importe quel fichier en object ( incorporation de blobs binarys en utilisant gcc mingw ):

     ld -r -b binary -o binary.o foo.bar # then link in binary.o 
  • utiliser un bin2c / bin2h pour transformer n’importe quel fichier en tableau d’octets ( Intégrer une image dans le code sans utiliser la section des ressources ou les images externes )


Mise à jour: Voici un exemple plus complet de l’utilisation des données liées à l’exécutable à l’aide de 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; } 

Mise à jour 2 – Obtenir la taille de la ressource: je n’ai pas pu lire correctement le fichier _binary_foo_bar_size. A l’exécution, gdb me montre la bonne taille de la ressource texte en utilisant display (unsigned int)&_binary_foo_bar_size . Mais l’atsortingbuer à une variable donne toujours une valeur erronée. Je pourrais résoudre ce problème de la manière suivante:

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

C’est une solution de contournement, mais cela fonctionne bien et n’est pas trop moche.

Outre les suggestions déjà mentionnées, sous Linux, vous pouvez utiliser l’outil de vidage hexadécimal xxd, qui comporte une fonctionnalité permettant de générer un fichier d’en-tête C:

 xxd -i mybinary > myheader.h 

Pas exactement une nouvelle façon, mais certainement très pratique. Je suis tombé sur cette bibliothèque sous licence totalement gratuite basée sur la méthode d’assembleur d’incbin non mentionnée parmi les réponses ici.

https://github.com/graphitemaster/incbin

Récapituler. La méthode incbin est comme ça. Vous avez un fichier d’assemblage thing.s que vous comstackz avec 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 

Dans votre code c ou cpp, vous pouvez le référencer avec:

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

Donc, vous liez le .o résultant au rest des unités de compilation. Le crédit est dû à @John Ripley avec sa réponse ici: C / C ++ avec GCC: Ajouter statiquement des fichiers de ressources à l’exécutable / bibliothèque

Mais ce qui précède n’est pas aussi pratique que ce que incbin peut vous donner. Pour accomplir ce qui précède avec incbin, vous n’avez besoin d’écrire aucun assembleur. Juste ce qui suit fera:

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

Vous pouvez le faire dans un fichier d’en-tête:

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

et juste inclure cela.

Une autre manière consiste à lire le fichier shader.