Charly
Charly

Reputation: 1139

Multi-dependency makefile target

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

TLDR

It is used to:

  1. Pull the latest docker image
  2. Run a generically designed Dockerfile against it to customize it
  3. Tag it as :custom for internal use

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

UPDATE (ANSWER)

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:

Upvotes: 0

Views: 605

Answers (2)

G.M.
G.M.

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

Renaud Pacalet
Renaud Pacalet

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

Related Questions