Как стать автором
Обновить

Комментарии 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 секции не добавлена в С. Хотя может считали избыточным, что есть другие тулы для этого.

Мы у себя именно так и сделали.
Тоже смотрели на ресурсы и 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. Да еще если используется какой либо фреймворк, то его подключать в исходник удобней только при сборке прошивки… и получается что все равно вызывать некий пребилд и смысла особого нет.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации