Subject: Re: [bug#60535] [PATCH] depend2: switch echo|sed to automatic vars

From: Mike Frysinger <[email-masked]>
Date: Wed, 4 Jan 2023 22:41:15 -0500

On 04 Jan 2023 21:10, Nick Bowler wrote:
> Except for one minor detail, $(@F) and $(@D) are highly portable.  I
> expect they were in the very first POSIX.2 specs as they predate the
> earliest standards; I believe they first appeared in UNIX System V (ca.
> 1983) and were later added to BSD in 4.3BSD-Reno (ca. 1990).
> 
> The only potential problem I am aware of with these features is one
> implementation (dmake) which does not follow the POSIX rule of excluding
> the trailing slash from the directory part, and (a bit more troublesome)
> will expand $(@D) to the empty string if the directory part is empty,
> instead of . as required by POSIX.  Usually this is not a major issue,
> as writing something like ./$(@D)/$(@F) is usually sufficient to avoid
> any problems with empty $(@D).

thanks ... i vaguely recall seeing a thread somewhere in the last year or
two talking about portable $(@D)/$(@F) issues somewhere which is how i
learned about these in the first place, but i can't seem to locate it, and
the syntax is not conducive to Google searches.  you don't happen to know
what i'm remembering ?  or have a link to some docs about how portable
these vars are ?  i thought it'd be useful to include them in our docs
and/or manual somewhere.

i can build & install dmake easily since someone is maintaining it in GH:
	https://github.com/jimjag/dmake
i'll throw some bugs at them :)

> It's worth noting that $(?F), $(?D), $(%F) and $(%D) were never added
> to BSD and as a result are missing from many BSD derivatives.  However,
> these variables are of limited utility and are unlikely to be missed.

that'll be good to note in our docs too

> The $(x:a=b) suffix substitutions are of identical vintage, and as
> far as I know every make supporting file/directory variables also,
> in principle, supports suffix substitution too.  However, there are
> many bugs in real-world implementations of this feature.
> 
> Of particular relevance to this patch: older versions of NetBSD make,
> while they do support suffix substitution, fail to correctly parse
> $(@F:.o=):
> 
>   % cat >Makefile <<'EOF'
> foo/bar.o:
> 	echo $(@F:.o=)
> EOF
>   % make
>   echo bar.o.o=)
>   Syntax error: ")" unexpected
>   *** Error code 2
> 
> NetBSD make was widely adopted by other systems, so this particular
> issue may actually be found elsewhere.  This bug was present as recently
> as NetBSD 7.2 (ca. 2018).  Furthermore, old versions of FreeBSD (before
> they ditched their own make in favour of NetBSD's version) also fail to
> correctly handle $(@F:.o=), but in a different way.
> 
> The good news is that these problems can be worked around pretty easily
> simply by using another variable:
> 
>   % cat >Makefile <<'EOF'
> at_f = $(@F)
> foo/bar.o:
> 	echo $(at_f:.o=)
> EOF
>   % make
>   echo bar
>   bar
> 
> But this workaround trips over a different suffix substitution bug on
> ULTRIX, which would otherwise work just fine with plain $(@F:.o=).
> Maybe ULTRIX is not worth worrying about these days, but nevertheless,
> it is not too hard to detect and work around both problems in pure
> shell, which should still work to avoid the additional forks/sed,
> maybe something like:
> 
>   % cat >Makefile <<'EOF'
> at_f = $(@F)
> foo/bar.o:
> 	a='$(@F:.o=)' b='$(at_f:.o=)'; test x"$$a.o" = x"$(@F)" || a=$$b;\
> 	  echo $$a
> EOF

this is interesting.  we actually have some uses of this already in
the tree.  no one seems to have complained though afaict.

automake-1.13+ has:
lib/am/subdirs.am:AM_RECURSIVE_TARGETS += $(am__recursive_targets:-recursive=)

automake-1.9+ has:
lib/am/texibuild.am:      for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \

dmake is one implementation that fails, and your suggestion doesn't work :/.
$ dmake foo/bar.o
dmake:  Error: -- Incomplete macro expression [)' b='$(at_f:.o=)'; test x"$$a.o" = x"$(@F)" || a=$$b;\
                echo $$a]

how portable is $() ?  that seems to work in GNU make & dmake.
$ cat Makefile
DEPDIR = ./$(@D)/depdir/$(@F:.o=$())
foo/bar.o:
	@echo $(DEPDIR)
$ dmake
./foo//depdir/bar
-mike