NetBSD Problem Report #43132

From  Tue Apr  6 06:49:37 2010
Return-Path: <>
Received: from ( [])
	by (Postfix) with ESMTP id A740463B86C
	for <>; Tue,  6 Apr 2010 06:49:37 +0000 (UTC)
Message-Id: <>
Date: Tue,  6 Apr 2010 02:48:35 -0400 (EDT)
Subject: make(1) improper variable expansion
X-Send-Pr-Version: 3.95

>Number:         43132
>Category:       toolchain
>Synopsis:       make(1) improper variable expansion
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    toolchain-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Apr 06 06:50:00 +0000 2010
>Originator:     David A. Holland
>Release:        NetBSD 5.99.24 (20100327)
System: NetBSD tanaqui 5.99.22 NetBSD 5.99.22 (TANAQUI) #31: Tue Dec 8 22:53:35 EST 2009 dholland@tanaqui:/usr/src/sys/arch/i386/compile/TANAQUI i386
Architecture: i386
Machine: i386

Make expands some variables at parse time and some variables at run
time, based on internal flags. This is well and good, if perhaps
sometimes aggravating and/or confusing to beginners; but it means that
some lines of the makefile are variable-expanded more than once:
   - recipe lines are expanded only at runtime
   - directive and assignment lines are expanded only at parse time
   - rule lines are expanded at both times.

This leads to inconsistencies if $$ appears on a rule line.
Specifically, $$ followed by a variable name, as in $$(FOO), is
expanded with the runtime value of the variable. $$(FOO) is turned
into $(FOO) by the first variable expansion pass, and then the second
runtime pass turns that into the post-parse value of FOO. However,
this works only on rule lines.

For variables that are not expanded at all until runtime, like
$(.TARGET), writing $$ instead of $ does not change the behavior; in
the $ case the variable is not expanded on the first pass, and in the
$$ case the firts pass does nothing but turn the $$ into $ where it's
seen by the second pass.

Note that the observed behavior is also inconsistent with the expected
behavior of variable expansion, which is that expansion continues
until every variable that can be expanded has been expanded.


   all: $(FOO)
   	@echo foo

   % make

   all: $$(FOO)
   	@echo foo

   % make
   make: don't know how to make bar. Stop

   all: $$$$(FOO)
   	@echo foo

   % make
   make: don't know how to make $(FOO). Stop

   all: $(.TARGET).foo
	   @echo foo

   % make
   make: don't know how to make Stop

   all: $$(.TARGET).foo
	   @echo foo

   % make
   make: don't know how to make Stop

   all: $$$$(.TARGET).foo
	   @echo foo

   % make
   make: don't know how to make $(.TARGET).foo. Stop

   all: $$(FOO)
	   @echo '$$(FOO)'

   % make

(which shows that the rule line and recipe line are being handled


In the long term, probably parse trees. For now, maybe substitute $$
back in on the first pass on rule lines? That'd be gross but it ought
to work.

Note that there perhaps ought to be some way to get the run-time value
on a rule line (and the parse-time value in a recipe too, probably)
but it should absolutely not be done by exposing this quirk of the
eval behavior. make has too many odd eval quirks already.

You can also sort of already get the run-time value in a recipe by
misusing for loops, like this:
   .for FU in $(FOO)
	   @echo $(FU)

   % make

but this is gross and only works for values that are single words.
(The :tW modifier doesn't help.) I think the right approach is to
allow the user to explicitly tag variables as loop-scope or
target-scope. (This would also allow working loop-local variables,
which is currently a thorny mess.)

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD:,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.