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:
(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.