Like most people, I have my pet peeves. I consider that documentation
is very important to code quality.

I ran into a school-book example a week ago, so I decided to share what I
mean.

There was this problem with dpb where some packages in a MULTI_PACKAGES show 
up as Errors when they don't build on a given architecture, even though 
they're marked as NOT_FOR_ARCHS-sub = ...

I had fixed that particular way of building things by getting those to
vanish when building all packages, so that the build would not error out,
but dpb was still getting them as errors (and the remaining subpackages were
built correclty)

Looking more closely, dpb actually dumps information for all subpackages,
including the non-building ones. Not including the non-building ones would
not work, because the listing job would retry and retry. Nope, what was needed
was the same mechanism that lets dpb ignore regular packages, that is the
IGNORE variable.

So, all that was needed was to set the IGNORE variable on a subpackage
dependent basis, and dpb would happily trudge along.

Thus, a patch was born, tested and committed that would make IGNORE subpackage
dependent. I tried to make it as simple as could be:

(the relevant part is setting all
IGNORE-sub, then having
IGNORE = ${IGNORE-sub} and testing IGNORE,
plus marking IGNORE as subpackage dependent for dump-vars)


Index: bsd.port.mk
===================================================================
RCS file: /home/openbsd/cvs/ports/infrastructure/mk/bsd.port.mk,v
retrieving revision 1.1074
retrieving revision 1.1075
diff -u -p -r1.1074 -r1.1075
--- bsd.port.mk 28 Mar 2011 00:16:13 -0000      1.1074
+++ bsd.port.mk 3 Apr 2011 07:19:05 -0000       1.1075
@@ -92,11 +92,11 @@ _SHSCRIPT = sh ${PORTSDIR}/infrastructur
 _PERLSCRIPT = perl ${PORTSDIR}/infrastructure/bin
 
 # All variables relevant to the port's description
-_ALL_VARIABLES = BUILD_DEPENDS IGNORE IS_INTERACTIVE \
+_ALL_VARIABLES = BUILD_DEPENDS IS_INTERACTIVE \
        SUBPACKAGE MULTI_PACKAGES
 # and stuff needing to be MULTI_PACKAGE'd
 _ALL_VARIABLES_INDEXED = FULLPKGNAME RUN_DEPENDS LIB_DEPENDS \
-       PKG_ARCH
+       PKG_ARCH IGNORE 
 _ALL_VARIABLES_PER_ARCH =
 
 .if ${DPB:L:Mfetch}
@@ -1320,7 +1320,6 @@ IS_INTERACTIVE = Yes
 #
 # Don't build a port if it comes with the base system.
 ################################################################
-IGNORE ?=
 TRY_BROKEN ?= No
 _IGNORE_REGRESS ?=
 .if defined(REGRESS_IS_INTERACTIVE) && defined(BATCH)
@@ -1328,44 +1327,49 @@ _IGNORE_REGRESS += "has interactive test
 .elif !defined(REGRESS_IS_INTERACTIVE) && defined(INTERACTIVE)
 _IGNORE_REGRESS += "does not have interactive tests"
 .endif
-.if defined(IS_INTERACTIVE) && defined(BATCH)
-IGNORE += "is an interactive port"
-.elif !defined(IS_INTERACTIVE) && defined(INTERACTIVE)
-IGNORE += "is not an interactive port"
-.endif
-.if !exists(${X11BASE})
-IGNORE += "building ports requires X11 but ${X11BASE} not found"
-.endif
-.if !defined(_ARCH_OK${SUBPACKAGE}) || ${_ARCH_OK${SUBPACKAGE}} == 0
-.  if defined(ONLY_FOR_ARCHS${SUBPACKAGE})
-.    if ${MACHINE_ARCH} == "${ARCH}"
-IGNORE += "is only for ${ONLY_FOR_ARCHS${SUBPACKAGE}}, not ${MACHINE_ARCH}"
+
+.for _s in ${MULTI_PACKAGES}
+IGNORE${_s} ?=
+.  if defined(IS_INTERACTIVE) && defined(BATCH)
+IGNORE${_s} += "is an interactive port"
+.  elif !defined(IS_INTERACTIVE) && defined(INTERACTIVE)
+IGNORE${_s} += "is not an interactive port"
+.  endif
+.  if !exists(${X11BASE})
+IGNORE${_s} += "building ports requires X11 but ${X11BASE} not found"
+.  endif
+.  if !defined(_ARCH_OK${_s}) || ${_ARCH_OK${_s}} == 0
+.    if defined(ONLY_FOR_ARCHS${_s})
+.      if ${MACHINE_ARCH} == "${ARCH}"
+IGNORE${_s} += "is only for ${ONLY_FOR_ARCHS${_s}}, not ${MACHINE_ARCH}"
+.      else
+IGNORE${_s} += "is only for ${ONLY_FOR_ARCHS${_s}}, not ${MACHINE_ARCH} 
\(${ARCH}\)"
+.      endif
 .    else
