У меня есть готовый 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. Пост будет не полон без ссылки на толковый ман