Makefile отсутствует разделитель

Хорошо, я застрял на этом, и я понятия не имею, что я делаю неправильно. Все отлично работало над более сложным make файлом, но вдруг я получил ошибку "Отсутствующий разделитель". Я смог изолировать его до очень простого сценария:

test.mk

define push_dir
$(info ${1})
endef

define pop_dir
$(info ${1})
endef

define include_submake
$(call push_dir,${1})
$(call pop_dir,${1})
endef

Простой

include test.mk

INITIAL_SUBMAKE:= includeme.mk
$(call include_submake,${INITIAL_SUBMAKE})

process:
    @echo Processed...

И вывод:

C:\project>make -f Simple process
includeme.mk
includeme.mk
Simple:4: *** missing separator.  Stop.

includeme.mk фактически не существует. Я понятия не имею, что здесь происходит. Я пробовал множество вещей. Если я окружаю вызов include_submake в такой информации:

$(info $(call include_submake,${INITIAL_SUBMAKE}))

Отсутствует ошибка разделителя. Кроме того, если в include_submake define я вызываю только одну из функций, она работает нормально. Кроме того, если я непосредственно вызываю функции вместо их вызова include_submake, он также работает:

include test.mk

INITIAL_SUBMAKE:= includeme.mk
$(call push_dir,${INITIAL_SUBMAKE})
$(call pop_dir,${INITIAL_SUBMAKE})

process:
    @echo Processed...


C:\project>make -f Simple process
includeme.mk
includeme.mk
Processed...

Мне кажется, что я не замечаю здесь ничего принципиального. Благодарим за помощь.

Ответы

Ответ 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)))&gt [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

Не стесняйтесь использовать любую часть кода в своих проектах!

Ответ 2

Я столкнулся с той же проблемой. Я вставил "вкладку", удалил "вкладку", повторно вставил, чтобы быть уверенным. Такое же сообщение об ошибке.

Но я сделал все это внутри XCodem, к моему удивлению, вставил белые пробелы, а не '\ t'. Когда я использовал другой редактор, эти ошибки phantom исчезли.

HTH...