Skip to content

generate-lisp-info never regenerates: its dependency on libclasp reaches it only through an order-only edge #1828

Description

@dg1sbg

The generated lisp-info files never regenerate when the Lisp or C++ content changes, so a build can silently use package, symbol and class data belonging to a completely different tree state.

The broken chain

build …/generated/features.sexp …/runtime-packages.lisp …/cxx-classes.lisp …:
    generate-lisp-info | boehmprecise/iclasp            <- implicit dep: iclasp only

build boehmprecise/iclasp: link boehmprecise/src/main/main.o || boehmprecise/lib/libclasp.so
                                                        <- ORDER-ONLY dep on libclasp.so

generate-lisp-info runs iclasp, which loads libclasp.so at runtime via rpath and dumps the packages, functions, variables, classes and type map it finds there. Its output therefore depends on libclasp.so's contents. But the only path from the generator to that library goes through iclasp, and iclasp depends on it order-only (||), which in ninja means "build it first if missing, but changes to it do not make me dirty". iclasp itself is just main.o plus a link, so it rarely changes.

Net effect: edit any Lisp or C++ source, rebuild, and the generated lisp-info is not refreshed.

Reproduction

Touching the library and rebuilding:

generated stamp before: 2026-08-03 23:42:47
libclasp.so stamp:      2026-08-04 00:05:50   <- newer
$ touch build/boehmprecise/lib/libclasp.so && ninja -C build
ninja rc=0    generated stamp: 2026-08-03 23:42:47   <- unchanged
$ ninja -C build -n boehmprecise/generated/runtime-packages.lisp
ninja: no work to do.

Worse in practice: I walked one build tree through eight different branches in sequence (rebuilding at each), and the generated files kept their original timestamp and byte sizes the entire way — including across a branch that adds new C++ sources and therefore new scraped symbols. Every one of those eight images was built from another branch's lisp-info, and nothing indicated a problem.

Fix

Make the dependency real. In src/koga/ninja.lisp, the :base variant target:

(libclasp (make-source (lib-filename configuration "libclasp" :dynamic t)
                       :variant-lib))
...
(ninja:write-build output-stream :generate-lisp-info
                   ...
                   :implicit-inputs (list iclasp libclasp))

lib-filename already returns .a under --static-linking, so one call is correct for both. With that in place:

edge: generate-lisp-info | boehmprecise/iclasp boehmprecise/lib/libclasp.so
$ touch build/boehmprecise/lib/libclasp.so
ninja sees generator dirty? YES

I have a PR ready if the approach looks right.

Relationship to #1823

These are separate bugs that produce similar-looking damage, and they interact badly:

Both yield an image built from lisp-info that does not match the source tree, with no diagnostic. Anything that reuses a build tree across branches — CI caches, git bisect, everyday local development — is exposed. Fixing #1823 alone is not sufficient, because this one means the regeneration that would apply the fix never happens.

Found on x86-64 Linux, LLVM 18, --build-mode=bytecode; nothing about it looks platform-specific.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions