Reputation: 1139
The problem I'm experiencing is an all
target has dependencies on others that set a variable, then run matching dependencies.
Outcome - It will run the first dependency then stop.
Expected - Run both dependencies, setting the variable properly between each run
Is make
smart enough to see pull
and build
were already ran and the dependency target itself has no execution, therefore it sees all dependencies as complete? Or I'm just abusing make
in ways it should not be used?
Said makefile
:
repo=rippio
image=default
pull:
@docker pull $(repo)/$(image):latest
build: pull
@sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$(image)/' Dockerfile.in > Dockerfile && \
docker build -t=$(repo)/$(image):custom .
@rm -f Dockerfile
node: image=node
node: | pull build
jdk8: image=jdk8
jdk8: | pull build
all: | node jdk8
It is used to:
Pretty handy for customizing images in a generic manner without managing many Dockerfiles
.
Dockerfile template (Dockerfile.in
), incase interested:
FROM {{repo}}/{{image}}:latest
... super secret sauce
Thanks to @G.M., ended up with:
IMAGE_NAMES := node jdk8
TARGETS := $(patsubst %,build-%,$(IMAGE_NAMES))
repo=rippio
all: $(TARGETS)
build-%: pull-%
@$sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$*/' Dockerfile.in > Dockerfile-$* && \
$docker build -f=Dockerfile-$* -t=$(repo)/$*:custom .
@rm -f Dockerfile-$*
pull-%:
@$docker pull $(repo)/$*:latest
Which allows for:
make -j
(note the Dockerfile-$*
file pattern)Upvotes: 0
Views: 605
Reputation: 12889
If you draw your dependency graph out long-hand you'll see that there are multiple paths from all
to both pull
and build
-- one via each of node
and jdk8
. But make
having reached/updated pull
and build
via one path will then assume that they are both up to date and, hence, not bother to update them further -- regardless of any change to target specific variables.
I think what you're trying to do (assuming I've understood correctly) might be more easily achieved using pattern rules.
IMAGE_NAMES := node jdk8
TARGETS := $(patsubst %,build-%,$(IMAGE_NAMES))
repo=rippio
all: $(TARGETS)
build-%: pull-%
@$sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$*/' Dockerfile.in > Dockerfile && \
$docker build -t=$(repo)/$*:custom .
@rm -f Dockerfile
pull-%:
@$docker pull $(repo)/$*:latest
Note: You currently have all build
recipes using the same input/output file DockerFile
. That will cause problems if you ever want to use parallel builds -- make -j
etc. It might be wise to use the stem from the pattern rule match to uniquely identify the output file if that's possible.
Upvotes: 2
Reputation: 29222
Normally, if you invoke make with:
make all
and if none of pull
, build
, node
, jdk8
are existing files, make should build pull
and build
. If you see only pull
being made, it can be because you invoke make without specifying a goal. In this case make builds the first target it finds in the Makefile (pull
in your case).
Anyway, there are several strange aspects in your Makefile: you use order-only prerequisites on what looks like phony targets and these phony targets are not declared as such.
I am not sure I fully understand what you are trying to do but maybe something like this would be a good starting point:
repo=rippio
image=default
.PHONY: all build node jdk8
all: node jdk8
node: image = node
jdk8: image = jdk8
build node jdk8:
@docker pull $(repo)/$(image):latest && \
sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$(image)/' Dockerfile.in > Dockerfile && \
docker build -t=$(repo)/$(image):custom . && \
rm -f Dockerfile
Note: if, instead of build
you name the default target default
you could even simplify further with:
repo=rippio
.PHONY: all default node jdk8
all: node jdk8
default node jdk8:
@docker pull $(repo)/$@:latest && \
sed -e 's/{{repo}}/$(repo)/' -e 's/{{image}}/$@/' Dockerfile.in > Dockerfile && \
docker build -t=$(repo)/$@:custom . && \
rm -f Dockerfile
Upvotes: 1