Skip to content

fix: support LLVM LTO DLL exports and optional automatic discovery - #763

Merged
Sunrisepeak merged 2 commits into
mcpp-community:mainfrom
julixian:fix/bitcode-dll-exports
Oct 5, 2026
Merged

Sunrisepeak merged 2 commits into
mcpp-community:mainfrom
julixian:fix/bitcode-dll-exports

Conversation

@julixian

@julixian julixian commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A release-profile MSVC-ABI DLL with LLVM LTO objects fails at coff-def with
unsupported COFF machine 0x4342. Even an annotated library reaches candidate
enumeration before its annotations can suppress the generated export list.

Export discovery now checks native COFF directives before inspecting bitcode
export intent. Any input's explicit exports still suppress automatic exports
for the entire DLL. Only unannotated inputs reach candidate enumeration. LLVM
bitcode candidates use llvm-nm from the selected compiler's installation;
the selected compiler reads IR without generating machine code. COFF and
bitcode share the symbol filter and i386 name normalization.

[targets.<name>] auto_export = false removes the discovery edge for targets
and dependency-owned shared libraries. The default stays true. The TOML and
xpkg readers implement the same boolean contract. The English and Chinese
references and lookup indexes document the key, platform scope and LTO inputs.
The new behavior is explicitly marked as unreleased source-build functionality.

Closes #762.

Criteria

Validation used a freshly built binary on Windows x64, MSVC 14.51.36231 and
Windows SDK 10.0.26100.0. The binary was built with llvm@22.1.8; the E2E
fixtures select llvm@20.1.7, which is the repository's Windows pin.

  • 881_pe_auto_exports_accept_llvm_bitcode.sh failed against the fresh,
    unmodified origin/main binary at bin/automatic.def with machine 0x4342.
    It passes with this branch. It builds and loads FullLTO DLLs, runs a module
    consumer, checks DATA exports, preserves annotated surfaces, checks the
    root and dependency opt-outs, and reads ThinLTO, mixed objects and x86 input.
    The ordinary annotated COFF tests deliberately supply nonexistent LLVM
    tools in both input orders; linker-option metadata deliberately supplies
    nonexistent llvm-nm. These paths succeed without candidate enumeration.
    The script runs in the Windows E2E shards (requires: msvc python3).
  • 258_shared_library_msvc_auto_def.sh passes with the fresh binary and
    native cl.exe. Native unannotated exports, annotation precedence and the
    consumer's dllimport requirement for DATA retain their existing behavior.
  • The full mcpp test --toolchain llvm@22.1.8 run has 145 passing test
    executables and one failing executable
    . The sole failure is the existing
    Glob.EscapedSpellingIsUtf8WhateverTheName Windows code-page exception in
    unit/test_modgraph; the same filtered test fails against the unmodified
    origin/main binary. This PR does not change that code.
  • New unit coverage checks IR names, comments and strings that resemble
    exports, linker metadata, DATA/COMDAT candidate types, invalid nm output,
    both bitcode signatures, i386 decoration, both manifest readers, selected
    tool argument quoting and the PE/MSVC-only planning gate. After the final
    IR-scanning optimization, all eight PeExports tests and E2E 881 pass again.
    The host-independent unit cases run on Linux, macOS and Windows CI; the
    native DLL E2E requires Windows and usable MSVC.
  • LLVM 22.1.8's clang-cl.exe was also exercised directly as the IR reader:
    annotated FullLTO produces an empty EXPORTS section, and unannotated
    ThinLTO produces function and DATA exports.

Intersections

