vc6_wine_environment - ryzom/ryzomcore GitHub Wiki
title: Visual C++ 6.0 build environment on Linux using Wine (draft) description: Toolchain package for building the original CVS-era NeL (github.com/ryzom/nel_cvs) with its original compiler β the 2000s counterpart of the VS2008 reference environment published: true date: 2026-10-30T00:00:00.000Z tags: editor: markdown dateCreated: 2026-08-06T00:00:00.000Z
Status: baseline packaged and validated (2026-10-30). A reproducible Wine prefix β VC6 SP5 + Processor Pack + the DirectX 9.0 SDK Update (Summer 2003), with the Wine-gap workarounds baked in β now exists as
toolchain_vc6_prefix.7zand builds the CVS-era trees through thewinecl6-*wrapper scripts. The Beta 2 reversal work runs on this same baseline with per-project externals overlaid. Companion pages: VS2008 under Wine for the conventions this mirrors, and Windows Compatibility Targets for the runtime-side matrix (which OS each era's binaries run on β this page covers the compiler-side ceilings instead). {.is-warning}
The original NeL / Ryzom / Snowballs codebase β preserved at github.com/ryzom/nel_cvs β was built with Visual C++ 6.0 (cl 12.00), with Format-6.00 .dsp/.dsw project files (55 projects: nel, nelns, snowballs2, tools). Building that tree with its original compiler under Wine gives the authentic 2000s-era x87 reference, the same role the VS2008/Wine environment plays for the Max-2010-era pipeline.
Survey of the final CVS state (2026-08-06):
-
nel/include/nel/misc/types_nl.hhard-requires STLport (#errorunless__SGI_STL_PORTβ any STLport 4.x defines it). VC6's native STL is not an option by the project's own gate. - Drivers in-tree: 3D = OpenGL only, sound = OpenAL only. No DirectX SDK requirement for the core libraries; link lines are plain system libs (
opengl32.lib,odbc32.lib, ...). No freetype in3d.dspat this tree state. - No exported
.makfiles β building the.dspprojects needs eitherMSDEV.EXE /MAKE(the VC6 command-line build driver) or an external build harness.
Service pack: SP5, not SP6. An earlier revision of this page assumed SP6 (mislabeling cl 12.00.8804, which is SP5). The shipped package is VC6 SP5 + Processor Pack: cl.exe 12.00.8804, C1.DLL 12.00.8867, C1XX.DLL 12.00.8964, and the backend c2.dll 12.00.9044 from the Processor Pack β which installs on SP5 only, never on SP6. This is not just preference: objects compiled by this tree carry @comp.id 12.00.9044, matching the Rich header of the original Ryzom Beta 2 artifacts. A pure-SP5-no-PP variant (RTM c2 12.00.8168) is kept alongside for A/B work.
Package layout (single archive, ~235 MiB, built the same way as the VS2008 toolchain_v90_prefix.7z):
| Path | What | From |
|---|---|---|
drive_c/Program Files/Microsoft Visual Studio |
VC6 SP5+PP (VC98, Common, incl. MSPDB60.DLL in Common/MSDev98/Bin) |
working WinXP install, zipped |
drive_c/DX90SDK |
DirectX 9.0 SDK Update (Summer 2003), trimmed to Include/Lib β ships un-pathed; stage via NL_VC6_DX (below) |
SDK archive |
drive_c/β¦/VC98/Bin/CL.EXE, LINK.EXE
|
injector wrappers, see below | source included |
wine-vc6/winecl6-{env,cc,lib,link,rc} |
build wrapper scripts | source included |
wine-vc6/src/{zmhook.c,cl_wrap.c} |
source of all custom executables | β |
README.md |
full documentation of the above, including a rebuild-from-archives recipe | β |
The prefix is win32 (WINEARCH=win32 at creation). No extern folder structuring is imposed β the Nevrax-convention C:\NEVRAX\EXTERN\* layout (a DX8-named shim over DX90SDK, per-library trees) is a per-project overlay, not baseline; where extern packages live is the consumer project's choice.
Deliberately excluded from the baseline: Platform SDKs (the Feb 2001 and Feb 2003 PSDKs are available separately for experiments β see the trap below for why they must stay off the include path), the 3ds Max SDK, STLport (per-project: era NeL stages its own), and the link-identity probe hooks used during the Ryzom Beta 2 work.
Externals are per-project, not in the baseline: STLport 4.x headers + VC6-built iostreams library (era-authentic 4.5.3 β upstream sourceforge tarball, md5 cd4dd34b623a8704fbc800de79705171, header-identical to the Nevrax-era wpkg package; must be first on INCLUDE β the NL_VC6_STLPORT env var stages it, /dev/null disables), FreeType 2.1.x, libxml2 2.4.x/2.6.x, libjpeg 6b, zlib, GLEXT, EAX 2.x β all built with this same VC6 where needed. The DX row in the dependency survey below stands: at the final CVS tree state the core needs no DX SDK; the Ryzom-era client is where the Summer 2003 SDK enters (see the reversal's pinned setup).
winecl6-env assembles the environment (INCLUDE/LIB/WINEPATH) and every winecl6-* script sources it, then runs the tool through Wine with UnixβWindows path translation (translate_args β same shape as the VS2008 layer, including the glued-/FI case; additionally drops /showIncludes, which cl 12.00 predates). Env knobs: NL_VC6_PREFIX (prefix location), NL_VC6_STLPORT (STLport staging; /dev/null for STLport-free builds such as modern ryzomcore), NL_VC6_DX (DX SDK staging: any Windows path to an SDK root with INCLUDE/LIB, e.g. 'C:\DX90SDK'; unset, the Nevrax C:\NEVRAX\EXTERN\DX8 location is used if it exists β reversal overlay convention β, otherwise no DX at all), WINEDEBUG (default -all).
Default include order in the pristine baseline is VC98 only. Fully staged (era NeL): STLport β DX β VC98 (+MFC/ATL). windows.h resolves to VC98 (the DX SDK has none); the only header collision is VC98 windows.h β winnt.h β DX basetsd.h, which is inert on _MSC_VER 1200 (_W64 is empty, INT_PTR stays 32-bit). LIB: DX libs first, then VC98, then STLport.
Never put a Platform SDK on this path for VC6. PSDK 2003
winbase.hInterlocked*overloads are C2733 on cl 12.00, and a later PSDK in front of VC98 also breaks VC6 C++ via the newerwinnt.h(__w64). The PSDK include order is a VS2008-era concern; for VC6 it is simply wrong. {.is-warning}
Validation battery (banner, x87 float bit-exactness β 1.0f/3.0f β 3eaaaaab under /O2 β, C++ /GX /MD smoke, STLport smoke, RC smoke) passes 8/8 on the packaged baseline; a PCH TU and a large client TU compile byte-identical (all content sections; only COFF TimeDateStamp / PDB NB10 build-time fields differ, as they must).
The VS2008 page's trap list mostly does not apply (VC6 has no manifests, no mt.exe, no SxS β plain MSVCRT.DLL, Wine's builtin serves; /Zi works: MSPDB60 is an in-process DLL, there is no mspdbsrv.exe server process until VC7). What bites on VC6 is the compiler's own memory appetite:
-
C1060(compiler out of heap space) at stock/Zm800 /YX./Zmscales the compiler's factoring heap;/Zm800makesCL.EXErequest two anonymousVirtualAlloc(NULL, 400 MB)blocks. Wine's 32-bit preloader parks builtins near0x7a000000, the first heap lands just below, and the second fails. Two simpler fixes were tried and rejected:WINEPRELOADRESERVEalone (the reserve is not consulted byVirtualAlloc(NULL)β it goes throughmap_free_area, so reserving just makes C1060 hit earlier), andLARGEADDRESSAWAREoncl/c1xx/c2(both heaps then fit in 4 GB, but/YXdies with C2437,allocator<char>already initialized). -
The fix: IAT-level
VirtualAllochook injected into the real compiler. Wine stubsLoadAppInitDlls, so the AppInit_DLLs registry route is unavailable; insteadVC98/Bin/CL.EXEandLINK.EXEare a ~16 KB injector (cl_wrap.c) that launches the realcl_orig.exe/link_orig.exesuspended, injectszmhook.dllvia a remote-threadLoadLibraryA, and resumes it. The hook matches Wine'skernel32!VirtualAllocthunk prologue (8B FF 55 8B EC 5D FF 25 <IAT>), swaps the IAT slot, and pinsVirtualAlloc(NULL, β₯128 MB)at0x20000000, stepping 32 MB β combined withWINEPRELOADRESERVE=0x20000000-0x78000000this reserves a corridor where the two/Zm800heaps always land. Every pin is logged toC:\nevrax\extern\zmhook.log. -
After a Wine upgrade, check that log β if the
VirtualAllocthunk prologue ever changes, the hook logsunexpected VirtualAlloc prologueand no-ops (C1060 returns). This is the one Wine-coupling to re-verify on toolchain updates. -
/Fe:name.execolon form β same as the VS2008 page: use the no-colon/Fename.exeform. - Case sensitivity has not needed the alias farm so far for VC98/STLport/DX headers (consistent internal casing); the dual-case farm trick exists in the externals tooling if a vendor tree ever needs it.
-
RC.EXElives inCommon/MSDev98/Binin VC6 (notVC98/Bin) β the wrapper points there;/nologois accepted at this vintage. -
WINEARCH=win32at prefix creation.wineboot -ion a 64-bit host without it gives a win64 prefix (Program Files (x86),syswow64). The 32-bit VC6 tools still run under WOW64 there β verified: a win64 prefix produced byte-identical object content against the win32 one β but the win32 convention is smaller, skips the WOW64 layer, and matches the VS2008 flow; verify#arch=win32insystem.regafter init.
The wrapper scripts compile/link/lib/rc directly β see the package README.md for the rebuild-from-archives recipe and full usage. Ninja/CMake-driven builds work the same way as the VS2008 flow (command-line only; MSDEV.EXE /MAKE for the .dsp projects remains untried under Wine β the fallback of a small .dsp parser emitting ninja still stands if the IDE route is ever needed).
-
β done (8/8, see above).validate_vc6.shgreen -
STLport 4.5.3 built with this toolchainβ done (era-authentic iostreams, VC6-built). -
A full DLL link against the original's link orderβ done for the STLport DLL during the Beta 2 work (/ORDER+ first-object IAT ordering; see the reversal notes for the linker-layout methodology). - CVS-era tree builds:
nel/src/misc.dspβnlmisc.lib(smallest real target, exercises STLport + the header set), then snowballs2.