в каком порядке выполняется Makefile?
NAME = test
CC = gcc
CFLAGS = -Wall -Wextra -Werror
INC = -I ./include
FILES = test.c main.c
LIBFT = ../ft_printf/libftprintf.a
OBJ = $(addprefix build/, $(FILES:.c=.o))
SRC = $(addprefix src/, $(FILES))
all: $(NAME)
$(NAME): $(OBJ)
@$(CC) -o $(NAME) $(LIBFT) $(OBJ)
build/%.o: src/%.c | build
@$(CC) -c $(CFLAGS) $(INC) $< -o $@
build:
@mkdir build
Если выполнить команду Make в каком порядке будет сборка? я думал будет выполнятся all: $(NAME) и после $(NAME): $(OBJ), но откуда make знает что нужно выполнить build/%.o: src/%.c | build @$(CC) -c $(CFLAGS) $(INC) $< -o $@ build: @mkdir build?
Ответы (1 шт):
При запуске без параметров make выполняет первую цель. Хотя так говорить не правильно. make работает (как минимум) в два прохода: сперва отыскивает все зависимости (это вроде поиска в ширину в графе), затем выполняет команды в обратном порядке.
Итак первая цель all. Она зависит от пререквизита (цели) test. "Зависит" означает что чтобы достигнуть цели all, нужно достигнуть цели test. Здесь и далее я буду раскрывать макросы, чтобы была видна механика:
all: test
Цель test зависит от build/test.o и build/main.o. Чтобы достигнуть её, нужно построить два объектных файла и запустить gcc для сборки исполнимого модуля:
test: build/test.o build/main.o
gcc -o test ../ft_printf/libftprintf.a build/test.o build/main.o
Цель build/test.o соответствует обобщенному правилу. По нему она зависит от build/test.с и build. На значок | пока не обращайте внимания. Обобщённое правило порождает конкретное правило:
build/test.o: src/test.c | build
gcc -c -Wall -Wextra -Werror -I ./include src/test.с -o build/test.o
Цель build/main.o обрабатывается аналогично:
build/main.o: src/main.c | build
gcc -c -Wall -Wextra -Werror -I ./include src/main.с -o build/main.o
Цели src/test.c и src/main.c не имеют соответствующих правил. В этой ситуации make убеждается что такие файлы есть на диске и помечает цели как достигнутые.
Цель build ни отчего не зависит, но приводит к созданию каталога build если его ещё не было на диске:
build:
mkdir build
Поиск завершён. Теперь выполняем команды в обратном порядке:
mkdir build
gcc -c -Wall -Wextra -Werror -I ./include src/test.с -o build/test.o
gcc -c -Wall -Wextra -Werror -I ./include src/main.с -o build/main.o
gcc -o test ../ft_printf/libftprintf.a build/test.o build/main.o
В описании поиска в графе я опустил сравнение времен файлов. make сравнивает времена цели и её пререквизитов и если цель свежая, то она считается достигнутой сразу.
Вы можете попросить make показать какие команды от собирается исполнить (make -n) или объяснить почему он собирается их выполнять (make --trace).
В комментариях заметил важный момент. make все цели считает файлами на диске. Если у вас на диске окажется файл с именем all и дата у него будет свежее чем у test, то make посчитает что делать ничего не надо. Цели, которые "не файлы" помечайте так:
.PHONY: all
all: test