Skip to content

cmake: name a symlinked entry's header the way the CLI does - #46

Merged
VeaaC merged 1 commit into
mainfrom
symlink-entry-2.28
Aug 14, 2026
Merged

cmake: name a symlinked entry's header the way the CLI does#46
VeaaC merged 1 commit into
mainfrom
symlink-entry-2.28

Conversation

@VeaaC

@VeaaC VeaaC commented Aug 14, 2026

Copy link
Copy Markdown
Owner

_rapidproto_output_header resolved symlinks for BOTH of its branches. That is right for the import-relative test -- canonical_entry_name weakly_canonical()s the entry and the include dir before relativizing -- but wrong for the fallback, where the CLI returns the spelling it was given and header_path reduces it with filename().

So an entry reached through a symlink whose name differs from its target's, and resolving under no import dir, had the helper declare aaa.rp.hpp while the CLI wrote alias.rp.hpp. The declared OUTPUT is never produced, so the target regenerates on every build; Ninja does not error, it just re-runs.

REALPATH also gives up on the WHOLE path as soon as its last component is missing, while weakly_canonical resolves the longest existing prefix -- so a .proto emitted by another rule, under a symlinked path, disagreed the same way, at any depth of not-yet-created directories (a build tree below macOS's /var -> /private/var makes that ordinary). The helper now walks up to the deepest part that exists, resolves that, and re-attaches the rest, which is what the CLI computes once the file is there.

tests/check_generate_names.sh keeps the two rules in step: they are written in different languages and nothing else compares them, which is how they drifted. It runs the real CLI and the real helper over eleven entry shapes and reports which side said what, needing no build or install (the helper is include-safe under cmake -P), so the stage costs about a second.

Every rule in the helper has a case that fails when it is mutated, which took three tries to get right: a symlinked import dir with a TOP-LEVEL entry cannot distinguish the right answer from the fallback, so that fixture is a directory deep; first-match and import-dir ORDER are invisible with a single -I, so two cases pass overlapping dirs in both orders; the ".proto$" anchor needs a name with ".proto" in the middle; and the resolve-the-existing-prefix rule needs an entry whose parents are absent when the helper predicts and present when the CLI runs.

_rapidproto_output_header resolved symlinks for BOTH of its branches. That is right
for the import-relative test -- canonical_entry_name weakly_canonical()s the entry
and the include dir before relativizing -- but wrong for the fallback, where the CLI
returns the spelling it was given and header_path reduces it with filename().

So an entry reached through a symlink whose name differs from its target's, and
resolving under no import dir, had the helper declare aaa.rp.hpp while the CLI wrote
alias.rp.hpp. The declared OUTPUT is never produced, so the target regenerates on
every build; Ninja does not error, it just re-runs.

REALPATH also gives up on the WHOLE path as soon as its last component is missing,
while weakly_canonical resolves the longest existing prefix -- so a .proto emitted by
another rule, under a symlinked path, disagreed the same way, at any depth of
not-yet-created directories (a build tree below macOS's /var -> /private/var makes
that ordinary). The helper now walks up to the deepest part that exists, resolves
that, and re-attaches the rest, which is what the CLI computes once the file is there.

tests/check_generate_names.sh keeps the two rules in step: they are written in
different languages and nothing else compares them, which is how they drifted. It
runs the real CLI and the real helper over eleven entry shapes and reports which side
said what, needing no build or install (the helper is include-safe under `cmake -P`),
so the stage costs about a second.

Every rule in the helper has a case that fails when it is mutated, which took three
tries to get right: a symlinked import dir with a TOP-LEVEL entry cannot distinguish
the right answer from the fallback, so that fixture is a directory deep; first-match
and import-dir ORDER are invisible with a single -I, so two cases pass overlapping
dirs in both orders; the ".proto$" anchor needs a name with ".proto" in the middle;
and the resolve-the-existing-prefix rule needs an entry whose parents are absent when
the helper predicts and present when the CLI runs.
@VeaaC
VeaaC merged commit fb2836e into main Aug 14, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant