2017-07-31 78 views
1

它能够通过$定义的规则家庭(EVAL $(呼叫)),像这样非常有用:

define SIMPLE_TEMPLATE 
    foo_$(1): 
     echo foo $(1) 
endef 

$(foreach _,A B C,$(eval $(call SIMPLE_TEMPLATE,$_))) 

这将创建目标foo_Afoo_Bfoo_C。在一个更复杂的模板中,引用参数可以很好地调用名称;即$(message)而不是$(1)。事情是这样的:

define SIMPLE_TEMPLATE 
    MSG := $1 
    foo_$(MSG): 
     echo foo $(MSG) 
endef 

$(foreach _,A B C,$(eval $(call SIMPLE_TEMPLATE,$_))) 

几乎作品。 foo_Afoo_B按预期工作,但foo_C没有。有趣的是,将A B C更改为A B C D会导致目标foo_C开始工作。以下是我如何理解发生了什么事情:每次通过eval都会为$(MSG)分配一个值,但直到下一个eval调用才会分配该值。再说一遍,如果在循环中附加额外的传递,这看起来可以工作。但感觉不对。有没有一种“正确”的方式来做到这一点 - 而无需进行额外的黑客攻击?

回答

2

根据定义的方式(A := ...A = ...)和其中(在目标,先决条件,配方中)作出变量定义并使函数在不同的可能时间递归展开。 This section of GNU make manual简要解释了这一点。

我看到2个不同的问题与你的第二个的Makefile:

  1. $(MSG)SIMPLE_TEMPLATE没有在结果作为补充语法的正常解析$(foreach _,A B C,...的膨胀过程中扩大。让我们来看看这一步一步:

    • foreach的扩展:

      $(eval $(call SIMPLE_TEMPLATE,A))) 
      $(eval $(call SIMPLE_TEMPLATE,B))) 
      $(eval $(call SIMPLE_TEMPLATE,C))) 
      
    • eval的扩张是特殊的,它扩展了它的参数,并对其进行实例作为补充结构。所以,要了解,我们必须首先扩大call。在SIMPLE_TEMPLATE的定义中,每个替代$(1)。什么是传递给第一eval,比如说是:

      MSG := A 
      foo_$(MSG): 
          echo foo $(MSG) 
      
    • 但是,在eval参数的扩张仍在继续,直到有一无所有扩大。到MSG引用,这还没有定义,由空字符串替换和最终实例化的构建体是:

      MSG := A 
      foo_: 
          echo foo 
      

    与的echo foo结束一个(不可见)的空间。由于任何构造构造都会依次展开,但这不会改变任何东西,因为没有其他任何东西可以展开。在第二个eval的扩展期间,这一次,MSG的值为A,这要归功于第一个。因此,第二eval接收:

    MSG := B 
        foo_$(MSG)  
         echo foo $(MSG) 
    

    call,其扩展为:

    MSG := B 
        foo_A  
         echo foo A 
    

    ,并对其进行实例作为使构造。这些构造函数再次被扩展(与其他构造一样),但它不会再改变任何东西。同样,第三eval实例:

    MSG := C 
        foo_B  
         echo foo B 
    

    所以,一切的一切,究竟会被实例使结构是:

    MSG := A 
    foo_: 
        echo foo 
    
    MSG := B 
    foo_A: 
        echo foo A 
    
    MSG := C 
    foo_B: 
        echo foo B 
    

    而且你没有任何foo_C目标(但你不想要的foo_目标...)

    逃脱$(MSG)第一和太早扩张$(foreach...扩张过程中,你可以双击该$迹象:

    define SIMPLE_TEMPLATE 
        MSG := $(1) 
        foo_$$(MSG): 
         echo foo $$(MSG) 
    endef 
    

    如果我们运行这一步一步的,第一call将通过:

    MSG := A 
    foo_$$(MSG): 
        echo foo $$(MSG) 
    

    到第一eval,这将扩大其作为:

    MSG := A 
    foo_$(MSG): 
        echo foo $(MSG) 
    

    (饮食一个$$$)并将其实例化为make构造。这些新的构建体也将扩大,因为任何其它品牌结构,这将给:

    MSG := A 
    foo_A: 
        echo foo $(MSG) 
    

    (在配方中$(MSG)尚未展开,因为在配方时,膨胀被推迟到第二阶段,只有在配方被选中执行时才会发生)。在$(foreach _,A B C,...的第一扩张之后,你有什么因而:

    MSG := A 
    foo_A: 
        echo foo $(MSG) 
    
    MSG := B 
    foo_B: 
        echo foo $(MSG) 
    
    MSG := C 
    foo_C: 
        echo foo $(MSG) 
    

    但在这里,你打第二个问题:

  2. 你不同的规则共享相同的MSG使变量。第一阶段后的价值因而解析为C和你有什么等价于:

    MSG := C 
    foo_A: 
        echo foo $(MSG) 
    foo_B: 
        echo foo $(MSG) 
    foo_C: 
        echo foo $(MSG) 
    

    结果将是:

    $ make foo_A foo_B foo_C 
    echo foo C 
    foo C 
    echo foo C 
    foo C 
    echo foo C 
    foo C 
    

    可能不是你想要什么。请注意,即使使用递归扩展变量(MSG = ...),它也是一样的。

为了解决第二个问题,你可以使用相同的对所有目标做变量名,但给它分配目标的具体数值,像:

define SIMPLE_TEMPLATE 
    foo_$(1): MSG := $(1) 
    foo_$(1): 
     echo foo $$(MSG) 
endef 

(注意在配方中$$),这扩展为:

foo_A: MSG := A 
foo_A: 
    echo foo $(MSG) 
... 

或者,也许,使用不同,建造,变量名:

define SIMPLE_TEMPLATE 
    MSG_$(1) := $(1) 
    foo_$(1): 
     echo foo $$(MSG_$(1)) 
endef 

它扩展为:

MSG_A := A 
foo_A: 
    echo foo $(MSG_A) 
... 

双方终于为运行:

$ make foo_A foo_B foo_C 
echo foo A 
foo A 
echo foo B 
foo B 
echo foo C 
foo C 

可能更接近您所期望的。

相关问题