Quelqu'un a-t-il une idée de la façon de compiler statiquement n'importe quel fichier de ressources directement dans l'exécutable ou le fichier de bibliothèque partagé en utilisant GCC?
Par exemple, je voudrais ajouter des fichiers image qui ne changent jamais (et s'ils le font, je devrais de toute façon remplacer le fichier) et je ne voudrais pas qu'ils traînent dans le système de fichiers.
Si cela est possible (et je pense que c'est parce que Visual C ++ pour Windows peut également le faire), comment puis-je charger les fichiers qui sont stockés dans le propre binaire? L'exécutable s'analyse-t-il, trouve-t-il le fichier et en extrait les données?
Peut-être qu'il y a une option pour GCC que je n'ai pas encore vue. L'utilisation des moteurs de recherche n'a pas vraiment craché les bonnes choses.
J'aurais besoin de cela pour fonctionner pour les bibliothèques partagées et les exécutables ELF normaux.
Toute aide est appréciée
Réponses:
Avec imagemagick :
Donne quelque chose comme:
Pour la compatibilité avec d'autres codes, vous pouvez ensuite utiliser soit
fmemopen
pour obtenir unFILE *
objet "normal" , soitstd::stringstream
pour créer un fichieriostream
.std::stringstream
ce n'est pas génial pour cela et vous pouvez bien sûr simplement utiliser un pointeur partout où vous pouvez utiliser un itérateur.Si vous l'utilisez avec automake, n'oubliez pas de définir BUILT_SOURCES de manière appropriée.
La bonne chose à faire de cette façon est:
la source
xxd -i infile.bin outfile.h
objcopy
pour convertir les données binaires directement en un fichier objet; cependant, c'est rarement un problème.Mise à jour J'ai grandi pour préférer la solution de contrôle basée sur l' assemblage de John Ripley
.incbin
et j'utilise maintenant une variante à ce sujet.J'ai utilisé objcopy (GNU binutils) pour lier les données binaires d'un fichier foo-data.bin dans la section data de l'exécutable:
Cela vous donne un
foo-data.o
fichier objet que vous pouvez lier à votre exécutable. L'interface C ressemble à quelque chose commepour que tu puisses faire des trucs comme
ou
Si votre architecture cible a des contraintes spéciales quant à l'emplacement de stockage des données constantes et variables, ou si vous souhaitez stocker ces données dans le
.text
segment pour qu'elles tiennent dans le même type de mémoire que votre code de programme, vous pouvez jouer unobjcopy
peu plus avec les paramètres.la source
ld
car le format de sortie y est implicite, voir stackoverflow.com/a/4158997/201725 .Vous pouvez incorporer des fichiers binaires dans un exécutable à l'aide de l'
ld
éditeur de liens. Par exemple, si vous avez un fichier,foo.bar
vous pouvez l'intégrer dans l'exécutable en ajoutant les commandes suivantes àld
Si vous invoquez
ld
via,gcc
vous devrez ajouter-Wl
Ici, il
--format=binary
indique à l'éditeur de liens que le fichier suivant est binaire et--format=default
revient au format d'entrée par défaut (cela est utile si vous spécifiez d'autres fichiers d'entrée aprèsfoo.bar
).Ensuite, vous pouvez accéder au contenu de votre fichier à partir du code:
Il y a aussi un symbole nommé
"_binary_foo_bar_size"
. Je pense que c'est du typeuintptr_t
mais je ne l'ai pas vérifié.la source
data_end
un tableau, pas un pointeur? (Ou est-ce idiomatique C?)data_end
sera un pointeur, le compilateur pensera qu'il y a un pointeur stocké après le contenu du fichier. De même, si vous changez le type dedata
en pointeur, vous obtiendrez un pointeur composé des premiers octets d'un fichier au lieu d'un pointeur vers son début. Je le pense.const pointer
. Le compilateur vous permet de changer la valeur des pointeurs non const, il ne vous permet pas de changer la valeur s'il s'agit d'un tableau. Il est donc peut-être moins difficile d'utiliser la syntaxe du tableau.Vous pouvez mettre toutes vos ressources dans un fichier ZIP et l' ajouter à la fin du fichier exécutable :
Cela fonctionne, car a) La plupart des formats d'image exécutables ne se soucient pas de savoir s'il y a des données supplémentaires derrière l'image et b) zip stocke la signature du fichier à la fin du fichier zip . Cela signifie que votre exécutable est un fichier zip normal après cela (à l'exception de votre exécutable initial, que zip peut gérer), qui peut être ouvert et lu avec libzip.
la source
install_name_tool
. À côté de cela, le binaire fonctionne toujours comme exécutable.De http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 :
J'ai récemment eu le besoin d'intégrer un fichier dans un exécutable. Puisque je travaille en ligne de commande avec gcc, et al et non avec un outil RAD sophistiqué qui fait que tout se passe comme par magie, il ne m'a pas été immédiatement évident de savoir comment y arriver. Un peu de recherche sur le net a trouvé un hack pour le mettre essentiellement à la fin de l'exécutable, puis déchiffrer où il était basé sur un tas d'informations que je ne voulais pas connaître. Il semblait qu'il devrait y avoir un meilleur moyen ...
Et il y a, c'est objcopy à la rescousse. objcopy convertit les fichiers objets ou exécutables d'un format à un autre. L'un des formats qu'il comprend est "binaire", qui est essentiellement tout fichier qui n'est pas dans l'un des autres formats qu'il comprend. Vous avez donc probablement envisagé l'idée: convertir le fichier que nous voulons incorporer en un fichier objet, puis il peut simplement être lié au reste de notre code.
Disons que nous avons un nom de fichier data.txt que nous voulons intégrer dans notre exécutable:
Pour le convertir en un fichier objet que nous pouvons lier avec notre programme, nous utilisons simplement objcopy pour produire un fichier ".o":
Cela indique à objcopy que notre fichier d'entrée est au format "binaire", que notre fichier de sortie doit être au format "elf32-i386" (fichiers objets sur le x86). L'option --binary-architecture indique à objcopy que le fichier de sortie est destiné à "s'exécuter" sur un x86. Ceci est nécessaire pour que ld accepte le fichier pour la liaison avec d'autres fichiers pour le x86. On pourrait penser que spécifier le format de sortie comme "elf32-i386" impliquerait cela, mais ce n'est pas le cas.
Maintenant que nous avons un fichier objet, nous n'avons besoin de l'inclure que lorsque nous exécutons l'éditeur de liens:
Lorsque nous exécutons le résultat, nous obtenons la sortie priée:
Bien sûr, je n'ai pas encore raconté toute l'histoire, ni montré main.c. Lorsque objcopy effectue la conversion ci-dessus, il ajoute des symboles "linker" au fichier objet converti:
Après la liaison, ces symboles spécifient le début et la fin du fichier incorporé. Les noms de symboles sont formés en ajoutant binaire au début et en ajoutant _start ou _end au nom de fichier. Si le nom de fichier contient des caractères qui ne seraient pas valides dans un nom de symbole, ils sont convertis en traits de soulignement (par exemple, data.txt devient data_txt). Si vous obtenez des noms non résolus lors de la liaison à l'aide de ces symboles, effectuez un hexdump -C sur le fichier objet et recherchez à la fin du vidage les noms choisis par objcopy.
Le code pour utiliser réellement le fichier incorporé devrait maintenant être raisonnablement évident:
Une chose importante et subtile à noter est que les symboles ajoutés au fichier objet ne sont pas des «variables». Ils ne contiennent aucune donnée, mais leur adresse est leur valeur. Je les déclare en tant que type char car c'est pratique pour cet exemple: les données incorporées sont des données de caractères. Cependant, vous pouvez les déclarer comme n'importe quoi, comme int si les données sont un tableau d'entiers, ou comme struct foo_bar_t si les données étaient n'importe quel tableau de foo bars. Si les données incorporées ne sont pas uniformes, alors char est probablement le plus pratique: prenez son adresse et transtypez le pointeur vers le type approprié lorsque vous parcourez les données.
la source
Si vous voulez contrôler le nom exact du symbole et le placement des ressources, vous pouvez utiliser (ou script) l'assembleur GNU (qui ne fait pas vraiment partie de gcc) pour importer des fichiers binaires entiers. Essaye ça:
Assemblage (x86 / bras):
C:
Quoi que vous utilisiez, il est probablement préférable de créer un script pour générer toutes les ressources et d'avoir des noms de symboles sympas / uniformes pour tout.
En fonction de vos données et des spécificités du système, vous devrez peut-être utiliser des valeurs d'alignement différentes (de préférence avec
.balign
pour la portabilité), ou des types entiers d'une taille différente pourthing_size
ou un type d'élément différent pour lething[]
tableau.la source
En lisant tous les articles ici et sur Internet, j'ai conclu qu'il n'y avait pas d'outil pour les ressources, à savoir:
1) Facile à utiliser dans le code.
2) Automatisé (pour être facilement inclus dans cmake / make).
3) multiplateforme.
J'ai décidé d'écrire l'outil moi-même. Le code est disponible ici. https://github.com/orex/cpp_rsc
L'utiliser avec cmake est très simple.
Vous devez ajouter à votre fichier CMakeLists.txt un tel code.
L'exemple réel, utilisant l'approche peut être téléchargé ici, https://bitbucket.org/orex/periodic_table
la source