Ответ 1
Ошибка missing separator
происходит из-за непустого возвращаемого значения include_submake
, который является символом перевода строки в вашем случае. Сделать только разрешать пробельные символы (то есть пробел или табуляцию) в выражении, которое не считается частью какого-либо правила или другой директивы.
Перепишите свои функции с помощью простого назначения переменной Make make и ошибка должна исчезнуть:
push_dir = \
$(info $1)
pop_dir = \
$(info $1)
include_submake = \
$(call push_dir,$1) \
$(call pop_dir,$1)
UPD.: define
против простого назначения старой переменной
Отвечая на вопрос с первого комментария. Лично я предпочел бы использовать директиву define
в нескольких случаях.
Использование с функцией eval
Как указано в руководстве GNU Make, директива define
очень полезна в сочетании с функцией eval
. Пример из руководства (акцент мой):
PROGRAMS = server client server_OBJS = server.o server_priv.o server_access.o server_LIBS = priv protocol client_OBJS = client.o client_api.o client_mem.o client_LIBS = protocol # Everything after this is generic .PHONY: all all: $(PROGRAMS) define PROGRAM_template $(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%) ALL_OBJS += $$($(1)_OBJS) endef $(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog)))) $(PROGRAMS): $(LINK.o) $^ $(LDLIBS) -o [email protected] clean: rm -f $(ALL_OBJS) $(PROGRAMS)
Шаблоны генераторов
Вербальные переменные идеально подходят для случаев, когда вы хотите сгенерировать файл из GNU Make. Например, рассмотрим создание файла заголовка на основе некоторой информации из Makefile.
# Args: # 1. Header identifier. define header_template /* This file is generated by GNU Make $(MAKE_VERSION). */ #ifndef $(inclusion_guard) #define $(inclusion_guard) $(foreach inc,$($1.includes), #include <$(inc).h>) /* Something else... */ #endif /* $(inclusion_guard) */ endef # 1. Unique header identifier. inclusion_guard = \ __GEN_$1_H # Shell escape. sh_quote = \ '$(subst ','"'"',$1)' foo.includes := bar baz HEADERS := foo.h $(HEADERS) : %.h : @printf "%s" $(call sh_quote,$(call header_template,$(*F)))> [email protected]
Синтаксис Extended Make
В нашем проекте мы используем нашу собственную систему сборки Mybuild, и она полностью реализована поверх GNU Make. Как один из низкоуровневых хаков, которые мы использовали для улучшения плохого синтаксиса встроенного языка Make, мы разработали специальный script, который позволяет использовать расширенный синтаксис для определения функций. Сам script также написан в Make, поэтому он является своего рода мета-программированием в Make.
В частности, можно использовать такие функции, как:
- Определение многострочных функций без использования обратного слэша
- Использование комментариев внутри функций (в простом-старом блоге) Комментарии могут возникать только вне директив назначения переменных)
- Определение настраиваемых макросов типа
$(assert ...)
или$(lambda ...)
- Вложение простых функций, таких как
$(eq s1,s2)
(проверка равенства строк)
Это пример того, как функция может быть написана с использованием расширенного синтаксиса. Обратите внимание, что он становится действительной функцией Make и может быть вызван как обычно после вызова $(def_all)
.
# Reverses the specified list. # 1. The list # Return: # The list with its elements in reverse order. define reverse # Start from the empty list. $(fold ,$1, # Prepend each new element ($2) to # the result of previous computations. $(lambda $2 $1)) endef $(def_all)
Используя эти новые функции, мы смогли реализовать некоторые действительно классные вещи (ну, по крайней мере, для Make:-)), включая:
- Объектно-ориентированный уровень с распределением динамических объектов, наследование классов, вызовы методов и т.д.
- Механизм выполнения парсера LALR для парсеров, сгенерированный GOLD Parser Builder
- Библиотека моделирования с поддержкой времени выполнения для моделей, созданных с помощью EMF
Не стесняйтесь использовать любую часть кода в своих проектах!