BMW
BMW

Reputation: 45273

multiple Target-specific Variable Values

Following the document to manage Target-specific Variable Values

prog : CFLAGS = -g
prog : prog.o foo.o bar.o

I can set a target-specific variable.

Now my question is, how to set multiple target-specific variables. Do I have to set them one by one?

dev_deploy: env = dev
dev_deploy: image = abc
dev_deploy: tag = 1.0.4-dev
dev_deploy:
      docker run -t --rm -e env=$(env) \
         $(image):$(tag) \
         sh -c "test.sh"


prod_deploy: env = prod
prod_deploy: image = abc
prod_deploy: tag = 1.0.3-prod
prod_deploy:
      docker run -t --rm -e env=$(env) \
         $(image):$(tag) \
         sh -c "test.sh"

Are there any ways I can set the local environments (target-specific variables) with simple way?

Upvotes: 19

Views: 4897

Answers (3)

Dat
Dat

Reputation: 5813

As mentioned in this answer, you can also use $(MAKECMDGOALS) to override variables before running a target.

Based on your example, I'd refactor it as the following


ifeq ($(filter dev_deploy,$(MAKECMDGOALS)),dev_deploy)
env   = dev
image = abc
tag   = 1.0.4-dev
endif


ifeq ($(filter prod_deploy,$(MAKECMDGOALS)),prod_deploy)
env   = prod
image = abc
tag   = 1.0.3-prod
endif

dev_deploy prod_deploy:
    docker run -t --rm -e env=$(env) \
         $(image):$(tag) \
         sh -c "test.sh"

Upvotes: 1

MadScientist
MadScientist

Reputation: 100876

The direct answer to your first question is yes, you have to use a separate target line for each target-specific variable and set them one-by-one.

The answer to your second question is yes: one is described by uzsolt. That would be my recommended method as well. One difference between uzsolt's solution and the target-specific variable solution is that target-specific variables are inherited by prerequisites. You don't seem to need that behavior here but if you did then this solution wouldn't work for you.

If you need target-specific variables or if one line per variable assignment is still too painful (for example you have very large numbers of these and you really want to have one line per group), there may be options which are more complicated to understand but simpler to use later.

For example if you know that none of your variable values will contain whitespace then you can create a user-defined macro that uses eval to set target-specific variables, like this:

assign-vars = $(foreach A,$2,$(eval $1: $A))

$(call assign-vars, dev_deploy,   env=devenv  image=abc  tag=1.0.4-dev)
$(call assign-vars, prod_deploy,  env=prod    image=abc  tag=1.0.3-prod)

Note: the first argument is the target, each assignment must be a single "word" (no embedded space) and there are no commas between assignments.

Upvotes: 11

uzsolt
uzsolt

Reputation: 6037

I would do it:

dev_deploy_env= devenv
dev_deploy_image=   abc
dev_deploy_tag= 1.0.4-dev

prod_deploy_env=    prod
prod_deploy_image=  abc
prod_deploy_tag=    1.0.3-prod

dev_deploy prod_deploy:
    @echo docker run -t --rm -e env=${${@}_env} \
      ${${@}_image}:${${@}_tag} \
      sh -c "test.sh"

.PHONY: dev_deploy prod_deploy

See the commands (I'm using FreeBSD and on it the GNU make command is gmake):

$  gmake prod_deploy 
docker run -t --rm -e env=prod abc:1.0.3-prod sh -c test.sh
$  gmake dev_deploy       
docker run -t --rm -e env=devenv abc:1.0.4-dev sh -c test.sh

Of course you should remove @echo to run commands.

Upvotes: 8

Related Questions