Сортировка Конфигов для Make Сборок

1e9975d58d99aec183ea9b057eff402d.png

Как известно любая большая программа на Си содержит много программных компонентов и, как следствие, много настроек: констант, макросов, конфигурационных структур и прочего. Всё это можно назвать одним словом: конфиги.

Все передают конфиги по-разному. Это один из религиозных аспектов в программировании микроконтроллеров. Junior разработчики прописываю прохардкоженные константы в каждом файле проекта или пихают всё в config.h, который подом вручную подключают #include (ом) во все файлы, Middle программисты передают конфиги через переменные окружения, Senior (ы) вообще передают конфиги через Device Tree и механизм Kconfig.

Терминология

Конфиг — набор определенных переменных окружения, которые используются при сборке программы (например на Си).

Цель — последовательность процессов, которые запускает утилита make, чтобы получить какой-то файл или просто выполнить действие.

Сборка — это папка с настройками конкретного проекта программы и артефакты. Обычно сборка это комплект следующих файлов: Makefile, config.mk, version.h. Если Вы работаете в Eclipse, то к файлам сборки также относятся настройки текстового редактора Eclipse для этой конкретной сборки. Это файлы *.project *.cproject. Всё перечисленное следует подвергать версионному контролю (например в GIT). Сборка порождает артефакты. Это файлы *.hex, *.bin, *.map, *.elf. Хорошей практикой считается, когда в папке со сборкой даже нет ни одного *.с файлика! Всё, что нужно сборка берёт из общей пере используемой кодовой базы, которая лежит в другой папке.

Пролог

У нас в репозитории есть много сборок (порядка 350) на все случаи жизни, где конфиги передаются прямо через переменные окружения прописанные в make скриптах.

У каждой сборки есть файл config.mk в котором перечислены программные компоненты из которых должна собираться эта конкретная сборка. Содержимое этого файла обычно выглядит так.

#Do not include .mk files here. That is general global configuration
ADC=Y
ADC_ISR=Y
ADT=Y
ALLOCATOR=Y
ARRAY=Y
ASICS=Y

....

TASK=Y
TBFP=Y
TERMINAL=Y
TIME=Y
UART0=Y
UART2=Y
UNIT_TEST=Y
UTILS=Y
UWB=Y

Это просто атомарные строчки. Тут происходит определение переменных окружения. Декларативно перечисляется из чего собирать прошивку. У другой сборки есть свой такой же декларативный config.mk файл и свой собственный набор переменных окружения.

В чем проблема?
1--Проблема в том что, когда сборок становится слишком много, то их приходится создавать по образу и подобию других сборок. Потом внезапно возникает потребность сравнить конфиги и выясняется, что конфиги отличаются не потому, что состоят из разных программных компонентов, а потому, что конфиг файлы перечислены в случайном порядке (не отсортированы). Как известно, правда в том, что минимальный diff будет у двух отсортированных файлов.

2--При командной разработке разные разработчики не глядя на существующий конфиг повторно добавляют новые конфиги, которые дублируют старые конфиги. Иногда они добавляют вперед и их конфиг не применяется. Когфиг перетирается предшественником. Если же добавляют конфиг в конец и он обнуляет конфиг предшественника. В общем это порождает анархию и взаимную ненависть.

3--Когда конфиг отсортирован, то его проще просматривать и искать в нем что -то. Также легче найти место для вставки нового нужного конфига методом визуального бинарного поиска.

В связи с этим возникают две задачи:

1--Удалить повторяющиеся конфиги.

2--Отсортировать конфиги по алфавиту.

Как отсортировать конфиги?

1--Понятное дело что вручную никто не хочет сортировать 150 строчек в файле. Дело в том что очень мало российских программистов вообще знают сколько букв содержится в английском алфавите и еще меньше людей могут сходу взять карандаш и правильно написать порядок букв английского алфавита. И это нормально! Надо просто автоматизировать процесс сортировки файла.

2--Можно написать отдельный *.bat файл для сортировки когфигов культовой консольной утилитой sort.exe. Утилиту sort можно установить из пакета CygWin. Однако вам придется при добавлении каждой новой сборки также прописывать новую строчку в этом *.bat файле сортировки. По факту оказалось что людям просто лень этим заниматься. И это тоже нормально!

3--Самое правильное решение — это встроить сортировку конфигов в сам процесс сборки артефактов. К счастью мы использует GNU Make и тут это сделать очень просто. Для этого надо всего лишь определить ещё одну крохотную цель.

SORTER_TOOL=C:/cygwin64/bin/sort.exe
$(info Sort Program config)

$(info MK_PATH=$(MK_PATH))
MK_PATH_WIN := $(subst /cygdrive/c/,C:/, $(MK_PATH))
$(info MK_PATH_WIN=$(MK_PATH_WIN))
$(info WORKSPACE_LOC=$(WORKSPACE_LOC))

PROJECT_DIR=$(MK_PATH_WIN)

CONFIG_FILE=$(PROJECT_DIR)/config.mk
$(info CONFIG_FILE=$(CONFIG_FILE))

#CONFIG_FILE:=$(subst /cygdrive/c/,C:/, $(CONFIG_FILE))
#$(info CONFIG_FILE=$(CONFIG_FILE))

sort_config: $(CONFIG_FILE)
	$(info SortConfig...)
	$(SORTER_TOOL) -u $(CONFIG_FILE) -o $(CONFIG_FILE)

Тут опция -u означает что утилита будет удалять повторения, конструкция $(CONFIG_FILE) -o $(CONFIG_FILE) означает, что имя файла на выходе будет совпадать с именем файла на входе. Получается сортировка in place.

Затем надо открыть основной rule.mk и встроить туда новую цель sort_config. Перед сборкой сорцов отсортировать конфиг


EXTRA_TARGETS += sort_config
EXTRA_TARGETS += $(DEPENDENCY_GRAPH)
EXTRA_TARGETS += $(STATIC_ANALYSIS_TARGET)
EXTRA_TARGETS += $(CLI_COMMAMD_LIST_GENERATE)
EXTRA_TARGETS += $(PREPROCESS_CODE_BASE)
EXTRA_TARGETS += generate_definitions

# default action: build all 
all: $(EXTRA_TARGETS) $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin 

generate_definitions:
	cpp $(CPP_FLAGS) $(WORKSPACE_LOC)empty_sourse.c -dM -E> c_defines_generated.h

Достоинство rule.mk в том, что он общий на все 350 сборок в нашем репозитории. И нам не нужно ничего больше прописывать в настройках каждого проекта, как если бы мы программировали микроконтроллер в пресловутом IAR или Keil.

Теперь если вы откроете папку сборки в консоли и напишите make all, Вы через минуту получите не только артефакты, но и чистый конфиг!

Сортировка нужна не только в сортировке конфигов. Автоматический форматировщик отступов в Си коде clang-format.exe, например, еще сортирует #include по алфавиту.

Итоги

Сортировка всегда хороша, когда от нее есть польза, например как тут это дает сокращение времени поиска сравнения конфигов и исключает ошибки на фазе прописывания этих самых конфигов.

При этом сортировка это признак наличия какого-то разума и культуры. Например посвящённые страны сортируют даже бытовые отходы.

Как видите, использование сборки из-под скриптов позволяет Вам помимо самой сборки артефактов еще и выполнять всяческую инфраструктурную DevOps (овую) работу. Это особенно просто и легко делается в GNU Make.

Links

https://ru.wikipedia.org/wiki/Sort

Почему Важно Собирать Код из Скриптов https://habr.com/ru/articles/723054/

© Habrahabr.ru