runtime: give ten cross-language globals C linkage in main.cpp (MSVC) - #246
Merged
Conversation
Second report on #244: main.cpp references C-defined globals that MSVC cannot resolve. MSVC mangles namespace-scope variables; the Itanium ABI does not, so a C++ reference to a C global links on GCC/Clang and fails under MSVC with an unresolved external. main.cpp already has the fix pattern -- the file-scope extern "C" block added by the earlier MSVC pass, with a comment saying exactly this. Ten globals added since then never made it into the block: memory.c i_stat, i_mask, g_guest_store_count, g_vblank_ack_count interrupts.c g_vblank_raise_count, g_vblank_deliver_count dirty_ram_interp.c g_dirty_ram_blocks_run, g_dirty_pump_count overlay_loader.c g_call_unit_depth psx_bios_backend.c g_psx_dispatch_depth Each is referenced only through a block-scope `extern` inside a function. With no namespace-scope declaration in view, that block-scope declaration gives the entity C++ linkage, which is the failure. Declaring them in the file-scope extern "C" block fixes it without touching the use sites: the block-scope redeclarations now inherit C linkage, as the block's comment already describes for the symbols that were there. Which ten was measured, not eyeballed. Every block-scope extern in main.cpp (31 distinct symbols) was probed by appending `extern "C++" { extern T sym; }` to a copy of the file compiled with the target's real command line: a conflicting-linkage diagnostic means the symbol already has C linkage from an extern "C" header, silence means it does not. 21 came back already-C (declared in psx_cycles.h, cpu_state.h, debug_server.h and friends, or already in this block); these 10 came back C++. After the change all 31 probe as C linkage. Audited beyond main.cpp: it is the only C++ TU in the runtime with this pattern. beetle_libretro.cpp's `extern PS_GPU GPU` / `extern PS_CDC *PSX_CDC` are genuine C++ symbols from the Beetle core, correctly left with C++ linkage, and psx-beetle is not built under MSVC in any case. No behaviour change on the existing toolchains: main.cpp.o is byte-identical to its origin/master build. Full runtime suite on a clean build dir is 47/48, the single failure being gte_register_access_test, which fails identically at origin/master (43/44 there) -- it links gte.cpp + pgxp.cpp but references gpu_ws_precise_nclip_enabled, defined in gpu.c, which is not in that target. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014YD7rrVK63Kncki6prB65S
Contributor
|
One more thing I forgot to mention. In main.cpp, the first 2 lines of main() will cause the game to fail to run after compiling with MSVC. This is because 0 is passed as the last argument, which is valid under GCC but not MSVC. MSVC requires a size to be passed when using _IOLBF. Changing the 0 to BUFSIZ fixes this and allows the game to run correctly. |
Member
Author
|
do you have a PR you could submit for that? |
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.
Follow-up to #245 (merged), covering the second problem @TheRealBiggs reported in #244:
Confirmed, and #245 did not address it — that PR was merged from a snapshot taken before this commit was pushed to the branch.
The problem
MSVC mangles namespace-scope variables; the Itanium ABI does not. So a C++ reference to a C-defined global links fine on GCC/Clang and fails on MSVC with an unresolved external.
main.cpp:180already carries the file-scopeextern "C"block from the earlier MSVC pass (PR #16 /df4cc5c), and its comment describes exactly this failure mode. Ten globals added since then never made it into the block:memory.ci_stat,i_mask,g_guest_store_count,g_vblank_ack_countinterrupts.cg_vblank_raise_count,g_vblank_deliver_countdirty_ram_interp.cg_dirty_ram_blocks_run,g_dirty_pump_countoverlay_loader.cg_call_unit_depthpsx_bios_backend.cg_psx_dispatch_depthEach is reached only through a block-scope
externinside a function. With no namespace-scope declaration in view, that block-scope declaration gives the entity C++ linkage — the failure. Adding them to the existing block fixes it without touching a single use site: the block-scope redeclarations inherit C linkage, exactly as the block's own comment already describes for the symbols that were there.+13 lines, one file.
Which ten was measured, not eyeballed
Whether a given block-scope
externis a problem depends on whether some included header already declares it insideextern "C"— reading the file doesn't tell you. So every distinct block-scope extern variable inmain.cpp(32 on current master) was probed by appendingextern "C++" { extern T sym; }to a copy compiled with the target's real command line: a conflicting-linkage diagnostic means the symbol already has C linkage, silence means it doesn't.The remaining one is
g_audio_unmute_resync, and it is not a bug — it's defined inmain.cppitself (main.cpp:1937, file scope) and referenced nowhere outside it, so C++ linkage is correct and consistent for it. Flagging it here so a reviewer re-running the probe doesn't think it was missed.The audit was re-run against current
master(which moved twice since #245 merged,88f07bc9touchingmain.cpp) — same ten, no new ones.main.cppis the only C++ TU in the runtime with this pattern.beetle_libretro.cpp'sextern PS_GPU GPU/extern PS_CDC *PSX_CDCare genuine Beetle C++ symbols, correctly left alone, andpsx-beetleisn't built under MSVC anyway.Verification
main.cpp.ois byte-identical to its unpatched-master build (540,360 bytes both sides) — a strict no-op on GCC/Clang, as expected for declarationsgte_register_access_test, pre-existing and unrelated — it linksgte.cpp+pgxp.cppbut referencesgpu_ws_precise_nclip_enabled, defined ingpu.c, which isn't in that target's source list (runtime/CMakeLists.txt:101-105). It fails identically without this patch.As with #245, I can't run
cl.exehere — this is the standardextern "C"remedy and a no-op on the toolchains I can test, but a Windows build is the real confirmation.Still outstanding from #244: nothing in CI compiles
runtime/srcwithcl.exe.cli-release.ymlhas awindows-latestjob, but it builds the CLI with the portable toolchain. That's why both the GNU-only constructs and these ten globals landed unnoticed, and why the next batch will too. Awindows-latestMSVC configure+build job is the durable fix.🤖 Generated with Claude Code
https://claude.ai/code/session_014YD7rrVK63Kncki6prB65S