Makefile:108: *** 配方在第一个目标之前开始
Makefile:108: *** recipe commences before first target
GNU Make 4.1 为 x86_64-pc-linux-gnu
构建
下面是Makefile
:
# Project variables
PROJECT_NAME ?= todobackend
ORG_NAME ?= shamdockerhub
REPO_NAME ?= todobackend
# File names
DEV_COMPOSE_FILE := docker/dev/docker-compose.yml
REL_COMPOSE_FILE := docker/release/docker-compose.yml
# Docker compose project names
REL_PROJECT := $(PROJECT_NAME)$(BUILD_ID)
DEV_PROJECT := $(REL_PROJECT)dev
# Check and inspect logic
INSPECT := $$(docker-compose -p $ -f $ ps -q $ | xargs -I ARGS docker inspect -f "{{ .State.ExitCode }}" ARGS)
CHECK := @bash -c '\
if [[ $(INSPECT) -ne 0 ]]; \
then exit $(INSPECT); fi' VALUE
# Use these settings to specify a custom Docker registry
DOCKER_REGISTRY ?= docker.io
APP_SERVICE_NAME := app
.PHONY: test build release clean tag
test: # Run unit & integration test cases
${INFO} "Pulling latest images..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) pull
${INFO} "Building images..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build cache
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build --pull test
${INFO} "Ensuring database is ready..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) run --rm agent
${INFO} "Running tests..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) up test
@ docker cp $$(docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) ps -q test):/reports/. reports
${CHECK} ${DEV_PROJECT} ${DEV_COMPOSE_FILE} test
${INFO} "Testing complete"
build: # Create deployable artifact and copy to ../target folder
${INFO} "Creating builder image..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build builder
${INFO} "Building application artifacts..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) up builder
${CHECK} ${DEV_PROJECT} ${DEV_COMPOSE_FILE} builder
${INFO} "Copying artifacts to target folder..."
@ docker cp $$(docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) ps -q builder):/wheelhouse/. target
${INFO} "Build complete"
release: # Creates release environment, bootstrap the environment
${INFO} "Building images..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build webroot
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build app
${INFO} "Ensuring database is ready..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm agent
${INFO} "Collecting static files..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm app manage.py collectstatic --noinput
${INFO} "Running database migrations..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm app manage.py migrate --noinput
${INFO} "Pull external image and build..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build --pull nginx
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) pull test
${INFO} "Running acceptance tests..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) up test
${CHECK} $(REL_PROJECT) $(REL_COMPOSE_FILE) test
@ docker cp $$(docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) ps -q test):/reports/. reports
${INFO} "Acceptance testing complete"
clean:
${INFO} "Destroying development environment..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) kill
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) rm -f -v
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) kill
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) rm -f -v
@ docker images -q -f dangling=true -f label=application=$(REPO_NAME) | xargs -I ARGS docker rmi -f ARGS
${INFO} "Clean complete"
tag:
$(INFO) "Tagging release image with tags $(TAG_ARGS)"
@ $(foreach tag, $(TAG_ARGS), docker tag $(IMAGE_ID) $(DOCKER_REGISTRY)/$(ORG_NAME)/$(REPO_NAME):$(tag);)
${INFO} "Tagging complete"
# Cosmetics
YELLOW := "\e[1;33m"
NC := "\e[0m"
# Shell functions
INFO := @bash -c '\
printf $(YELLOW); \
echo "=> $"; \
printf $(NC)' VALUE
# Get container id of application service container
APP_CONTAINER_ID := $$(docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) ps -q $(APP_SERVICE_NAME))
# Get image id of application service
IMAGE_ID := $$(docker inspect -f '{{ .Image }}' $(APP_CONTAINER_ID))
# Extract tag arguments
ifeq (tag, $(firstword $(MAKECMDGOALS)))
TAG_ARGS := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
ifeq ($(TAG_ARGS),)
$(error You must specify a tag)
endif
$(eval $(TAG_ARGS):;@:) # line 108 Do not interpret "0.1 latest whatever" as make target files
endif
下面是 运行 make 命令的错误:
$ make tag 0.1 latest $(git rev-parse --short HEAD)
Makefile:108: *** recipe commences before first target. Stop.
第 108 行,$(eval $(TAG_ARGS):;@:)
的目的是传达 0.1 latest $(git rev-parse --short HEAD)
不是 make
目标。
为什么$(eval $(TAG_ARGS):;@:)
报错?
我无法重现这个问题。我将您的最后一个 ifeq
语句放入一个 makefile 中,它对我来说在 GNU make 4.1 和 4.2.1 中运行良好。你的情况一定有更不寻常的地方。
调试 eval
问题的经典方法是复制该行并将 eval
替换为 info
;这样 make 将准确打印出它所看到的内容。通常这会告诉你哪里出了问题。
这个 makefile 还有其他令人困惑的地方。
首先,您为什么首先在这里使用 eval
?为什么不直接写规则呢?没有错:
$(TAG_ARGS):;@:
无需将其包装在 eval
.
中
其次,为什么要使用 :=
然后转义变量?为什么不直接使用 =
而不用担心转义?
INSPECT = $(docker-compose -p -f ps -q | xargs -I ARGS docker inspect -f "{{ .State.ExitCode }}" ARGS)
工作正常。
最后,我强烈建议您不要将 @
添加到您的食谱中。它使调试 makefile 变得非常困难和令人沮丧。相反,请考虑使用 Managing Recipe Echoing 等方法来处理此问题。
发生该特定错误是因为您的 $(eval ...)
行被 TAB 缩进(它被这个可怕的损坏的网络界面隐藏了)。
示例:
$ make -f <(printf '\t$(eval foo:;echo yup)')
/dev/fd/63:1: *** recipe commences before first target. Stop.
# now with spaces instead of TAB
$ make -f <(printf ' $(eval foo:;echo yup)')
echo yup
yup
错误记录在 make
manual:
recipe commences before first target. Stop.
This means the first thing in the makefile seems to be part of a
recipe: it begins with a recipe prefix character and doesn't appear
to be a legal make
directive (such as a variable assignment).
Recipes must always be associated with a target.
"recipe prefix character"默认为TAB
$ make -f <(printf '\tfoo')
/dev/fd/63:1: *** recipe commences before first target. Stop.
它不一定是 "first thing in the makefile",但是:如果前面有像宏赋值这样的指令,同样的错误将在许多规则之后触发:
$ make -f <(printf 'all:;\nkey=val\n\tfoo')
/dev/fd/63:3: *** recipe commences before first target. Stop.
即使宏展开为空字符串,GNU make 也不会考虑空行,其中仅包含展开为空字符串的宏:
$ make -f <(printf '\t\nfoo:;@:')
$ make -f <(printf '\t$(info foo)\nfoo:;@:')
/dev/fd/63:1: *** recipe commences before first target. Stop.
$ make -f <(printf ' $(info foo)\nfoo:;@:')
foo
GNU Make 4.1 为 x86_64-pc-linux-gnu
构建下面是Makefile
:
# Project variables
PROJECT_NAME ?= todobackend
ORG_NAME ?= shamdockerhub
REPO_NAME ?= todobackend
# File names
DEV_COMPOSE_FILE := docker/dev/docker-compose.yml
REL_COMPOSE_FILE := docker/release/docker-compose.yml
# Docker compose project names
REL_PROJECT := $(PROJECT_NAME)$(BUILD_ID)
DEV_PROJECT := $(REL_PROJECT)dev
# Check and inspect logic
INSPECT := $$(docker-compose -p $ -f $ ps -q $ | xargs -I ARGS docker inspect -f "{{ .State.ExitCode }}" ARGS)
CHECK := @bash -c '\
if [[ $(INSPECT) -ne 0 ]]; \
then exit $(INSPECT); fi' VALUE
# Use these settings to specify a custom Docker registry
DOCKER_REGISTRY ?= docker.io
APP_SERVICE_NAME := app
.PHONY: test build release clean tag
test: # Run unit & integration test cases
${INFO} "Pulling latest images..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) pull
${INFO} "Building images..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build cache
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build --pull test
${INFO} "Ensuring database is ready..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) run --rm agent
${INFO} "Running tests..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) up test
@ docker cp $$(docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) ps -q test):/reports/. reports
${CHECK} ${DEV_PROJECT} ${DEV_COMPOSE_FILE} test
${INFO} "Testing complete"
build: # Create deployable artifact and copy to ../target folder
${INFO} "Creating builder image..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) build builder
${INFO} "Building application artifacts..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) up builder
${CHECK} ${DEV_PROJECT} ${DEV_COMPOSE_FILE} builder
${INFO} "Copying artifacts to target folder..."
@ docker cp $$(docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) ps -q builder):/wheelhouse/. target
${INFO} "Build complete"
release: # Creates release environment, bootstrap the environment
${INFO} "Building images..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build webroot
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build app
${INFO} "Ensuring database is ready..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm agent
${INFO} "Collecting static files..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm app manage.py collectstatic --noinput
${INFO} "Running database migrations..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) run --rm app manage.py migrate --noinput
${INFO} "Pull external image and build..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) build --pull nginx
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) pull test
${INFO} "Running acceptance tests..."
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) up test
${CHECK} $(REL_PROJECT) $(REL_COMPOSE_FILE) test
@ docker cp $$(docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) ps -q test):/reports/. reports
${INFO} "Acceptance testing complete"
clean:
${INFO} "Destroying development environment..."
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) kill
@ docker-compose -p $(DEV_PROJECT) -f $(DEV_COMPOSE_FILE) rm -f -v
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) kill
@ docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) rm -f -v
@ docker images -q -f dangling=true -f label=application=$(REPO_NAME) | xargs -I ARGS docker rmi -f ARGS
${INFO} "Clean complete"
tag:
$(INFO) "Tagging release image with tags $(TAG_ARGS)"
@ $(foreach tag, $(TAG_ARGS), docker tag $(IMAGE_ID) $(DOCKER_REGISTRY)/$(ORG_NAME)/$(REPO_NAME):$(tag);)
${INFO} "Tagging complete"
# Cosmetics
YELLOW := "\e[1;33m"
NC := "\e[0m"
# Shell functions
INFO := @bash -c '\
printf $(YELLOW); \
echo "=> $"; \
printf $(NC)' VALUE
# Get container id of application service container
APP_CONTAINER_ID := $$(docker-compose -p $(REL_PROJECT) -f $(REL_COMPOSE_FILE) ps -q $(APP_SERVICE_NAME))
# Get image id of application service
IMAGE_ID := $$(docker inspect -f '{{ .Image }}' $(APP_CONTAINER_ID))
# Extract tag arguments
ifeq (tag, $(firstword $(MAKECMDGOALS)))
TAG_ARGS := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
ifeq ($(TAG_ARGS),)
$(error You must specify a tag)
endif
$(eval $(TAG_ARGS):;@:) # line 108 Do not interpret "0.1 latest whatever" as make target files
endif
下面是 运行 make 命令的错误:
$ make tag 0.1 latest $(git rev-parse --short HEAD)
Makefile:108: *** recipe commences before first target. Stop.
第 108 行,$(eval $(TAG_ARGS):;@:)
的目的是传达 0.1 latest $(git rev-parse --short HEAD)
不是 make
目标。
为什么$(eval $(TAG_ARGS):;@:)
报错?
我无法重现这个问题。我将您的最后一个 ifeq
语句放入一个 makefile 中,它对我来说在 GNU make 4.1 和 4.2.1 中运行良好。你的情况一定有更不寻常的地方。
调试 eval
问题的经典方法是复制该行并将 eval
替换为 info
;这样 make 将准确打印出它所看到的内容。通常这会告诉你哪里出了问题。
这个 makefile 还有其他令人困惑的地方。
首先,您为什么首先在这里使用 eval
?为什么不直接写规则呢?没有错:
$(TAG_ARGS):;@:
无需将其包装在 eval
.
其次,为什么要使用 :=
然后转义变量?为什么不直接使用 =
而不用担心转义?
INSPECT = $(docker-compose -p -f ps -q | xargs -I ARGS docker inspect -f "{{ .State.ExitCode }}" ARGS)
工作正常。
最后,我强烈建议您不要将 @
添加到您的食谱中。它使调试 makefile 变得非常困难和令人沮丧。相反,请考虑使用 Managing Recipe Echoing 等方法来处理此问题。
发生该特定错误是因为您的 $(eval ...)
行被 TAB 缩进(它被这个可怕的损坏的网络界面隐藏了)。
示例:
$ make -f <(printf '\t$(eval foo:;echo yup)')
/dev/fd/63:1: *** recipe commences before first target. Stop.
# now with spaces instead of TAB
$ make -f <(printf ' $(eval foo:;echo yup)')
echo yup
yup
错误记录在 make
manual:
recipe commences before first target. Stop.
This means the first thing in the makefile seems to be part of a recipe: it begins with a recipe prefix character and doesn't appear to be a legal
make
directive (such as a variable assignment). Recipes must always be associated with a target.
"recipe prefix character"默认为TAB
$ make -f <(printf '\tfoo')
/dev/fd/63:1: *** recipe commences before first target. Stop.
它不一定是 "first thing in the makefile",但是:如果前面有像宏赋值这样的指令,同样的错误将在许多规则之后触发:
$ make -f <(printf 'all:;\nkey=val\n\tfoo')
/dev/fd/63:3: *** recipe commences before first target. Stop.
即使宏展开为空字符串,GNU make 也不会考虑空行,其中仅包含展开为空字符串的宏:
$ make -f <(printf '\t\nfoo:;@:')
$ make -f <(printf '\t$(info foo)\nfoo:;@:')
/dev/fd/63:1: *** recipe commences before first target. Stop.
$ make -f <(printf ' $(info foo)\nfoo:;@:')
foo