NetBSD Problem Report #43821

From cheusov@tut.by  Tue Aug 31 12:15:26 2010
Return-Path: <cheusov@tut.by>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by www.NetBSD.org (Postfix) with ESMTP id 325C763BC45
	for <gnats-bugs@gnats.netbsd.org>; Tue, 31 Aug 2010 12:15:26 +0000 (UTC)
Message-Id: <s93occjt234.fsf@centos.imb.invention.com>
Date: Tue, 31 Aug 2010 15:10:23 +0300
From: cheusov@tut.by
To: gnats-bugs@gnats.netbsd.org
Subject: make: longstanding bug with loop variables
X-Send-Pr-Version: 3.113.1
X-GNATS-Notify:

>Number:         43821
>Category:       bin
>Synopsis:       make: oldstanding bug with loop variables
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    bin-bug-people
>State:          suspended
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 31 12:20:00 +0000 2010
>Closed-Date:    
>Last-Modified:  Mon May 23 22:35:01 +0000 2022
>Originator:     Aleksey Cheusov
>Release:        Linux 2.6.18-194.el5xen
>Organization:
<organization of PR author (multiple lines)>
>Environment:
System: Linux centos.imb.invention.com 2.6.18-194.el5xen #1 SMP Fri Apr 2 16:16:54 EDT 2010 i686 i686 i386 GNU/Linux
Architecture: i686

>Description:

    .for i in 1 2
    .if empty(i:M2)
    res=passed
    .endif
    .endfor

    all:
            @echo ${res}

With Makefile shown above bmake works like this

    0 cheusov>nbmake -f ~/tmp/2.mk
    nbmake: "/home/cheusov/tmp/2.mk" line 2: Malformed conditional (empty(i:M2))
    nbmake: "/home/cheusov/tmp/2.mk" line 2: Malformed conditional (empty(i:M2))
    nbmake: Fatal errors encountered -- cannot continue

    nbmake: stopped in /home/cheusov
    1 cheusov>

At the same time 

    .for i in 1 2
    j=${i}
    .if empty(j:M2)
    res=passed
    .endif
    .endfor

    all:
            @echo ${res}

works normally.

    0 cheusov>nbmake -f ~/tmp/2.mk
    passed
    0 cheusov>

As far as I understand this bug is very old. In bsd.subdir.mk
we can see

    # for obscure reasons, we can't do a simple .if ${dir} == ".WAIT"
    # but have to assign to __TARGDIR first.
    .for targ in ${TARGETS}
    .for dir in ${__REALSUBDIR}
    __TARGDIR := ${dir}
    .if ${__TARGDIR} == ".WAIT"

but I cannot find any explanation in bmake.1.
So, I assume this is a bug and hope it can be fixed.

>How-To-Repeat:
>Fix:

>Release-Note:

>Audit-Trail:

State-Changed-From-To: open->suspended
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Wed, 01 Sep 2010 03:22:53 +0000
State-Changed-Why:
Whether it's a bug is debatable (getting "malformed conditional" is a bug
but that's a minor aspect of the issue) but this is deeply ingrained
behavior of loop variables and it's not readily changed or "fixed". Try
this example on for size:

.for i in 1 2 3
j=${i}       
.if !empty(j:M2)
res=passed ${j}
.endif  
.endfor

 all:
	@echo ${res}



From: Aleksey Cheusov <cheusov@tut.by>
To: gnats-bugs@NetBSD.org
Cc: gnats-admin@netbsd.org, netbsd-bugs@netbsd.org, dholland@NetBSD.org
Subject: Re: bin/43821 (make: oldstanding bug with loop variables)
Date: Wed, 01 Sep 2010 10:09:46 +0300

 > Whether it's a bug is debatable (getting "malformed conditional" is a bug
 > but that's a minor aspect of the issue) but this is deeply ingrained
 > behavior of loop variables and it's not readily changed or "fixed".
 From the documentation it is unclear that loop variables cannot be used
 in condition statements directly just like normal variables. So,
 formally speaking, it is definitely a bug. If it is really really
 impossible to fix it, then it should be documented ;-) As for your
 example code, of course I know about such a workaround. My original post
 contained mostly the same fragment. I also know when variables are
 expanded but loop variable expansion doesn't relate to this PR.

 http://mail-index.netbsd.org/tech-userlevel/2010/06/08/msg003690.html
 http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.bin/make/make.1.diff?r1=1.174&r2=1.175&only_with_tag=MAIN&f=h

 > Try this example on for size:

 > .for i in 1 2 3
 > j=${i}       
 > .if !empty(j:M2)
 > res=passed ${j}
 > .endif  
 > .endfor

 >  all:
 > 	@echo ${res}

 -- 
 Best regards, Aleksey Cheusov.

