
��рограммирование микроконтроллеров это не только написание прошивок, но и программирование самого процесса сборки. Для этого есть целые языки: make, cmake, ninja и прочее. Это дает больше гибкости в том что можно делать с самим кодом. Вот классические пример. Настройка автоматического выравнивания отступов в исходном тексте программы.
Есть специальная широко известная утилита для автоматического выравнивания отступов в исходных кодах. Называется astyle.exe (Artistic Style ). Достоинство таких утилит в том, что ей всё равно в каком текстовом редакторе вы пишите код. Что в Eclipse, что Notepad++, что MS Visual Code. astyle он выровняет всё, что ему подадут на вход в соответствии с указанным конфигом в опциях командной строки. Есть еще тоже консольный GNU indent, однако indent очень устарел и слаб. Плюс падает от обнаружения препроцессора cpp. Есть также clang-format, но он часто не узнает свои собственные ключи из документации и отказывается выравнивать код, хотя там есть мега удобная опция сортировки include по алфавиту.
Цель данного текста-показать, как интегрировать утилиту Artistic Style в общий процесс сборки прошивки. Как добавить фазу выравнивания сорцов в конвейер производства бинаря. Итак обо всем по порядку...
Теория
Синтаксис — набор правил, описывающий комбинации символов алфавита, считающиеся правильно структурированной программой или её фрагментом. Синтаксис — это правила написания кода, как грамматика в языке. Синтаксис — это о том, как мы пишем.
Семантика — о том, что мы пишем, или о значении кода. Семантика языка — это смысловое значение слов.
Утилиты автоматического форматирования кода видоизменяют синтаксис программы, но не задевают семантику программы.
Почему обычно делают форматирование отступов в исходниках?
На то я вижу минимум три причины:
1--Для однообразности и красоты. Как говорил патрон: "делаем единообразно безобразно". В каждой российской компании свой собственный, внутренний, уникальный, самобытный, ни на кого больше не похожий стандарт оформления исходных текстов программ на Си. Причем отличается обычно всё кардинально по каждому пункту на 85%..95% от других организаций.
2--Чтобы был минимальный diff при сравнении разных по времени версий одного и того же куска Си кода
3--Чтобы можно было составлять простые и предсказуемые регулярные выражения для поиска шаблонов кусков кода утилитой grep и find в репозитории с кодом.
В чем проблема?
Проблем тут две:
1--Первая проблема в том, что вручную выставлять отступы это очень утомительно, рутинно и глупо. Однако эта проблема решается, как раз, многочисленными, разнообразными и широко известными утилитами автоматического выставления отступов.
2--Вторая проблема в том, что для автоматического форматирования кода утилитами приходится составлять .bat файл и явно прописывать внутри какой файл надо форматировать. Это тоже очень рутинно с учетом, что файлов в сборке порядка нескольких сотен. А в крупных проектах тысячи и тысячи файлов. Вот у меня типичная сборка собирает 287 .с файликов. И что, мне прописывать 287 строчки в *.bat файле что ли?
Очевидно же, что надо как-то автоматизировать процесс прогона с-файлов через утилиту форматировщик отступов astyle.
Надо написать вот такой простенький make скрипт. Он перебирает все пути из переменной окружения SOURCES_MY_C и к каждому пути применяет утилиту astyle с константным пучком из 20 опций. Вот так.
$(info Artistic_Style_Script ) # https://microsin.net/programming/arm/astyle-automatic-source-code-indenter.html?ysclid=mm4uoqrxyc654682115 # https://astyle.sourceforge.net/astyle.html ASTYLE_TOOL =astyle.exe SOURCES_CODE_CFM := $(subst .c,.ascode, $(SOURCES_MY_C)) #$(error SOURCES_MY_C=$(SOURCES_MY_C)) #$(error SOURCES_CODE_CFM=$(SOURCES_CODE_CFM)) ASTYLE_CFG1 = ASTYLE_CFG1 +=--mode=c ASTYLE_CFG1 +=--style=allman ASTYLE_CFG1 +=--indent=spaces=4 ASTYLE_CFG1 +=--indent=tab ASTYLE_CFG1 +=--indent=force-tab ASTYLE_CFG1 +=--indent-switches ASTYLE_CFG1 +=--indent-preproc-block ASTYLE_CFG1 +=--indent-preproc-define ASTYLE_CFG1 +=--indent-col1-comments ASTYLE_CFG1 +=--pad-oper ASTYLE_CFG1 +=--pad-comma ASTYLE_CFG1 +=--pad-include ASTYLE_CFG1 +=--pad-paren-in ASTYLE_CFG1 +=--delete-empty-lines ASTYLE_CFG1 +=--squeeze-lines=1 ASTYLE_CFG1 +=--squeeze-ws ASTYLE_CFG1 +=--align-pointer=type ASTYLE_CFG1 +=--add-braces ASTYLE_CFG1 +=--remove-comment-prefix ASTYLE_CFG1 +=--max-code-length=120 #$(error ASTYLE_CFG1=$(ASTYLE_CFG1)) .PHONY: %.ascode %.ascode: %.c $(info Run_Artistic_Style_Script_for_separate_code) $(ASTYLE_TOOL) $(ASTYLE_CFG1) $< # make -i astyle_code .PHONY: astyle_code astyle_code: $(SOURCES_CODE_CFM) $(info ArtisticStyleDone)
Однако есть один момент. Не все файлы исходников следует подвергать автоматическому выравниванию. Дело в том, что если ты меняешь форматирование third_party в файле, то ты, как бы, автоматически становишься владельцем (автором) этого кода. Оно тебе надо? Ты же не хочешь нести ответственность за этот странный чужой код просто потому, что ты там везде поменял 4 пробела на TAB? Поэтому существует такое негласное правило буравчика:
"Ни в коем случае нельзя менять форматирование в чужом коде!"
Очевидно, что в скриптах сборки надо как-то пометить те файлы сорцов, которые мы не будем форматировать. Это могут быть сорцы с конфигурационными таблицами для GPIO, конфиги таймеров и прочее. Надо чтобы они и остались в первозданном виде таблиц.
Дак вот, в системе сборки GNU make сделать это очень просто. Надо всего-навсего проиндексировать (прописать пути к *.с файлам) свои сорцы в переменную окружения SOURCES_MY_C.
Если лень это производить вручную, то можно применить этот bash скрипт, или воспользоваться утилитой R.
grep -rl SOURCES_C . | xargs sed -i 's/SOURCES_C/SOURCES_MY_C/g'
Далее в rules.mk просуммировать те сорцы, которые мы форматируем SOURCES_C и те, которые мы не форматируем SOURCES_THIRD_PARTY_C в одну переменную окружения SOURCES_TOTAL_C
SOURCES_TOTAL_C += $(SOURCES_C) SOURCES_TOTAL_C += $(SOURCES_MY_C) SOURCES_TOTAL_C += $(SOURCES_THIRD_PARTY_C) SOURCES_TOTAL_C += $(SOURCES_DIAG_C) SOURCES_TOTAL_C += $(SOURCES_TEST_C) SOURCES_TOTAL_C += $(SOURCES_CONFIGURATION_C) SOURCES_TOTAL_C := $(subst /cygdrive/c/,C:/, $(SOURCES_TOTAL_C))
далее из папки с make файлом вызвать
make -i astyle_code
Все ваши с-файлы станут с выровненными отступами. Автоматически... Крастота!
Достоинства авто форматирования из-под скриптов сборки (GNU Make)
++Форматирование отступов из-под системы сборки тем хорошо, что вы можете к одной и той же кодовой базе в репозитории применять различные форматирования в зависимости от программного компонента. Например две команды разработчиков в одно репе работают. В то время как форматирование git hook (ами) заставляет причесывать весь репозиторий под одну гребёнку. А это недопустимо.
++Дело в том, что далеко не все компании вообще используют системы контроля версий. Там даже понятие такое, как "коммит" отсутствует. Вот в одном секретном предприятии мы писали прошивки для электронных плат и прошивки передавали в *.zip архиве через USB флешку, или архивом по внутренней электронной почте ЧебурНета. Никакой системы контроля версий вообще не было из-за конспирации. Вот и оставалось делать автоформатирование из скриптов сборки.
++Благодаря скриптам сборки make Вы можете форматировать разными утилитами. Одной после другой. Сначала пройтись clang format-ом а потом причесать astyle-лом.
Итоги
Как видите, сборка из скриптов (в частности make) дает такие преимущества как автоматическое выравнивание отступов исходного кода.
Понятное дело, что если вы собираете программы из IDE мышкой, то вам такое и многое другое просто не доступно в принципе. Поэтому имеет смысл задуматься о переносе проекта на сборки скриптами.
А с Make удалось с полпинка вмонтировать утилиту astyle в основной конвейер сборки прошивки. Успех!
Удалось наладить автоматическое выравнивание отступов согласно специфическому стилю оформления исходных текстов программ.
Ссылки
Вопросы
Господа, буду очень признателен, если поможете мне найти code-style утилиты для решения вот этих прикладных задач:
Существует ли авто форматирование Си-кода, который принудительно и всегда выставляет аргументы функции в столбик? Вот так:
STD_RESULT GPIO_SetPinState(const U8 nPortNumber,
const U8 nPinNumber,
const U8 nLogicState)
{..............}
Утилиты Clang-format, Astyle и GNU indent не предлагать, так как там таких ключей просто нет.Существует ли утилита для сортировки прототипов и определений функций в алфавитном порядке?
Существует ли утилита, которая в Си-коде автоматически делает порядок объявления static функций совпадающим с порядком определения static функций?
Существует ли утилита, которая в Си-коде автоматически делает порядок объявления функций совпадающим с порядком определения функций?
Существует ли утилита, которая в Си-коде автоматически делает в конце файла надпись //****************************************** end of file *******************************************
?Существует ли утилита, которая в Си-коде автоматически делает для всех объявлений глобальных функций в h-файле обязательно ключевое слово extern?
Существует ли утилита, которая в Си-коде автоматически делает ко всем константам для указания размера массива обязательно суффикс U? Пример: не Array[10] а Array[10U]