Skip to content

build: add function/data-section garbage collection#56

Merged
erfanjazebnikoo merged 1 commit into
devfrom
build/gc-sections
Jul 10, 2026
Merged

build: add function/data-section garbage collection#56
erfanjazebnikoo merged 1 commit into
devfrom
build/gc-sections

Conversation

@erfanjazebnikoo

Copy link
Copy Markdown
Member

Summary

Direct response to markrages and fb39ca4 on r/embedded, pointed out that per-module code duplication isn't actually the best way to get small binaries, function-section garbage collection does it properly regardless of whether code is shared or duplicated.

Real gap this closes

If an application links more than one numx module that needs the same private helper (fft and autodiff both implement trig independently), each module's copy was kept in full, no way to dedupe or strip what's unused.

Platform handling

Apple's linker doesn't understand --gc-sections and fails outright (verified, this broke the build on first attempt, see commit history on the branch). Uses -dead_strip on Apple, --gc-sections on GNU ld/lld/embedded cross-toolchains, /Gy + /OPT:REF /OPT:ICF on MSVC.

Verification

  • Confirmed via nm that a linalg-only binary contains none of NTT's twiddle-factor tables (real const data, can't be inlined away), while an NTT-using binary does
  • Measured a real size reduction on a desktop A/B build
  • Full test suite: 335/335 passing after the change

Also included

Fixed project(numx VERSION 0.1.0 ...), stale since the v1.0.0 tag, noticed while editing the adjacent block.

Direct response to the r/embedded thread with markrages and fb39ca4: adds
-ffunction-sections/-fdata-sections at compile time and the platform-correct
dead-stripping flag at link time, so unused functions and data are dropped
at function granularity instead of whole-object-file granularity.

Real gap this closes: if an application links more than one numx module
that needs the same private helper (e.g. fft and autodiff both need
trig), each module's private copy was previously kept in full since each
lives in its own translation unit with no shared internal header.

Handles the platform split properly rather than assuming GNU ld everywhere:
Apple's linker doesn't understand --gc-sections and fails outright if you
pass it, it uses -dead_strip instead. MSVC uses /Gy plus /OPT:REF /OPT:ICF.
GNU ld, lld, and embedded cross-toolchains (arm-none-eabi-gcc,
xtensa-esp32s3-elf-gcc) accept --gc-sections normally.

Verified, not just compiled: confirmed via nm that a linalg-only binary
contains none of NTT's twiddle-factor data tables (real const data, not
something that could be silently inlined away), while an NTT-using binary
does. Measured a real size reduction on a desktop build; the proportional
effect on a bare-metal embedded .elf with no OS/dynamic-loader overhead
diluting it would be larger. Full test suite still 335/335 passing.

Also fixes project(numx VERSION 0.1.0 ...) on line 2, stale since the
v1.0.0 release, noticed while editing the same block.
@erfanjazebnikoo
erfanjazebnikoo merged commit d7b2465 into dev Jul 10, 2026
@erfanjazebnikoo
erfanjazebnikoo deleted the build/gc-sections branch July 10, 2026 17:07
@erfanjazebnikoo erfanjazebnikoo self-assigned this Jul 10, 2026
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