LINUX.ORG.RU

Предварительный этап в Makefile

 ,


1

1

Приветствую.

Есть следующая структура каталогов:

.
├── interrupts
│   ├── handlers
│   │   ├── file.a65
│   │   └── Makefile // Вложенный
│   └── Makefile // Вложенный
├── defines.mk
├── common.mk
└── Makefile // Корневой

В первую очередь, файл defines.mk:

PROJECT_NAME = xxx

PROG_AS ?= ca65
PROG_LD ?= ld65
PROG_DOX ?= doxygen
PROG_RM ?= rm -f
PROG_MV ?= mv -f
PROG_MKDIR ?= mkdir -p
PROG_FIND ?= find
PROG_MAKE ?= make

DIR_BUILD ?= build

Файл common.mk

TARGET_SUBMAKE = $(shell \
	$(PROG_FIND) \
	. \
	-mindepth 2 \
	-type f \
	-name Makefile \
	-printf '%h\n' \
)

TARGET_SRC = $(shell \
	$(PROG_FIND) \
	. \
	-maxdepth 1 \
	-type f \
	-name '*.a65' \
	-printf '%f\n' \
)

TARGET_OBJ = $(patsubst \
	%.a65, \
	$(DIR_BUILD)/$(PROJECT_NAME)/%.o, \
	$(TARGET_SRC) \
)

.PHONY: all $(PROJECT_NAME) $(TARGET_SUBMAKE)

$(DIR_BUILD)/$(PROJECT_NAME)/%.o : %.a65
	$(PROG_MKDIR) \
	    $(DIR_BUILD)/$(PROJECT_NAME)
	$(PROG_AS) \
	    -o $@ \
	    $<

$(TARGET_SUBMAKE):
	$(PROG_MAKE) \
	    -C $@ \
	    MAKEFILE_DEF=$(MAKEFILE_DEF) \
	    MAKEFILE_COMMON=$(MAKEFILE_COMMON) \
	    DIR_BUILD=$(DIR_BUILD)

$(PROJECT_NAME): $(TARGET_SUBMAKE) $(TARGET_OBJ)

all: $(PROJECT_NAME)

Корневой Makefile

MAKEFILE_DEF    := $(CURDIR)/defines.mk
MAKEFILE_COMMON := $(CURDIR)/common.mk

include $(MAKEFILE_DEF)
include $(MAKEFILE_COMMON)

.PHONY: doc clean

all: doc

doc:
	$(PROG_DOX) Doxygen

clean:
	$(PROG_RM) $(DIR_BUILD)/$(PROJECT)/*.o

Вложенные Makefile (все одинаковые)

include $(MAKEFILE_DEF)
include $(MAKEFILE_COMMON)

Итак, в чём вопросы:

1

Оно сейчас работает. Но меня не устраивает, что оно на каждый файл вызывает создание целевого каталога (см.

$(DIR_BUILD)/$(PROJECT_NAME)/%.o : %.a65
	$(PROG_MKDIR) \
	    $(DIR_BUILD)/$(PROJECT_NAME)
	...

). Что я пытался сделать: а) Вынести mkdir в отдельный сегмент и вызывать как $(DIR_BUILD)/$(PROJECT_NAME)/%.o : %.a65 | build-dir
б) Вынести mkdir в отдельный сегмент и вызывать тут: $(PROJECT_NAME): build-dir $(TARGET_SUBMAKE) $(TARGET_OBJ)

Оба варианта приводят к тому, что при вызове корневого make он просто создаёт директорию и даже не пытается заходить в дочерние Makefile.

2

Приветствуется общая критика. Я не эксперт в make, соответственно буду рад услышать, что я делаю не так.

P.S. Сразу уточню насчёт build директории. «Корневой» makefile на самом деле тоже не корневой и его вызывают выше с

DIR_BUILD := $(CURDIR)/build

make -C code/xxx DIR_BUILD=$(DIR_BUILD)
★★★★★
Ответ на: комментарий от wandrien

Я немного наискосок всё читаю, вообще думал про вариант с дописыванием build-dir в зависимость проекта в начало. Он про него пишет что он у него не работает.

А что делает | в make я не помню и вообще игнорировал эту ветку.

firkax ★★★★★
()
Ответ на: комментарий от wandrien

Что именно в словах

а) Вынести mkdir в отдельный сегмент и вызывать как $(DIR_BUILD)/$(PROJECT_NAME)/%.o : %.a65 | build-dir б) Вынести mkdir в отдельный сегмент и вызывать тут: $(PROJECT_NAME): build-dir $(TARGET_SUBMAKE) $(TARGET_OBJ)

вам непонятно?

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от firkax

| делает так, что более новый mtime у зависимости не приводит к пересборке того, что указано зависящим.

Но если зависящая цель отправлена на пересборку по иным зависимостям, то тогда |-зависимость тоже проверяется, и если требуется, то пересобирается.

Это ровно то, что ты описывал к проблематике каталогов в начале ветки, и ровно то, что нужно для ТСа.

Эта фича была в том числе и для создания каталогов придумана.

Как выше уже уточнили, это GNU-тое расширение.

wandrien ★★★
()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от firkax

diff common.mk: https://pastebin.com/UkGt7YFB
когда не работает: https://pastebin.com/NwkggyfM
когда работает: https://pastebin.com/pGVKfUan
Рабочий common.mk (но на каждый файл вызывает mkdir): https://pastebin.com/8jfZhzJy
Нерабочий common.mk (создается только директория, не работает рекурсивный спуск: https://pastebin.com/QZhMtXZN

То же самое поведение, если написать $(DIR_BUILD)/$(PROJECT_NAME)/%.o : %.a65 | build-dir

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Нерабочий common.mk

Какую цель выполняет make по умолчанию?

Ты бы, дурень, слушал, что тебе говорят умные люди, вместо своих понтов, тогда может чего и набрался бы в свою голову: Предварительный этап в Makefile (комментарий)

Какая цель у тебя первой указана в файле?

wandrien ★★★
()
Ответ на: комментарий от wandrien

Я уже устал от того, что вы не умеете читать. Самый первый пост буквально содержит ПОЛНОЕ содержимое ВСЕХ файлов.

И ВЫШЕ, в том самом common.mk, в который вы таки смогли заглянуть и найти знакомые буквы написано:

$(PROJECT_NAME): build-dir $(TARGET_SUBMAKE) $(TARGET_OBJ)
 
all: $(PROJECT_NAME)

А в самом первом посте (в котором вы, очевидно, знакомые буквы найти не смогли) написано:

.PHONY: all $(PROJECT_NAME) $(TARGET_SUBMAKE)
PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

.PHONY это не цель. Это ключевое слово такое.

Какая цель ПЕРВОЙ указана в файле и НЕ НАЧИНАЕТСЯ С ТОЧКИ?

Для особо одарённых помогу с цитатой:

   By default, the goal is the first target in the makefile (not
counting targets that start with a period).  Therefore, makefiles are
usually written so that the first target is for compiling the entire
program or programs they describe.  If the first rule in the makefile
has several targets, only the first target in the rule becomes the
default goal, not the whole list.  You can manage the selection of the
default goal from within your makefile using the '.DEFAULT_GOAL'
variable (*note Other Special Variables: Special Variables.).
wandrien ★★★
()
Последнее исправление: wandrien (всего исправлений: 1)