-IGNORE += "is only for ${ONLY_FOR_ARCHS${SUBPACKAGE}}, not ${MACHINE_ARCH} 
\(${ARCH}\)"
+IGNORE${_s} += "is not for ${NOT_FOR_ARCHS}"
 .    endif
-.  else
-IGNORE += "is not for ${NOT_FOR_ARCHS}"
 .  endif
-.endif
-.if ${SHARED_ONLY:L} == "yes" && ${NO_SHARED_LIBS:L} == "yes"
-IGNORE += "requires shared libraries"
-.endif
-
-.if ${TRY_BROKEN:L} != "yes"
-.  if defined(BROKEN-${ARCH})
-IGNORE += "is marked as broken for ${ARCH}: ${BROKEN-${ARCH}:Q}"
+.  if ${SHARED_ONLY:L} == "yes" && ${NO_SHARED_LIBS:L} == "yes"
+IGNORE${_s} += "requires shared libraries"
 .  endif
-.  if ${MACHINE_ARCH} != ${ARCH} && defined(BROKEN-${MACHINE_ARCH})
-IGNORE += "is marked as broken for ${MACHINE_ARCH}: 
${BROKEN-${MACHINE_ARCH}:Q}"
+
+.  if ${TRY_BROKEN:L} != "yes"
+.    if defined(BROKEN-${ARCH})
+IGNORE${_s} += "is marked as broken for ${ARCH}: ${BROKEN-${ARCH}:Q}"
+.    endif
+.    if ${MACHINE_ARCH} != ${ARCH} && defined(BROKEN-${MACHINE_ARCH})
+IGNORE${_s} += "is marked as broken for ${MACHINE_ARCH}: 
${BROKEN-${MACHINE_ARCH}:Q}"
+.    endif
+.    if defined(BROKEN) 
+IGNORE${_s} += "is marked as broken: ${BROKEN:Q}"
+.    endif
 .  endif
-.  if defined(BROKEN) 
-IGNORE += "is marked as broken: ${BROKEN:Q}"
+.  if defined(COMES_WITH)
+IGNORE${_s} += "-- ${FULLPKGNAME${SUBPACKAGE}:C/-[0-9].*//g} comes with 
OpenBSD as of release ${COMES_WITH}"
 .  endif
-.endif
-.if defined(COMES_WITH)
-IGNORE += "-- ${FULLPKGNAME${SUBPACKAGE}:C/-[0-9].*//g} comes with OpenBSD as 
of release ${COMES_WITH}"
-.endif
+.endfor
 
+IGNORE = ${IGNORE${SUBPACKAGE}}
 IGNORE_IS_FATAL ?= "No"
 .if !empty(IGNORE) && ${IGNORE_IS_FATAL:L} == "yes"
 ERRORS += "Fatal: can't build"


So all was fine. All was fine ? Well, I wrote the documentation part.
Yeouch. Now, new IGNORE was not behaving at all like the other indexed
variables. It did work, but it was a very special case...

So I sat down again, and wrote a new version of the bsd.port.mk patch.
Turns out there was a nicer, more regular way to do things.

