Bash :在变量中使用变量(嵌套循环)



我有一个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-acompile-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))

它将在库中编译amake 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

到你的生成文件。还有许多可能的改进,例如,每个图书馆的目标......

最新更新