refactor(ec): generate ECCodes.h / ECTagTypes.h only, drop the committed copies - #716
Merged
got3nks merged 1 commit intoJul 30, 2026
Merged
Conversation
…ted copies The EC headers existed twice: generated from their .abstract sources into the build tree, and committed under src/libs/ec/cpp/ where they were hand-maintained. Adding a tag meant editing the abstract AND hand-adding the matching enum entry and name-string case to the committed header, with nothing enforcing that the two agreed. They did not agree in one respect already: `#include <cstdint>` was added to the committed header by 5a6f5e8, and the generator never learned about it. Worse, both copies reached the same binary. Measured with ninja's dependency data on master, 24 TUs compiled against the committed ECCodes.h and 3 (Api.cpp, PrefsSchema.cpp, Refresher.cpp) against the generated one, with amuleapi linking objects of both kinds. Divergence there would not have been a compile error -- it would have linked cleanly and put two different values for the same tag on the EC wire. Make the generated header the only one. The abstract becomes the single source of truth: edit it and the enum entry, the DEBUG_EC_IMPLEMENTATION name string and the documentation all follow. The generator had to learn three things first, so the output is not a regression on the header it replaces: * emit `#include <cstdint>` when the abstract has a TypeDef section (those emit `typedef uint8_t ec_opcode_t`). ECTagTypes has none and uses aMule's own uint8, so it does not get the include. * `##` is a documentation comment, emitted into the header above the entry that follows it. Plain `#` keeps its meaning of an abstract-only note. The 28 comment lines the committed header carried move into the abstract, and come out byte-identical. * a literal `;` no longer corrupts the output. The file is turned into a CMake list by swapping newlines for `;`, so a semicolon in prose split one line into several and the fragments were parsed as entries. The same unquoted-variable bug was silently eating semicolons in the licence block ("free software; you can" -> "free software you can"). Verified against the header being deleted: enum name=value pairs and typedefs are identical, and every documentation comment is preserved verbatim. The only remaining differences are cosmetic -- brace placement and the switch-case layout in the debug block, neither of which any consumer sees now that the file lives solely in the build tree. All 86 TUs that include ECCodes.h and all 84 that include ECTagTypes.h now resolve to the generated copy; none to a source-tree one. A cold parallel build from an empty tree succeeds, so the ordering holds without a race. The ec/java/ counterparts are deleted too: nothing built, shipped or referenced them, and they were only ever updated by hand alongside the headers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The EC headers existed twice: generated from their
.abstractsources into the build tree, and committed undersrc/libs/ec/cpp/where they were hand-maintained. Adding a tag meant editing the abstract and hand-adding the matching enum entry and name-stringcaseto the committed header, with nothing enforcing that the two agreed.They already disagreed in one respect:
#include <cstdint>was added to the committed header by5a6f5e86dand the generator never learned about it.The reason this matters beyond the chore: both copies reached the same binary. Measured with ninja's dependency data on master, 24 TUs compiled against the committed
ECCodes.hand 3 (Api.cpp,PrefsSchema.cpp,Refresher.cpp) against the generated one, withamuleapilinking objects of both kinds —Api.cpp.opulls in both. Divergence there would not have been a compile error. It would have linked cleanly and put two different values for the same tag on the EC wire.This makes the generated header the only one, so the abstract is the single source of truth: edit it and the enum entry, the
DEBUG_EC_IMPLEMENTATIONname string and the documentation all follow.The generator had to learn three things first
So that the output is not a regression on the header it replaces:
#include <cstdint>when the abstract has aTypeDefsection (those emittypedef uint8_t ec_opcode_t).ECTagTypeshas none and uses aMule's ownuint8, so it deliberately does not get the include.##is a documentation comment, emitted into the header above the entry that follows it. Plain#keeps its existing meaning of an abstract-only note (section headings, commented-out*_UNUSEDplaceholders). The 28 comment lines the committed header carried move into the abstract and come out byte-identical.;no longer corrupts the output. The file is turned into a CMake list by swapping newlines for;, so a semicolon in prose split one line into several and the fragments were then parsed as entries. The same unquoted-variable bug was silently eating semicolons in the licence block —"free software; you can"was being emitted as"free software you can".src/libs/ec/java/goes too: nothing built, shipped or referenced those files, and they were only ever updated by hand alongside the headers. The now-deadECCodes.h/ECTagTypes.hentries inwhitespace_fixer's exclusion list are removed with them.For contributors
@LSalami @ngosang @danim7 @mrjimenez — heads-up, since this changes the workflow for anyone adding an EC tag.
Adding an EC tag is now one edit. In
ECCodes.abstract:The
##lines become//comments above the entry in the generated header. Nothing else to touch.Test plan
Equivalence against the header being deleted — enum
NAME = 0xVALUEpairs identical (521 inECCodes.h, 11 inECTagTypes.h),typedefs identical, and every one of the 28 documentation comment lines preserved verbatim. The only remaining differences are cosmetic: brace placement and the switch-case layout inside the debug block, neither of which any consumer sees now that the file lives solely in the build tree.Single source confirmed — from ninja's dependency data after a full build, all 86 TUs that include
ECCodes.hand all 84 that includeECTagTypes.hresolve to the generated copy. None to a source-tree one.Round trip — adding a tag plus a
##comment to the abstract and nothing else regenerates the header with the enum entry, the documentation comment and theDEBUG_EC_IMPLEMENTATIONname-string case, and a TU compiles against it with the correct value.Cold parallel builds from an empty tree, so the generate-before-compile ordering holds without a race:
macOS covered the full target set (
MONOLITHIC+DAEMON+REMOTEGUI+AMULECMD+WEBSERVER+TESTING+AMULEAPI).Lint gates —
git clang-format origin/masterreports nothing to format, and diff-scoped clang-tidy is clean against both.clang-tidy-new-codeand.clang-tidy. Both analysed 0 TUs, which is honest rather than a false pass: this diff changes CMake and the abstract only, with no C++ source touched.Note
src/libs/ec/cpp/gen_ECVersionreads the committedECCodes.h, so this leaves that reference stale. It was already dead before this change — nothing invokes it, and themkFileSumit pipes into does not exist in the tree — so removing it felt like a separate decision rather than something to fold in here.