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

时间:2017-07-10 07:49:53

标签: bash makefile

我有一个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)无法识别。

1 个答案:

答案 0 :(得分:2)

我想在$($$core_lib.VHDL_SRC_FILES_LIST) core_lib中是一个shell变量,你希望make首先展开它,然后展开名为${core_lib}.VHDL_SRC_FILES_LIST的make变量。这不是如何使作品。你不能指望make扩展shell变量。

相反,你应该只依赖make变量。假设:

  • make variable 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-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))

将在库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。并且还有许多可能的改进,例如,每个库的目标......

相关问题