From: David Laight <david@l8s.co.uk>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: bin/43821: make: longstanding bug with loop variables
Date: Wed, 1 Sep 2010 10:53:01 +0100

 On Tue, Aug 31, 2010 at 12:20:01PM +0000, cheusov@tut.by wrote:
 > >Number:         43821
 > >Category:       bin
 > >Synopsis:       make: oldstanding bug with loop variables
 ...
 > >Description:
 > 
 >     .for i in 1 2
 >     .if empty(i:M2)
 >     res=passed
 >     .endif
 >     .endfor
 ...

 The 'problem' is that the code that substitutes the loop variables
 into the loop body before the body is parsed (yes it does work that way)
 doesn't identify empty(...) as equivalent to $(...) and modify the text.

 Since empty() is just a comparison against "" there is a trivial
 work around.

 A better fix is to rework the .for handling (again) so that the loop
 control variables are put into the main symbol table for the first
 pass processing, and the textual substitution done when lines are saved.
 eg for variable assignments (except :=) and shell commands.

 If that were done then all the . directives would work identically
 on loop variables.

 	David

 -- 
 David Laight: david@l8s.co.uk

From: Aleksey Cheusov <vle@gmx.net>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: bin/43821: make: longstanding bug with loop variables
Date: Wed, 01 Sep 2010 23:16:30 +0300

 offlist.

 I don't try to push people to fix this issue.
 But I whould like to see this behaviour documented in one way or another.
 How about something like?

 .SS BUGS
 Due to ... loop variable cannot be used inside the loop in condition
 statements. Workaround is...

 As you understand what it's happening here maybe you can update man page?

 >  The 'problem' is that the code that substitutes the loop variables
 >  into the loop body before the body is parsed (yes it does work that way)
 >  doesn't identify empty(...) as equivalent to $(...) and modify the text.
 >  
 >  Since empty() is just a comparison against "" there is a trivial
 >  work around.
 >  
 >  A better fix is to rework the .for handling (again) so that the loop
 >  control variables are put into the main symbol table for the first
 >  pass processing, and the textual substitution done when lines are saved.
 >  eg for variable assignments (except :=) and shell commands.
 >  
 >  If that were done then all the . directives would work identically
 >  on loop variables.
 >  
 >  	David
 >  
 >  -- 
 >  David Laight: david@l8s.co.uk
 >  


 -- 
 Best regards, Aleksey Cheusov.

From: Aleksey Cheusov <cheusov@tut.by>
To: gnats-bugs@NetBSD.org, David Laight <david@l8s.co.uk>
Cc: gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Subject: Re: bin/43821: make: longstanding bug with loop variables
Date: Wed, 01 Sep 2010 23:29:44 +0300

 Sorry. I sent this email to this list by mistake :-/
 Now I added David to "To".

 >  I don't try to push people to fix this issue.
 >  But I whould like to see this behaviour documented in one way or another.
 >  How about something like?
 >  
 >  .SS BUGS
 >  Due to ... loop variable cannot be used inside the loop in condition
 >  statements. Workaround is...
 >  
 >  As you understand what it's happening here maybe you can update man page?

 -- 
 Best regards, Aleksey Cheusov.

From: David Holland <dholland-bugs@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: bin/43821: make: longstanding bug with loop variables
Date: Sat, 9 Oct 2010 21:03:41 +0000

 On Wed, Sep 01, 2010 at 09:50:04AM +0000, David Laight wrote:
  >  The 'problem' is that the code that substitutes the loop variables
  >  into the loop body before the body is parsed (yes it does work that way)
  >  doesn't identify empty(...) as equivalent to $(...) and modify the text.

 ...which it can't without doing a full parse.

  >  Since empty() is just a comparison against "" there is a trivial
  >  work around.
  >  
  >  A better fix is to rework the .for handling (again) so that the loop
  >  control variables are put into the main symbol table for the first
  >  pass processing, and the textual substitution done when lines are saved.
  >  eg for variable assignments (except :=) and shell commands.

 I think that's going to turn into a nightmare. I think the only
 reasonable approach for this (and many other related problems) is to
 tokenize and parse first before substituting anything, as I've
 suggested before. Unfortunately, it's a huge undertaking.

 -- 
 David A. Holland
 dholland@netbsd.org

From: "Roland Illig" <rillig@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/43821 CVS commit: src
Date: Mon, 23 May 2022 22:33:56 +0000

 Module Name:	src
 Committed By:	rillig
 Date:		Mon May 23 22:33:56 UTC 2022

 Modified Files:
 	src/distrib/sets/lists/tests: mi
 	src/usr.bin/make/unit-tests: Makefile
 Added Files:
 	src/usr.bin/make/unit-tests: directive-for-empty.exp
 	    directive-for-empty.mk

 Log Message:
 tests/make: document and demonstrate .for i containing .if empty(i)

 PR bin/43821 describes the inconsistency that in a '.for i' loop, the
 condition '.if ${i:M*.c}' works since 2009 while the seemingly
 equivalent condition '.if !empty(i:M*.c)' does not access the variable
 'i' from the .for loop but instead the global 'i'.

 Resolving this situation in a backwards-compatible and non-surprising
 way is hard, as make has grown several features during the last 20 years
 that interact in various edge cases.  For now, document the most obvious
 pitfalls.


 To generate a diff of this commit:
 cvs rdiff -u -r1.1206 -r1.1207 src/distrib/sets/lists/tests/mi
 cvs rdiff -u -r1.315 -r1.316 src/usr.bin/make/unit-tests/Makefile
 cvs rdiff -u -r0 -r1.1 src/usr.bin/make/unit-tests/directive-for-empty.exp \
     src/usr.bin/make/unit-tests/directive-for-empty.mk

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.46 2020/01/03 16:35:01 leot Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2020 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.