Iterating Over Lists in Makefiles

Iterating over lists in Makefiles?

Makefiles are essentially declarative in nature, so I don't think that make itself provides what you want. However, you seem to be wanting to associate some string values with specific targets, so maybe the Target specific variable values feature of GNU make will be of interest. This is an extract from the manual:

There is one more special feature of
target-specific variables: when you
define a target-specific variable,
that variable value is also in effect
for all dependencies of this target
(unless those dependencies override it
with their own target-specific
variable value). So, for example, a
statement like this:

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

will set CFLAGS to -g in the command
script for prog, but it will also
set CFLAGS to -g in the command
scripts that create prog.o, foo.o,
and bar.o, and any command scripts
which create their dependencies.

If you haven't already read it, the GNU make manual is pretty damn good.

Edit: To do what you asked about in your comment:

dog: ANIMAL=dog.c BULLY=pull_tail SOUND=bark


dog: ANIMAL=dog.c 
dog: BULLY=pull_tail
dog: SOUND=bark

Iterating over lists in Makefiles - revisited

It's because you're stringing together print_tmp blocks on a single line-- but the blocks have internal line breaks. Consider:

$(foreach color, red blue, \
$(call print_tmp, $(color)) \

define print_tmp
@echo first $(1)

The foreach evaluates to @echo first red @echo first blue, which is then executed as a shell command and produces:

first red @echo first blue

Now add another line to the macro:

$(foreach color, red blue, \
$(call print_tmp, $(color)) \

define print_tmp
@echo first $(1)
@echo second $(1)

Now the foreach evaluates to

@echo first red 
@echo second red @echo first blue
@echo second blue

which produces:

first red 
second red @echo first blue
second blue

To correct the problem, just add a blank line:

define print_tmp
@echo in print_tmp
@echo set_global -name PARTITION_NAME $(1)
@echo set_global -color PARTITION_COLOR $(2) -name PARTITION_NAME $(1)


Iterating through a list of directories in a Makefile

There are lots of ways of doing this.

You can do what Andrew suggests without hard-coding a prefix:

directories = module1 module2 module2

%/foo: ; mkdir -p -- "$@"

copy: $(addsuffix /foo,$(directories))

which gives

$ make -n copy
mkdir -p -- "module1/foo"
mkdir -p -- "module2/foo"
mkdir -p -- "module3/foo"

You can also generate the copy target from the makefile:

directories = module1 module2 module2

define copy-target
copy:: ; cd $1 && mkdir foo

$(foreach dir,$(directories),$(eval $(call copy-target,$(dir))))

This gives:

$ make -n copy
cd module1 && mkdir foo
cd module2 && mkdir foo
cd module3 && mkdir foo

You could also generate the commands, not the target:

directories = module1 module2 module2

copy: ; $(foreach dir,$(directories),(cd $(dir) && mkdir foo) &&) :

which results in

$ make -n copy
(cd module1 && mkdir foo) && (cd module2 && mkdir foo) && (cd module3 && mkdir foo) && :

How to generate targets in a Makefile by iterating over a list?

Use text-transforming functions. With patsubst you can make quite general transformations. For constructing filenames, addsuffix and addprefix are both convenient.

For the rules, use pattern rules.

The overall result might look something like this:

LIST = 0 1 3 4 5
targets = $(addprefix rambo, $(LIST))

all: $(targets)

$(targets): rambo%:
sh $<

Iterating over a list in a Makefile and getting both values and indexes

There are several ways to do this, none of them very clean (which is a strong hint that you're trying to do something that isn't really suited to Make), and your particular case may require special handling, but here goes:

OBJECTS = foo bar baz

NLIST = $(shell for x in {1..$(words $(OBJECTS))}; do echo $$x; done)

LIST = $(foreach x,$(NLIST), do_something_with_$(x)_and_$(word $(x),$(OBJECTS)))

How to create a multiple recipes by looping over a Makefile list?

You would use pattern rules most likely:

apply: stage process

var := 2000 2001 2002

process: $(foreach V,$(var),output/$V/config.json)
stage: $(foreach V,$(var),output/$V/esc)

output/%/config.json: dir/level/%/config.json
cp $< $@

output/%/esc : dir/common/%/esc
mkdir -p $(@D)
cp $< $@

Iterating through makefile argument list

This can't be right:


because that just sets, then overrides, the single value +uvm_set_config_int. At the end the variable +uvm_set_config_int will contain the single value *,C,5 since that's the last assignment. Maybe you mean to use uvm_set_config_int += ... in each of the above, to append to the existing value?

I really don't understand what you're trying to accomplish here.

However, here's an example of how to do what you've asked, even though it doesn't seem to make much sense:

c = ,
$(foreach X,$(subst $c, ,$(cfg)),$(eval +uvm_set_config_int=*,$(subst =,$c,$X)))

Since commas are special to make functions we have to hide them behind a variable $c above. The first subst turns commas into spaces, since that's what make uses to delimit words. The second converts = to comma so you can change A=3 to A,3 etc. The eval evaluates the text given as a makefile line.

Parallel iteration over lists in makefile or CMake file

Here you go:

set(list1 1 2 3 4 5)
set(list2 6 7 8 9 0)

list(LENGTH list1 len1)
math(EXPR len2 "${len1} - 1")

foreach(val RANGE ${len2})
list(GET list1 ${val} val1)
list(GET list2 ${val} val2)
message(STATUS "${val1} ${val2}")

Related Topics

Leave a reply