August 29th, 2019

Лампа

Makefile

Может показаться смешным и забавным, но не смотря на то, что я программирую большую часть своей сознательной жизни, я никогда особо не умел писать мейкфайл.
У меня есть готовый Make, который кочует из проекта в проект и я его редактирую по мере надобностей. Ну я просто правил его под свои нужды, не особо задумываясь над смыслом того, что происходит. И тут ВНЕЗАПНО решил на make сделать систему сборки. Не, ну а чего, в ядре, убуте и прочем есть make, питон есть не везде и не всегда, и типа система сборки должна быть на нём.

Основная проблема была даже не в самом make, а тупо в самом подходе системы сборки. Когда ты собираешь что-то здоровенное с подтягиванием с гитов, созданием образов и т.п. - это очень долго. Пересборка может занимать 20 минут. И если ты ошибся, то минус 20 минут. Десять ошибок с поиском и редактированием - минус пол рабочего дня. Тут make конечно не при чём.

А вот теперь о Make. Все инструкции по мейкфайлам написаны людьми, которые на них съели собаку и пока не попробуешь что же там написано, нифига непонятно что они хотели сказать. Итак, ряд открытий, которые я сделал.

1. Makefile - двухпроходной. Сначала инициализируются переменные и цели, а потом уже выполняется. Это хорошо и плохо. Хорошо, потому что не надо думать в каком месте у тебя находится цель.

2. Переменные. Это вообще раздел специальной олимпиады (примерно как + ++ +++ в js).
Простой пример, задание переменной идёт как обычно:

imagename:="image.img" , но есть нюанс.
imagename="image.img" - это уже не строгое присваивание. Может быть сделано во второй проход...

Обращение к переменной идёт ВНЕЗАПНО через функцию. $(imagename) - это не как в BASH обращение к переменной, это обращение к функции, которая возвращает значение переменной!!! Доказательство, что это функция в следующем коде

gitcheckout= cd $(1) && git checkout $(2) && cd ..
...
trololo:
	$(call gitcheckout, $(dtsdir), master)


Или ещё интереснее:

current_dir = $(shell pwd)

Получает текущую дирректорию в переменную, к которой будет обращение через функцию. Функции могут быть рекурсивными. Отсюда идёт третий пункт.

3. bash в Make - это боль и унижение...
Серьёзно, я внятно так и не понял как использовать переменные bash в Make. В результате использую временные файлы, в которое сохраняю содержимое... А. Ещё многострочное надо писать таким образом ;\ . При чём, при такой записи надо самостоятельно проверять ошибку в коде bash, make никак не проверяет эту порнографию. Вот пример извращений
$(imagename): 
	{ \
	fallocate -l $(imagesize) $(imagename) ; \
	sudo losetup --find --show $(imagename) > mountpoint ; \
	sudo parted --script `cat mountpoint` mklabel msdos ; \
	sudo parted --script `cat mountpoint` mkpart primary fat32 0% 100M ; \
	sudo parted --script `cat mountpoint` mkpart primary ext4 100M 100% ; \
	sudo mkfs.vfat -F32  `cat mountpoint`p1 ; \
	sudo mkfs.ext4 -F  `cat mountpoint`p2 ; \
...
	}


Простой кусок кода, который алокирует разреженный файл заданной длинный, потом монтирует его как loop-устройство и дальше мы начинаем его размечать. Вместо того, чтобы написать, как в bash (кавычка где буква "Ё")

mountpoint=`sudo losetup --find --show $(imagename)`
sudo parted --script $mountpoint mklabel msdos 


Пришлось городить этот цирк с конями. Пока писал этот пост, подумал, что можно было через функцию $(shell sudo losetup --find --show $(imagename)) , но лень пробовать.

В общем если нужна помощь по Make и вы боялись спросить, то у вас есть уникальный шанс!

P.S. Пост будет не полон без ссылки на толковый ман