«Если смотреть на закипающий чайник, то он никогда не закипит»
Пролог
Компиляцию большой программы можно сравнить с кипячением воды. Вы никогда не можете сказать сколько еще осталось ждать до окончания процесса. Многим пользователям 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, апельсины и чёрная магия |
Комментарии (11)

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

PoksPoks
13.11.2025 19:22Симпатичное решение, три строки кода за наглядность процесса сборки выглядят вполне честной ценой

13werwolf13
13.11.2025 19:22занимательное совпадение, как раз сегодня раздумывал над выводом прогресса силами make и Makefile. Ваше решение мне однозначно нравится, жаль что не применимо для того что нужно мне, но верное направление я точно получил.

DirectoriX
13.11.2025 19:22Многим пользователям GUI-IDE приходится страдать от того, что запустив сборку проекта приходится ждать окончания непредсказуемое время.
У меня в MS VS прям графический прогресс-бар рисуется :)
Простой счётчик файлов в принципе не сильно поможет решить проблему "Вы никогда не можете сказать сколько еще осталось ждать до окончания процесса":
есть великое множество single-header библиотек, они просто не попадут в счётчик как он есть. Это легко исправить, но...
файл на 50 строк и файл на 1050 строк будут собираться за очень разное время. Очень может быть, что у вас не очень большая программа, которая по тем или иным причинам собирает SQLite из его амальгамации - там пара
.hи.cзанимают вместе под 10 мегабайта ещё после сборки чаще всего идёт линковка, и может быть не одна (если это какой-то массивный проект с пачкой промежуточных библиотек), и может быть ещё и с LTO, которое может линковку замедлить в десятки раз
В итоге, конечно, со счётчиком чуть нагляднее, чем совсем вслепую, но не сильно точнее, чем прогресс-бары / счётчики при копировании файлов: есть и число файлов, и суммарный объём, и подсчёт уже затраченного времени - но предсказание всё равно плавает как ветка в шторм
kipar
В CMake по умолчанию такой индикатор.
randomsimplenumber
Но его можно отключить ;)