Drop ModuleInfo from LDC release builds - #519
Open
TurkeyMan wants to merge 2 commits into
Open
Conversation
TurkeyMan
force-pushed
the
agent/no-moduleinfo
branch
2 times, most recently
from
August 14, 2026 17:02
3547add to
5c863aa
Compare
Saves 26,864 bytes of static RAM on x86-64 and 23,728 bytes on ESP32-C6 (142,732 -> 119,004, 16.6%), all of it .data. urt no longer declares a module ctor, so ModuleInfo's only remaining job is enumerating unittests, which is why CONFIG=unittest keeps it. The flag is dangerous in a way the compiler will not tell you about: LDC silently skips module ctors under it - no error, no warning, the initialisation simply never runs. So the build scans for one and refuses to proceed if it finds one, naming the file. And because the scan is only as good as $(shell), which is unusable under some Windows makes, a scan that cannot find a file known to exist leaves the flag off rather than trusting a guard that never ran. ramreport.py classifies sections by substring: ESP-IDF emits .dram0.bss and .dram0.data, which the exact-match list missed entirely, and rodata has to be excluded explicitly or "data" swallows it. Needs the matching urt change; the submodule bump points at it.
Walks the CollectionTypeInfo chain the objects already carry, so downcasts stay checked once TypeInfo goes away. No call sites yet: converting them is only worth doing alongside --fno-rtti, which is still blocked by runtime `new` in urt's AA implementation.
TurkeyMan
force-pushed
the
agent/no-moduleinfo
branch
from
August 16, 2026 01:45
5c863aa to
e1ff26d
Compare
Member
Author
|
Rebased onto master and re-pinned at the rebased urt#225 ( Note for whoever builds this: |
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.
Depends on open-watt/urt#225 -- the submodule bump points at it. The Makefile guard here scans urt for module ctors, so this will not build against urt master until that lands.
All of it
.data. ModuleInfo exists to run module ctors/dtors and to enumerate unittests; urt no longer declares a module ctor, so only the test runner still needs it, which is whyCONFIG=unittestkeeps it. (urt#225 carries a second, independent saving of 2,752 bytes RAM / 16,872 bytes binary that does not depend on this flag at all.)The guard is the part worth reviewing
--fno-moduleinfois dangerous in a way the compiler will not tell you about: LDC silently skips module ctors under it. No error, no warning -- the initialisation simply never runs. I confirmed that directly rather than assuming it.So the build scans for a module ctor and refuses to proceed if it finds one:
And because that scan is only as good as
$(shell)-- which is unusable under some Windows makes, pre-existing and unrelated to this change -- a scan that cannot find a file known to exist leaves the flag off rather than trusting a guard that never ran. Windows loses the saving; it does not get a silent hazard. ESP firmware builds go through WSL, where the guard works.If you would rather this were opt-in, it is a one-line change.
A related hazard that turned out not to bite: a module-scope AA literal cannot be statically initialised in general, so if the compiler had emitted a hidden module ctor for one, this flag would have silently left it empty -- and the guard greps for a written
static this(, so it would never have seen it. Checked directly: LDC statically initialises them, including struct-keyed ones. No exposure.Also here
ramreport.pyclassifies sections by substring. ESP-IDF emits.dram0.bss/.dram0.data, which the exact-match list missed entirely, so the tool previously reported nothing on ESP targets.rodatahas to be excluded explicitly or"data"swallows it.dyn_caston the BaseObject hierarchy, walking theCollectionTypeInfochain the objects already carry. This has no call sites yet -- it is groundwork so downcasts stay checked once TypeInfo goes away.--fno-rtti(~18KB more) is blocked by runtimenewin urt's AA implementation, not by anything here; see urt#225 for the measurements.Verification
Linux LDC unittest 134/134, Windows DMD 135/135, ESP32-C6 firmware links and builds. The release binary carries zero
__ModuleInfosymbols, boots, and runs the recorder -- which exercisesfind_type_details, whoseassert(false)survives-release-- with no halt.