我有一个makefile,我想在正确的库中编译我的每个vhdl文件。还有我的代码:
$(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;
但$($$ core_lib.VHDL_SRC_FILES_LIST)无法识别。
答案 0 :(得分:2)
我想在$($$core_lib.VHDL_SRC_FILES_LIST)
core_lib
中是一个shell变量,你希望make首先展开它,然后展开名为${core_lib}.VHDL_SRC_FILES_LIST
的make变量。这不是如何使作品。你不能指望make扩展shell变量。
相反,你应该只依赖make变量。假设:
CORE_LIB_LIST
是库列表,LIB
都有一个make变量LIB.VHDL_SRC_FILES_LIST
列出源文件,$(BLOCK_PATH)/cores/
,.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))))
解释:define COMPLIB_rule ... endef
只是另一种定义名为COMPLIB_rule
的make变量的方法。必须将$(foreach ...
构造放在Makefile中(不在配方中)。它迭代make变量CORE_LIB_LIST
定义中的单词。对于每个单词LIB
,它会在$(1)
的定义中将LIB
替换为COMPLIB_rule
(它还会将每个$$
替换为单个$
)并将结果实例化为常规make规则。例如,如果make变量CORE_LIB_LIST
的计算结果为a b
,则结果将与:
.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
因此,如果您输入make compile-all-libs
,make会尝试构建compile-a
和compile-b
compile-all-libs
的两个先决条件。为了构建compile-a
,它将执行配方:
$(DEBUG)$(COMPILER_VHDL) $(CC_VHDL_OPTIONS) $(COVER_OPTIONS) -work a $(addprefix $(BLOCK_PATH)/cores/,$(a.VHDL_SRC_FILES_LIST))
将在库a
中编译make变量a.VHDL_SRC_FILES_LIST
中列出的所有源文件,并在目录$(BLOCK_PATH)/cores
中找到。与compile-b
相同。
但是,当然,如果您只重新编译所需的内容(即自上次编译以来发生更改的源文件),那会好得多。这可以使用空标记文件来完成,这些文件跟踪上次编译源文件的时间:
.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
解释:在那里,foreach-foreach-eval-call
遍历库/源文件对。对于每个LIB-FILE
对,它会在$(1)
的定义中将LIB
替换为$(2)
而FILE
替换为COMPLIB_rule
(它也会替换$$
$
1}}由单个LIB.FILE.tag
)并将结果实例化为常规make规则。所有这些都将所有compile-all-libs
文件声明为目标FILE
的先决条件,并通过在LIB
中编译FILE
并触摸标记文件来声明构建标记的规则。这就像是,对于库LIB
的每个源$(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
,您将其添加到Makefile:
make compile-all-libs
只需键入.o
并查看:make将构建所有标记文件,即在每个源文件中编译每个源文件并触摸标记文件。由于VHDL源文件是标记文件的先决条件,因此仅当VHDL源文件比标记文件更新时才会执行配方。这与C程序的.c
/ .o
依赖项相同。唯一的区别是我们不使用编译结果本身($(BLOCK_PATH)/cores/foo.vhd
),因为我们并不真正知道它与Modelsim的关系。相反,我们创建一个标记文件,仅用于此目的。副作用:对于不同的VHDL编译器/模拟器,它将完全相同。
这甚至可以让您在源文件之间声明依赖关系:如果FOO_LIB
必须在库$(BLOCK_PATH)/cores/bar.vhd
中编译,那么BAR_LIB
可以在库$(BLOCK_PATH)/cores/BAR_LIB.bar.vhd.tag: $(BLOCK_PATH)/cores/FOO_LIB.foo.vhd.tag
中编译,你可以添加:
{{1}}
到你的Makefile。并且还有许多可能的改进,例如,每个库的目标......