New rule or feature Invariant it crosses Test at the crossing
Bitcode export discovery LTO preserves usable module code and data exports E2E 881 A/E/G/H; PeExports.NmCandidatesKeepDataAndComdatButExcludeNonDefinitions
Intent before enumeration Any explicit export suppresses the entire automatic surface, regardless of object order E2E 881 B/D/F; IR intent unit cases; existing E2E 258
Per-target auto_export Source-library dependencies retain their own target properties E2E 881 C for root and path dependency; manifest/xpkg boolean unit cases
PE/MSVC-only opt-out ELF, Mach-O and MinGW retain their native export behavior PeExports.OptOutAffectsOnlyTheMsvcAbiSharedLinkForm
Selected LLVM tools The chosen LLVM, target and argument boundaries survive Ninja emission NinjaBackend.BitcodeExportToolsComeFromTheSelectedLlvmAndAreQuotedAsWords; E2E 881 H
IR intent parsing Text data and debug metadata cannot change the DLL export policy PeExports.NamesCommentsAttributesAndDataDoNotDeclareExports; linker-metadata unit cases; E2E 881 E/F

Compatibility

Existing projects keep automatic export discovery enabled. A library with
explicit exports still controls its own surface. Ordinary COFF discovery
needs no LLVM tools. Unannotated LTO inputs require llvm-nm alongside the
selected LLVM compiler; errors retain the object name and tool diagnostics.

The switch only affects MSVC-ABI PE shared links. ELF, Mach-O, MinGW, static
libraries and executables retain their export behavior. Native annotations,
link flags and explicit exports lists remain effective with discovery off.
Existing generated export commands change once when Ninja regenerates the
graph. No manifest migration is required. This is separate from #761's
same-package executable link fix and does not include that patch.

Checks before merging

The preceding revision passed platform builds and Linux/macOS E2E. Windows
E2E 881 failed before compilation because native Windows MCPP_HOME paths
were written into TOML without normalization. The shared fixture helper now
normalizes drive-absolute paths; E2E 00 covers native and mixed Windows spelling
and relative-path preservation. E2E 881 passes locally with native Windows
MCPP_HOME. The new CI run
verifies commit a702dee4; its results are pending.

  • Documentation structure, style and version-pin checks pass locally.
    Move the Chinese README's CI badge outside its navigation table to match
    the English layout and correct the existing table-row mismatch.
  • python .github/tools/check_workflow_assertions.py passes (22 workflows,
    zero problems).
  • check_modules_wiring.sh, check_narrow_conversions.sh and
    git diff --check pass.
  • No commit on the branch carries an attribution trailer:
    git log origin/main..HEAD -i --grep='Co-Authored-By' prints nothing.
  • The squash merge receives an explicit subject and body; this PR is not
    merged by the contributor.

Export intent is checked before candidate enumeration. The selected LLVM compiler and llvm-nm handle LTO objects, while ordinary COFF retains its native reader. Per-target auto_export disables discovery for root and dependency DLLs.
@Sunrisepeak
Sunrisepeak merged commit 68e7310 into mcpp-community:main Oct 5, 2026
103 of 105 checks passed
Sunrisepeak added a commit that referenced this pull request Oct 5, 2026
…ow-ups of #766 (#767)

mcpp run, mcpp run -q --release and the named runners now give the program the terminal. On POSIX mcpp replaces itself with the program once the build is done; on Windows the program runs in mcpp's console and process group while mcpp ignores Ctrl-C. A death by signal reaches the caller as that signal, and closing notices precede the Running line.

The follow-ups of #761, #763 and #765 recorded in #766: members and artifacts link the shared dependencies of the statics placed in their own image and not the objects of statics placed in another image; exports narrows discovered symbols on the MSVC ABI, with a warning beside source declarations and an error for an empty surface a program of the build links; auto_export is renamed windows_auto_export before its first release under SPEC-004 section 5.3; build-program glob inputs share the walk of sources globs, report unwatchable patterns, match absolute patterns and refuse patterns leaving a registry or git dependency; run_all.sh bounds each test where GNU timeout is absent.

SPEC-004 v1.11 and SPEC-009 v0.2. Closes #766.
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.

fix: support LLVM LTO objects without overriding explicit DLL exports

2 participants