Reputation: 623
I have a makefile and I want to compile each of my vhdl files in the correct library. And there is my code :
$(DEBUG)for core_lib in $(CORE_LIB_LIST); \
do for core_lib_src_vhd in $($$core_lib.VHDL_SRC_FILES_LIST); \
do $(COMPILER_VHDL) $(CC_VHDL_OPTIONS) $(COVER_OPTIONS) -work $$core_lib $(BLOCK_PATH)/cores/$$core_lib_src_vhd; \
done; \
done;
But $($$core_lib.VHDL_SRC_FILES_LIST) is unrecognized.
Upvotes: 0
Views: 100
Reputation: 29137
I guess that in $($$core_lib.VHDL_SRC_FILES_LIST)
core_lib
is a shell variable and you want make to expand it first, and then expand the make variable which name is ${core_lib}.VHDL_SRC_FILES_LIST
. This is not how make works. You cannot expect make to expand shell variables.
Instead you should rely on make variables only. Assuming:
CORE_LIB_LIST
is the list of libraries,LIB
there is a make variable LIB.VHDL_SRC_FILES_LIST
listing the source files,$(BLOCK_PATH)/cores/
,you could try this:
.PHONY: compile-all-libs
# $(1): library
define COMPLIB_rule
.PHONY: compile-$(1)
compile-$(1):
$$(DEBUG)$$(COMPILER_VHDL) $$(CC_VHDL_OPTIONS) $$(COVER_OPTIONS) -work $(1) $$(addprefix $$(BLOCK_PATH)/cores/,$$($(1).VHDL_SRC_FILES_LIST))
compile-all-libs: compile-$(1)
endef
$(foreach LIB,$(CORE_LIB_LIST),$(eval $(call COMPLIB_rule,$(LIB))))
Explanation: the define COMPLIB_rule ... endef
is just another way to define a make variable named COMPLIB_rule
. The $(foreach ...
construct must be put flat in the Makefile (not in a recipe). It iterates over the words in the definition of make variable CORE_LIB_LIST
. For each word LIB
, it replaces $(1)
by LIB
in the definition of COMPLIB_rule
(it also replaces every $$
by a single $
) and it instantiates the result as a regular make rule. If the make variable CORE_LIB_LIST
evaluates as a b
, for instance, the result will be the same as:
.PHONY: compile-a
compile-a:
$(DEBUG)$(COMPILER_VHDL) $(CC_VHDL_OPTIONS) $(COVER_OPTIONS) -work a $(addprefix $(BLOCK_PATH)/cores/,$(a.VHDL_SRC_FILES_LIST))
compile-all-libs: compile-a
.PHONY: compile-b
compile-b:
$(DEBUG)$(COMPILER_VHDL) $(CC_VHDL_OPTIONS) $(COVER_OPTIONS) -work b $(addprefix $(BLOCK_PATH)/cores/,$(b.VHDL_SRC_FILES_LIST))
compile-all-libs: compile-b
So, if you type make compile-all-libs
, make will try to build compile-a
and compile-b
, the two pre-requisites of compile-all-libs
. In order to build compile-a
it will execute the recipe:
$(DEBUG)$(COMPILER_VHDL) $(CC_VHDL_OPTIONS) $(COVER_OPTIONS) -work a $(addprefix $(BLOCK_PATH)/cores/,$(a.VHDL_SRC_FILES_LIST))
which will compile in library a
all source files listed in make variable a.VHDL_SRC_FILES_LIST
and found in directory $(BLOCK_PATH)/cores
. Same with compile-b
.
But of course, it would be much better if you were recompiling only what's needed (that is, source files that changed since the last time they were compiled). This can be done with empty tag files that keep track of the last time a source file was compiled:
.PHONY: compile-all-libs
# $(1): library
# $(2): source file basename
define COMPLIB_rule
$$(BLOCK_PATH)/cores/$(1).$(2).tag: $$(BLOCK_PATH)/cores/$(2)
$$(DEBUG)$$(COMPILER_VHDL) $$(CC_VHDL_OPTIONS) $$(COVER_OPTIONS) -work $(1) $$< && \
touch $$@
compile-all-libs: $$(BLOCK_PATH)/cores/$(1).$(2).tag
endef
$(foreach LIB,$(CORE_LIB_LIST),$(foreach FILE,$($(LIB).VHDL_SRC_FILES_LIST),$(eval $(call COMPLIB_rule,$(LIB),$(FILE)))))
clean:
$(DEBUG)rm -f $(BLOCK_PATH)/cores/*.tag
Explanation: there, the foreach-foreach-eval-call
iterates over library/source file pairs. For each LIB-FILE
pair, it replaces $(1)
by LIB
and $(2)
by FILE
in the definition of COMPLIB_rule
(it also replaces every $$
by a single $
) and it instantiates the result as a regular make rule. All this declares all LIB.FILE.tag
files as pre-requisites of target compile-all-libs
and declares the rule to build the tag by compiling FILE
in LIB
and touching the tag file. This is just like if, for each source FILE
of library LIB
, you added this to your Makefile:
$(BLOCK_PATH)/cores/LIB.FILE.tag: $(BLOCK_PATH)/cores/FILE
$(DEBUG)$(COMPILER_VHDL) $(CC_VHDL_OPTIONS) $(COVER_OPTIONS) -work LIB $< && \
touch $@
compile-all-libs: $(BLOCK_PATH)/cores/LIB.FILE.tag
Just type make compile-all-libs
and see: make will build all tag files, that is, compile each source file in its own library and touch the tag file. As the VHDL source file is a pre-requisite of the tag file, it is only if the VHDL source file is more recent than the tag file that the recipe will be executed. This is the same as the .o
/ .c
dependency for C programs. The only difference is that we do not use the compilation result itself (.o
) because we do not really know what it is with Modelsim. Instead, we create a tag file, just for this purpose. Side effect: it would be exactly the same with a different VHDL compiler/simulator.
This would even give you the possibility to declare dependencies between your source files: if $(BLOCK_PATH)/cores/foo.vhd
must be compiled in library FOO_LIB
before $(BLOCK_PATH)/cores/bar.vhd
can be compiled in library BAR_LIB
, you could add:
$(BLOCK_PATH)/cores/BAR_LIB.bar.vhd.tag: $(BLOCK_PATH)/cores/FOO_LIB.foo.vhd.tag
to your Makefile. And there are also many possible improvements like, for instance, per-library goals...
Upvotes: 2