This project is maintained by kenakofer
Outcome: the corpus is on 2.24.4. 2.24.4 and 2.26.0 were tested from
the upstream binary tarballs under ~/.local/lilypond/, which install
alongside the Ubuntu package and do not disturb it. The 2.22.1 system
package is still present and still works on this source.
2.24.4 builds the entire corpus with only the two small fixes below.
Full build of abide-with-me emits all 24 books, exit 0, no errors; the
shape-note book — the one that 2.26 breaks — builds on 150 of 150
songs. 2.26 fails 128 of those 150.
2.24 is the previous stable series (last release July 2024) and runs Guile 2.2; 2.26 moved to Guile 3.0, which is where the trouble starts. 2.25 is not a candidate: it is the unstable development series that became 2.26, so it carries the same breakage.
Both fixes below are still required on 2.24 — unmodified public-main
fails there with the same arity error. They are just sufficient on 2.24,
and not sufficient on 2.26.
lib/left-align-lyrics.ily — (_ "...") no longer parses.
The file vendors a copy of LilyPond’s own define-grob-property, taken
from a 2015 mailing list post, including its gettext call. Under Guile 3
a bare _ is a syntactic keyword, so the whole file failed to parse and
took define-grob-property down with it — nothing compiled at all. 2.22
spells the wrapper _ and 2.26 spells it G_, so no single name works
in both; the message is now untranslated.
lib/clairnote.ily — accidental rule arity.
LilyPond 2.23 dropped the measurepos argument from accidental rules.
Clairnote’s rule still declared (context pitch barnum measurepos) and
died with an arity error during “Interpreting music”. It now accepts
either arity, reading measurePosition off the context when the caller
does not supply it, so the file still loads under 2.22.
lib/clairnote.ily — down stems on the wrong side of the note head.
Up to 2.22, a NoteHead.stem-attachment x of 1 meant “the far edge of
the head as seen from the stem”, so the single pair '(1 . 0.2) that
\cnNoteheadStyle "funksol" installs served both stem directions. 2.23
made the coordinate literal — x is the right edge whichever way the stem
points — so every down stem in the Clairnote books moved to the wrong
side. Clairnote now mirrors x itself, gated on ly:version? >= 2.23:
2.22 already mirrors internally, and applying ours there double-flips
(110408 pixels off baseline on amazing-grace before the gate,
byte-identical after).
This one is not a parse or arity error — it compiles clean and simply engraves wrongly, which is why only a visual check caught it.
Note that only the first is Guile-3 specific. The arity change landed in
2.23 and the attachment change in 2.23 as well, so both bite on 2.24 —
which is why unmodified public-main does not build there either.
With the two fixes above, 2.26 builds every book except the two
shape-note ones. Verified across the full corpus (150 songs with a
.ly), shapenote alone:
| result | songs |
|---|---|
| builds | 22 |
| fails | 128 |
Every other book — trad, clairnote, lead sheets, transposed leads, guitar, ukulele, slides — builds clean.
2.26’s define-grobs.scm gives NoteHead a direction default that
2.22 did not have:
(define-public (note-head::calc-direction grob)
(let ((stem (ly:grob-object grob 'stem)))
(ly:grob-property stem 'direction)))
This function does not exist in 2.24 — it was added after that series, which is precisely why 2.24 is unaffected.
ly:grob-object returns '() when the note head has no stem, and this
function does not check before reading direction off it. The result is:
ERROR: In procedure ly:grob-property:
Wrong type argument in position 1 (expecting Grob): ()
Confirmed directly rather than inferred: shimming ly:grob-object shows
exactly one stem-less lookup in abide-with-me, on a NoteHead, landing
immediately before the error. The failure is late — during
“Preprocessing graphical objects”, after the music interprets fine.
Which grob arrangement produces the stem-less NoteHead. It is not
predicted by key signature, verse count, whole notes, ties, or \pa —
all of those appear on both sides of the pass/fail split. Only one such
note head occurs per failing song, which fits an incidental grob
configuration rather than a whole category of song, and explains why the
128/22 split looks arbitrary.
Reproducing it in a standalone file did not succeed: \omit Stem and
\remove "Stem_engraver" both still satisfy the callback under 2.26
(the latter actually crashes 2.22 and passes 2.26 — the reverse of the
repo’s symptom). So the trigger needs the real \partCombine +
\fillTradScore context, and pinning it down is the next task.
Override NoteHead.direction with a stem-checking version. Two attempts
did not take effect and were reverted:
\override NoteHead.direction inside the shapenote book’s \layout
never reached the grob.set! on note-head::calc-direction did not apply, because the grob
default captured the original procedure at definition time.Worth trying next: setting the property in \globalParts where the other
per-staff properties are already set, or reporting it upstream, since the
missing grob check is an upstream bug rather than repo code.
To 2.24.4: done, pending a full-corpus rebuild and visual check. The two committed fixes are all it needs. No song files change.
To 2.26: additionally blocked on the upstream NoteHead.direction
defect above — one book out of nine, one symptom, but the trigger has to
be identified before the guard can be placed correctly, and it is worth
reporting upstream rather than only patching around locally.
Either way, nothing found suggests the songs themselves need editing — all three problems are in vendored library code or in LilyPond itself.
The binary lives at ~/.local/lilypond/lilypond-2.24.4/, with
~/.local/bin/lilypond symlinked to it. That directory precedes
/usr/bin on PATH, so the build scripts — which call plain lilypond —
pick up 2.24.4 without needing a $LILYPOND override. The Ubuntu 2.22.1
package is untouched and is still what /usr/bin/lilypond runs, which is
how the before/after comparisons below were produced.
Worth being precise about, because the engraving check was a sample:
Across those 312 pages there were zero page-count or geometry changes — every page is the same size, so nothing reflowed. What remains is a global spacing and kerning drift from the Guile version change: ink boxes shift by a pixel or two and stave spacing grows very slightly, which inflates pixel-diff counts (5-20% of pixels on dense pages) without changing what is on the page.
The one real regression this sample caught was the Clairnote stem side, below. That is the argument for looking at renders and not just exit codes — it would not have surfaced any other way.