Now, instead of defining IGNORE-sub backwards, I do derive IGNORE-sub
from normal IGNORE. The only -subpackage dependent part in bsd.port.mk
concerns adding ONLY_FOR_ARCHS/NOT_FOR_ARCHS to the right variable.
Not too surprisingly, some stuff vanishes (namely __ARCH_OK-sub is only
used to set IGNORE-sub, so let's set IGNORE-sub directly).

Looking more closely at all uses of IGNORE* and ONLY_FOR_ARCHS*, I also
fixed a bug later on with respect to describe (which was written a looong
time ago and which is obviously not interpreting the difference between
empty ONLY_FOR_ARCHS and  undefined ONLY_FOR_ARCHS).

(to be committed once it's fully tested. There may be typos in there).

Index: bsd.port.mk
===================================================================
RCS file: /home/openbsd/cvs/ports/infrastructure/mk/bsd.port.mk,v
retrieving revision 1.1074
diff -u -p -r1.1074 bsd.port.mk
--- bsd.port.mk 28 Mar 2011 00:16:13 -0000      1.1074
+++ bsd.port.mk 8 Apr 2011 21:10:39 -0000
@@ -92,11 +92,11 @@ _SHSCRIPT = sh ${PORTSDIR}/infrastructur
 _PERLSCRIPT = perl ${PORTSDIR}/infrastructure/bin
 
 # All variables relevant to the port's description
-_ALL_VARIABLES = BUILD_DEPENDS IGNORE IS_INTERACTIVE \
+_ALL_VARIABLES = BUILD_DEPENDS IS_INTERACTIVE \
        SUBPACKAGE MULTI_PACKAGES
 # and stuff needing to be MULTI_PACKAGE'd
 _ALL_VARIABLES_INDEXED = FULLPKGNAME RUN_DEPENDS LIB_DEPENDS \
-       PKG_ARCH
+       PKG_ARCH IGNORE 
 _ALL_VARIABLES_PER_ARCH =
 
 .if ${DPB:L:Mfetch}
@@ -441,28 +441,36 @@ ONLY_FOR_ARCHS${_s} ?= ${ONLY_FOR_ARCHS}
 NOT_FOR_ARCHS${_s} ?= ${NOT_FOR_ARCHS}
 .  endif
 
+IGNORE${_s} ?=
+IGNORE${_s} += ${IGNORE}
+
 # compute _ARCH_OK for ignore
 .  if defined(ONLY_FOR_ARCHS${_s})
-_ARCH_OK${_s} = 0
+_ARCH_OK = 0
 .    for __ARCH in ${MACHINE_ARCH} ${ARCH}
 .      if !empty(ONLY_FOR_ARCHS${_s}:M${__ARCH})
-_ARCH_OK${_s} = 1
+_ARCH_OK = 1
 .      endif
 .    endfor
-.  else
-_ARCH_OK${_s} = 1
+.    if ${_ARCH_OK} == 0
+.      if ${MACHINE_ARCH} == "${ARCH}"
+IGNORE${_s} += "is only for ${ONLY_FOR_ARCHS${_s}}, not ${MACHINE_ARCH}"
+.      else
+IGNORE${_s} += "is only for ${ONLY_FOR_ARCHS${_s}}, not ${MACHINE_ARCH} 
\(${ARCH}\)"
+.      endif
+.    endif
 .  endif
 .  if defined(NOT_FOR_ARCHS${_s})
 .    for __ARCH in ${MACHINE_ARCH} ${ARCH}
 .      if !empty(NOT_FOR_ARCHS${_s}:M${__ARCH})
-_ARCH_OK${_s} = 0
+IGNORE${_s} += "is not for ${NOT_FOR_ARCHS${_s}}"
 .      endif
 .    endfor
 .  endif
 
 # allow subpackages to vanish on architectures that don't
 # support them
-.  if ${_ARCH_OK${_s}} == 1
+.  if empty(IGNORE${_s})
 _MULTI_PACKAGES += ${_s}
 .  endif
 .endfor
@@ -1320,7 +1328,6 @@ IS_INTERACTIVE = Yes
 #
 # Don't build a port if it comes with the base system.
 ################################################################
-IGNORE ?=
 TRY_BROKEN ?= No
 _IGNORE_REGRESS ?=
 .if defined(REGRESS_IS_INTERACTIVE) && defined(BATCH)
@@ -1328,6 +1335,7 @@ _IGNORE_REGRESS += "has interactive test
 .elif !defined(REGRESS_IS_INTERACTIVE) && defined(INTERACTIVE)
 _IGNORE_REGRESS += "does not have interactive tests"
 .endif
+
 .if defined(IS_INTERACTIVE) && defined(BATCH)
 IGNORE += "is an interactive port"
 .elif !defined(IS_INTERACTIVE) && defined(INTERACTIVE)
@@ -1336,17 +1344,7 @@ IGNORE += "is not an interactive port"
 .if !exists(${X11BASE})
 IGNORE += "building ports requires X11 but ${X11BASE} not found"
 .endif
-.if !defined(_ARCH_OK${SUBPACKAGE}) || ${_ARCH_OK${SUBPACKAGE}} == 0
-.  if defined(ONLY_FOR_ARCHS${SUBPACKAGE})
-.    if ${MACHINE_ARCH} == "${ARCH}"
-IGNORE += "is only for ${ONLY_FOR_ARCHS${SUBPACKAGE}}, not ${MACHINE_ARCH}"
-.    else
-IGNORE += "is only for ${ONLY_FOR_ARCHS${SUBPACKAGE}}, not ${MACHINE_ARCH} 
\(${ARCH}\)"
-.    endif
-.  else
-IGNORE += "is not for ${NOT_FOR_ARCHS}"
-.  endif
-.endif
+
 .if ${SHARED_ONLY:L} == "yes" && ${NO_SHARED_LIBS:L} == "yes"
 IGNORE += "requires shared libraries"
 .endif
@@ -1367,9 +1365,9 @@ IGNORE += "-- ${FULLPKGNAME${SUBPACKAGE}
 .endif
 
 IGNORE_IS_FATAL ?= "No"
-.if !empty(IGNORE) && ${IGNORE_IS_FATAL:L} == "yes"
+.if !empty(IGNORE${SUBPACKAGE}) && ${IGNORE_IS_FATAL:L} == "yes"
 ERRORS += "Fatal: can't build"
-ERRORS += ${IGNORE}
+ERRORS += ${IGNORE${SUBPACKAGE}}
 .endif
 
 .if !defined(DEPENDS_TARGET)
@@ -2024,7 +2022,7 @@ _internal-fetch-all:
        @${_MAKE} post-fetch __FETCH_ALL=Yes
 .endif
 
-.if !empty(IGNORE) && !defined(NO_IGNORE)
+.if !empty(IGNORE${SUBPACKAGE}) && !defined(NO_IGNORE)
 _internal-all _internal-build _internal-checksum _internal-configure \
        _internal-deinstall _internal-extract _internal-fake _internal-fetch \
        _internal-install _internal-install-all _internal-manpages-check \
@@ -2034,10 +2032,10 @@ _internal-all _internal-build _internal-
        _internal-update-or-install-all _internal-update-plist \
        port-lib-depends-check update-patches:
 .  if !defined(IGNORE_SILENT)
-       @${ECHO_MSG} "===>  ${FULLPKGNAME${SUBPACKAGE}}${_MASTER} ${IGNORE}."
+       @${ECHO_MSG} "===>  ${FULLPKGNAME${SUBPACKAGE}}${_MASTER} 
${IGNORE${SUBPACKAGE}}."
 .  endif
 .  if defined(_IGNORE_COOKIE)
-       @echo "${IGNORE}" >${_IGNORE_COOKIE}
+       @echo "${IGNORE${SUBPACKAGE}}" >${_IGNORE_COOKIE}
 .  endif
 .else
 
@@ -2908,14 +2906,13 @@ describe:
        @echo -n '${_${_d}_DEP3${_S}:C/ +/ /g}'| tr '\040' '\012'|sort -u|tr 
'\012' '\040' | sed -e 's, $$,,'
        @echo -n '|'
 .  endfor
-       @case "${ONLY_FOR_ARCHS}" in \
-        "") case "${NOT_FOR_ARCHS}" in \
-                "") echo -n "any|";; \
-                *) echo -n "!${NOT_FOR_ARCHS}|";; \
-                esac;; \
-        *) echo -n "${ONLY_FOR_ARCHS}|";; \
-        esac
-
+.  if defined(ONLY_FOR_ARCHS${_S})
+       @echo -n "${ONLY_FOR_ARCHS${_S}}|"
+.  elif defined(NOT_FOR_ARCHS${_S})
+       @echo -n "!${NOT_FOR_ARCHS${_S}}|"
+.  else
+       @echo -n "any|"
+.  endif
 .  if defined(_BAD_LICENSING)
        @echo "?|?|?|?"
 .  else

And now, the documentation writes itself... or rather, things are very
simple to explain, and quite sane compared to the first version.

This is just a small example. That shit happens to me all the time.
Specifically, bsd.port.mk got improved immensely those past few years, based
on actual usage, based on taking feedback from fellow porters at the ports
hackathons (old-timers will recall current MULTI_PACKAGES looks nothings like
the first versions of it), and also based on documenting stuff.

I almost never document stuff before writing the code. I have an idea of
what I want  to do (informal spec), then I write and test the code, then
I validate what I did by documenting it. And most of the time, I find obvious
improvements just by doing that: documentation forces me to look at things
another way, and to make things better.

Reply via email to