Files
Python3-Win9x/PORT_STATUS.md
T

167 KiB

Port Status — CPython 3.11.16 to Windows 98 SE

Date: 2026-08-22 Baseline: CPython v3.11.16 Compiler: MSVC 6.0 (cl.exe 12.00.8804), from external MSVC600 Host test environment: Linux + Wine

Files changed in this revision (_blake2/blake2b_impl.c ULL-literal + declaration-order + long long/designated-initializer slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Modules/_blake2/impl/blake2b-ref.c — two separate slices, each re-probed individually before moving to the next:
    • ULL/LL literal-suffix root blocker. Inventoried every C99 ULL/LL-suffixed integer literal in the file by grep (grep -n "ULL\|[0-9]LL\b"): the 8 blake2b_IV[8] initializer constants (lines 23-26) and 4 occurrences of ~0ULL/0ULL in blake2b_set_lastnode()/blake2b_clear_lastnode()/blake2b_set_lastblock()/blake2b_clear_lastblock() (lines 48, 54, 63, 71) — 12 literals total, and no others (blake2b_impl.c itself has one more at line 163, but it sits inside a dead #ifdef HAVE_BLAKE2S branch that is never defined in this port, so the C preprocessor only needs to recognize it as a pp-number token to skip it, not evaluate its suffix, and it was left alone). VC6's C89 front end rejects the C99 ULL/LL suffix spelling outright (error C2059: syntax error : 'bad suffix on number') but does accept the Microsoft-specific i64/ui64 64-bit literal suffixes. Rather than rewriting the literals to bare ui64 (a new, unreviewed spelling choice), every literal was routed through the existing PY_LL/PY_ULL macro pair already defined in PC/pyconfig.h for exactly this compiler (#define PY_ULL(x) x##ui64 when _MSC_VER < 1300, else x##ULL) — the same macro pair Include/pyport.h already anticipates via its own #ifndef PY_LL guard and accompanying comment ("see PC/pyconfig.h for the compilers that need something other than the C99 LL/ULL suffixes"), and the same defect family/fix shape as the earlier PY_LONG_LONG routing for _abc.c. blake2b-ref.c is #included from blake2b_impl.c after #include "Python.h", so PY_ULL is already visible by the time it is preprocessed; no new include was added. Every literal's digit value is unchanged — 0x6a09e667f3bcc908ULL became PY_ULL(0x6a09e667f3bcc908), ~0ULL became ~PY_ULL(0), etc. — this is a suffix-spelling change only, and it round-trips to the identical x##ULL expansion on every non-VC6 compiler, so no behavior change on any other target.
    • C89 declaration-order fallout in the same file, the next diagnostic once the literal-suffix errors cleared: blake2b_init0() declared its for loop counter as a C99 for( int i = 0; ...) init-declaration, and blake2b_init_param() declared uint8_t *p after the blake2b_init0( S ) statement and used a second C99 for( size_t i = 0; ...) init-declaration. Both were hoisted to each function's opening declaration group (int i; / uint8_t *p; size_t i;), with every assignment left at its original execution point (p = (uint8_t *)(P); still runs right after blake2b_init0(S), in the same order) — the same hoist-and-reprobe pattern already used throughout this port (_abc.c, getpath.c, pystate.c). No control flow or arithmetic changed.
  • cpython/Modules/_blake2/blake2b_impl.c — two more of the previously-characterized-but-unfixed defect families, each re-probed individually:
    • Changed unsigned long long node_offset (the py_blake2b_new_impl() parameter, line 94) to unsigned PY_LONG_LONG node_offset. VC6 has no long long keyword (error C2632: 'long' followed by 'long' is illegal); this is not a new port-local convention — CPython's own public headers already spell 64-bit unsigned parameters exactly this way for the same reason (e.g. Include/longobject.h's PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG) and PyLong_AsUnsignedLongLong). _PyLong_UnsignedLongLong_Converter() (the Argument Clinic-generated converter call site for this parameter) takes a void * out-parameter, so the declared-type change has no call-site ABI/type-mismatch implications.
    • py_blake2b_dealloc(): hoisted PyTypeObject *type into the function's opening declaration group (previously declared, C89-illegally, after the lock-free and secure-zero statements); the assignment type = Py_TYPE(self); stays at its original point, immediately before PyObject_Free(self)/Py_DECREF(type), unchanged.
    • blake2b_type_spec: converted from C99 designated initializers (.name = ..., .basicsize = ..., .flags = ..., .slots = ...) to plain positional initializers in PyType_Spec's declared field order from Include/object.h (name, basicsize, itemsize, flags, slots); the struct's initializer omitted itemsize, so the positional form spells that slot 0 explicitly, matching the implicit C99 zero-fill it already had. Same defect family and fix approach as _abc_data_type_spec/_abcmodule/_bisectmodule's PyModuleDef literals earlier in this port. Field values and order are unchanged.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff (4800 lines) so the project-local compatibility patch includes this _blake2/blake2b_impl.c slice plus all prior uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 worktree exited 0; the temporary worktree was removed afterward.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-stdint.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, stdint shim suite, and pythoncore frontier regression suite all passed with no regressions after this slice.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (before this revision's first edit) exit 2 — confirmed the recorded first blocker reproduces exactly: bare ULL literal-suffix errors in impl/blake2b-ref.c (error C2059: syntax error : 'bad suffix on number') as the first diagnostic for Modules/_blake2/blake2b_impl.c.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after the PY_ULL/PY_LL literal-suffix slice only) exit 2 — every ULL-suffix diagnostic is gone. New first blocker: cpython\Modules\_blake2\impl/blake2b-ref.c(143) : error C2143: syntax error : missing ';' before 'type' (the for( int i = ...) C99 init-declaration in blake2b_init0()), with follow-on errors at lines 165/168-169 in blake2b_init_param().
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after the blake2b-ref.c declaration-order slice) exit 2 — impl/blake2b-ref.c is now fully clean (no diagnostics reference it anymore). New first blockers, all in Modules/_blake2/blake2b_impl.c/its clinic header: error C2632: 'long' followed by 'long' is illegal at clinic/blake2b_impl.c.h(18), clinic/blake2b_impl.c.h(39), and blake2b_impl.c(94); error C2275: 'PyTypeObject' : illegal use of this type as an expression at blake2b_impl.c(397); and error C2059: syntax error : '.' at blake2b_impl.c(412).
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after the unsigned PY_LONG_LONG slice only) exit 2 — all three long long diagnostics are gone; the PyTypeObject/designated-initializer diagnostics at lines 397/412 remain, confirming they are independent defects rather than parser-desync fallout.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after the py_blake2b_dealloc()/blake2b_type_spec slice — final state this revision) exit 2 — Modules/_blake2/blake2b_impl.c now compiles with zero errors and zero warnings; total=6 compiled=5 cached=0 skipped=0. The frontier advances to the next source in pythoncore.vcxproj order, Modules/_blake2/blake2s_impl.c (autogenerated from blake2b_impl.c per its own header comment), whose first blockers are the identical defect families mirrored into the s-variant files: C99 for-init-declarations in impl/blake2s-ref.c (lines 231, 275), unsigned long long in clinic/blake2s_impl.c.h(18,39)/blake2s_impl.c(94), a bare ULL-suffix literal at blake2s_impl.c(163) (if (node_offset > 0xFFFFFFFFFFFFULL), guarded by #ifdef HAVE_BLAKE2S in blake2b_impl.c but not guarded in blake2s_impl.c, so it is live code there), and the same PyTypeObject *type = Py_TYPE(self);/designated-initializer pair at blake2s_impl.c(397)/(412). None of this has been fixed yet.
bash scripts/vc6-probe-core.sh cpython/Modules/main.c exit 0 — still compiles cleanly after this slice.
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after this slice.
git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force exit 0 — regenerated compatibility patch applies cleanly to a pristine detached v3.11.16 worktree; temporary worktree removed.

Current pythoncore compile-frontier status: Modules/_blake2/blake2b_impl.c (and its #included impl/blake2b-ref.c) is fully clean under the VC6 frontier probe (0 errors, 0 warnings), advancing the frontier past _abc.c, _bisectmodule.c, blake2module.c, and now blake2b_impl.c. The frontier has moved on to Modules/_blake2/blake2s_impl.c, whose first blocker set is the same defect families just fixed here, mirrored into the autogenerated s-variant sources — plus one new wrinkle: the 0xFFFFFFFFFFFFULL node-offset overflow check that sits inside a dead #ifdef HAVE_BLAKE2S branch in blake2b_impl.c (and so never needed fixing there) is not dead code in blake2s_impl.c, so its ULL suffix will need the same PY_ULL() treatment as a live diagnostic this time. Recommended next slice: mirror this revision's three sub-slices onto the s-variant files in the same order (literal suffixes in impl/blake2s-ref.c plus the live blake2s_impl.c(163) literal first, then blake2s-ref.c's C89 declaration-order fallout, then unsigned PY_LONG_LONG/PyTypeObject/designated-initializer in blake2s_impl.c/its clinic header), re-probing after each sub-slice as done here.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (compat/msvc600/stdint.h shim + _blake2/blake2module.c slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • compat/msvc600/stdint.h — new VC6-scoped project-local compatibility header providing the missing C99 <stdint.h> that cpython/Modules/_blake2/impl/blake2.h and blake2-impl.h #include. Evidence before adding it: grepped every fixed-width-integer identifier (u?int(8|16|32|64)_t, u?intptr_t, u?int_least*_t, u?int_fast*_t, size_t) across the entire Modules/_blake2/ tree (both impl headers/sources and the blake2b_impl.c/blake2s_impl.c/clinic wrappers). The only fixed-width types actually used anywhere in that tree are uint8_t, uint32_t, and uint64_t (in load32/64/48, store32/64/48, rotl32/64, rotr32/64, and the reference block-compression loops); no int8_t/int16_t/int32_t/int64_t or intptr_t/uintptr_t appear at all. size_t is also used but is unaffected — it already comes from <stddef.h>, which VC6 has natively. Design: rather than re-declaring these three typedefs a second time under a second include guard, stdint.h forwards to the already-existing, already-verified compat/msvc600/inttypes.h (added in an earlier revision so CPython's own Include/pyport.h, which does #include <inttypes.h>, would compile) via #include "inttypes.h". inttypes.h's own include guard makes this forwarding idempotent regardless of which of the two headers a given translation unit reaches first, so a TU that ends up pulling in both Python.h (→ pyport.h → <inttypes.h>) and blake2.h (→ <stdint.h>) cannot hit a duplicate-typedef error. Width assumptions (unchanged, already relied on by inttypes.h): uint8_t = unsigned char (1 byte), uint32_t = unsigned long (4 bytes on Win32/ILP32), uint64_t = unsigned __int64 (VC6's non-standard 64-bit extension, 8 bytes) — verified sufficient by a compile-time fixture (below) using typedef char check[(sizeof(uint32_t)==4) ? 1 : -1];-style width assertions, since VC6 has no static_assert.
  • scripts/fixtures/vc6_stdint_smoke.c — new focused compile fixture: includes both <stdint.h> and <inttypes.h> in the same translation unit (reproducing the Python.h + blake2.h coexistence case), asserts sizeof(uint8_t)==1/sizeof(uint32_t)==4/sizeof(uint64_t)==8 at compile time, and exercises load32/load64/rotl32/rotl64 in the same shape blake2-impl.h uses.
  • scripts/vc6-probe-stdint.test.sh — new regression test for the shim and fixture under the VC6 probe, modeled directly on the existing scripts/vc6-probe-pathcch.test.sh (skips, not fails, when Wine/MSVC600 are unavailable).
  • cpython/Modules/_blake2/blake2module.c — with the <stdint.h> blocker gone, the file advanced to two blockers from defect families already fixed elsewhere in this port: (1) blake2_exec() declared PyObject *d = st->blake2b_type->tp_dict; after preceding statements (C89 mixed-declaration; VC6 requires declarations before statements) — hoisted PyObject *d; into the function's opening declaration group and changed the first assignment to plain d = ..., leaving the second assignment (d = st->blake2s_type->tp_dict;) unchanged since d was already in scope there; (2) the blake2_module PyModuleDef struct literal mixed a positional PyModuleDef_HEAD_INIT/"_blake2" prefix with C99 designated initializers (.m_doc = ... etc.) for the rest — converted to plain positional initializers in Include/moduleobject.h's declared field order (m_base, m_name, m_doc, m_size, m_methods, m_slots, m_traverse, m_clear, m_free), the same defect family and fix already used in _abc.c and _bisectmodule.c. Field values and order are unchanged — this is a spelling change only, not a behavior change.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff (4651 lines) so the project-local compatibility patch includes this stdint.h/blake2module.c slice plus all prior uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 worktree exited 0; the temporary worktree was removed afterward.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-stdint.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, new stdint shim suite, and pythoncore frontier regression suite all passed with no regressions after this slice.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (before this slice) exit 2 — confirmed the recorded first blocker reproduces exactly: cpython\Modules\_blake2\impl/blake2.h(18) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory. Summary: total=4 compiled=3 cached=0 skipped=0.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after adding compat/msvc600/stdint.h only, before the blake2module.c source edits) exit 2 — the missing-stdint.h fatal error is gone; new first blocker is cpython\Modules\_blake2\blake2module.c(98) : error C2275: 'PyObject' : illegal use of this type as an expression (C89 mixed-declaration) immediately followed by the .m_doc = ... designated-initializer error C2059: syntax error : '.' at line 145.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after the blake2module.c slice) exit 2 — Modules/_blake2/blake2module.c now compiles with zero errors and zero warnings. The frontier advances to the next source in pythoncore.vcxproj order, Modules/_blake2/blake2b_impl.c, whose new first blockers are a different defect family: bare 0ULL/64ULL-style integer-literal suffixes in Modules/_blake2/impl/blake2b-ref.c (error C2059: syntax error : 'bad suffix on number' — VC6's C89 front end does not accept the C99 ULL/LL integer-constant suffixes at all, only UL/L/U), C99 mixed-declaration/for-init-declaration fallout in the same file, unsigned long long in clinic/blake2b_impl.c.h and blake2b_impl.c itself (the same long long-keyword gap already routed through PY_LONG_LONG elsewhere in this port), and a PyTypeObject *type = ... C89 mixed-declaration plus a . designated-initializer in blake2b_impl.c. None of this has been fixed yet. Summary: total=5 compiled=4 cached=0 skipped=0.
bash scripts/vc6-probe-core.sh cpython/Modules/main.c exit 0 — still compiles cleanly after this slice.
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after this slice.
git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force exit 0 — regenerated compatibility patch applies cleanly to a pristine detached v3.11.16 worktree; temporary worktree removed.

Current pythoncore compile-frontier status: Modules/_blake2/blake2module.c is fully clean under the VC6 frontier probe (0 errors, 0 warnings), advancing the frontier past _abc.c, _bisectmodule.c, and now blake2module.c. The frontier has moved on to Modules/_blake2/blake2b_impl.c (via its #included impl/blake2b-ref.c), whose first blocker is a new defect family for this port: VC6's C89 front end rejects the C99 ULL/LL unsigned-long-long integer-literal suffixes used throughout the BLAKE2 reference constants and IV tables. This is distinct from the already-solved long long keyword gap (PY_LONG_LONG) — it is about literal-suffix spelling, and will need either rewriting the affected literals (e.g. 0x6A09E667F3BCC908ULL → a PY_LONG_LONG-safe spelling, likely via a cast or an _LL/ui64-suffix substitution valid under VC6) or a targeted macro, plus the follow-on C89 declaration-order, long long-keyword, and designated-initializer fixes already characterized above in blake2b_impl.c and its clinic header. Recommended next slice: Modules/_blake2/impl/blake2b-ref.c's integer-literal suffixes first (it is the root blocker blake2b_impl.c #includes), then re-probe before touching blake2b_impl.c itself.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (_bisectmodule.c designated-initializer slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Modules/_bisectmodule.c — converted the _bisectmodule PyModuleDef struct literal from C99 designated initializers (.m_name = ..., .m_size = ..., etc.) to plain positional initializers in the struct's declared field order (m_base, m_name, m_doc, m_size, m_methods, m_slots, m_traverse, m_clear, m_free, per Include/moduleobject.h). This is the same defect family and same fix approach already used twice in _abc.c (error C2059: syntax error : '.'; VC6 has no C99 designated-initializer support). The struct had no m_traverse initializer in the original, so the corresponding positional slot is NULL. Field values and order are otherwise unchanged — this is a spelling change only, not a behavior change. No declaration-order (C89 mixed-declaration) errors followed this fix; the file compiles clean end-to-end on the first re-probe.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff (4609 lines) so the project-local compatibility patch includes this _bisectmodule.c slice plus all prior uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 worktree exited 0; the temporary worktree was removed afterward.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed with no regressions after this slice.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (before this slice) exit 2 — confirmed the recorded first blocker reproduces exactly: cpython\Modules\_bisectmodule.c(329) : error C2059: syntax error : '.' at .m_name = "_bisect", in the _bisectmodule PyModuleDef initializer.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after this slice) exit 2 — Modules/_bisectmodule.c now compiles with zero errors and zero warnings (only the source-filename echo from cl.exe, same as a clean compile). The frontier advances to the next source in pythoncore.vcxproj order, Modules/_blake2/blake2module.c, whose new first blocker is cpython\Modules\_blake2\impl/blake2.h(18) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory — a missing modern-C/SDK standard header, a different defect family from designated initializers or C89 declaration ordering, and not yet addressed here. Summary: total=4 compiled=3 cached=0 skipped=0.
bash scripts/vc6-probe-core.sh cpython/Modules/main.c exit 0 — still compiles cleanly after this slice.
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after this slice.
git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force exit 0 — regenerated compatibility patch applies cleanly to a pristine detached v3.11.16 worktree; temporary worktree removed.

Current pythoncore compile-frontier status: Modules/_bisectmodule.c is fully clean under the VC6 frontier probe (0 errors, 0 warnings), advancing the frontier past both _abc.c and _bisectmodule.c. The frontier has moved on to Modules/_blake2/blake2module.c, whose first blocker is a missing <stdint.h> (needed by Modules/_blake2/impl/blake2.h for fixed-width integer types like uint32_t/uint64_t). This is a new defect family — a missing standard/SDK header, not a source-level C89/C99 compatibility issue — and will likely need either a project-local stdint.h compatibility shim (similar in spirit to the existing compat/msvc600/pathcch.h shim) or a decision to exclude/stub the _blake2 module for this port, rather than a source-hoist slice. The recommended next step is to characterize the actual uint32_t/uint64_t/etc. usage in Modules/_blake2/impl/*.h before choosing between those two approaches.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (_abc.c C89 declaration-hoist + designated-initializer slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Modules/_abc.c — advanced the _abc.c frontier past its full body with a sequence of small, individually re-probed slices:
    • abc_data_dealloc(): hoisted PyTypeObject *tp before the PyObject_GC_UnTrack(self) statement (the exact line-67 blocker recorded at the start of this revision).
    • _abc_data_type_spec and the _abcmodule PyModuleDef: converted from C99 designated initializers (.name = ..., .m_name = ..., etc.) to plain positional initializers in declared field order. VC6 has no C99 designated-initializer support at all (error C2059: syntax error : '.'); this is a different defect family from declaration-hoisting, so it is called out separately here. Field values and order are unchanged — this is a spelling change only, not a behavior change.
    • _in_weak_set(), _add_to_weak_set(), _abc__get_dump(), compute_abstract_methods() (both for loops, including replacing their C99 for (Py_ssize_t pos = 0; ...) init-declarations with a function-scoped pos and hoisting per-iteration locals to the top of each loop body), set_collection_flag_recursive(), _abc__abc_register_impl(), _abc__abc_instancecheck_impl(), _abc__abc_subclasscheck_impl() (including its inner for loop over subclasses), and subclasscheck_check_registry() (including its inner for loop over the registry snapshot): hoisted all locals into each function's or block's opening declaration group, preserving every assignment at its original execution point (after argument validation, inside the same if/for/while branch, etc.). No control flow, lock/refcount ordering, or error-path behavior was changed anywhere in this slice.
    • The previously reported "generated clinic/_abc.c.h struct-redefinition conflict around line 583" was characterized while fixing _abc__abc_instancecheck_impl() (whose opening declaration group sat at old line 583): it was parser-desync fallout from the preceding unfixed declaration-hoist errors, not a real redefinition. clinic/_abc.c.h itself is unmodified and is only 163 lines long; there is no struct redefinition in it. This matches the caveat already recorded about that hypothesis.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff (4583 lines) so the project-local compatibility patch includes this _abc.c slice plus all prior uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 worktree exited 0; the temporary worktree was removed afterward.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed with no regressions after this slice.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (before this slice) exit 2 — confirmed the recorded first blocker reproduces exactly: cpython\Modules\_abc.c(67) : error C2275: 'PyTypeObject' : illegal use of this type as an expression at PyTypeObject *tp = Py_TYPE(self); in abc_data_dealloc().
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after each incremental slice, ~10 live re-probes) exit 2 each time until the final one — the first diagnostic advanced monotonically through _abc.c: line 67 (abc_data_dealloc) → line 109 designated-initializer error C2059 (_abc_data_type_spec) → line 138 (_in_weak_set) → line 203 (_add_to_weak_set) → line 291 (_abc__get_dump) → line 311 (compute_abstract_methods) → line 507/512 (set_collection_flag_recursive) → line 537 (_abc__abc_register_impl) → line 612 (_abc__abc_instancecheck_impl) → line 695 (_abc__abc_subclasscheck_impl) → line 849 (subclasscheck_check_registry). Each slice was verified against the live VC6 frontier before moving to the next.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after the final _abc.c slice) exit 2 — Modules/_abc.c now compiles with zero errors and zero warnings; total=3 compiled=2 cached=0 skipped=0. The frontier advances to the next source in pythoncore.vcxproj order, Modules/_bisectmodule.c, whose new first blocker is cpython\Modules\_bisectmodule.c(329) : error C2059: syntax error : '.' — the same C99 designated-initializer defect family just fixed twice in _abc.c, not yet fixed here.
bash scripts/vc6-probe-core.sh cpython/Modules/main.c exit 0 — still compiles cleanly after this slice.
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after this slice.
git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch && git -C cpython worktree remove ../build/verify-vc6-patch-worktree --force exit 0 — regenerated compatibility patch applies cleanly to a pristine detached v3.11.16 worktree; temporary worktree removed.

Current pythoncore compile-frontier status: Modules/_abc.c is fully clean under the VC6 frontier probe (0 errors, 0 warnings). The frontier has moved on to Modules/_bisectmodule.c, whose first blocker is a C99 designated-initializer struct literal (error C2059: syntax error : '.' at line 329), the same defect family already fixed twice above (_abc_data_type_spec, _abcmodule). The recommended next slice is _bisectmodule.c's designated initializer(s), followed by whatever C89 declaration-order issues follow in that file, using the same per-function hoist-and-reprobe approach used throughout this revision.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (_abc.c frontier: pycore_moduleobject.h declaration-hoist + long long spelling)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Include/internal/pycore_moduleobject.h — hoisted _PyModule_GetDict()'s PyObject *dict declaration into the function's opening declaration group (C89/VC6 requires declarations before statements; the prior form declared dict after the assert(PyModule_Check(mod)); statement). The assignment stays at the original point, and the following assert(dict != NULL);/return are unchanged.
  • cpython/Modules/_abc.c — changed the two unsigned long long struct field declarations (_abcmodule_state.abc_invalidation_counter, _abc_data._abc_negative_cache_version) to unsigned PY_LONG_LONG. VC6 has no long long keyword at all (error C2632: 'long' followed by 'long' is illegal); CPython's own PC/pyconfig.h already defines PY_LONG_LONG to fall back to __int64 for _MSC_VER < 1300 (VC6) for exactly this reason. This routes through that existing, already-correct CPython compatibility macro instead of adding a new shim; no other files in the current frontier use the bare long long spelling.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff so the project-local compatibility patch includes this slice plus all prior uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 (each script individually) — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed with no regressions after this slice.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (before this slice) exit 2 — first blocker cpython\Include\internal\pycore_moduleobject.h(33) : error C2143: syntax error : missing ';' before 'type' at PyObject *dict = ((PyModuleObject *)mod) -> md_dict;, cascading into spurious dict-undeclared fallout plus pycore_gc.h(15) : error C2061: syntax error : identifier 'uintptr_t' and further undefined-struct fallout through pycore_interp.h, pycore_global_objects.h, pycore_runtime.h, and pycore_object.h, then _abc.c fallout until fatal error C1003: error count exceeds 100.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after pycore_moduleobject.h hoist only) exit 2 — confirms the hoist was the true root cause: every pycore_gc.h/pycore_interp.h/pycore_global_objects.h/pycore_runtime.h/pycore_object.h diagnostic is gone (those headers were never actually broken; VC6's error recovery from the single C89 syntax error had desynced parsing for the rest of the translation unit). New first blocker is cpython\Modules\_abc.c(22) : error C2632: 'long' followed by 'long' is illegal at unsigned long long abc_invalidation_counter;.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh (after both fixes) exit 2 — _abc.c's long long blocker is gone. New first blocker is cpython\Modules\_abc.c(67) : error C2275: 'PyTypeObject' : illegal use of this type as an expression (a C89 mixed-declaration pattern, same family as already fixed repeatedly in pystate.c/pylifecycle.c/getpath.c), followed by many more declaration-order and declaration-after-statement errors throughout the rest of _abc.c's ~35 functions until fatal error C1003: error count exceeds 100 at line 784. Summary: total=2 compiled=1 cached=0 skipped=0.
bash scripts/vc6-probe-core.sh cpython/Modules/main.c exit 0 — still compiles cleanly after this slice.
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after this slice.
git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch exit 0 — regenerated compatibility patch applies cleanly to a pristine detached v3.11.16 worktree.

Current pythoncore compile-frontier status: the frontier has advanced past the pycore_moduleobject.h/GC-header cascade and past _abc.c's long long blocker. Modules/_abc.c is now the active frontier file; the next blocker is a large set of C89 declaration-order violations spread across most of its functions (starting at line 67), plus at least one apparent struct-redefinition conflict with the Argument Clinic-generated clinic/_abc.c.h at line 583 that has not yet been individually characterized. This will need a multi-slice declaration-hoist pass through _abc.c, similar in shape to the pystate.c slices recorded below, rather than a single edit.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (VC6 frontier /D string define transport)

All still uncommitted; nothing in this list has been pushed anywhere.

  • scripts/vc6-probe-pythoncore-frontier.sh — moved live VC6 compile arguments into per-object response files so quoted /D string literals no longer traverse wine cmd /c as inline command text. quote_define_for_cmd() now doubles define-owned backslashes before protecting literal quotes, so VPATH="..\\.." reaches CL preprocessing as the C string literal "..\\.."; empty-string defines such as PYDEBUGEXT="" are preserved. Added render_compile_command_for_test() as a safe no-Wine regression helper for define rendering.
  • scripts/vc6-probe-pythoncore-frontier.test.sh — added a list-only/no-toolchain assertion that checks rendered per-file string defines for VPATH, PYDEBUGEXT, and PLATLIBDIR before the optional live Wine/VC6 run.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash -n scripts/vc6-probe.test.sh scripts/vc6-probe-core.test.sh scripts/vc6-probe-pathcch.test.sh scripts/generate-getpath-frozen.test.sh scripts/vc6-probe-pythoncore-frontier.test.sh scripts/vc6-probe-pythoncore-frontier.sh scripts/generate-getpath-frozen.sh scripts/vc6-probe-minlink.sh scripts/vc6-probe-core.sh scripts/vc6-probe.sh && bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 — shell syntax plus public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh exit 2 — Modules/getpath.c now compiles cleanly under the forced frontier. The frontier advances to Modules/_abc.c; first exact blocker is cpython\\Include\\internal\\pycore_moduleobject.h(33) : error C2143: syntax error : missing ';' before 'type', followed by dict undeclared fallout, missing/undefined GC internals beginning with pycore_gc.h(15) : error C2061: syntax error : identifier 'uintptr_t', and then _abc.c VC6/C89/modern-C fallout until fatal error C1003: error count exceeds 100. Summary: total=2 compiled=1 cached=0 skipped=0.

Current pythoncore compile-frontier status: the quoted macro transport blocker is resolved in the harness, and the frontier has advanced past Modules/getpath.c. The next actionable blocker is now in shared internal headers reached while compiling Modules/_abc.c, starting with C89 declaration ordering in pycore_moduleobject.h and missing/unsupported GC typedef structure (uintptr_t / PyGC_Head) fallout.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (getpath.c _PyConfig_InitPathConfig C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Modules/getpath.c — advanced _PyConfig_InitPathConfig() past the first main-body VC6/C89 declaration-order blocker by hoisting active locals (configDict, dict, co, Windows-only winreg, and r) into the function opening declaration group. Assignments remain at their original execution points after _PyPathConfig_ReadGlobal(), early status/compute_path_config return, and GIL check; refcount cleanup, winreg fallback handling, code evaluation, _PyConfig_FromDict(), and return statuses are unchanged. Disabled #if 0 debug locals were left untouched.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff so the compatibility patch includes this _PyConfig_InitPathConfig() declaration-hoist slice plus prior uncommitted compatibility edits.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh exit 2 — _PyConfig_InitPathConfig() now gets past the prior line-887 PyObject *configDict = _PyConfig_AsDict(config); blocker, plus the follow-on dict, co, Windows winreg, and r declaration-order blockers. New exact first blocker is build\generated\cpython\Modules\getpath.c(956) : error C2001: newline in constant at !decode_to_dict(dict, "VPATH", VPATH), followed by adjacent newline-in-constant diagnostics for PLATLIBDIR, PYDEBUGEXT, and PYWINVER, then parse fallout. Summary: total=1 compiled=0 cached=0 skipped=0.
git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch exit 0 — regenerated compatibility patch applies cleanly to a pristine detached v3.11.16 worktree.

Current pythoncore compile-frontier status: the requested _PyConfig_InitPathConfig() declaration-order slice is complete and verified. The frontier still starts at Modules/getpath.c, but the next blocker has advanced from C89 declarations to quoted macro/value handling in the initial-value dictionary expression.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in this revision (getpath.c first VC6/C89 helper slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Modules/getpath.c — advanced the first Modules/getpath.c pythoncore frontier slice by moving early helper declarations to C89/VC6-safe declaration groups while preserving assignment timing after argument parsing and other checks. Covered getpath_abspath(), getpath_basename(), getpath_dirname(), getpath_hassuffix(), Windows file-attribute helpers (isdir/isfile/isxfile), getpath_joinpath(), getpath_readlines(), funcs_to_dict(), decode_to_dict(), env_to_dict(), and winmodule_to_dict().
  • cpython/Modules/getpath.c — added a narrow VC6/old-SDK fallback for missing INVALID_FILE_ATTRIBUTES, guarded as defined(_MSC_VER) && _MSC_VER < 1300 && !defined(INVALID_FILE_ATTRIBUTES) under MS_WINDOWS after including <windows.h>.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff so the project-local compatibility patch includes this getpath.c slice plus prior uncommitted compatibility edits.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 — public probe suite, core probe suite, PathCch shim suite, getpath frozen-header generator suite, and pythoncore frontier regression suite all passed.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh exit 2 — Modules/getpath.c gets past the prior line-66 Py_ssize_t len blocker, the immediate helper declaration-order blockers, and the old-SDK INVALID_FILE_ATTRIBUTES blocker. New exact first blocker is build\\generated\\cpython\\Modules\\getpath.c(887) : error C2275: 'PyObject' : illegal use of this type as an expression at PyObject *configDict = _PyConfig_AsDict(config); in _PyConfig_InitPathConfig(), followed by the same function's later C89 declaration-order fallout. Summary: total=1 compiled=0 cached=0 skipped=0.
git -C cpython worktree add --detach ../build/verify-vc6-patch-worktree v3.11.16 && git -C build/verify-vc6-patch-worktree apply --check ../../compat/msvc600/cpython-3.11.16-vc6-headers.patch exit 0 — regenerated compatibility patch applies cleanly to a pristine detached v3.11.16 worktree.

Current pythoncore compile-frontier status: the first bounded getpath.c helper declaration-order/old-SDK slice is complete and verified. The frontier still starts at Modules/getpath.c, but the next blocker has advanced into _PyConfig_InitPathConfig()'s main path-calculation body.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in this revision (generated getpath.h provisioning)

All still uncommitted; nothing in this list has been pushed anywhere.

  • scripts/generate-getpath-frozen.sh — new reproducible project-local generation step for Python/frozen_modules/getpath.h. It invokes CPython's documented Programs/_freeze_module.py getpath Modules/getpath.py ... path with host python3 and writes only to ignored build/generated/cpython/Python/frozen_modules/getpath.h.
  • scripts/generate-getpath-frozen.test.sh — new regression coverage for the generated path and header format: verifies the _freeze_module.py banner, _Py_M__getpath symbol, 16-byte line formatting, unmarshaled <frozen getpath> code object, and byte-for-byte equality with a direct Programs/_freeze_module.py invocation.
  • scripts/vc6-probe-pythoncore-frontier.sh — now provisions the generated getpath header before live VC6 compilation and compiles Modules/getpath.c from an ignored generated cpython-shaped source copy so its relative ../Python/frozen_modules/getpath.h include resolves without tracking generated output.
  • scripts/vc6-probe-pythoncore-frontier.test.sh — live integration check now rejects a stale missing-getpath.h blocker and verifies the frontier harness created the ignored generated header.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
chmod +x scripts/generate-getpath-frozen.sh scripts/generate-getpath-frozen.test.sh scripts/vc6-probe-pythoncore-frontier.sh && bash -n scripts/generate-getpath-frozen.sh scripts/generate-getpath-frozen.test.sh scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh && bash scripts/generate-getpath-frozen.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 — generator format/path regression passed and frontier regression passed, including live provisioning of build/generated/cpython/Python/frozen_modules/getpath.h.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh exit 2 — Modules/getpath.c now gets past both <pathcch.h> and the generated ../Python/frozen_modules/getpath.h include. It stops at the next honest VC6/C89 compile blocker: mixed declarations in getpath.c, first diagnostic build\\generated\\cpython\\Modules\\getpath.c(66) : error C2275: 'Py_ssize_t' : illegal use of this type as an expression, followed by more declaration-order errors and INVALID_FILE_ATTRIBUTES not being declared before the compiler reaches its 100-error cap. Summary: total=1 compiled=0 cached=0 skipped=0.

Current pythoncore compile-frontier status: generated frozen getpath.h is now reproducibly provisioned from CPython source into ignored build output and integrated into the frontier harness. The current first blocker remains Modules/getpath.c, now at VC6/C89 declaration-order and old-SDK constant compatibility work rather than missing generated input.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (VC6 PathCchFindExtension shim)

All still uncommitted; nothing in this list has been pushed anywhere.

  • compat/msvc600/pathcch.h — new VC6-scoped project-local compatibility header that implements only PathCchFindExtension(PCWSTR, size_t, PCWSTR *) for the existing Modules/getpath.c use. It scans a null-terminated wide path within cchPath, returns the last . after the last \\, /, or : separator, returns the terminating NUL when no extension is present, and returns E_INVALIDARG for null arguments, zero cchPath, or a too-small count with no NUL.
  • scripts/fixtures/vc6_pathcch_smoke.c — focused compile fixture covering .exe, no extension, a dot in a directory name, dotfiles, trailing directory separators, multiple suffixes, and invalid/too-small arguments.
  • scripts/vc6-probe-pathcch.test.sh — new regression test for the shim and fixture under the VC6 probe when Wine/MSVC600 are available.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
chmod +x scripts/vc6-probe-pathcch.test.sh && bash -n scripts/vc6-probe-pathcch.test.sh scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh scripts/vc6-probe-minlink.sh scripts/vc6-probe-core.sh scripts/vc6-probe.sh exit 0
bash scripts/vc6-probe-pathcch.test.sh exit 0, ALL TESTS PASSED — 4/4 checks ok; the smoke fixture compiles under VC6 and no longer hits missing pathcch.h.
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pathcch.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 — public probe suite, core probe suite, pathcch smoke suite, and frontier regression suite all passed.
VC6_FRONTIER_FORCE=1 bash scripts/vc6-probe-pythoncore-frontier.sh exit 2 — Modules/getpath.c now gets past <pathcch.h> and stops at the next honest blocker: cpython\\Modules\\getpath.c(22) : fatal error C1083: Cannot open include file: '../Python/frozen_modules/getpath.h': No such file or directory. Summary: total=1 compiled=0 cached=0 skipped=0.

Current pythoncore compile-frontier status: the narrow PathCchFindExtension compatibility needed by Modules/getpath.c is implemented and verified under VC6 compile probes. The next blocker in full project order is the missing generated/frozen header Python/frozen_modules/getpath.h required by Modules/getpath.c; this is separate from the PathCch API gap. No CompareStringOrdinal blocker has been reached yet.

Caveat: this is still compile-probe work only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (source-list-driven pythoncore compile frontier)

All still uncommitted; nothing in this list has been pushed anywhere.

  • scripts/vc6-probe-pythoncore-frontier.sh — new project-local pythoncore compile-frontier harness. It parses cpython/PCbuild/pythoncore.vcxproj's 198 <ClCompile> entries, normalizes Windows-style paths to project-local cpython/... paths, compiles supported sources incrementally, preserves common/per-file defines, reports external/generated sources, and stops on the first VC6 front-end blocker with cl.exe's real status.
  • scripts/vc6-probe-pythoncore-frontier.test.sh — new regression test covering source-list parsing, path normalization, per-file define preservation, unsupported/generated/external reporting, and a bounded live first-source VC6 run when Wine/MSVC600 are present.
  • PORT_STATUS.md — that revision.

Command results (previous revision):

Command Result
`for f in scripts/vc6-probe-pythoncore-frontier.sh scripts/vc6-probe-pythoncore-frontier.test.sh scripts/vc6-probe-minlink.sh scripts/vc6-probe-core.sh; do bash -n "$f"
bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0, ALL TESTS PASSED — 12/12 checks ok
bash scripts/vc6-probe-pythoncore-frontier.sh exit 2 — generated the source list, began with cpython/Modules/getpath.c, preserved its per-file defines, invoked VC6 cl.exe, and stopped truthfully at the first blocker: missing pathcch.h at Modules/getpath.c(14).
bash scripts/vc6-probe.test.sh && bash scripts/vc6-probe-core.test.sh && bash scripts/vc6-probe-pythoncore-frontier.test.sh exit 0 — public probe suite, core probe suite, and new frontier suite all passed.
bash scripts/vc6-probe-minlink.sh exit 96 — unchanged minimal link-frontier behavior: all four selected translation units compile, then LINK.EXE fails with fatal error LNK1120: 267 unresolved externals.

Previous pythoncore compile-frontier status: source-list-driven frontier infrastructure was implemented and verified. The first actionable VC6 compile blocker in full project order was Modules/getpath.c requiring pathcch.h, a modern Windows SDK header not present in the VC6/MSVC600 include set.

Caveat: this was a compile-frontier harness only. No full pythoncore.dll/python.exe build, no successful link, no Wine launch, and no Windows 98 runtime execution was claimed.

All still uncommitted; nothing in this list has been pushed anywhere.

  • scripts/vc6-probe-minlink.sh — new project-local link-frontier harness. It reuses the existing Wine/MSVC600 helpers, compiles Programs/python.c plus the three currently clean core translation units (Modules/main.c, Python/pylifecycle.c, and Python/pystate.c) with pythoncore-style core/shared defines, then invokes VC6 LINK.EXE for a minimal python-min.exe attempt. This is intentionally not a full pythoncore.vcxproj build; pythoncore.vcxproj lists 198 C sources (without externals disabled: plus zlib-conditioned entries), while python.vcxproj only contributes Programs/python.c and references the core project.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe-minlink.sh exit 96 — all four frontier translation units compile under VC6, then LINK.EXE runs and fails truthfully with fatal error LNK1120: 267 unresolved externals. First unresolved symbols include __PyPathConfig_ComputeSysPath0 / __PyPathConfig_UpdateGlobal (Python/pathconfig.c), __Py_Dealloc (Objects/object.c), _PyErr_Print (Python/pythonrun.c), and PyStatus_Ok (Python/initconfig.c).
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — existing core compile-probe regression checks still pass after adding the link-frontier script

Current minimal-link status: the first post-core-probe link milestone is now implemented as a reproducible harness that reaches the VC6 linker. A successful link is not feasible from only the already-clean TUs: the exact blocker is the expected unresolved-symbol frontier caused by not yet compiling the rest of pythoncore.vcxproj's source graph. Recommended next artifact is a source-list-driven VC6 pythoncore compile frontier (generate/consume the pythoncore.vcxproj <ClCompile> list, with per-file defines such as getpath.c and sysmodule.c handled explicitly) that compiles additional core objects one at a time before attempting a real pythoncore/python.exe link.

Caveat: this is a link-frontier probe only. No pythoncore.dll/full python.exe build, no Wine launch, and no Windows 98 runtime execution is claimed.

Files changed in previous revision (pystate.c final tail helper C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — _Py_GetConfig() now declares PyThreadState *tstate in the function opening declaration group while preserving the assert(PyGILState_Check()) before assigning tstate = _PyThreadState_GET(). push_chunk() now declares _PyStackChunk *new and PyObject **res in its opening declaration group while preserving the allocation-size loop, allocate_chunk(...) assignment point, chunk linking/top/limit updates, root-chunk offset, and returned stack pointer. _PyThreadState_PopFrame() now declares PyObject **base in the function opening declaration group while preserving the datastack assertion before assigning base = (PyObject **)frame, plus the chunk-pop and top-reset paths. _PyThreadState_BumpFramePointerSlow()'s inner block declaration was not changed.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff (3703 lines); includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c compiles cleanly end-to-end (compile-only)
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the final tail-helper declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 0 — gets past the prior line 3405 (PyThreadState *tstate = _PyThreadState_GET();) blocker in _Py_GetConfig(), the push_chunk() declaration-order blockers at line 3418 (_PyStackChunk *new = allocate_chunk(...)) and line 3431 (PyObject **res = &new->data[...]), and the follow-on line 3460 (PyObject **base = (PyObject **)frame;) blocker in _PyThreadState_PopFrame(). No next C89 declaration blocker is currently exposed by the pystate.c compile probe; the only diagnostic left in this probe output is the pre-existing line 3361 warning (warning C4550: expression evaluates to a function which is missing an argument list).
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c PyGILState_Check/Ensure C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists PyGILState_Check()'s PyThreadState *tstate into the function opening declaration group while preserving the early check_enabled and TSS-created returns before assigning tstate = _PyRuntimeGILState_GetThreadState(gilstate). PyGILState_Ensure() now declares PyThreadState *tcur and int current in the opening declaration group, keeps tcur = PyThread_tss_get(...) after the initialization assertions, and leaves the new/current thread-state branches, restore/save ordering, counter update, and return value unchanged.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the PyGILState_Check()/PyGILState_Ensure() declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior line 2886 (error C2275: 'PyThreadState' : illegal use of this type as an expression) blocker at PyThreadState *tstate = _PyRuntimeGILState_GetThreadState(gilstate); in PyGILState_Check() and the adjacent PyGILState_Ensure() declaration-order fallout. New exact first blocker is line 3052 (error C2059: syntax error : '{') at *data = (_PyCrossInterpreterData){0}; in _PyObject_GetCrossInterpreterData(), followed by line 3057 crossinterpdatafunc getdata = _lookup_getdata(obj);, line 3062 int res = getdata(obj, data);, and later cross-interpreter-data helper declaration-order fallout.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c frame access and async-exception C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists PyThreadState_GetFrame()'s _PyInterpreterFrame *f and PyFrameObject *frame declarations into the function's opening declaration group while preserving the f = tstate->cframe->current_frame assignment immediately after the assert and the frame = _PyFrame_GetFrameObject(f) assignment after the NULL check. PyThreadState_SetAsyncExc() now declares PyThreadState *tstate in the function opening group and uses for (tstate = ...; ...); its loop body declares PyObject *old_exc before the skip check and assigns it at the original point before the async exception replacement, preserving head-lock traversal, skip behavior, unlock-before-decref, signal, and return paths.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 32/32 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the frame access and async-exception declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior PyThreadState_GetFrame() blockers at line 2457 (_PyInterpreterFrame *f = tstate->cframe->current_frame;) and line 2464 (PyFrameObject *frame = _PyFrame_GetFrameObject(f);), plus PyThreadState_SetAsyncExc()'s C99 for (PyThreadState *tstate = ...) initializer and post-if PyObject *old_exc loop-body declaration. New exact first blocker is line 2576 (error C2275: 'PyObject' : illegal use of this type as an expression) at PyObject *result = PyDict_New(); in _PyThread_CurrentFrames(), followed by line 2582 (int gc_was_enabled = PyGC_Disable();) and later declaration-order fallout.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c thread-state deletion helpers C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists the thread-state deletion helper locals needed by VC6/C89: tstate_delete_common() now declares PyInterpreterState *interp, _PyRuntimeState *runtime, and _PyStackChunk *chunk in the opening declaration group while assigning them at their original post-ensure/post-TSS points; _PyThreadState_DeleteCurrent() declares struct _gilstate_runtime_state *gilstate before _Py_EnsureTstateNotNULL() and assigns it immediately after; _PyThreadState_DeleteExcept() declares PyThreadState *list, p, and next before HEAD_LOCK(runtime) while preserving the locked list capture/unlinking and post-unlock clear/free loop. The stack-chunk loop's block-local prev remains at the start of its while block.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 32/32 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the thread-state deletion helper declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior tstate_delete_common() blockers at line 2245 (PyInterpreterState *interp = tstate->interp;), line 2249 (_PyRuntimeState *runtime = interp->runtime;), and line 2268 (_PyStackChunk *chunk = tstate->datastack_chunk;), plus _PyThreadState_DeleteCurrent()'s post-ensure gilstate declaration and _PyThreadState_DeleteExcept()'s post-lock list declaration. New exact first blocker is line 2457 (error C2143: syntax error : missing ';' before 'type') at _PyInterpreterFrame *f = tstate->cframe->current_frame; in PyThreadState_GetFrame(), followed by line 2464 (PyFrameObject *frame = _PyFrame_GetFrameObject(f);) and later declaration-order fallout.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c new_threadstate C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists new_threadstate()'s PyThreadState *new_tstate, uint64_t id, and PyThreadState *old_head declarations into the function's opening declaration group. new_tstate = alloc_threadstate() remains before the lock, id = interp->threads.next_unique_id remains after the locked increment, and old_head = interp->threads.head remains immediately before the old_head == NULL branch, preserving allocation-before-lock, used_newtstate behavior, initialization branches, and lock/unlock order.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 32/32 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the new_threadstate() declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior new_threadstate() blockers at line 1970 (uint64_t id = interp->threads.next_unique_id;) and line 1973 (PyThreadState *old_head = interp->threads.head;). New exact first blocker is line 2080 (error C2275: 'PyInterpreterState' : illegal use of this type as an expression) at PyInterpreterState *interp = tstate->interp; in _PyState_AddModule(), followed by declaration-order fallout for interp and later locals.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c _PyInterpreterState_IDDecref C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists _PyInterpreterState_IDDecref()'s struct _gilstate_runtime_state *gilstate, int64_t refcount, PyThreadState *tstate, and PyThreadState *save_tstate declarations to the function's opening declaration group. gilstate = &_PyRuntime.gilstate remains immediately after the id_mutex assert; refcount = interp->id_refcount remains after the decrement while the mutex is still held; tstate and save_tstate assignments remain inside the refcount == 0 && interp->requires_idref block, preserving lock acquisition/release plus _PyThreadState_Swap()/Py_EndInterpreter() ordering.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the _PyInterpreterState_IDDecref() declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior _PyInterpreterState_IDDecref() blockers at line 1812 (struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate;), line 1816 (int64_t refcount = interp->id_refcount;), and the block-local tstate/save_tstate declarations. New exact first blocker is line 1876 (error C2143: syntax error : missing ';' before 'type') at _PyStackChunk *res = _PyObject_VirtualAlloc(size_in_bytes); in allocate_chunk(), followed by declaration-order fallout for res.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c PyInterpreterState_Get C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists PyInterpreterState_Get()'s PyInterpreterState *interp declaration beside the existing PyThreadState *tstate local. tstate = _PyThreadState_GET() remains immediately before _Py_EnsureTstateNotNULL(tstate), and interp = tstate->interp remains at the original post-ensure point, preserving the fatal-error check and return behavior.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the PyInterpreterState_Get() declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior PyInterpreterState_Get() blocker at line 1719 (PyInterpreterState *interp = tstate->interp;). New exact first blocker is line 1812 (error C2143: syntax error : missing ';' before 'type') at struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate; in _PyInterpreterState_IDDecref(), followed by line 1816 int64_t refcount = interp->id_refcount; and later declaration-order fallout.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c PyInterpreterState_Delete C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists PyInterpreterState_Delete()'s PyInterpreterState **p declaration beside the existing runtime and interpreters locals. The for (p = &interpreters->head; ...) initializer remains under HEAD_LOCK(runtime), preserving the unlink search, remaining-thread checks, main-interpreter checks, assignment to *p, and lock/unlock ordering.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the PyInterpreterState_Delete() declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior PyInterpreterState_Delete() blocker at line 1638 (PyInterpreterState **p;). New exact first blocker is line 1719 (error C2275: 'PyInterpreterState' : illegal use of this type as an expression) at PyInterpreterState *interp = tstate->interp; in PyInterpreterState_Get(), followed by declaration-order fallout in the same and later functions.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c interpreter_clear C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists interpreter_clear()'s PyThreadState *p declaration beside the existing _PyRuntimeState *runtime local. The p = interp->threads.head; assignment remains at the same point under HEAD_LOCK(runtime), preserving the lock/unlock ordering and the thread-clear loop behavior.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the interpreter_clear() declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior interpreter_clear() blocker at line 1537 (PyThreadState *p = interp->threads.head;). New exact first blocker is line 1638 (error C2275: 'PyInterpreterState' : illegal use of this type as an expression) at PyInterpreterState **p; in PyInterpreterState_Delete(), followed by declaration-order fallout in the same and later functions.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c PyInterpreterState_New C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists PyInterpreterState_New()'s PyThreadState *tstate, PyThread_type_lock pending_lock, _PyRuntimeState *runtime, struct pyinterpreters *interpreters, int64_t id, and PyInterpreterState *old_head declarations into the function's opening declaration group. tstate = _PyThreadState_GET() remains immediately before the audit, and the pending_lock, runtime, interpreters, id, and old_head assignments stay at the original execution points after the audit, after lock allocation succeeds, after HEAD_LOCK(runtime), and before the old_head == NULL test respectively.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the PyInterpreterState_New() declaration-hoist slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior PyInterpreterState_New() blockers at line 1438 (PyThread_type_lock pending_lock = PyThread_allocate_lock();) and its runtime, interpreters, id, and old_head declaration-order fallout. New exact first blocker is line 1537 (error C2275: 'PyThreadState' : illegal use of this type as an expression) at PyThreadState *p = interp->threads.head; in interpreter_clear(), followed by later declaration-order fallout in the same translation unit.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pystate.c alloc_for_runtime lock C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pystate.c — hoists alloc_for_runtime()'s PyThread_type_lock lock1, lock2, and lock3 declarations beside PyMemAllocatorEx old_alloc. The three PyThread_allocate_lock() calls remain at their original execution points as assignments; the existing NULL checks, lock1/lock2 cleanup order, allocator restoration, output assignments, and return paths are unchanged.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the pystate.c lock declaration slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior alloc_for_runtime() blockers at lines 1185/1190/1196 (PyThread_type_lock lock1/lock2/lock3 = PyThread_allocate_lock();). New exact first blocker is line 1438 (error C2275: 'PyThread_type_lock' : illegal use of this type as an expression) at PyThread_type_lock pending_lock = PyThread_allocate_lock(); in PyInterpreterState_New(), followed by that function's runtime, interpreters, id, and old_head declaration-order fallout.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pycore_frame.h frame inline C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Include/internal/pycore_frame.h — hoists the first VC6/C89 mixed-declaration blockers exposed while compiling Python/pystate.c: _PyFrame_GetFrameObject() now declares PyFrameObject *res before the assert() and assigns frame->frame_obj at the original point; _PyThreadState_BumpFramePointer() keeps _PyInterpreterFrame *res scoped inside the stack-space if block but declares it before the assignment; _PyFrame_GetGenerator() declares size_t offset_in_gen before the assert() and assigns offsetof(PyGenObject, gi_iframe) at the original point.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary v3.11.16 cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — still compiles cleanly after the header slice
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — gets past the prior pycore_frame.h blockers at _PyFrame_GetFrameObject(), _PyThreadState_BumpFramePointer(), and _PyFrame_GetGenerator(). New exact first blocker is line 1185 (error C2275: 'PyThread_type_lock' : illegal use of this type as an expression) at PyThread_type_lock lock1 = PyThread_allocate_lock(); in threadstate_update_waiting_for_thread_shutdown(), followed by the same function's lock2 and lock3 declaration-order fallout.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c call_ll_exitfuncs C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists call_ll_exitfuncs()'s void (*exitfunc)(void) declaration before the loop and assigns it at the original post-decrement point, preserving the decrement, slot clearing, LIFO invocation order, and final stdout/stderr flushes.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 0 — gets past the prior line 3045 void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs]; blocker in call_ll_exitfuncs(); no next pylifecycle.c blocker was found because the translation unit now compiles cleanly in the VC6 core compile probe.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c fatal_error/_Py_FatalErrorFormat C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists fatal_error() locals (runtime, tstate, interp, tss_tstate, and has_tstate_and_gil) into the function declaration area while preserving the original assignment/evaluation points, including runtime = &_PyRuntime, interp = NULL, tss_tstate = PyGILState_GetThisThreadState(), and the has_tstate_and_gil boolean assignment. _Py_FatalErrorFormat() now declares stream, fd, and vargs before its reentrancy check, then assigns stream = stderr and fd = fileno(stream) at the original post-reentrancy point before output begins.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 2866 _PyRuntimeState *runtime = &_PyRuntime; blocker in fatal_error() plus the immediately adjacent tstate/interp/tss_tstate/has_tstate_and_gil declaration-order fallout and _Py_FatalErrorFormat()'s FILE *stream, fd, and va_list vargs mixed declarations. New exact first blocker is line 3045 (error C2143: syntax error : missing ';' before 'type') at void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs]; in call_ll_exitfuncs().
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c fatal-error dump C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists fatal_error_dump_runtime()'s PyThreadState *finalizing to the function declaration area and assigns it at the original point after the PUTS() call. _Py_DumpExtensionModules() now declares its function-scope locals (modules, pos, key, value, stdlib_module_names, header, and count) before the interp == NULL early return; the modules, stdlib_module_names, header, and count initializers are preserved as assignments at their original execution points. The inner is_stdlib_ext, i, item, and hash block declarations are unchanged.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ tree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 2698 PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); blocker in fatal_error_dump_runtime() and the adjacent _Py_DumpExtensionModules() function-scope declaration-order blockers. New exact first blocker is line 2866 (error C2275: '_PyRuntimeState' : illegal use of this type as an expression) at _PyRuntimeState *runtime = &_PyRuntime; in fatal_error(), followed by additional fatal_error() declaration-order fallout.
git apply --check compat/msvc600/cpython-3.11.16-vc6-headers.patch against pristine v3.11.16 tree exit 0

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c is_valid_fd platform-branch C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists is_valid_fd()'s platform-branch locals into the function declaration area under the same preprocessor ladder: int fd2 for the Linux dup() branch, HANDLE hfile for MS_WINDOWS, and struct stat st for the fallback branch. The existing fd < 0 early return, platform conditions, and branch behavior are unchanged; the original declaration sites now only assign/use (fd2 = dup(fd), _get_osfhandle(), and fstat(fd, &st)).
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 2296 HANDLE hfile; blocker in is_valid_fd(). New exact first blocker is line 2403 (error C2275: 'PyObject' : illegal use of this type as an expression) at PyObject *encoding_str = PyUnicode_FromWideChar(encoding, -1); in create_stdio(), followed by line 2409 PyObject *errors_str = PyUnicode_FromWideChar(errors, -1); and later declaration-order blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c add_main_module shadowed-loader C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists PyObject *bimod and a distinct PyObject *loader_obj into add_main_module()'s existing declaration group. The builtins import and BuiltinImporter lookup remain at their original execution points; the outer borrowed loader variable and its NULL/Py_None test are unchanged, while loader_obj carries only the formerly shadowed strong reference through its NULL check, __loader__ dict set, and decref.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 2212 PyObject *bimod = PyImport_ImportModule("builtins"); blocker and the same function's formerly shadowed line 2233 PyObject *loader = PyObject_GetAttrString(...) declaration-order blocker in add_main_module(). New exact first blocker is line 2296 (error C2275: 'HANDLE' : illegal use of this type as an expression) at HANDLE hfile; in is_valid_fd(), followed by later declaration-order blockers in create_stdio() and finalization diagnostics.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c finalize_modules C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists int verbose and PyObject *weaklist to the top declaration group in finalize_modules(). verbose is assigned after the existing modules == NULL early return, and weaklist is assigned at the original finalize_remove_modules(modules, verbose) call site, preserving early-return behavior and call order.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 1606 int verbose = _PyInterpreterState_GetConfig(interp)->verbose; blocker and line 1624 PyObject *weaklist = finalize_remove_modules(modules, verbose); in finalize_modules(). New exact first blocker is line 1838 (error C2275: 'PyThreadState' : illegal use of this type as an expression) at PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); in Py_FinalizeEx(), followed by line 1868 int malloc_stats = tstate->interp->config.malloc_stats; and later finalization declaration-order blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c finalize_modules_clear_weaklist C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists Py_ssize_t i plus PyObject *tup, name, mod, and dict to the top declaration group in finalize_modules_clear_weaklist(). The reverse loop now assigns i = PyList_GET_SIZE(weaklist) - 1 at the original loop point, and each former loop-local declaration is now an assignment at the same position, preserving evaluation order and the two existing continue paths.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 1551 for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) blocker and the same loop's PyObject *tup, name, mod, and dict mixed declarations. New exact first blocker is line 1606 (error C2143: syntax error : missing ';' before 'type') at int verbose = _PyInterpreterState_GetConfig(interp)->verbose; in finalize_modules(), followed by line 1624 PyObject *weaklist = finalize_remove_modules(modules, verbose); and later finalization declaration-order blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c finalize_modules_delete_special C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists const char * const *p and PyObject *value to the top declaration group in finalize_modules_delete_special(). The first loop now assigns p = sys_deletes at the original declaration point, and the second loop assigns value = _PyDict_GetItemStringWithError(...) where the mixed declaration used to be. name and orig_name remain loop-local, preserving their evaluation/order.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 1411 const char * const *p; blocker and the line 1426 PyObject *value blocker in finalize_modules_delete_special(). New exact first blocker is line 1551 (error C2143: syntax error : missing ';' before 'type') at for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) in finalize_modules_clear_weaklist(), followed by PyObject *tup, PyObject *name, PyObject *mod, and PyObject *dict mixed declarations in the same loop/function plus later finalization blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c pyinit_main/public initialization API C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists declaration-order blockers in pyinit_main(), Py_InitializeFromConfig(), Py_InitializeEx(), and _Py_InitializeMain(). Locals are declared at function top, while assignments/calls (tstate->interp, _PyRuntime_Initialize(), &_PyRuntime, tstate = NULL, _PyConfig_InitCompatConfig(), and _PyRuntimeState_GetThreadState(runtime)) remain at their original execution points to preserve behavior.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 1285 PyStatus status = init_interp_main(tstate); blocker in pyinit_main() and the declaration-order fallout in Py_InitializeFromConfig(), Py_InitializeEx(), and _Py_InitializeMain(). New exact first blocker is line 1411 (error C2143: syntax error : missing ';' before 'const') at const char * const *p; in finalize_modules_delete_special(), followed by PyObject *value in the same function and later finalization mixed-declaration blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c pyinit_core/init_interp_main C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists PyConfig config to the top of pyinit_core() while leaving PyConfig_InitPythonConfig(&config) at its original execution point. init_interp_main() now declares PyStatus status, then initialized is_main_interp, interp, and config at function top before the existing assert, preserving the declaration initializer order requested for this narrow VC6 declaration-order slice.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 1104 PyConfig config; blocker in pyinit_core() and the immediately exposed init_interp_main() mixed declarations. New exact first blocker is line 1285 (error C2275: 'PyStatus' : illegal use of this type as an expression) at the mixed declaration PyStatus status = init_interp_main(tstate); in pyinit_main(), followed by additional declaration-order fallout in Py_InitializeFromConfig() and later functions.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c pre-initialization C89/C99 slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — removes the two pre-initialization _PyArgv designated initializers in Py_PreInitializeFromBytesArgs() and Py_PreInitializeFromArgs() by declaring args first and assigning use_bytes_argv, argc, and the active argv pointer field explicitly before the existing _Py_PreInitializeFromPyArgv() call. _Py_PreInitializeFromConfig() now declares PyStatus status, _PyRuntimeState *runtime, PyPreConfig preconfig, and _PyArgv config_args at function top, assigns status/runtime at their original execution points, and replaces the args == NULL branch's designated config_args initializer with field-by-field assignments immediately before the existing call. Evaluation and call order are unchanged.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 1008 and 1016 _PyArgv args = { .use_bytes_argv = ... } designated initializers, plus the mixed declarations and designated config_args initializer inside _Py_PreInitializeFromConfig(). New exact first blocker is line 1104 (error C2275: 'PyConfig' : illegal use of this type as an expression) at the mixed declaration PyConfig config; in pyinit_core(), followed by nearby pyinit_main() declaration-order blockers and later C89/C99 fallout.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c builtins C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists the remaining VC6-rejected PyObject * declarations in pycore_init_builtins() (bimod, builtins_dict, isinstance, len, list_append, and import_func) to the function top, then assigns each at its original execution site. Evaluation order and existing error paths are unchanged; each local is still assigned before use.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past all mixed declarations in pycore_init_builtins(). New exact first blocker is line 912 (error C2143: syntax error : missing ';' before 'const') at the mixed declaration const PyConfig *config = _PyInterpreterState_GetConfig(interp); in pycore_interp_init(), followed by the undeclared config fallout and later C89/C99 blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c create-interpreter C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists only the two next VC6-rejected declarations in pycore_create_interpreter(): PyInterpreterState *interp and PyThreadState *tstate are now declared at function top, while _PyGILState_Init(runtime), PyInterpreterState_New(), and PyThreadState_New(interp) still execute at their original call sites and in the same order.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 682 pycore_create_interpreter() PyInterpreterState *interp mixed declaration and line 693 PyThreadState *tstate mixed declaration. New exact first blocker is line 812 (error C2275: 'PyObject' : illegal use of this type as an expression) at the mixed declaration PyObject *builtins_dict = PyEval_GetBuiltins(); in pycore_init_builtins(), followed by the same function's line 819 PyObject *isinstance = PyDict_GetItem(...) and additional C89 mixed-declaration blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (pylifecycle.c interpreter-config C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists only the interpreter-configuration PyStatus locals that VC6 rejected as mixed declarations: interpreter_update_config() now declares one PyStatus status at function top and assigns it at the two original call sites, and _PyInterpreterState_SetConfig() declares PyConfig config / PyStatus status before calling PyConfig_InitPythonConfig(). Assignment/evaluation order is unchanged and the former inner status shadowing is removed.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 528 _PyInterpreterState_SetConfig() mixed-declaration blocker and the nearby line 505 interpreter_update_config() PyStatus shadow declaration. New exact first blocker is line 580 (error C2275: 'PyInterpreterState' : illegal use of this type as an expression) at the mixed declaration PyInterpreterState *interp = tstate->interp; in pyinit_core_reconfigure(), followed by additional C89 mixed-declaration blockers including line 614 PyStatus status = _PyConfig_Write(config, runtime); in pycore_init_runtime().

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (_PyStatus_OK() recursion fix and _PyStatus_ERR() VC6 helper slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Include/internal/pycore_initconfig.h — replaces the VC6-only _PyStatus_OK() mapping to PyStatus_Ok() with a local static C89 helper that assigns all PyStatus fields explicitly, avoiding the PyStatus_Ok() -> _PyStatus_OK() -> PyStatus_Ok() recursion. Adds a VC6-only _PyStatus_ERR() helper that assigns _type = _PyStatus_TYPE_ERROR, func = NULL (matching public PyStatus_Error() semantics because VC6 has neither __func__ nor __FUNCTION__), err_msg, and exitcode = 0. Non-VC6 compound-literal macros are unchanged.
  • scripts/fixtures/vc6_compound_literal_smoke.c — now exercises both _PyStatus_OK() and _PyStatus_ERR() through the real internal header.
  • scripts/vc6-probe-core.test.sh — adds a focused regression check that _PyStatus_OK() no longer maps to PyStatus_Ok(), and updates the compound-literal smoke-test description.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_compound_literal_smoke.c exit 0 — focused smoke fixture compiles while calling both _PyStatus_OK() and _PyStatus_ERR() directly under VC6.
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 28/28 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 259 _PyStatus_ERR("external importer setup failed") compound-literal blocker. New exact first blocker is line 528 (error C2275: 'PyStatus' : illegal use of this type as an expression) at the mixed declaration PyStatus status = _PyConfig_Copy(&config, src_config); in _PyInterpreterState_SetConfig(), followed by additional C89 mixed-declaration blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (init_importlib() C89 declaration-hoist slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — hoists only the existing init_importlib() local declarations (interp, verbose, importlib, imp_mod, value) to the top of the function, then preserves the prior assignment/evaluation order after the existing assertion and at each original use site.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ worktree exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 27/27 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 202 init_importlib() mixed-declaration blocker. New exact first blocker is line 259 (error C2059: syntax error : '{') at _PyStatus_ERR("external importer setup failed") in init_importlib_external(), followed by further PyStatus compound-literal/designated-initializer and C89 mixed-declaration blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (_PyStatus_OK() VC6 macro fallback slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Include/internal/pycore_initconfig.h — keeps the existing C99 compound-literal _PyStatus_OK() macro for non-VC6 compilers, but maps _PyStatus_OK() to the existing public PyStatus_Ok() API only for _MSC_VER < 1300 so VC6 no longer has to parse (PyStatus){._type = ...} at _PyRuntime_Initialize().
  • scripts/fixtures/vc6_compound_literal_smoke.c — now exercises _PyStatus_OK() itself, verifying the VC6-only macro fallback rather than bypassing it by calling PyStatus_Ok() directly.
  • scripts/vc6-probe-core.test.sh — updates the focused compound-literal smoke-test description for the shared macro fallback.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits. Reproducibility check: git apply --check against a pristine temporary cpython/ copy exited 0.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_compound_literal_smoke.c exit 0 — focused smoke fixture now compiles while calling _PyStatus_OK() directly under VC6.
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 27/27 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior line 143 _PyStatus_OK() compound-literal blocker. New exact first blocker is line 202 (error C2143: syntax error : missing ';' before 'type'), the existing C89 mixed-declaration wall in init_importlib(), followed by further declaration-order and remaining non-OK compound-literal/designated-initializer blockers.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in previous revision (_PyRuntimeState_INIT VC6 replacement slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Include/internal/pycore_runtime_init.h — keeps the existing C99 designated initializer path for non-VC6 compilers, but exposes _PyRuntimeState_InitStaticDefaults() for VC6 instead of making VC6 parse _PyRuntimeState_INIT.
  • cpython/Python/pylifecycle.c — leaves _PyRuntime zero-initialized only for VC6, then calls the shared explicit defaults routine once before _PyRuntimeState_Init(). Non-VC6 still uses = _PyRuntimeState_INIT.
  • cpython/Python/pystate.c — adds the VC6 field-by-field default routine used by both the process-global runtime and later runtime/interpreter/thread resets. It explicitly preserves the required defaults: gilstate.check_enabled = 1, zeroed Py_tss_NEEDS_INIT storage, interpreters.next_id = -1, global small ints/bytes/strings/empty tuple, _main_interpreter (_static, id_refcount, recursion/gc thresholds), and _initial_thread (_static, recursion limit, context_ver = 1). Non-VC6 still uses the upstream static const initial = _PyRuntimeState_INIT/memcpy path.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated from git -C cpython diff; includes this slice plus earlier uncommitted compatibility edits.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 27/27 checks ok; Modules/main.c still compiles cleanly
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — the _PyRuntime definition no longer fails at _PyRuntimeState_INIT line 112. New first error is line 143 (_PyStatus_OK() compound literal), followed by existing C89 declaration-order and C99 initializer blockers in the rest of the file.
bash scripts/vc6-probe-core.sh cpython/Python/pystate.c exit 2 — the former static const _PyRuntimeState initial = _PyRuntimeState_INIT C2059 errors are gone and later initial._main_interpreter reset users are covered by the same VC6 defaults helpers. Current first errors are pre-existing C89 declaration-order issues in pycore_frame.h and then in pystate.c; no remaining _PyRuntimeState_INIT parse error is reported before the 100-error cap.

Caveat: this is still compile-probe work only. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Files changed in this revision (pylifecycle.c VC6 PyRuntime section slice)

All still uncommitted; nothing in this list has been pushed anywhere.

  • cpython/Python/pylifecycle.c — narrow VC6-only compatibility edit for the first Python/pylifecycle.c blocker: keep the modern Windows #pragma section("PyRuntime", read, write) + __declspec(allocate("PyRuntime")) path unchanged for non-VC6 compilers, but use VC6's supported #pragma data_seg("PyRuntime") / #pragma data_seg() spelling around the initialized _PyRuntime object when _MSC_VER < 1300. The _PyRuntimeState_INIT initializer remains exactly at the definition site.
  • compat/msvc600/cpython-3.11.16-vc6-headers.patch — regenerated in full from git -C cpython diff; now 767 lines and includes the Python/pylifecycle.c hunk alongside previous uncommitted compatibility edits.
  • PORT_STATUS.md — this revision.

Command results (all reproduced in this revision):

Command Result
bash scripts/vc6-probe.test.sh exit 0, ALL TESTS PASSED — 6/6 checks ok
bash scripts/vc6-probe-core.test.sh exit 0, ALL TESTS PASSED — 27/27 checks ok; includes Modules/main.c compile-only clean check
bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c exit 2 — gets past the prior VC6-incompatible PyRuntime section pragma/declaration pair; no unknown pragma warning and no C2341 segment error remain. New first blocker is cpython\Python\pylifecycle.c(112) : error C2059: syntax error : '.' in _PyRuntimeState_INIT, followed by more C99 compound-literal/designated-initializer and C89 mixed-declaration errors; the run later hits fatal error C1003 at line 1232.

Caveat: all probe results here are compile-only (/c) results. No link, no pythoncore/python.exe build, no Wine launch, and no Windows 98 runtime execution was attempted or claimed.

Verified

  • CPython source checkout is at the requested v3.11.16 baseline.

  • The MSVC600 tool bundle is present locally and its VC98/bin/VCVARS32.BAT environment script runs under Wine.

  • MSVC6 reports:

    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
    
  • A direct compile probe reaches CPython 3.11 headers. The first unmodified probe fails before linking, proving the compiler is being invoked against the intended baseline.

  • Project-local compatibility headers have been added under compat/msvc600/: inttypes.h (first isolated shim) and, as of this revision, stdbool.h (see "stdbool slice" below). Neither is declared sufficient for the port on its own.

  • scripts/vc6-probe.sh was fixed and is now truthful. The script piped cl.exe output through grep/sed to drop Wine's :err: debug noise and to shorten absolute host paths to repo-relative ones. The path-shortening step was silently broken: it built a sed pattern directly from a Windows-style path (e.g. Z:\home\ubuntu\...\), and both sed BRE and bash glob patterns treat a bare \ in a pattern as an escape character, so \h, \u, \p, etc. were consumed as (mostly no-op) escapes instead of literal characters and the substitution never matched anything — diagnostics always showed full absolute Wine paths instead of the intended repo-relative ones. Fixed by matching the prefix as a literal string via a quoted bash ${line//"$prefix"/} expansion (quoting forces literal, not glob, matching) instead of an unescaped regex. The pipeline's exit-status capture via PIPESTATUS[0] was already correct (verified with a deliberately broken translation unit: cl.exe's real nonzero exit code propagated correctly both before and after this fix); it is now covered by a regression test so it cannot regress silently. A new regression test, scripts/vc6-probe.test.sh, exercises both the path-stripping helper directly and — when wine + MSVC600 are available, as they are in this environment — the real script against a deliberately invalid .c file, asserting a nonzero exit code, a surfaced error C diagnostic, and no leaked absolute Wine path. Run: bash scripts/vc6-probe.test.sh. Last run: all 6 checks ok.

  • **Include/internal/pycore_atomic.h's VC6/intrin.h blocker is now resolved for 32-bit x86 (_M_IX86) and verified; see "Atomics slice" below for full detail and honesty notes on what is and is not covered.

  • **Include/internal/pycore_interp.h's VC6/<stdbool.h> blocker is now resolved and verified; see "stdbool slice" below for full detail.

  • **The VC6 C89-vs-C99 mixed-declarations blocker in four Include/internal/pycore_*.h headers (pycore_code.h, pycore_dict.h, pycore_list.h, pycore_call.h) reachable from Modules/main.c is now resolved and verified; see "Mixed-declarations header slice" below for full detail.

  • The same C89-vs-C99 mixed-declarations pattern, pervasive within Modules/main.c's own body (29 error sites across roughly a dozen functions), is now also resolved and verified; see "Modules/main.c declaration-order slice" below for full detail. With that fix applied, Modules/main.c hits a new, unrelated, and out-of-scope-for-that-slice blocker: several C99 compound-literal/designated-initializer macros (_PyStatus_OK(), _PyCompilerFlags_INIT, and the _PyArgv-style struct literals in Py_Main()/Py_BytesMain()) that VC6 does not support at all, independent of declaration position.

  • That compound-literal/designated-initializer blocker is now also resolved and verified for all 8 sites in Modules/main.c; see "Compound-literal / designated-initializer slice" below for full detail. With that fix applied, cpython/Modules/main.c compiles with cl.exe exit status 0 under scripts/vc6-probe-core.sh — no errors, no warnings. This is a compile-only (/c) result for one translation unit; it is not a link, not a pythoncore/python.exe build, and not a runtime claim (vc6-probe-core.sh never attempts to link). Probing the next core translation unit in Modules/main.c's own call chain, Python/pylifecycle.c, hits the same two already-solved blocker classes again (recurring, not novel) plus enough additional errors to exceed the compiler's 100-error cap before the whole file is even seen; see "Next blocker: Python/pylifecycle.c" below. No link or runtime success is claimed anywhere in this document.

pycore_object.h VC6 __func__ / GC helper declaration-order slice

Scope: one internal header only, as requested. The real Python/pylifecycle.c core probe previously stopped first in Include/internal/pycore_object.h: VC6 reported __func__ undeclared at the _PyObject_ASSERT_FROM(..., __func__) calls in _PyObject_GC_TRACK(), then cascaded into C89 mixed-declaration errors for the local PyGC_Head * and PyInterpreterState * declarations in _PyObject_GC_TRACK() and _PyObject_GC_UNTRACK().

The header now has a VC6-only fallback:

#if defined(_MSC_VER) && _MSC_VER < 1300 && !defined(__func__)
#  define __func__ "<unknown>"
#endif

A quick VC6 smoke probe showed __FUNCTION__ is also unavailable in VC6, so there was no exact function-name extension to preserve. This mapping only degrades debug/fatal diagnostic function-name text on VC6; C99 compilers and newer MSVC keep their normal behavior. The only declaration-order edits are the mechanical C89 transform in _PyObject_GC_TRACK() and _PyObject_GC_UNTRACK(): declarations at block start, assignments left at the original evaluation points.

Verification: bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c now gets past pycore_object.h; the new first blocker is the Windows section-allocation pragma pair in Python/pylifecycle.c (see "Next blocker" below).

Atomics slice (pycore_atomic.h, VC6 / _M_IX86)

Scope: 32-bit x86 only, matching this port's only target (Windows 9x has no x64 edition). Include/internal/pycore_atomic.h previously included <intrin.h> and used _Interlocked* compiler intrinsics unconditionally for any _MSC_VER-defined compiler; VC6 (_MSC_VER 1200) has neither. The now-applied, still-uncommitted compat/msvc600/cpython-3.11.16-vc6-headers.patch adds two things to this header, both gated strictly to defined(_MSC_VER) && _MSC_VER < 1300 && defined(_M_IX86) (a new _Py_ATOMIC_VC6_X86 macro) so every other compiler/version — including modern MSVC on _M_X64/ARM and the GCC/clang/C11 paths — keeps its exact prior behavior, byte-for-byte (verified: git diff on the non-VC6 branches shows only their line numbers moving under the new #elif, no content changes):

  1. The top-of-file <intrin.h>/<immintrin.h> include is skipped for VC6/_M_IX86; <windows.h> is included instead, to declare InterlockedExchange/InterlockedCompareExchange.
  2. A new #if defined(_Py_ATOMIC_VC6_X86) branch (ahead of the existing _M_IX86 || _M_X64 branch, now #elif) implements _Py_atomic_store_explicit/_Py_atomic_load_explicit for _Py_atomic_int/_Py_atomic_address using the Win32 InterlockedExchange/InterlockedCompareExchange API — present in KERNEL32.DLL since Windows 98 (confirmed against this project's actual MSVC600 VC98 SDK headers, MSVC600/VC98/Include/WINBASE.H, which declare both for _M_IX86 outside the MRx000/Alpha-only intrinsic path). Both give a full memory barrier on x86, same as the intrinsics they replace, so — as the original comment already notes for the HLE-unavailable case — every _Py_memory_order maps to the same fully-fenced operation; VC6 has no HLE (_HLEAcquire/_HLERelease, VS2013+) intrinsics or hardware support to preserve here regardless.

64-bit atomics are explicitly NOT implemented, and this is not a gap in practice for this port. _Py_atomic_address (uintptr_t) and _Py_atomic_int (int) are both 4 bytes on 32-bit x86, so the existing sizeof(...) == 8 branches that select the 64-bit store/load paths in the pre-existing _M_IX86 || _M_X64 code are already unreachable dead code on _M_IX86 upstream, before this patch — VC6 never defines _M_X64. The VC6 branch added here therefore has no 64-bit path to implement, and a #error guards the (unreachable-under-VC6) case where _M_X64 were ever also defined, so a future misconfiguration fails loudly at compile time instead of silently truncating a 64-bit atomic. No CMPXCHG8B inline assembly was written, and none is required for this header; if some other part of the port needs genuine 64-bit interlocked ops on VC6 later, that is a separate, not-yet-encountered problem, not something papered over here.

Verified with two independent probes, both under scripts/vc6-probe-core.sh (new; extends scripts/vc6-probe.sh's approach to Py_BUILD_CORE translation units — /D Py_BUILD_CORE plus Include/internal on the include path):

  • scripts/fixtures/vc6_atomic_smoke.c (new) — a minimal, isolated translation unit that includes only pycore_atomic.h (via <inttypes.h> for uintptr_t, which real callers get from Python.h/pyport.h) and exercises _Py_atomic_store/_Py_atomic_load and their _relaxed variants on both _Py_atomic_int and _Py_atomic_address:

    $ bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_atomic_smoke.c
    == MSVC600 Py_BUILD_CORE compile probe ==
    source : scripts/fixtures/vc6_atomic_smoke.c
    ...
    vc6_atomic_smoke.c
    
    == cl.exe exit status: 0 ==
    

    No errors, no warnings.

  • cpython/Modules/main.c, the same real core translation unit identified as the next blocker previously. It now compiles past pycore_atomic.h (reached transitively via pycore_runtime.h before pycore_interp.h) and hits a new, different, and unrelated blocker:

    $ bash scripts/vc6-probe-core.sh
    == MSVC600 Py_BUILD_CORE compile probe ==
    source : cpython/Modules/main.c
    ...
    cpython\Include\internal\pycore_interp.h(11) : fatal error C1083:
    Cannot open include file: 'stdbool.h': No such file or directory
    
    == cl.exe exit status: 2 ==
    

    Include/internal/pycore_interp.h line 11 does #include <stdbool.h> before its own #include "pycore_atomic.h" on line 13 — a C99 standard header VC6 does not ship, unrelated to atomics. This is the next blocker for this port and is left unaddressed here, out of scope for this slice.

Both probes are covered by a new regression test, scripts/vc6-probe-core.test.sh, which additionally asserts (so this result cannot regress silently) that a deliberately broken translation unit still fails with a surfaced error C diagnostic, and that Modules/main.c's current failure is specifically not at pycore_atomic.h/intrin.h (i.e. that blocker has not resurfaced). Run: bash scripts/vc6-probe-core.test.sh. At the time this atomics slice was written, this was all 6 checks ok; the stdbool slice below added 5 more checks to the same file (now 11; see that section for the current count and last-run result). scripts/vc6-probe.test.sh was re-run after the atomics change and still passed (all 6 checks ok), confirming the public-header probe was unaffected.

stdbool slice (pycore_interp.h, VC6 / C99 <stdbool.h>)

Include/internal/pycore_interp.h line 11 does #include <stdbool.h> before its own #include "pycore_atomic.h" on line 13 — a C99 standard header VC6 (_MSC_VER 1200, which predates C99 entirely) does not ship. In VC6's C mode, bool/true/false are not keywords at all (they are C++-only there), and there is no standard-library <stdbool.h> to fall back on.

The now-added, still-uncommitted compat/msvc600/stdbool.h is a project-local fallback for this single header, not a patch to CPython source. It is picked up purely through include-path ordering: both scripts/vc6-probe.sh and scripts/vc6-probe-core.sh already put compat/msvc600 first on the VC6 /I include path (needed earlier for compat/msvc600/inttypes.h), so VC6's #include <stdbool.h> resolves to this project-local header before it would ever reach a (nonexistent) system one. Nothing under cpython/ changes for this slice, so compat/msvc600/cpython-3.11.16-vc6-headers.patch is unchanged. Every other compiler is unaffected for the same reason a browser's /I search order doesn't affect other browsers: compat/msvc600 is never added to any other compiler's include path, so a conforming C99/C11 compiler still gets its own real <stdbool.h> (or built-in _Bool/bool), untouched. As defence in depth (not because it is expected to be reachable), the header itself also #errors out if included under anything but _MSC_VER < 1300.

The shim defines the same four names as the standard C99 header — bool (as int, since VC6 has no _Bool built-in type to alias), true, false, and __bool_true_false_are_defined — as plain #define macros rather than a typedef, matching the standard's requirement that a conforming program be able to #undef/redefine bool/true/false.

Verified with the same two-probe approach used for the atomics slice:

  • scripts/fixtures/vc6_stdbool_smoke.c (new) — a minimal, isolated translation unit that includes only <stdbool.h> and exercises bool/true/false/__bool_true_false_are_defined:

    $ bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_stdbool_smoke.c
    == MSVC600 Py_BUILD_CORE compile probe ==
    source : scripts/fixtures/vc6_stdbool_smoke.c
    ...
    vc6_stdbool_smoke.c
    
    == cl.exe exit status: 0 ==
    

    No errors, no warnings.

  • cpython/Modules/main.c, the same real core translation unit used to verify the atomics slice. It now compiles past pycore_interp.h line 11 (reached the same way as before, transitively via pycore_runtime.h) — the fatal stdbool.h/C1083 error is gone — and proceeds through pycore_atomic.h and pycore_ast_state.h before hitting a new, unrelated, and considerably larger blocker; see "Current first-blocker evidence" below for the full detail.

Both probes are covered by 5 new checks added to the existing scripts/vc6-probe-core.test.sh (positive isolated-fixture compile, no-errors check, a negative deliberately-broken-fixture check, its error-surfaced check, and a check that Modules/main.c's output no longer contains Cannot open include file: 'stdbool.h'), bringing that file to 11 checks total. Run: bash scripts/vc6-probe-core.test.sh. Last run: all 11 checks ok (wine + MSVC600 available in this environment). scripts/vc6-probe.test.sh was re-run after this change and still passes (all 6 checks ok), confirming the public-header probe is unaffected.

Mixed-declarations header slice (pycore_code.h, pycore_dict.h, pycore_list.h, pycore_call.h)

Scope: the four Include/internal/pycore_*.h headers that the Modules/main.c #include chain directly reaches with VC6 C89 mixed-declaration violations, and no others. This is a bounded slice of the "Compiler language gap" blocker recorded below, not an attempt at the whole gap: it fixes exactly the sites the real core probe (Modules/main.c via scripts/vc6-probe-core.sh) hits inside CPython's own headers, and stops there. Modules/main.c itself has the same pattern pervasively throughout its own function bodies; that is explicitly out of scope for this slice and is now the next recorded blocker (see "Current first-blocker evidence" below) rather than something papered over here.

Six static inline functions across the four headers declared a variable after a preceding statement (typically an assert(...)), which C89 (VC6's only supported dialect, give or take Microsoft extensions) does not allow inside a block — only C99 does. VC6's parser, on hitting the declaration where it expects a statement, fails to recognize it as a declaration at all and instead cascades into unrelated-looking C2065/C2109/C2106 errors for the rest of the block, exactly as described for the first instance (pycore_code.h:154) in earlier revisions of this document.

The now-applied, still-uncommitted compat/msvc600/cpython-3.11.16-vc6-headers.patch fixes each site the same way: hoist the declaration (no initializer) to the top of its enclosing block, and turn the original TYPE name = expr; into a plain assignment (name = expr;) at its original position. This changes no evaluation order and no semantics — it is the standard, mechanical C89 transform for this exact pattern — and is applied only to the six functions that actually needed it, not the surrounding file:

  • Include/internal/pycore_code.h: _PyLocals_GetKind(), _PyLocals_SetKind() (both hoist a char *ptr), and adaptive_counter_backoff() (hoists unsigned int value).
  • Include/internal/pycore_dict.h: _PyDictValues_AddToInsertionOrder() (hoists uint8_t *size_ptr and int size).
  • Include/internal/pycore_list.h: _PyList_AppendTakeRef() (hoists Py_ssize_t len and Py_ssize_t allocated).
  • Include/internal/pycore_call.h: _PyVectorcall_FunctionInline() (hoists PyTypeObject *tp, Py_ssize_t offset, and vectorcallfunc ptr).

Every other compiler is unaffected: these are plain C source edits (no #ifdef/_MSC_VER gating, unlike the atomics slice), and hoisting a declaration without an initializer, then assigning immediately after the same statements that used to compute the initializer, is behavior-identical under C89, C99, C11, and C++ alike — no code path, value, or evaluation order changes for any compiler already accepting the original source.

Verified with the same two-probe approach used for the atomics and stdbool slices:

  • scripts/fixtures/vc6_mixed_decls_smoke.c (new) — includes the real Python.h (these four headers assume public types like PyObject, PyCodeObject, PyListObject, PyDictValues, and vectorcallfunc already declared, the same way real CPython .c sources reach them, so full isolation without Python.h is not meaningful here unlike the atomics/stdbool fixtures) plus all four headers, and calls all six fixed functions:

    $ bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_mixed_decls_smoke.c
    == MSVC600 Py_BUILD_CORE compile probe ==
    source : scripts/fixtures/vc6_mixed_decls_smoke.c
    ...
    vc6_mixed_decls_smoke.c
    ...
    == cl.exe exit status: 0 ==
    

    No errors, no warnings.

  • cpython/Modules/main.c, the same real core translation unit used for the earlier slices. All four headers now compile clean — no pycore_code.h/pycore_dict.h/pycore_list.h/pycore_call.h error appears anywhere in the probe output — and the compiler proceeds entirely into Modules/main.c's own body, where a new, considerably larger, and out-of-scope-for-this-slice blocker is hit; see "Current first-blocker evidence" below.

Both probes are covered by 5 new checks added to scripts/vc6-probe-core.test.sh (positive isolated-fixture compile, no-errors check, a negative deliberately-broken-fixture check, its error-surfaced check, and a check that Modules/main.c's output no longer contains any pycore_code.h/pycore_dict.h/pycore_list.h/ pycore_call.h error line), bringing that file to 16 checks total. Run: bash scripts/vc6-probe-core.test.sh. Last run: all 16 checks ok (wine + MSVC600 available in this environment). scripts/vc6-probe.test.sh was re-run after this change and still passes (all 6 checks ok), confirming the public-header probe is unaffected. The patch's reproducibility was also re-verified directly: git apply --check --directory=cpython compat/msvc600/cpython-3.11.16-vc6-headers.patch against a freshly stashed (pristine v3.11.16) cpython/ working tree exits 0.

Modules/main.c declaration-order slice

Scope: the C89-vs-C99 mixed-declarations pattern inside Modules/main.c's own function bodies only — declaration position, not any other C99 feature. No other file was touched, and no whole-tree mechanical rewrite was attempted. This is the follow-on to the "Mixed-declarations header slice" above: the same pattern (a block-scope declaration appearing after a preceding statement, which C89's parser cannot recognize as a declaration), but recurring roughly a dozen times across Modules/main.c's own ~740 lines rather than in a handful of small header functions.

The now-applied, still-uncommitted compat/msvc600/cpython-3.11.16-vc6-headers.patch fixes every site the same mechanical way used for the header slice: hoist the bare declaration (no initializer) to the top of its enclosing block, and turn the original TYPE name = expr; into a plain assignment (name = expr;) at its original position. This changes no evaluation order and no semantics for any compiler, VC6 or otherwise. Two variants of this same transform were needed, both already implicit in the mechanical rule but worth calling out explicitly:

  • A declaration whose original initializer is a side-effecting call (e.g. FILE *fp = _Py_fopen_obj(filename, "rb"); in pymain_run_file_obj()) is hoisted bare and the call is kept as an assignment at its original position, specifically so the call still happens after the same preceding statements (an audit-hook check, in this case) instead of moving earlier and changing behavior.
  • A platform-conditional declaration with the same name but a different type per branch (pymain_run_startup()'s env: const wchar_t *env under #ifdef MS_WINDOWS, const char *env under #else) is hoisted under the identical #ifdef/#else/#endif structure at the top of the function, so each platform still only ever sees its own declaration.

Functions touched (8 total, 20 hoisted declarations, all in cpython/Modules/main.c): pymain_init() (preconfig, config), pymain_import_readline() (mod), pymain_run_command() (cf), pymain_run_file_obj() (fp, sb, cf, run), pymain_run_file() (filename, program_name, res), pymain_run_startup() (startup, env, fp, cf), pymain_run_stdin() (a nested-block exitcode, plus outer-scope cf, run), and pymain_repl() (cf, res). pymain_get_importer(), pymain_sys_path_add_path0(), pymain_run_module(), pymain_run_interactive_hook(), pymain_run_python(), Py_RunMain(), and pymain_main() were inspected and found to already declare every local before the first statement in their block (including two back-to-back declarations in pymain_run_python()'s else if (!config->safe_path) block, which is valid C89 since no statement separates them) — left untouched, consistent with "only the sites that actually need it."

A note on scope, since it matters for what this slice does and does not claim: several of the hoisted declarations are of type PyCompilerFlags or are assigned via _PyStatus_OK(), both of which are initialized through C99 compound-literal macros (_PyCompilerFlags_INIT, _PyStatus_OK()). Hoisting the declaration is still the correct, necessary C89 fix for the mixed-declaration violation at each of those sites — it eliminates that specific error class everywhere it appeared in main.c, as confirmed below — but the compound-literal initializer itself is a separate C99 feature VC6 does not support at any declaration position. That is a new, distinct blocker, not a residue of this slice's fix; see "Current first-blocker evidence" below, where it is documented rather than papered over.

Verified with the same two-probe approach used for the earlier slices:

  • scripts/fixtures/vc6_decl_order_smoke.c (new) — a minimal, self-contained fixture (no CPython headers) that exercises, in isolation, the shape of every hoist pattern used in main.c: a bare hoist above an early return, a side-effecting-initializer hoist, a hoisted pair where fixing the first declaration would otherwise turn an immediately-following second declaration into a new violation, a nested-block hoist, and the platform-conditional same-name/different-type hoist. Kept separate from main.c itself so it keeps guarding the general transformation shape even as main.c changes upstream:

    $ bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_decl_order_smoke.c
    == MSVC600 Py_BUILD_CORE compile probe ==
    source : scripts/fixtures/vc6_decl_order_smoke.c
    ...
    vc6_decl_order_smoke.c
    
    == cl.exe exit status: 0 ==
    

    No errors, no warnings.

  • cpython/Modules/main.c itself, the same real core translation unit used throughout this document. Every C2146/C2065/C2275 declaration-position error is gone; the previous 29-error-line run is now down to 8 error lines, all a different error code (C2059) at a different root cause (compound literals / designated initializers, not declaration position — see "Current first-blocker evidence" below for the full transcript).

Both probes are covered by 5 new checks added to scripts/vc6-probe-core.test.sh (positive isolated-fixture compile, no-errors check, a negative deliberately-broken-fixture check, its error-surfaced check, and a check that Modules/main.c's output no longer contains any declaration-position error — C2146, an "undeclared identifier" C2065, or a type-as-expression C2275 — anywhere in its own body), bringing that file to 21 checks total. Run: bash scripts/vc6-probe-core.test.sh. Last run: all 21 checks ok (wine + MSVC600 available in this environment). scripts/vc6-probe.test.sh was re-run after this change and still passes (all 6 checks ok), confirming the public-header probe is unaffected. The patch's reproducibility was re-verified against a genuinely pristine tree (a fresh cp -a cpython /tmp/cpython_pristine_check && git -C /tmp/cpython_pristine_check checkout -- ., not a stash of the working checkout): git apply --check from inside that pristine copy exits 0, and after applying, diff -rq between the patched pristine copy and this project's actual cpython/ working tree (excluding .git) reports no differences. The temporary copy was removed afterward; nothing under cpython/ or compat/ was affected by this verification step.

Compound-literal / designated-initializer slice

Scope: the 8 C99 compound-literal/designated-initializer call sites inside Modules/main.c's own body only — no header-level macro change, and no other file touched. This is the follow-on to the "Modules/main.c declaration-order slice" above, addressing exactly the blocker that slice left recorded as out of scope: VC6 (a pre-C99 compiler) supports neither C99 compound literals ((PyStatus){...}) nor C99 designated initializers ({ .field = value, ... }), at any position in a block, regardless of where the destination variable is declared.

Three distinct patterns were responsible, each fixed a different way, all still uncommitted in compat/msvc600/cpython-3.11.16-vc6-headers.patch:

  • status = _PyStatus_OK(); (1 site, pymain_init()). Rather than reimplementing the macro's field assignment by hand, this is replaced with status = PyStatus_Ok(); — the existing public API function declared in Include/cpython/initconfig.h (PyAPI_FUNC(PyStatus) PyStatus_Ok(void);) and defined in Python/initconfig.c as PyStatus PyStatus_Ok(void) { return _PyStatus_OK(); } — i.e. it returns the exact value the macro would have produced, by construction, not by re-derivation. This needed no header change: the function was already declared and part of the public ABI; main.c just wasn't calling it. Behavior is identical for every compiler, VC6 or otherwise — main.c now calls a function that itself still uses the compound-literal macro internally in Python/initconfig.c, which is fine because Python/initconfig.c is not part of this slice's compile-only probe (no link is attempted or claimed) and is explicitly the next kind of file this port will need to work through, not something silently skipped.
  • cf = _PyCompilerFlags_INIT; (5 sites: pymain_run_command(), pymain_run_file_obj(), pymain_run_startup(), pymain_run_stdin(), pymain_repl()). No public-API equivalent exists for this one (unlike PyStatus_Ok()), so each site is replaced with the field-by-field assignment the macro itself expands to: cf.cf_flags = 0; cf.cf_feature_version = PY_MINOR_VERSION;. PyCompilerFlags is a two-field plain struct (Include/cpython/compile.h), and cf was already declared (bare, no initializer) at the top of its enclosing block by the prior declaration-order slice, so this is a pure compound-literal-to-assignment substitution with no interaction with declaration position.
  • _PyArgv args = { .argc = argc, ... }; (2 sites: Py_Main(), Py_BytesMain()). No macro is involved here, just a plain C99 designated-initializer aggregate initializer on a local variable declaration. Replaced with a bare declaration followed by one assignment per field (args.argc = argc; args.use_bytes_argv = 0; ...); field order in the replacement does not matter, unlike the initializer list it replaces, since each is now an independent assignment statement.

Every other compiler is unaffected: PyStatus_Ok() is a normal function call (no macro expansion difference for any compiler), and hoisting a designated-initializer aggregate into field-by-field assignment, or a compound-literal assignment into field-by-field assignment, changes no value, no evaluation order, and no code path for any compiler that already accepted the C99 form — it is strictly a syntax substitution for an identical runtime effect.

Verified with the same two-probe approach used for the earlier slices:

  • scripts/fixtures/vc6_compound_literal_smoke.c (new) — includes the real Python.h/pycore_initconfig.h (like vc6_mixed_decls_smoke.c, since PyStatus, PyCompilerFlags, and _PyArgv are real CPython types, not reproducible in isolation the way the atomics/stdbool fixtures are) and exercises all three replacement patterns:

    $ bash scripts/vc6-probe-core.sh scripts/fixtures/vc6_compound_literal_smoke.c
    == MSVC600 Py_BUILD_CORE compile probe ==
    source : scripts/fixtures/vc6_compound_literal_smoke.c
    ...
    vc6_compound_literal_smoke.c
    
    == cl.exe exit status: 0 ==
    

    No errors, no warnings.

  • cpython/Modules/main.c itself, the same real core translation unit used throughout this document. Every C2059 compound-literal/ designated-initializer error is gone — the previous 8-error-line run is now 0 error lines, and the probe reports cl.exe exit status: 0:

    $ bash scripts/vc6-probe-core.sh
    == MSVC600 Py_BUILD_CORE compile probe ==
    source : cpython/Modules/main.c
    prefix : /home/ubuntu/.wine-win9xport
    
    Setting environment for using Microsoft Visual C++ tools.
    main.c
    ...
    == cl.exe exit status: 0 ==
    

    (The only other output is MSVC600's standard informational NOTE: about WINVER 0x0500 being a beta-era SDK combination, present on every probe run in this environment, not new to this slice and not an error or warning.) This is a compile-only (/c) result for one translation unit — scripts/vc6-probe-core.sh never invokes the linker (see its own header comment) — not a claim that Modules/main.c links, that pythoncore/python.exe builds, or that anything runs on Windows 9x.

Both probes are covered by 6 new checks added to scripts/vc6-probe-core.test.sh (positive isolated-fixture compile, no-errors check, a negative deliberately-broken-fixture check, its error-surfaced check, a check that Modules/main.c's output no longer contains any C2059 compound-literal/designated-initializer error anywhere in its own body, and a new end-to-end check that the Modules/main.c probe itself now exits 0), bringing that file to 27 checks total. Run: bash scripts/vc6-probe-core.test.sh. Last run: all 27 checks ok (wine + MSVC600 available in this environment). scripts/vc6-probe.test.sh was re-run after this change and still passes (all 6 checks ok), confirming the public-header probe is unaffected. The patch's reproducibility was re-verified against a genuinely pristine tree (a fresh cp -a cpython /tmp/cpython_pristine_check && git -C /tmp/cpython_pristine_check checkout -- ., not a stash of the working checkout): git apply --check from inside that pristine copy exits 0, and after applying, diff -rq between the patched pristine copy and this project's actual cpython/ working tree (excluding .git) reports no differences. The temporary copy was removed afterward; nothing under cpython/ or compat/ was affected by this verification step.

Next blocker: Python/pylifecycle.c

After the PyRuntime section slice, the same real core probe was re-run:

$ bash scripts/vc6-probe-core.sh cpython/Python/pylifecycle.c
== MSVC600 Py_BUILD_CORE compile probe ==
source : cpython/Python/pylifecycle.c
...
cpython\Python\pylifecycle.c(112) : error C2059: syntax error : '.'
cpython\Python\pylifecycle.c(112) : error C2059: syntax error : ','
cpython\Python\pylifecycle.c(130) : error C2059: syntax error : '{'
cpython\Python\pylifecycle.c(189) : error C2143: syntax error : missing ';' before 'type'
cpython\Python\pylifecycle.c(190) : error C2143: syntax error : missing ';' before 'type'
...
cpython\Python\pylifecycle.c(1232) : fatal error C1003: error count exceeds 100; stopping compilation

== cl.exe exit status: 2 ==

The prior first blocker at Python/pylifecycle.c:91-92 is gone: VC6 no longer reports warning C4068: unknown pragma for #pragma section, and no longer rejects __declspec(allocate("PyRuntime")) with C2341. The new exact first blocker is now the _PyRuntimeState_INIT designated-initializer macro used by _PyRuntime itself (C2059: syntax error : '.' at the definition line, now line 112 after the VC6 guard was added). After that, the file still reaches the previously known broader C99 compound-literal/designated-initializer and C89 mixed-declaration wall, eventually hitting the compiler's 100-error cap. This slice did not attempt those broader pylifecycle.c rewrites.

Current first-blocker evidence

The previously recorded long long / C99 integer-suffix blocker is now resolved and verified. The uncommitted compat/msvc600/cpython-3.11.16-vc6-headers.patch (already applied to the cpython/ working tree) replaces bare long long with the existing PY_LONG_LONG macro in Include/longobject.h, Include/pythread.h, and Include/pyexpat.h, and introduces a PY_LL/PY_ULL literal-suffix macro pair (spelled i64/ui64 for _MSC_VER < 1300, i.e. VC6) in PC/pyconfig.h and Include/pyport.h, used in place of raw 123LL/123ULL literals in Include/pythread.h. With this patch applied, the full public header stack compiles cleanly:

$ bash scripts/vc6-probe.sh
== MSVC600 compile probe ==
source : cpython/Programs/python.c
prefix : /home/ubuntu/.wine-win9xport

Setting environment for using Microsoft Visual C++ tools.
python.c

== cl.exe exit status: 0 ==

cpython/Programs/python.c (#include "Python.h" plus a wmain/main stub) now compiles to build/vc6-probe/python.obj (verified present, 7115 bytes) with exit status 0. This exercises the entire public Include/*.h surface reachable from Python.h, not just pyport.h.

The pycore_atomic.h/intrin.h blocker, the pycore_interp.h/ <stdbool.h> blocker, and the mixed-declarations blocker in pycore_code.h/pycore_dict.h/pycore_list.h/pycore_call.h described in earlier revisions of this document are all now resolved; see "Atomics slice", "stdbool slice", and "Mixed-declarations header slice" above for full detail. Probing the same real core translation unit (cpython/Modules/main.c, which needs Include/internal on the include path and Py_BUILD_CORE defined — both required unconditionally by every pycore_*.h header) now gets past all of CPython's internal headers reachable from its #include chain with no header-level error at all, and the compiler proceeds into Modules/main.c's own body — where it hits a new wall, spread across nearly the entire 743-line file:

$ bash scripts/vc6-probe-core.sh
== MSVC600 Py_BUILD_CORE compile probe ==
source : cpython/Modules/main.c
...
cpython\Modules\main.c(44) : error C2275: 'PyPreConfig' : illegal use of this type as an expression
cpython\Modules\main.c(44) : error C2146: syntax error : missing ';' before identifier 'preconfig'
cpython\Modules\main.c(44) : error C2065: 'preconfig' : undeclared identifier
...
cpython\Modules\main.c(52) : error C2275: 'PyConfig' : illegal use of this type as an expression
...
cpython\Modules\main.c(215) : error C2275: 'PyObject' : illegal use of this type as an expression
...
cpython\Modules\main.c(253) : error C2275: 'PyCompilerFlags' : illegal use of this type as an expression
...
== cl.exe exit status: 2 ==

(29 distinct error source lines total in that run, spanning lines 44 through 734 of main.c — effectively the whole file — across roughly a dozen separate functions/blocks.)

This mixed-declarations pattern inside Modules/main.c's own body is now resolved and verified; see "Modules/main.c declaration-order slice" above for full detail. With that fix applied, the same probe now gets past every declaration-position error and hits a new, different, and out-of-scope-for-that-slice blocker:

$ bash scripts/vc6-probe-core.sh
== MSVC600 Py_BUILD_CORE compile probe ==
source : cpython/Modules/main.c
...
cpython\Modules\main.c(71) : error C2059: syntax error : '{'
cpython\Modules\main.c(256) : error C2059: syntax error : '{'
cpython\Modules\main.c(366) : error C2059: syntax error : '{'
cpython\Modules\main.c(448) : error C2059: syntax error : '{'
cpython\Modules\main.c(531) : error C2059: syntax error : '{'
cpython\Modules\main.c(564) : error C2059: syntax error : '{'
cpython\Modules\main.c(748) : error C2059: syntax error : '.'
cpython\Modules\main.c(760) : error C2059: syntax error : '.'

== cl.exe exit status: 2 ==

Down from 29 error lines to 8. Every one of these is the same new root cause, unrelated to declaration position: a C99 compound literal, optionally with designated initializers, neither of which VC6 (a pre-C99 compiler) supports at all, at any position in a block. Two distinct macros/patterns are responsible:

  • main.c:71, 256, 366, 448, 531, 564 — six sites assigning PyCompilerFlags cf = _PyCompilerFlags_INIT; (now cf = _PyCompilerFlags_INIT; after the declaration-order fix) or status = _PyStatus_OK();. _PyCompilerFlags_INIT and _PyStatus_OK() are defined in Include/cpython/compile.h and Include/internal/pycore_initconfig.h respectively as C99 compound literals with designated initializers, e.g.:
    #define _PyStatus_OK() \
        (PyStatus){._type = _PyStatus_TYPE_OK,}
    #define _PyCompilerFlags_INIT \
        (PyCompilerFlags){.cf_flags = 0, .cf_feature_version = PY_MINOR_VERSION}
    
    (PyStatus){...} is a compound literal (C99 §6.5.2.5); ._type = ... inside it is a designated initializer (C99 §6.7.8). VC6 recognizes neither construct and reports the same C2059: syntax error : '{' for every one, regardless of whether the assignment is the first statement in its block or not — hoisting the declaration (already done) cannot fix this, because the problem is the initializer expression's syntax, not where the variable is declared.
  • main.c:748, 760 — the two _PyArgv args = { .argc = argc, ... }; aggregate initializations in Py_Main()/Py_BytesMain(), which use plain C99 designated-initializer syntax (no compound-literal macro involved, just { .field = value, ... } directly in a local variable's initializer) for the same reason: VC6 predates C99 designated initializers entirely.

This is a distinct C99 language-feature gap from mixed declarations, narrower in one sense (it doesn't force auditing every block in the file the way declaration-position did) but not fixable by moving code around: the fix, when attempted, will need to replace each compound-literal initializer with explicit field-by-field assignment statements (e.g. cf.cf_flags = 0; cf.cf_feature_version = PY_MINOR_VERSION;) or an equivalent non-compound-literal C89 construct, and — for _PyStatus_OK() / _PyCompilerFlags_INIT specifically — probably wants a header-level macro change (in pycore_initconfig.h / cpython/compile.h) analogous to the _Py_ATOMIC_VC6_X86 gating already used for pycore_atomic.h, rather than a per-call-site rewrite in every .c file that uses these macros, since they are used far more broadly than just Modules/main.c. No such fix is attempted here; it is out of scope for this narrowly-scoped declaration-order pass and is recorded as the next blocker. No link or runtime success is claimed at this or any earlier point in this document.

Update: this blocker (all 8 C2059 sites above) is now resolved for Modules/main.c, via a per-call-site rewrite rather than the header-level macro change speculated above — see "Compound-literal / designated-initializer slice" above for what was actually done and why the per-call-site approach (not the header macro change) was chosen for this narrow slice, and "Next blocker: Python/pylifecycle.c" above for where the same two blocker classes (mixed declarations and compound literals/designated initializers) recur next. This "Current first-blocker evidence" section is kept as a historical record of how the diagnosis proceeded; it is no longer the current state.

Larger blockers to plan for

  1. Build-system mismatch: CPython 3.11's Windows build expects Visual Studio 2017-era MSBuild/vcxproj tooling. VC6 cannot consume the build as-is. A dedicated minimal VC6 makefile/project set is required.
  2. Compiler language gap: CPython 3.11 source and headers use C99-era and later MSVC features that VC6 does not implement. Compatibility macros and carefully scoped source backports are required.
    • VC6's C89-only parser rejects CPython's pervasive C99-style mixed declarations-and-code. The instances of this pattern in four Include/internal/pycore_*.h headers reachable from Modules/main.c are fixed (see "Mixed-declarations header slice" above), and the same pattern recurring throughout Modules/main.c's own body (29 error sites across roughly a dozen functions) is also now fixed (see "Modules/main.c declaration-order slice" above). Whether this pattern recurs in CPython's other .c sources has not yet been surveyed; each file would need its own probe-and-fix pass the same way main.c did, not a whole-tree sweep in one change.
    • VC6 does not support C99 compound literals or designated initializers at all, independent of declaration position. The 8 sites of this pattern in Modules/main.c itself (_PyStatus_OK(), _PyCompilerFlags_INIT, and inline { .field = value } initialization in Py_Main()/Py_BytesMain()) are now fixed via a per-call-site rewrite, not a header-level macro change (see "Compound-literal / designated-initializer slice" above for why: a public-API function already existed for _PyStatus_OK(), and the other two patterns are cheap to rewrite in place without touching shared headers used far more broadly than main.c). _PyStatus_OK() and _PyCompilerFlags_INIT are still used, unmodified, at many other call sites across CPython outside main.c — this fix is scoped to main.c only, as directed; a header-level VC6 branch (mirroring _Py_ATOMIC_VC6_X86) remains a live option if a future slice finds the per-call-site approach doesn't scale to the rest of the codebase. The same two patterns (mixed declarations and compound literals) both recur in Python/pylifecycle.c, the next core translation unit in main.c's own call chain; see "Next blocker: Python/pylifecycle.c" above. Not yet fixed there.
  3. Win9x API gap: CPython 3.11's Windows layer assumes NT-family Unicode, synchronization, process, filesystem, and networking APIs. Windows 98 has no wide-character file APIs and lacks multiple newer kernel APIs.
  4. Runtime/library gap: SSL, SQLite, ctypes, multiprocessing, asyncio, Unicode filesystem behavior, and parts of subprocess will need explicit feature gates or Win9x-specific implementations.
  5. Validation gap: final success requires booting the built executable on Windows 98 SE; Wine compilation alone is not proof of Win9x runtime compatibility.

Do not attempt the complete CPython solution yet. The public header surface compiles; Include/internal/pycore_atomic.h compiles for VC6/_M_IX86 (see "Atomics slice" above); Include/internal/pycore_interp.h's <stdbool.h> include now resolves via the project-local compat/msvc600/stdbool.h shim (see "stdbool slice" above); the C99 mixed-declarations pattern in the four pycore_*.h headers reachable from Modules/main.c is fixed (see "Mixed-declarations header slice" above); that same pattern inside Modules/main.c's own body is fixed (see "Modules/main.c declaration-order slice" above); and the C99 compound-literal/designated-initializer pattern inside Modules/main.c's own body is now also fixed (see "Compound-literal / designated-initializer slice" above). cpython/Modules/main.c now compiles with cl.exe exit status 0 under scripts/vc6-probe-core.sh — no errors, no warnings — a compile-only (/c) result for this one translation unit; no link or runtime claim is made.

The next blocker is still Python/pylifecycle.c, the next core translation unit in main.c's own call chain (via Py_InitializeFromConfig()), but it has advanced past the VC6-incompatible PyRuntime section pragma. See "Next blocker: Python/pylifecycle.c" above for the current probe transcript. It now hits the same two already-solved blocker classes recurring at greater scale (mixed declarations, compound literals/designated initializers), plus enough sites of both to hit the compiler's 100-error cap before the whole file is seen, so the true scope is not yet known. Recommended next steps:

  1. Continue with Python/pylifecycle.c by applying the same two mechanical transforms already validated on Modules/main.c — hoist mid-block declarations (declaration-order slice) and replace compound-literal/