¿Alguien tiene una idea de cómo compilar estáticamente cualquier archivo de recursos directamente en el ejecutable o en el archivo de biblioteca compartida usando GCC?
Por ejemplo, me gustaría agregar archivos de imagen que nunca cambian (y si lo hacen, tendría que reemplazar el archivo de todos modos) y no querría que se quedaran en el sistema de archivos.
Si esto es posible (y creo que es porque Visual C ++ para Windows también puede hacer esto), ¿cómo puedo cargar los archivos que están almacenados en el propio binario? ¿El ejecutable se analiza a sí mismo, encuentra el archivo y extrae los datos?
Tal vez haya una opción para GCC que aún no he visto. El uso de motores de búsqueda realmente no arrojó las cosas correctas.
Necesitaría que esto funcione para bibliotecas compartidas y ejecutables ELF normales.
Se agradece cualquier ayuda
Respuestas:
Con imagemagick :
Da algo como:
Por compatibilidad con otro código, puede usar
fmemopen
para obtener unFILE *
objeto "normal" o, alternativamente,std::stringstream
para crear uniostream
.std::stringstream
Sin embargo, no es bueno para esto y, por supuesto, puede usar un puntero en cualquier lugar donde pueda usar un iterador.Si está usando esto con automake, no olvide configurar BUILT_SOURCES apropiadamente.
Lo bueno de hacerlo de esta manera es:
fuente
xxd -i infile.bin outfile.h
objcopy
para convertir los datos binarios directamente en un archivo objeto; sin embargo, esto rara vez es motivo de preocupación.Actualización He llegado a preferir el control que ofrece la solución basada en ensamblaje de John Ripley
.incbin
y ahora uso una variante de eso.He usado objcopy (GNU binutils) para vincular los datos binarios de un archivo foo-data.bin a la sección de datos del ejecutable:
Esto le proporciona un
foo-data.o
archivo de objeto que puede vincular a su ejecutable. La interfaz C se parece apara que puedas hacer cosas como
o
Si su arquitectura de destino tiene restricciones especiales en cuanto a dónde se almacenan los datos constantes y variables, o si desea almacenar esos datos en el
.text
segmento para que quepan en el mismo tipo de memoria que su código de programa, puede jugar con losobjcopy
parámetros un poco más.fuente
ld
ya que el formato de salida está implícito allí, consulte stackoverflow.com/a/4158997/201725 .Puede incrustar archivos binarios en ejecutables mediante el
ld
vinculador. Por ejemplo, si tiene un archivofoo.bar
, puede incrustarlo en un ejecutable agregando los siguientes comandos ald
Si está invocando a
ld
travésgcc
, deberá agregar-Wl
Aquí
--format=binary
le dice al enlazador que el siguiente archivo es binario y--format=default
vuelve al formato de entrada predeterminado (esto es útil si especificará otros archivos de entrada despuésfoo.bar
).Luego puede acceder al contenido de su archivo desde el código:
También hay un símbolo llamado
"_binary_foo_bar_size"
. Creo que es de tipouintptr_t
pero no lo comprobé.fuente
data_end
una matriz, no un puntero? (¿O es C idiomática?)data_end
será un puntero, el compilador pensará que hay un puntero almacenado después del contenido del archivo. De manera similar, si cambia el tipo dedata
a un puntero, obtendrá un puntero que consta de los primeros bytes de un archivo en lugar de un puntero al inicio. Creo que sí.const pointer
. El compilador le permite cambiar el valor de punteros no constantes, no le permite cambiar el valor si es una matriz. Así que quizás sea menos tipeado usar la sintaxis de matriz.Puede poner todos sus recursos en un archivo ZIP y agregarlo al final del archivo ejecutable :
Esto funciona porque a) a la mayoría de los formatos de imagen ejecutables no les importa si hay datos adicionales detrás de la imagen yb) zip almacena la firma del archivo al final del archivo zip . Esto significa que su ejecutable es un archivo zip normal después de esto (excepto su ejecutable inicial, que zip puede manejar), que se puede abrir y leer con libzip.
fuente
install_name_tool
. Además de eso, el binario todavía funciona como ejecutable.De http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 :
Recientemente tuve la necesidad de incrustar un archivo en un ejecutable. Como estoy trabajando en la línea de comandos con gcc, et al, y no con una elegante herramienta RAD que hace que todo suceda mágicamente, no me fue inmediatamente obvio cómo hacer que esto sucediera. Un poco de búsqueda en la red encontró un truco que esencialmente lo capturó al final del ejecutable y luego descifró dónde estaba basado en un montón de información que no quería conocer. Parecía que debería haber una mejor manera ...
Y lo hay, es obvio al rescate. objcopy convierte archivos objeto o ejecutables de un formato a otro. Uno de los formatos que entiende es "binario", que es básicamente cualquier archivo que no esté en uno de los otros formatos que entiende. Entonces, probablemente haya imaginado la idea: convertir el archivo que queremos incrustar en un archivo de objeto, luego simplemente se puede vincular con el resto de nuestro código.
Digamos que tenemos un nombre de archivo data.txt que queremos incrustar en nuestro ejecutable:
Para convertir esto en un archivo de objeto que podamos vincular con nuestro programa, simplemente usamos objcopy para producir un archivo ".o":
Esto le dice a objcopy que nuestro archivo de entrada está en formato "binario", que nuestro archivo de salida debe estar en formato "elf32-i386" (archivos de objeto en el x86). La opción --binary-architecture le dice a objcopy que el archivo de salida está destinado a "ejecutarse" en un x86. Esto es necesario para que ld acepte el archivo para vincularlo con otros archivos para x86. Uno pensaría que especificar el formato de salida como "elf32-i386" implicaría esto, pero no es así.
Ahora que tenemos un archivo de objeto, solo necesitamos incluirlo cuando ejecutamos el enlazador:
Cuando ejecutamos el resultado, obtenemos el resultado pedido:
Por supuesto, aún no he contado toda la historia, ni les he mostrado el main.c. Cuando objcopy realiza la conversión anterior, agrega algunos símbolos de "vinculador" al archivo de objeto convertido:
Después de vincular, estos símbolos especifican el inicio y el final del archivo incrustado. Los nombres de los símbolos se forman anteponiendo binario y añadiendo _start o _end al nombre del archivo. Si el nombre del archivo contiene caracteres que no serían válidos en un nombre de símbolo, se convierten en guiones bajos (por ejemplo, data.txt se convierte en data_txt). Si obtiene nombres sin resolver al vincular usando estos símbolos, haga un hexdump -C en el archivo de objeto y busque al final del volcado los nombres que eligió objcopy.
El código para usar realmente el archivo incrustado ahora debería ser razonablemente obvio:
Una cosa importante y sutil a tener en cuenta es que los símbolos agregados al archivo de objeto no son "variables". No contienen ningún dato, más bien, su dirección es su valor. Los declaro como tipo char porque es conveniente para este ejemplo: los datos incrustados son datos de caracteres. Sin embargo, puede declararlos como cualquier cosa, como int si los datos son una matriz de enteros, o como struct foo_bar_t si los datos fueran cualquier matriz de barras foo. Si los datos incrustados no son uniformes, entonces char es probablemente lo más conveniente: tome su dirección y envíe el puntero al tipo adecuado a medida que recorre los datos.
fuente
Si desea controlar el nombre exacto del símbolo y la ubicación de los recursos, puede usar (o script) el ensamblador GNU (que no es realmente parte de gcc) para importar archivos binarios completos. Prueba esto:
Montaje (x86 / brazo):
C:
Independientemente de lo que use, probablemente sea mejor hacer un script para generar todos los recursos y tener nombres de símbolo agradables / uniformes para todo.
Dependiendo de sus datos y las especificaciones del sistema, es posible que deba usar diferentes valores de alineación (preferiblemente con
.balign
para la portabilidad) o tipos enteros de un tamaño diferentething_size
o un tipo de elemento diferente para lathing[]
matriz.fuente
Leyendo todas las publicaciones aquí y en Internet he llegado a la conclusión de que no existe una herramienta para los recursos, que es:
1) Fácil de usar en código.
2) Automatizado (para facilitar su inclusión en cmake / make).
3) multiplataforma.
He decidido escribir la herramienta yo mismo. El código está disponible aquí. https://github.com/orex/cpp_rsc
Usarlo con cmake es muy fácil.
Debe agregar dicho código a su archivo CMakeLists.txt.
El ejemplo real, usando el enfoque se puede descargar aquí, https://bitbucket.org/orex/periodic_table
fuente