Skip to content

Add cc_check_undefined (static undefined-symbol check) - #63

Merged
chen3feng merged 1 commit into
mainfrom
feat/cc-check-undefined
Jul 3, 2026
Merged

Add cc_check_undefined (static undefined-symbol check)#63
chen3feng merged 1 commit into
mainfrom
feat/cc-check-undefined

Conversation

@chen3feng

Copy link
Copy Markdown
Contributor

Ports Blade's cc_check_undefined (#1225). For each cc_library, every undefined external symbol must resolve to one of: the library's own archive, a declared dep's archive, a system library a final link would pull in, or a residual/allow-list regex. Anything left is a missing dependency — reported without a real link.

How

  • internal/ccundef (new): nm -P -g external extraction, a system-symbol baseline (macOS reads the SDK .tbd text stubs via xcrun --show-sdk-path; Linux resolves libstdc++/c/m/pthread/dl/rt/gcc_s via cc -print-file-name then nm), and the residual baseline regexes verbatim from Blade (C++ ABI, operator new/delete, PIC/TLS bootstrap, coverage + sanitizer runtimes).
  • Wiring: build.CheckUndefined runs as a post-build pass in build/test (archives must exist). Severity from cc_library_config.check_undefined + check_undefined_severity (default on/warning), plus per-target and global allow_undefined. --cc-check-undefined / --no-cc-check-undefined force on/off.
  • gen.LinkArchives exposes a node's own + dep + vcpkg (incl. protobuf) archives.

Verification

On flare (macOS/clang) the whole repo is clean (0 findings), matching Python Blade. An intermediate missing-dep (packing's protobuf symbols) surfaced and was fixed by including the protobuf archive in the link closure — proving the check isn't vacuous. Unit tests cover resolution/baseline/allow and severity mapping.

Ports Blade's cc_check_undefined (#1225): for each cc_library, every
undefined external symbol must be resolvable from the library's own
archive, a declared dep's archive, the system libraries a final link
pulls in, or a residual/allow-list regex -- anything left is a missing
dependency. No real link: one `nm -P -g` per archive, set arithmetic,
regex full-match.

New internal/ccundef package:
  * nm -P -g external extraction (U undefined; w/v weak-undef ambient; u +
    uppercase defined) -- ELF .so gets -D.
  * system-symbol baseline: macOS reads the SDK's .tbd stubs
    (libc++/libSystem, via xcrun --show-sdk-path -- the dylibs live in the
    dyld shared cache, only the text stubs are on disk); Linux resolves
    each of libstdc++/c/m/pthread/dl/rt/gcc_s via `cc -print-file-name`
    then nm's it. Conservative: an over-broad system set only reduces
    findings.
  * the residual baseline regexes verbatim from Blade (C++ ABI
    typeinfo/vtable/guard, operator new/delete, PIC/TLS bootstrap,
    coverage + sanitizer runtimes).

Wiring: build.CheckUndefined runs it as a post-build pass in build/test
(archives must exist); severity from cc_library_config.check_undefined +
check_undefined_severity (default on/warning), plus per-target and global
allow_undefined; --cc-check-undefined / --no-cc-check-undefined force
on/off. gen.LinkArchives exposes a node's own + dep + vcpkg (incl.
protobuf) archives.

Verified on flare (macOS/clang): the whole repo is CLEAN (0 findings),
matching Python Blade. A missing-dep intermediate (packing's protobuf
symbols) surfaced and was fixed by including the protobuf archive in the
link closure -- proving the check isn't vacuous. Unit tests cover the
resolution/baseline/allow logic and severity mapping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chen3feng
chen3feng merged commit 9cbeb76 into main Jul 3, 2026
1 check passed
@chen3feng
chen3feng deleted the feat/cc-check-undefined branch July 3, 2026 08:51
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