Встраивание ресурсов в исполняемый файл с использованием GCC - PullRequest
44 голосов
/ 11 ноября 2010

Я ищу способ легко встроить любые внешние двоичные данные в приложение C / C ++, скомпилированное GCC.

Хороший пример того, что я хотел бы сделать, - это обработка кода шейдера - яможно просто сохранить его в исходных файлах, таких как const char* shader = "source here";, но это крайне непрактично.

Я бы хотел, чтобы компилятор сделал это для меня: после компиляции (этап компоновки) прочитайте файл "foo.bar" и ссылкуего содержимое для моей программы, чтобы я мог получить доступ к содержимому в виде двоичных данных из кода.

Может быть полезно для небольших приложений, которые я хотел бы распространять в виде одного файла .exe.

GCC поддерживает что-то подобное?

Ответы [ 4 ]

43 голосов
/ 11 ноября 2010

Есть несколько вариантов:


Обновление: вот более полный пример того, как использовать данные, привязанные к исполняемому файлу, используя 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;
}

Обновление 2 - получение размера ресурса: я не могу правильно прочитать _binary_foo_bar_size. Во время выполнения GDB показывает правильный размер текстового ресурса, используя display (unsigned int)&_binary_foo_bar_size. Но присвоение этого переменной всегда давало неправильное значение. Я мог бы решить эту проблему следующим образом:

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

Это обходной путь, но он работает хорошо и не слишком уродливо.

21 голосов
/ 06 февраля 2014

Помимо уже упомянутых предложений, в linux вы можете использовать инструмент шестнадцатеричного дампа xxd, который имеет функцию для создания заголовочного файла C:

xxd -i mybinary > myheader.h
7 голосов
/ 30 марта 2016

Для этой задачи можно использовать директиву .incbin GAS . Вот совершенно бесплатная лицензионная библиотека, которая ее оборачивает:

https://github.com/graphitemaster/incbin

Напомним. Метод incbin такой. У вас есть файл сборки thing.s, который вы компилируете с помощью 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

В вашем коде c или cpp вы можете ссылаться на него:

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

Итак, вы связываете полученный .o с остальными единицами компиляции. Надо отдать должное @John Ripley с его ответом: C / C ++ с GCC: Статически добавлять файлы ресурсов в исполняемый файл / библиотеку

Но вышесказанное не так удобно, как то, что может дать вам incbin. Чтобы выполнить вышеизложенное с помощью incbin, вам не нужно писать никакой ассемблер. Подойдет только следующее:

#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);   
}
0 голосов
/ 11 ноября 2010

Вы можете сделать это в заголовочном файле:

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

//source

";
#endif

и просто включите это.

Другой способ - прочитать файл шейдера.

...