Как сделать функцию makefile, которая генерирует правила возврата к построенным объектам - PullRequest
0 голосов
/ 27 марта 2019

У меня есть текущий код Это позволяет мне легко создавать объектные файлы из двоичных файлов

define ASSET_RULE
$(addsuffix .o,$(basename $(1))): $(1)
    $(LD) -r -b binary $(1) -o $(addsuffix .o,$(basename $(1)))
endef


SRC=avatar.jpg  \
    avatar2.png

OBJ=$(addsuffix .o,$(basename $(SRC)))

NAME=assets.a

all: $(NAME)

$(foreach file,$(SRC), $(eval $(call ASSET_RULE,$(file))))

$(NAME): $(OBJ)
    $(AR) rcs $(NAME) $(OBJ)

clean:
    $(RM) $(OBJ)

fclean: clean
    $(RM) $(NAME)

re: fclean all

.PHONY: clean fclean all re

Я хотел бы сделать функцию, которая принимает активы в качестве параметра, генерирует для них правила и возвращает мне файл .o для компиляции в качестве зависимостей. К концу я ожидаю что-то вроде.

ASSETS=avatar.jpg   \
    avatar2.png

OBJ=$(call BINARY_ASSETS,$(ASSETS))

NAME=assets.a

all: $(NAME)

$(NAME): $(OBJ)
    $(AR) rcs $(NAME) $(OBJ)

clean:
    $(RM) $(OBJ)

fclean: clean
    $(RM) $(NAME)

re: fclean all

.PHONY: clean fclean all re

Я пытался объединить цикл foreach eval с окончательными именами объектов, однако я получаю *** prerequisites cannot be defined in recipes., когда делаю это. Можно ли делать такие вещи?

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Вам необходимо обновить OBJS внутри ASSET_RULE, потому что макрос сможет вернуть код make-файла только для $(eval). Я упустил все части вашего make-файла, которые не имеют отношения к рассматриваемой проблеме:

# $(1): source file name
define ASSET_RULE
_obj_name := $(addsuffix .o,$(basename $(1)))
$$(_obj_name): $(1)
        $(LD) -r -b binary $$< -o $$@

OBJS      += $$(_obj_name)
_obj_name :=

endef

# $(1): list of source files
BINARY_ASSETS = $(eval \
        $(foreach _a,$(1), \
                $(call ASSET_RULE,$(_a)) \
        ) \
)

ASSETS := \
        avatar.jpg   \
        avatar2.png
OBJS   :=

$(call BINARY_ASSETS,$(ASSETS))

.PHONY: all
all: $(OBJS)

Тестовый прогон, в котором я заменил eval на info, чтобы показать сгенерированный код:

$ make
 _obj_name := avatar.o
$(_obj_name): avatar.jpg
        ld -r -b binary $< -o $@

OBJS      += $(_obj_name)
_obj_name :=
   _obj_name := avatar2.o
$(_obj_name): avatar2.png
        ld -r -b binary $< -o $@

OBJS      += $(_obj_name)
_obj_name :=

make: Nothing to be done for 'all'.

Если вы хотите обновить различные переменные с помощью BINARY_ASSETS, вам потребуется второй параметр для передачи имени переменной:

# $(1): source file name
# $(2): variable name to add object file name to
define ASSET_RULE
_obj_name := $(addsuffix .o,$(basename $(1)))
$$(_obj_name): $(1)
        $(LD) -r -b binary $$< -o $$@

$(2)      += $$(_obj_name)
_obj_name :=

endef

# $(1): list of source files
# $(2): variable name to add object file names to
BINARY_ASSETS = $(eval \
        $(foreach _a,$(1), \
                $(call ASSET_RULE,$(_a),$(2)) \
        ) \
)

$(call BINARY_ASSETS,$(ASSETS),OBJS)
0 голосов
/ 27 марта 2019
OBJ=$(call BINARY_ASSETS,$(ASSETS))

Это неправильно, так как значение OBJ, т.е. $(call ...), расширяется (то есть вызывается) позже, внутри других рецептов и предпосылок, что является причиной жалобы make. Вы можете использовать только простое задание здесь:

OBJ:=$(call BINARY_ASSETS,$(ASSETS))

Обратитесь к руководству по make для двух разновидностей переменных (если вам, как и мне, этот текст плохо понятен, просто попытайтесь представить, что оператор '=' в make присваивает переменной литеральную строку без изменений) .

Кроме того, я настоятельно рекомендую по возможности использовать автоматические переменные, например ::

$(NAME): $(OBJ)
    $(AR) $(ARFLAGS) $@ $?
...