Nilesh Patra wrote:
> While this is technically correct, is there a reason that you do not wish to 
> use "%"?
One is that the percent comes from the GNU Make-specific syntax for inference 
rules, which are usually expressed as something like "%.o: %.c". In this 
instance there are no prerequesites for the rule with the percent symbol, so in 
my opinion it's a botch to use pattern rules for this. Based solely on merits, 
".DEFAULT" is a lot more clear and less cryptic than "%", especially because 
there is no intention to match an actual pattern. I wish I had a less harsh 
phrase, but this feels like cargo cult boilerplate, and in that regard 
Lintian's exceptionally harsh treatment of respectable syntax which is more 
interoperable feels like ossification (see my next answer to your other 
remark): tying my hands and barring me from using my creativity to try 
something neat. Using a dot before a rule name is also the standard convention 
for denoting that a target is somehow "special" and may not conceptually 
represent a typical target.
Also, .DEFAULT is inherently a unique target definition, but the 
"pseudo-pattern-rule" syntax can cause extra confusion and also partially 
breaks using pattern rules for their intended purpose. Consider this example:
%:
        echo Foo
%: %.c
        echo Bar # in real usage this would be something like 'c99 -o $@ $<'

Now create a file 'foo.c' in the same directory, and pretend you want to make 
the file 'foo' from it like so:
$ touch foo.c
$ make foo
        echo Foo
        Foo

So here GNU Make didn't care about the specificity of the rules and ignored 
that the more specific rule, to make foo from foo.c, existed. Experimentation 
suggests Make solely uses the first rule it reads in the file. This means that 
even when including makefiles (possibly from upstream projects), as they are 
effectively appended to yours, any such pattern rules of theirs may never be 
invoked.
As specified at 
https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html#tag_20_76_13_04
 the rules for the .DEFAULT special target are only run if there would 
otherwise be no matching recipe at all. So if we swap out "%:" and replace it 
with ".DEFAULT:", the Makefile looks like this:
.DEFAULT:
        echo Foo
%: %.c
        echo Bar

and try the invocation just as earlier:
$ touch foo.c && make foo
        echo Bar
        Bar

Huzzah! So this syntax, chosen from a "what you mean is what you get" sort of 
thought process, has an advantage for when you actually *do* have a 
circumstance that calls for pattern rules. In the first makefile, the second 
"%: %.c" recipe appears to have become dead code. But I've pushed this to find 
something even more weird: try
%:
        echo Foo
%:
        echo Bar

From what we saw so far, we'd think the first rule would be the one chosen, but 
actually not!
$ make baz
        echo Bar
        Bar

So now Make is going by the last definition it sees instead of the first, when 
two pattern rules would match...
As one can see at https://cgit.git.savannah.gnu.org/cgit/make.git/tree/NEWS the 
non-standard features of GNU Make may and frequently do change behavior, 
intentionally or otherwise, so when the POSIX features are adequate using those 
is preferable. It also makes it easier to cross-check the soundness of 
debian/rules and other makefiles by using other versions of Make; this might 
help catch parallel make race conditions (which have plagued Debian packages 
before, a la "noparallel" and mass bug filings).
Also I've learned Make from resources other than GNU's manual, so a lot of the 
GNU-specific syntax really makes my head spin and, as here, sometimes doesn't 
actually solve a problem.

Lastly, I'm a member of The Austin Group which develops POSIX and the Single 
UNIX Specifications, so I like to "eat my own dogfood" and reference those 
standards when they're relevant. They sometimes solve, or try to solve, 
problems of interest to Debian (e.g. should -latomic ever be needed for a C 
compiler? https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81358#c16 has my verdict 
about this issue affecting many of our architectures), and comparing 
specifications and discussion with other distros and operating systems sets me 
up to be an effective problem solver, I think.

Also Debian Policy lays out a tip for shell scripts:
> If a shell script requires non-POSIX.1-2017 features from the shell 
> interpreter other than those listed above, the appropriate shell must be 
> specified in the first line of the script (e.g., #!/bin/bash) and the package 
> must depend on the package providing the shell (unless the shell package is 
> marked “Essential”, as in the case of bash).
That makes sense. The GNU Make package provides the 'gmake' symlink as an alias 
for GNU Make; this is common on BSD systems. However, as described in that 
Debian Policy bug, the languages suffers from confusion of necessity and 
sufficiency. It prescribes that the first line must be exactly the string 
"#!/usr/bin/make -f", so if I were to generalize the best practice for shell 
scripts and write instead "#!/usr/bin/gmake -f", that would actually be 
prohibited by Debian Policy. That would be the right, semantic way to say 
debian/rules is designed for GNU Make; but since this is forbidden, even if by 
an oversight, it would be nice to make a more portable makefile.

[This paragraph is a digression.] Using and contributing to Debian is a lot 
less fun for me when I feel held back, and for reasons I'm struggling to 
articulate, it feels much worse when this happens due to some accident or 
oversight. I follow discussion on debian-devel about normalizing policies and 
best practices, rulemaking and such. It feels like as a project we're kind of 
missing the plot: what's this actually going to help? For example, if a Debian 
package that *genuinely* didn't have the required targets defined were made, 
and uploading it were attempted, it probably wouldn't get very far anyway... In 
general this rule is useful as a tool when drafting packages, but if it were 
removed from the no-override auto-reject list, would it really be missed?
Likewise there are ways to make an executable makefile without have the shebang 
line (which Debian Policy doesn't explicitly prescribe needs to work, and it's 
optional per https://www.kernelconfig.io/config_binfmt_script even in the 
kernel). Consider this six-line text file:
# \
exec make -f - -- "$@" <<'#END'
.POSIX:
.DEFAULT:
        @echo 'Hello from $<'
#END
It is both a valid Makefile and a shell script that takes care of calling 
'make' for you; that's pretty neat! I learned this from someone else who 
probably had just as much fun, at 
https://xrefactor.com/blog/polyglot-in-c-makefile-and-shell-script and it works 
because line continuation inside a comment works in make syntax but not shell 
syntax. That's fun and it solves the problem perfectly, but again, Debian 
Policy forbids this.
For another example of this troubling issue take a look at my mail 
https://lists.debian.org/msgid-search/7fa5675f5f658471d4cbb51a0f583337%40posteo.net
 from last year, about /usr/lib/bpf/ technically being a disallowed path for 
eBPF binary files:
> However, I think the prohibition on using /usr/lib/$ARCH for values of $ARCH 
> that can never be true Debian architectures by their very nature, is probably 
> an oversight in crafting Debian Policy.
In particular the *reason* or *intention* for use of those paths being 
forbidden, does not apply in the specific case, but nevertheless it's 
increasingly exhausting to steer clear of these cemented mistakes.
[/end digression]

> I ran a search [1] and I don't see even a single package in the archive that 
> uses .DEFAULT rule.
That's because, as I had happen to me, the fatal Lintian error is so serious 
that it results in an automatic and non-overridable FTP Master rejection: 
https://salsa.debian.org/lintian/lintian/-/blob/master/data/archive/auto-rejection.yaml#L76

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to