benathon
benathon

Reputation: 7653

get base variable in Makefile targets that are made from a list

I have a Makefile which manages multiple FPGA builds in their own directory. I have a variable CS_FPGA_FETCH which has the unique name of each fpga. (Many subfolders in my project are based on this name).

I would like a clean way to deal with adding a target for each FPGA. What I came up with is addprefix and removing the prefix.

# Every FPGA
CS_FPGAS_FETCH := cs00 cs01 cs02 cs03 cs10 cs11 cs12 cs13 cs20 cs21 cs22 cs23 cs30 cs31 cs32 cs33

# this is a list of variables that has the words copy_official_  prefixed
# to all of the cs00, cs01
COPY_OFFICIAL_CS_TARGETS=$(addprefix copy_official_,$(CS_FPGAS_FETCH))

# because we use add prefix, we HAVE to strip it off
# this replases $(@) for guys with a prefix, so we can access the base variable inside the loop below
COPY_TARGET_FPGA_NAME=$(@:copy_official_%=%)

# this evaluates out to targets named:
#   copy_official_cs00, copy_official_cs01 etc
$(COPY_OFFICIAL_CS_TARGETS):
    @echo In $(@) target.  Here i copy file $(COPY_TARGET_FPGA_NAME)
    cp build/$(COPY_TARGET_FPGA_NAME)/file.bit install/$(COPY_TARGET_FPGA_NAME)

This method seems backwards to me. I need to create a COPY_TARGET_FPGA_NAME for each prefix I want to use. This seems very confusing. I need to add many such targets all with different prefixes.

Upvotes: 0

Views: 101

Answers (1)

Renaud Pacalet
Renaud Pacalet

Reputation: 29345

Not sure I understand all details because your prefix does not appear in your recipe. So, as I do not see the point in having several of them, I will assume that the destination bitstream is install/<prefix><fpga>, not install/<fpga>.

I will also use a slightly more make-oriented approach where targets and prerequisites are real files. To copy your bitstreams, for instance, it is more natural to have install/<prefix><fpga> as target and build/<fpga>/file.bit as prerequisite.

I also add install as an order-only prerequisite and a rule to create it.

Back to your main question: if you use GNU make you can use foreach-eval-call to iterate over lists and instantiate make constructs in each iteration:

# Every FPGA
CS_FPGAS_FETCH := cs00 cs01 cs02 cs03 cs10 cs11 cs12 cs13 cs20 cs21 cs22 cs23 cs30 cs31 cs32 cs33

# Every prefix
PREFIXES = copy_official_

.PHONY: all

# $(1): prefix
# $(2): FPGA name
define MY_rule
all: install/$(1)$(2)

install/$(1)$(2): build/$(2)/file.bit | install
    @echo In $$@ target.  Here i copy file $(2)
    cp build/$(2)/file.bit $$@
endef
$(foreach p,$(PREFIXES),$(foreach f,$(CS_FPGAS_FETCH),$(eval $(call MY_rule,$(p),$(f)))))

install:
    mkdir $@

Adapt to your needs but remember that the MY_rule variable is expanded twice: one time by eval and one more by make in its regular processing. So, some variables must be protected against the first expansion (thus the $$@).

Upvotes: 2

Related Questions