Search code examples
makefilegnu

Why do I need eval to set variable in makefile function?


If I have the following at the top of a gnu makefile:

$(if _,a:=1)
$(info a=$a)

Compilation fails (make-3.81: *** No rule to make target '=1', needed by 'a'. Stop., or *** missing separator. Stop. if I exclude the colon). I know I can get around this by using an eval, but I'm not understanding why it's required. Shouldn't this expand to a:=1, be parsed, and set a to 1?


Solution

  • I'm not understanding why it's required

    Well, such is the design.

    Evaluation procedure always performs a (recursive) expansion (except for "the initial evaluation" where subsequent expansion can be effectively stopped by =, i.e. "lazy assignment"), but expansion procedure never does evaluation, unless it's explicitly told so (basically, $(eval ...) is such an order to switch from expansion to evaluation).

    Consider this:

    x := 0
    y := 1
    # z is set to "y<space><equal><space><dollar>x"
    z = y = $x
    
    # [0] [1] [y = $x]
    $(info [$x] [$y] [$(value z)])
    
    # error as "y = $x" will not be re-evaluated
    #$z
    
    # effectively sets y to "0"
    $(eval $z)
    
    # [0] [0] [y = $x]
    $(info [$x] [$y] [$(value z)])
    

    From make's point of view $(if cond,x=y) does not differ much from $z --- it's expanded but not evaluated. No matter where it stands. Just think anything of a form $(...) to be "data", not "code".