【问题标题】:Defining custom GNU make functions定义自定义 GNU make 函数
【发布时间】:2011-06-29 12:51:49
【问题描述】:

下面示例代码中的dep2函数有什么问题?

dep1 = $(eval makefile_list_$1 := $(MAKEFILE_LIST))$(eval -include $1.mk)$(eval MAKEFILE_LIST := $(makefile_list_$1))

define dep2
$(eval makefile_list_$1 := $(MAKEFILE_LIST))
$(eval -include $1.mk)
$(eval MAKEFILE_LIST := $(makefile_list_$1))
endef

$(call dep1,test)
$(call dep2,test)

.DEFAULT_TARGET: all
.PHONY: all
all:
    @echo $@

GNU make 3.81 和 3.82 产生 Makefile:10: *** missing separator. Stop. 指向 dep2 调用, dep1 运行没有错误。这两个变体之间的唯一区别是 dep2 中的换行符(以及我想使用 define 的全部原因)。

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    你忘了=:
    定义 dep2 =

    编辑:
    在每一行的末尾放置一个分号。我已经对此进行了测试,它可以工作(在 GNUMake 3.81 中)。

    define dep2
    $(eval makefile_list_$1 := $(MAKEFILE_LIST));
    $(eval -include $1.mk);
    $(eval MAKEFILE_LIST := $(makefile_list_$1));
    endef
    

    为什么我不知道这些分号是必需的,但在文档中 define 似乎仅在定义要用于的 shell 命令序列时用于多行“变量”食谱,而不是制作命令,所以可能规则有点不同。

    【讨论】:

    • 不,= 是可选的(仅在 GNU make 3.82 中引入)。添加它并没有什么不同。
    • @g.b.:你真的尝试过吗?我做到了(使用 GNU make 3.81),它确实有所作为。如果我添加=,它会按预期工作。
    • @eriktous:是的,我尝试使用 3.82。如果定义语句后面跟着 =,旧版本将完全忽略它,这就是您没有收到错误消息的原因。
    • @eriktous:哦,太好了,现在我今晚睡不着了,非常感谢。
    • 我可以在 make 手册中找到的关于分号的唯一相关内容是关于 make 生成的错误的附录 B:if the line has a semicolon as the first non-whitespace character; make interprets this to mean you left out the "target: prerequisite" section of a rule。注意eval 函数的结果总是空字符串。
    【解决方案2】:

    我会将$(eval ...) 调用移到dep2 之外。通过这种方式,dep2 中不需要分号。这意味着将某些扩展的$ 标志加倍,以避免过早进行扩展。所以:

    define dep2
    makefile_list_$1 := $$(MAKEFILE_LIST)
    -include $1.mk
    MAKEFILE_LIST := $$(makefile_list_$1)
    endef
    
    $(eval $(call dep2,test))
    
    # Quick checks for testing, to be removed from the final code...
    $(info $(makefile_list_test))
    $(info $(MAKEFILE_LIST))
    
    .DEFAULT_TARGET: all
    .PHONY: all
    all:
        @echo $@
    

    我已经测试了上面的代码,它适用于 Gnu Make 4.0。我希望它可以恢复到 Gnu Make 3.8x。 $(eval $(call ...)) 模式是我执行自定义函数时经常使用的方法,而且我已经使用了很长时间了。

    【讨论】:

      【解决方案3】:

      您可以按照以下行来终止错误:

      FOO := $(call dep2, test)
      

      我猜原因是早期版本的gcc(3.8.1/2)只能接受nothing作为表达式的返回。

      例如$(info string) 不返回任何内容,但$(call dep2, test) 返回2 个换行符。

      【讨论】:

        【解决方案4】:

        您所做的事情有很多可以改进的地方。一方面,您真的想将 eval 调用分解为顶部的单个调用。

        但是,您的特殊问题源于不了解 make 的 define 命令使用的多行递归字符串从不包含 Lady 新行。编写可评估函数最自然的约定是

        定义 Foo 1号线 2号线

        endef

        您可以通过 info 命令查看字符串 eval is seen 并查看它的作用,例如 $(info $(call Foo,x) $(call Foo,y))。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多