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
signature.asc
Description: This is a digitally signed message part

