我有一个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( 无法识别。
我猜在$($$core_lib.VHDL_SRC_FILES_LIST)
core_lib
中是一个shell变量,你想先扩展它,然后展开名称为${core_lib}.VHDL_SRC_FILES_LIST
的make变量。这不是制作的工作方式。你不能指望 make 扩展外壳变量。
相反,您应该仅依赖 make 变量。若:
- 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 ...
构造必须平放在生成文件中(而不是在配方中(。它迭代了 make 变量CORE_LIB_LIST
定义中的单词。对于每个LIB
的单词,它在COMPLIB_rule
的定义中用LIB
替换$(1)
(它也用一个$
替换每个$$
(,并将结果实例化为常规的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 variablea.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
对,它在COMPLIB_rule
的定义中用LIB
替换$(1)
,用FILE
替换$(2)
(它也用单个$
替换每个$$
(,并将结果实例化为常规的make规则。所有这些都将所有LIB.FILE.tag
文件声明为目标compile-all-libs
的先决条件,并通过在LIB
中编译FILE
并触摸标记文件来声明构建标记的规则。这就像对于库LIB
的每个源FILE
,将其添加到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
只需输入make compile-all-libs
即可查看:make 将构建所有标记文件,即编译每个源文件在其自己的库中并触摸标记文件。由于 VHDL 源文件是标记文件的先决条件,因此仅当 VHDL 源文件比标记文件更新时,才会执行配方。这与 C 程序的.o
/.c
依赖项相同。唯一的区别是我们不使用编译结果本身(.o
(,因为我们并不真正知道Modelsim是什么。相反,我们创建一个标签文件,只是为了这个目的。副作用:使用不同的VHDL编译器/模拟器完全相同。
这甚至可以让你声明源文件之间的依赖关系:如果$(BLOCK_PATH)/cores/foo.vhd
必须在库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
到你的生成文件。还有许多可能的改进,例如,每个图书馆的目标......