«Если смотреть на закипающий чайник, то он никогда не закипит»
Пролог
Компиляцию большой программы можно сравнить с кипячением воды. Вы никогда не можете сказать сколько еще осталось ждать до окончания процесса. Многим пользователям GUI-IDE приходится страдать от того, что запустив сборку проекта приходится ждать окончания непредсказуемое время.
Однако эту проблему можно решить если собирать код скриптами сборки. Достоинством сборки проекта из самостоятельно написанных скриптов является то, что в процесс сборки можно добавлять всяческие полезные механизмы. Вы программируете не только свою прошивку, но и процесс сборки самой прошивки.
В этом тексте я написал про то, как добавить индикатор прогресса в процесс сборки прошивки.
Теория
переменная окружения - ( environment variable) — это просто текстовая строка. Её видят все процессы в операционной системе. Благодаря переменным окружения программы могут получать себе конфиги.
инкрементировать - увеличивать на единицу
Реализация
Основная идея очень проста. Надо сначала посчитать сколько нам надо собрать объектных файлов TOTAL_FILES, затем собирать си файлы один за другим и каждый раз увеличивать на единицу отдельную переменную окружения CURRENT_CNT. После каждой сборки файла печатать в консоль рациональное число CURRENT_CNT/TOTAL_FILES для оценки проделанной работы на текущем этапе. Но обо всем по порядку.
Проще всего сделать progress bar как раз в случае когда, в качестве системы сборки выбран GNU Make.
Утилита make хороша тем, что может работать практически с неограниченным количеством переменных окружения.
Первым делом надо определить сколько всего файлов участвует в сборке программы. Это можно определить просто просчитав количество слов в переменной окружения OBJECTS
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES_TOTAL_C:.c=.o)))
TOTAL_FILES := $(words $(OBJECTS))
$(info TOTAL_FILES:$(TOTAL_FILES) )
Да. В языке make есть функции которые могут получать аргументы и возвращать результат.
Имя функции GNU Make |
Назначение |
info |
функция печатает то, что передается ей в аргументы в stdout |
eval |
это функция, которая позволяет вычислять простые математические формулы. Позволяет определять не постоянные переменные. То есть в переменную помещает результат оценки других переменных или функций. Аргумент функции eval расширяется. eval функция ничего не возвращает |
notdir |
извлечь имя файла отбросив информацию об расположении папки |
shell |
это функция, которая может общаться с окружением вне make-файла |
addprefix |
Добавляет приставку к каждому слову в переменной окружения |
words |
Возвращает количество слов в тексте |
Львиную долю процесса сборки занимает компиляция си-файлов. Поэтому имеет смысл инкрементировать переменную окружения CURRENT_CNT каждый раз, когда происходит одно преобразование из *.с файла в *.o файл.
Перед вами правило получения объектных файлов.
Цель (что надо получить) : зависимости (исходное сырье)
действия для достижения цели (рецепты)
В этом вся суть GNU Make.
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
$(eval CURRENT_CNT=$(shell echo $$(($(CURRENT_CNT)+1))))
@echo Compiling $(CURRENT_CNT)/$(TOTAL_FILES) $@
@ $(CC) -c -MD $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
Тут оператор @ перед вызовом компилятора нужен для того, чтобы не печатать строку в консоль а только запустить ее на исполнение. Когда строка начинается с @, то эхо набора команды подавляется. Это нужно, чтобы не захламлять многословием лог сборки проекта, ибо переменная окружения CFLAGS содержит длинные пути к заголовочным файлам и плотные пучки опций для компилятора gcc.
Тут можно еще заметить специальную переменную $@. Она просто заменяется на имя цели обрабатываемого правила. Это раскроется в объектные файлы build/test_libc.o build/test_sw_list.o build/test_drv8870.o и т д
Специальная переменная $< - это имя первой зависимости обрабатываемого правила. В данном случае это си файлы.
Всё готово. Теперь можно и запустить сборку программы набрав make all.
В натуре выглядит это так.

Как по, мне очень наглядно.
Итог
Удалось добавить в процесс сборки индикацию прогресса буквально добавив всего 3 строчки кода в скрипт сборки проекта. Вот так просто и не затейливо. Вам уже нравится GNU Make?
Теперь больше нет мучительных ожиданий окончания компиляции. Всё стало прозрачнее и понятнее. Можно распределять свое внимание между другими задачами.
Ссылки
Название |
URL |
Сколько Надо Строк Кода Для Того Чтобы Подписать Артефакты? (3 строки в Makefile) |
|
Генерация зависимостей внутри программы в Makefile |
|
Сборка firmware для CC2652 из Makefile |
|
ToolChain: Настройка сборки прошивок для микроконтроллеров Artery из Makefile |
|
Интеграция clang-format в Процесс Сборки c Makefile |
|
Как составить функцию инициализации микроконтроллера в Makefile |
|
Как собрать Си программу в OS Windows через Makefile |
|
Автоматическое Обновление Версии Прошивки в Makefile |
|
Настройка ToolChain(а) для Win10+GCC+С+Makefile+ARM Cortex-Mx+GDB |
|
Обновление Прошивки из Make Скрипта |
|
Почему важно собирать код из скриптов |
|
Вёрстка Учебника (LaTeX + CPP + GNU Make + Jenkins = Учебник) |
|
Почему Сборка с Помощью Есlipse ARM GCC Плагинов это Тупиковый Путь |
|
Сортировка Конфигов для Make Сборок |
|
Техникум: Автоматическое Aрхивирование Aртефактов в Makefile |
|
Сборка и отладка прошивки IoT-модуля: Python, make, апельсины и чёрная магия |
Комментарии (7)

zubrbonasus
13.11.2025 19:22Можно доверить сборку бинарника ci скрипту и делать это все на сервере, занимаясь при этом разработкой следующих задач.

aabzel Автор
13.11.2025 19:22Уже сделано
Пуск Сервера Сборки Jenkins
https://habr.com/ru/articles/695978/

viordash
13.11.2025 19:22а Вы не рассчитываете запускать сборку проектов в несколько потоков? например make all -j8
kipar
В CMake по умолчанию такой индикатор.
randomsimplenumber
Но его можно отключить ;)