Skip to content

Fix six Linux/gcc portability gaps surfaced building flare - #64

Merged
chen3feng merged 1 commit into
mainfrom
fix/linux-portability
Jul 3, 2026
Merged

Fix six Linux/gcc portability gaps surfaced building flare#64
chen3feng merged 1 commit into
mainfrom
fix/linux-portability

Conversation

@chen3feng

Copy link
Copy Markdown
Contributor

Building the whole flare RPC framework end to end on aarch64 Linux/gcc (in an Ubuntu container) surfaced six portability gaps that clang had masked. After these fixes every //flare/... target compiles + links, the tests run, and cc-check-undefined reports zero findings — matching the macOS/Python baseline.

Build / link (internal/cc, internal/build)

  1. Missing--I-dir race — a globally-configured -Ibuild_dir/<pkg> (flare lists build_dir/thirdparty in cc_config.extra_incs) is fatal under -Wmissing-include-dirs -Werror when the dir doesn't exist yet; ninja's lazy per-edge mkdir races the first compile. Now precreate build_dir/<pkg> per target (as Blade's makedirs does) + any build-dir-rooted global -I. clang silently ignores a missing -I dir, so this only broke on gcc.
  2. ELF static-link ordering — put the vcpkg archives inside the target's --start-group so curl → ssl → crypto / protobuf → absl forward refs resolve (GNU ld re-scans only within a group; ld64 re-scans regardless).
  3. Per-target extra_cppflags/extra_cxxflags/extra_cflags/extra_asflags (#492) — flare's crypto md5/sha pass -Wno-deprecated-declarations for OpenSSL 3.x's HMAC deprecation.
  4. //-rooted include normalization — mirror Blade's _incs_to_fullpath (leading // = root-relative; else package-relative). flare's foreign_cc_library sets export_incs='//'+build_dir/.../include, which reached gcc as a nonexistent -I//build_dir/....
  5. Multi-archive foreign_cc_library selection — pick lib<name>.a, not an arbitrary .a. One gen_rule (gperftools_build) emits many archives shared by sibling targets; the old code left consumers of :profiler without libprofiler.a (ProfilerStart/Stop/Flush undefined across 45 targets).

cc-check-undefined Linux baseline (internal/ccundef)

  1. Four fixes so the system-symbol baseline is complete on ELF: strip symbol-version suffixes (sym@@GLIBCXX_3.4 → sym); treat nm IFUNC i/I as defined (glibc memcpy/memmove); follow the glibc libc.so linker script + scan every resolvable spelling (real libgcc_s.so.1_Unwind_Resume, libc_nonshared.a) and scan libgcc.a (aarch64 outline atomics); baseline __stack_chk_* (loader-provided, U everywhere). Without these, every C++ target on Linux flagged std-library symbols.

Tests

Unit tests cover ELF link grouping, // include normalization, foreign archive selection, and the stack-protector baseline; the flare whole-repo build/link/test + clean undefined-check is the integration proof.

Verified by building the whole flare RPC framework end to end on aarch64
Linux/gcc (Ubuntu container): every target compiles + links, the tests
run, and cc-check-undefined reports zero findings -- matching the macOS
baseline. clang had masked all six; they only bit on Linux/gcc.

Build/link (internal/cc, internal/build):
  * precreate build-dir include directories. A globally-configured
    -Ibuild_dir/<pkg> (flare's cc_config.extra_incs lists
    build_dir/thirdparty) is a fatal -Wmissing-include-dirs under -Werror
    when the dir doesn't exist yet; ninja's lazy per-edge mkdir races the
    first compile. Blade sidesteps this by makedirs'ing build_dir/<pkg>
    per target -- we now do the same (+ any build-dir-rooted global -I).
    clang silently ignores a missing -I dir, so this only failed on gcc.
  * put vcpkg archives inside the target's --start-group on ELF. GNU ld
    re-scans only within a group, so curl -> ssl -> crypto forward refs
    across the group boundary went unresolved; ld64 re-scans regardless.
  * apply per-target extra_cppflags/extra_cxxflags/extra_cflags/
    extra_asflags (#492) -- flare's crypto md5/sha pass
    -Wno-deprecated-declarations for OpenSSL 3.x's HMAC deprecation.
  * normalize incs/export_incs like Blade's _incs_to_fullpath: a leading
    // is root-relative (strip it), else package-relative. flare's
    foreign_cc_library sets export_incs='//'+build_dir/.../include, which
    reached gcc as the nonexistent -I//build_dir/... .
  * select a foreign_cc_library's archive by lib<name>.a, not an
    arbitrary .a. One autotools gen_rule (gperftools_build) emits many
    archives shared by sibling targets (tcmalloc, profiler, ...); the old
    "any .a" left consumers of :profiler without libprofiler.a
    (ProfilerStart/Stop/Flush undefined across 45 targets).

cc-check-undefined system baseline on Linux (internal/ccundef):
  * strip ELF symbol-version suffixes (sym@@GLIBCXX_3.4 -> sym) so the
    versioned libstdc++/libc/libgcc exports match a consumer's bare
    undefined ref -- otherwise every C++ target flagged std symbols.
  * treat nm IFUNC types i/I as defined (glibc memcpy/memmove/... are
    indirect functions).
  * follow the glibc `libc.so` linker script to its members (libc.so.6 +
    libc_nonshared.a + AS_NEEDED loader) and scan every resolvable lib
    spelling, so the real versioned ELF (libgcc_s.so.1 -> _Unwind_Resume)
    and the static helpers are both covered; also scan libgcc.a (aarch64
    outline atomics __aarch64_ldadd*/cas*/swp*).
  * baseline __stack_chk_* (loader-provided; U in every scannable lib).

Unit tests cover ELF link grouping, // include normalization, foreign
archive selection, and the stack-protector baseline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chen3feng
chen3feng merged commit e840308 into main Jul 3, 2026
1 check passed
@chen3feng
chen3feng deleted the fix/linux-portability branch July 3, 2026 10:38
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