pandaero
pandaero

Reputation: 27

How do I write a prerequisite to loop through two lists of files together?

This is an example illustrating the output I would like:

LIST1 := hello.o world.o
LIST2 := hello.c world.c

# Make the first object
# hello.o: hello.c
$(word 1, $(LIST1)): $(word 1, $(LIST2))
  cc -c $^ -o $@

# Make the second object
# world.o: world.c
$(word 2, $(LIST1)): $(word 2, $(LIST2))
  cc -c $^ -o $@

Is there a way to summarise the target: prerequisite text so that it loops through two entire lists?

I have tried using foreach functions with word functions but I don't get the output. I get non-numeric arguments to word and other invalid expressions.

Upvotes: 0

Views: 156

Answers (2)

MadScientist
MadScientist

Reputation: 100946

The short answer is "no". Why don't you just write a pattern rule?

all: $(LIST1)

%.o : %.c
        cc -c $^ -o $@

? In fact you don't even need to write a pattern rule at all: make already has a default rule that can build object files from C source files.

ETA

If you have source files in different directories, you have two choices. The best choice is to have one pattern rule and create all your objects in a subdirectory structure that mimics your source directories. So, like this:

SRCS := foo.c bar/bar.c bar/biz/baz.c

OBJS := $(patsubst %.c,obj/%.o,$(SRCS))

all: $(OBJS)

obj/%.o : %.c
         @mkdir -p $(@D)
         $(COMPILE.c) -o $@ $<

If you really don't want to do that and you want to put all the object files into the same directory (a bad idea because if you have two source files with the same name in different source directories, your build will fail) you can use VPATH:

SRCS := foo.c bar/bar.c bar/biz/baz.c

OBJS := $(patsubst %.c,obj/%.o,$(notdir $(SRCS)))

VPATH := $(sort $(dir $(SRCS)))

all: $(OBJS)

obj/%.o : %.c
         @mkdir -p $(@D)
         $(COMPILE.c) -o $@ $<

Upvotes: 1

HardcoreHenry
HardcoreHenry

Reputation: 6387

You actually can do it, but it's really ugly (and would be hard to maintain), I'm showing the answer, but I am definitely not suggesting using it... If you can use pattern rules as @MadScientist suggests, that would be best. If not (say the names differ, you can do something like):

LIST1 := hello.o bob.o

hello.o : hello.c
bob.o : sally.c

$(LIST1):
    cc -c $< -o $@

Which allows you to specify custom prereqs for each target. If you really need two lists, the technical answer to your question would be as follows:

LIST1 := hello.o bob.o
LIST2 := hello.c sally.c

all:

define recursive_def
$(firstword $(1)) : $(firstword $(2))
        cc -c $$^ -o $$@

$(if $(wordlist 2,3,$1),$(call recursive_def,$(wordlist 2,$(words $(1)),$1),$(wordlist 2,$(words $(2)),$(2))))
endef

$(info -v---v-)
$(info $(call recursive_def,$(LIST1),$(LIST2)))
$(info -^---^-)

$(eval $(call recursive_def,$(LIST1),$(LIST2)))

Upvotes: 1

Related Questions