Pull to refresh

Comments 33

Интересный проект. Но автору такое скорей всего не подойдет.
Судя по коду, этот CMakeRC задействует пол стандартной библиотеки.
Что конечно удобно, но просто не влезет в AVR.
Автору точно не подойдет. Я понадеялся, что он в принципе кому-то может быть полезен.

Решение интересное, но, кажется, что некоторых кейсах это проще сделать через xxd.


xxd --include filename

выведет что-то вроде:


unsigned char filename[]={ 0x48, ...}; 
unsigned int filename_len = 123;

Для небольших файлов. Если файл несколько Мб, то зачем лишний раз напрягать компилятор? (И хранить сам файл в двух вариантах: оригинал и с-массив.) Лучше сделать через objcopy, как замечено в комментарии ниже. Да и xdd нет под виндой из коробки.

Особенно это хорошо для эмбеддеда, потому что он не дописывает const. В результате полмегабайтный файл пытается влезть в оперативку. И руками этот const приходится дописывать

Я пару раз делал подключал бинарные файлы через objcopy --input-target binary
Быстрый гуглинг так же предлагает https://github.com/graphitemaster/incbin.


А вообще — ждем принятия соответствующего Proposal и облизываемся на растовый std::include_bytes

Еще один вариант — сначала перевести в *.o, а потом подключать как любой другой объектник:
$%.o: $src/example.img
mkdir -p $(builddir)
arm-none-eabi-ld -r -b binary -o $@ $<
arm-none-eabi-objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents $@ $@

extern const char *data_start = asm("_binary_src_fatexample_img_start");
extern const char* data_end = asm("_binary_src_fatexample_img_end");
Делал аналогично.

ld -r -b binary demo.ui -o demo_ui.o


// from demo.ui
extern const char _binary_demo_ui_start[];
extern const char _binary_demo_ui_end[];
Преобразование из .data секции в .rodata все же важный шаг.

Насчёт микроконтроллеров: во время работы контроллера данные хранятся на flash или целиком загружаются в RAM? У меня почему-то получалось, что при объявлении в коде статического массива с данными на stm32 тот грузился целиком в оперативку и это меня не очень устраивало.

Смотря, как объявить. Если массив объявить константным (static const xxx[] = {...}), то он не будет перегружаться в ОЗУ.

Для разных микроконтроллеров по-разному. Для stm32 вам ответили, а, например, для avr надо кроме этого добавлять к определению массива attribute(progmem) или что-то ещё, смотря какой компилятор.

Секция .rodata у ARM Cortex M, как правило, располагается во флеше, а .data — в оперативке. Но если у вас что-то чуть сложнее микроконтроллера, то правила линковки и загрузки могут быть уже другими (к примеру, если программа грузится не с eXecute In Place-накопителя)

А для js/ts есть не велосипедный способ сделать такое? Интересует вкомпиляция (например) картинки в бинарном виде. В golang завезли embed на туже тему.

Если используете бандлер, например webpack, то да.

rust+webassembly, а дальше уже используешь из ts/js
:D

Кстати говоря, я еще год назад рассказывал[1], что в следующем стандарте препроцессор C будет, вероятно, поддерживать такое включение директивой embed [2].


[1] Статья про преполагаемые нововведения
[2] Последняя итерация предложения в комитете

А что про С++? Означает ли добавление директивы в С, что в С++ её тоже будут должны поддержать?
В Sonic Adventure эксешник больше 100Мб был в 2004 году, там все модели уровней и пропов лежат, кроме персонажей.
Что то типа json_encode (для php, или JSON.stringify дляjavascript) использовать не хотите?
Эти методы сами экранирует 'опасные' символы, делая очень эффективную строку (с оговорками для не латинских символов и неправильного выбора кодировки), совместимую с C-языками.

p.s. objcopy добавляет данные в obj файл

Главная проблема перечисленных вами функций — в том, что они работают с юникодовыми строками, т.е. последовательностями символов — в то время как бинарные данные являются последовательностью байт. И не любую последовательность байт можно интерпретировать как последовательность символов для кодирования.


Вторая проблема такого кодирования — в том, что оно ничуть не эффективно, формат \uNNNN требует шести байт для представления двух.


с оговорками для не латинских символов

Таких "символов" в бинарных данных будет половина.

А вторая половина вообще не будет иметь символа в юникод, из-за чего энкодинг станет невозможен. В json все данные обязаны быть в юникоде.


Можно обойти проблему загнав всё в hex, от которого автор успешно ушёл.

Интересно, а для обычной Visual Studio такая возможность имеется?
PS Вообще фича вставки бинарников весьма очевидна, странно что еще в Си ее не реализовали. В языке D кстати такая возможность добавлена официально.

Я использую objcopy как некое кроссплатформенное решение, но нужно установить objcopy на винду.


Про очевидность :) Для вас — очевидно, для меня — очевидно, но я поспрашивал знакомых с/с++ разработчиков, оказываается для многих совершенно не очевидно :) следуют вопросы: а зачем? а почему в файлах не устраивает? и тп :)


И я тоже не понимаю почему возможность добавлять бинарные данные в .data и в .rdata секции не добавлена в С. Хотя может считали избыточным, что есть другие тулы для этого.

А получится ли обойтись просто string literal?
По крайней мере, в с+11 всякие экзотические строки можно так задавать:
const auto str = 
R"(
   first line blabla #~\/&$
   second line blabla
)";
  

Мы у себя именно так и сделали.
Тоже смотрели на ресурсы и xxd.
Но ресурсы — это всё же не от языка, а внешнее (нет желания напороться на формат экзешников, где они не предусмотрены). xxd — да, но с "сырыми" литералами он тоже выглядит излишне (к тому же требует установки).
В итоге "навелосипедили" скрипт для cmake, который нужные файлы кодирует в один или несколько литералов. которые потом в основной сборке подключаются через #include.


(в один или несколько — потому что эти самые "экзотические строки" всё же имеют ограничения. Под виндой — 65к на литерал).

Если просто положить бинарник — то можно и так.
А если нужно посчитать CRC всей секции данных (а то и всех секций сразу) и положить его в бинарник, то кроме как посчитать CRC в python-скрипте и пропатчить бинарник — ничего не придумывается.
вот такой способ ещё встречал
ld -r -b binary file.txt -o file.o
а в остальных файлах можно использовать
extern char _binary_file_txt_end[];
extern char _binary_file_txt_start[];
решение хорошее, но на практике получается что мелкий html практически пофиг как подключать, а вот большой код отдается сжатым типа index.html.gz. Да еще если используется какой либо фреймворк, то его подключать в исходник удобней только при сборке прошивки… и получается что все равно вызывать некий пребилд и смысла особого нет.
Sign up to leave a comment.

Articles