Subject: Re: fixing pkglint warnings
To: None <tech-pkg@netbsd.org>
From: Roland Illig <rillig@NetBSD.org>
List: tech-pkg
Date: 12/02/2005 23:45:39
Roland Illig wrote:
> joerg@britannica.bec.de wrote:
> 
>> On Thu, Dec 01, 2005 at 07:14:03PM +0100, Roland Illig wrote:
>>
>>> - Any objections against this?
>>
>>
>>
>> No objection, but please try to commit it in one big swap. It saves the
>> bulk builders a bunch of time :-)
> 
> 
> After a one-day-marathon of going through all packages that had pkglint 
> warnings, this is the result:
> 
>     ftp://ftp.NetBSD.org/pub/pkgsrc/misc/rillig/pkgsrc.diff
>     ftp://ftp.NetBSD.org/pub/pkgsrc/misc/rillig/pkgsrc.diff.gz
> 
> Any volunteers to review it?

To make a review easier, I will outline some of the ideas leading to the 
changes, in order of appearance in the diff file.

===> Replacing ".ifdef" with ".if defined(...)"

This is generally useful because the parser of NetBSD's make(1) is 
sloppy in many areas. It accepts weird directives like ".elifndef", but 
doesn't understand them. Therefore I decided that it's best to only use 
the most basic features. Furthermore, the ".ifndef" directive isn't in 
such wide use as that of the C preprocessor, maybe because the visually 
appealing counterpart ".define" does not exist. Compare the following 
code snippets:

     #ifndef HAVE_FOO_H
     #define HAVE_FOO_H

and

     .ifndef HAVE_FOO_H
     HAVE_FOO_H=        # defined

The first one looks like a block, while the second one does not. So I 
didn't see the need to keep the ".ifndef".

===> Forcing many variables to be modified using only "+="

The whole pkgsrc system would be much more understandable if we had only 
variables that are modified using a very restricted set of operations. 
The operations I have in mind are:

     "?="    default value assignment
     "+="    appending to a list
     "="     simple assignment (should happen only once per variable)

That way, if you add something to a list you can be sure that it doesn't 
get removed later. Currently this is not guaranteed. Just have a look 
for the various places where CONFIGURE_ARGS is modified using the ":=" 
operator, which evaluates its right-hand-side and assigns it to its 
left-hand-side. So let's say you have the following lines:

     CPPFLAGS+=         -DFOO=1
     CONFIGURE_ARGS+=   CPPFLAGS=${CPPFLAGS:M*:Q}
     CONFIGURE_ARGS:=   ${CONFIGURE_ARGS:N--with-ncurses}
     CPPFLAGS+=         -I/usr/local/include

The last addition to CPPFLAGS won't make it into CONFIGURE_ARGS. Now 
imagine that these four assignments are all in individual files, spread 
around the whole pkgsrc tree. How do you find the cause that 
"-I/usr/local/include" is not included in the CPPFLAGS passed to the 
configure script?

For the GCC_REQD variable, the "+=" operator is required because there 
may be many sources requiring a special version of gcc. It wouldn't be 
helpful if one source could override all the others. The same goes for 
the BUILD_DEFS variable, which has also been assigned unconditionally in 
many cases, including ones in Makefile.common files. In these cases you 
cannot be sure at all what has happened before.

===> Platform triples

A platform triple has the form <OPSYS>-<OS_VERSION>-<MACHINE_ARCH>. Each 
of these components may be a shell globbing expression.

I had been curious which combinations of OPSYS, OS_VERSION and 
MACHINE_ARCH were used in pkgsrc, so I have written a pkglint check for 
it. As a result I noticed that in many cases, the platform triples were 
actually only pairs. To make pkgsrc more uniform, I decided to change 
the pairs into triples, so that a human, reading a package Makefile, 
will see that a triple is meant.

===> White-space at the beginning of lines

I often search for variables with "grep -wr ^MAKE_ENV /usr/pkgsrc", 
because by looking at many Makefiles, this seemed to be the way 
variables are declared: starting in line 1. Because there are only very 
few exceptions to this scheme, I had not expected variables that are 
declared with leading white-space. To make pkgsrc more "expected", I've 
added this check to pkglint.

===> The :Q and the :M*:Q operators for quoting variables

Currently pkgsrc cannot handle white-space. No, it really cannot. But 
I'd like it to be able to handle white-space. Maybe one day, when the 
GNU make(1) and the GNU autotools become mature, they will allow 
white-space in filenames, and how great would it be if it worked 
immediately with pkgsrc?

All jokes aside, we already have packages containing white-space and 
other special characters in their filenames. They already work if you're 
lucky, but please, please, please, don't try to embed white-space into 
your LOCALBASE variable. That does not work and will lead to undefined 
behavior, because even in the pkgsrc infrastructure, not enough time and 
knowledge has been invested for these kinds of things.

To make the situation better we need more knowledge about proper quoting 
and filename handling. Replacing the various ad-hoc quoting styles with 
the one and only that works in all cases is the first step into that 
direction. See http://www.NetBSD.org/Documentation/pkgsrc/makefile.html 
for further details, especially the :M*:Q operator.

===> Making DIST_SUBDIR independent of PKGREVISION

These two variables are completely unrelated, but as almost nobody knows 
that PKGNAME is modified internally in bsd.pkg.mk by appending the 
"nb${PKGREVISION}" string to it if PKGREVISION is non-empty and not "0", 
some people thought that choosing ${PKGNAME} as the value for 
DIST_SUBDIR was the right thing. They overlooked that PKGREVISION might 
change without the need to refetch the DISTFILES. Now these two 
variables are independent again. To not cause the DISTFILES to be 
downloaded again as a result of this change, I've set the DIST_SUBDIR to 
the current value of ${PKGNAME}, expressed as ${PKGNAME_NOREV}nb1 in the 
case of audio/festvox-aec.

===> Explicit PKGNAME (audio/mp3asm)

The version number in a PKGNAME should only contain digits and dots. As 
the DISTNAME contains a dash in the version number part, the PKGNAME has 
been defined explicitly.

===> Two-level relative paths (audio/mpg123-esound)

It just looks more uniform if every relative path starts with "../../".

===> Removing partial RCS tags from patch files

Up to now, a partial $NetBSD$ tag makes bsd.pkg.mk and bsd.pkg.patch.mk 
ignore the complete line when generating the checksum. Depending on the 
quality of the algorithms, other programs may have problems 
distinguishing partial RCS tags from complete ones, so the easiest thing 
is to avoid them as far as possible.

===> ".else if" (biology/rasmol)
===> ".ifdef (${OPSYS} == "SunOS")" (comms/lrzsz)

The parser of NetBSD's make(1) didn't even warn on these lines, so I had 
to add this check to pkglint. Obviously it has to be fixed.

===

So far for now. I'm preparing a diff that does not include the changes 
done by pkglint --autofix. This will be easier to review than the 28000 
lines the patch currently has. I'll add the remaining things later.

Roland