tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: 10.1 make oddity



Am 09.06.2026 um 01:13 schrieb Mouse:
> I recently tried to help someone set up some of my infrastructure on a
> 10.1 machine.  I got reports of some bizarre messages from make.  So I
> tried it on a 9.1 machine.  I got the same messages:
> 
> make: Unclosed substitution for  (; missing)
> make: Unclosed substitution for  (; missing)
> make: "/home/mouse/z.local/lib/make/local-prog" line 115: Need an operator
> 
> Here's a cut-down test case:
> 
> V = a.1
> D = /tmp
> 
> .MAIN: dummy
> 
> .PHONY: dummy
> dummy:
> 
> .for x in $V
> $(x:C;^(.*)\.([0-9].*)$;$D/cat\2/\1.0;):		\
> 		$(x:C;^.*\.([0-9].*)$;$D/cat\1;)	\
> 		$(x:C;\.([0-9].*)$;.cat\1;)
> 	cp $(x:C;\.([0-9].*)$;.cat\1;) $(.TARGET)
> .endfor
> 
> On a hunch, I tried replacing the ;s with ^Bs (as in, tr \; \\2 for the test
> case) - and the symptom went away.

> make(1) on 9.1 says that :C is just like :S except that it uses
> regexes.  I *think* I originated this code, long ago, and my version of
> it does indeed work with semicolons as delimiters.

According to my make-archive, there was indeed a time where your test
ran successfully:

> 1998.09.18.20.35.12
> | exit status 0
> 2008.12.21.10.44.10

Then, in December of 2008, the handling of .for loops changed, and since
then, your test failed:

> 2008.12.21.18.06.53
> | make: Unknown modifier '      '
> | make: "/home/rillig/proj/make-archive/mouse.mk" line 8: Missing dependency operator
> | make: Fatal errors encountered -- cannot continue
> |
> | make: stopped in /home/rillig/proj/make-archive
> | exit status 1
> 2009.10.02.07.43.15

More than a year earlier, make's parser was changed to look for ";" in
dependency lines, to support shell commands in the same line:

> target: sources; cc -o target -c sources

Finding that semicolon has always been messy, since its first appearance
in parse.c 1.127 from 2007.01.01.21.47.32, where a comment said:

> No attempt is made to avoid ';' inside substitution patterns.

It improved a bit in parse.c 1.158 from 2009.10.07.16.40.30, where the
comment changed to:

> Attempt to avoid ';' inside substitution patterns.

But still, the code for finding a semicolon didn't cover all edge cases,
as it didn't simply call Var_Parse but instead grew its own parser for
balanced parentheses and braces. Since 2009, that code counts "$(" as
opening and every ")" as closing. For your test case, this means:

> $(x:C;^(.*)\.([0-9].*)$;$D/cat\2/\1.0;):		\
> 		$(x:C;^.*\.([0-9].*)$;$D/cat\1;)	\
> 		$(x:C;\.([0-9].*)$;.cat\1;)

The "$(" is interpreted as an opening parenthesis, but the following "("
is not. The ")" after the ".*" is interpreted as closing, so we're back
at depth 0.

The following "(" is not opening, and the following ")" is not closing,
as we're already at depth 0.

The "$;" is then not interpreted as an expression with variable name
";", instead this semicolon is interpreted as terminating the dependency
line, starting the shell command.

> but it appears this is not actually true.  What are the actual
> restrictions?  Or is this a bug that needs fixing?  Or am I completely
> confused here somehow?

I consider the ad-hoc semicolon finder a bug.

I have a patch ready that fixes the code to use the existing expression
parser. With this fix, your test results in this dependency:

> /tmp/cat1/a.0:		 /tmp/cat1	 a.cat1

That looks good to me.

Roland



Home | Main Index | Thread Index | Old Index