Skip to content

vs2008_linux_wine

Jan Boon edited this page Jul 7, 2026 · 2 revisions

title: Visual C++ 2008 build environment on Linux using Wine description: Running the VS2008 x86 command-line toolchain (cl/link) in a 32-bit Wine prefix — for plugin_max builds and pipeline_max reference-arithmetic probes published: true date: 2026-07-07T00:00:00.000Z tags: editor: markdown dateCreated: 2026-07-07T00:00:00.000Z

Companion page to 3ds Max 9 on Linux using Wine, which covers the usual prefix conventions. This page covers the command-line toolchain only (cl.exe, link.exe, lib.exe, nmake.exe) — not the Visual Studio IDE, which is not worth fighting under Wine. {.is-info}

Why this exists: the ~/pipeline_export reference outputs were produced by 3ds Max 2010, a VS2008 x86 build (see the provenance note in the pipeline_max design document, §10i). Reproducing the reference exporter's float arithmetic bit-for-bit therefore means VS2008 x86 codegen. This environment is for building small kernel probe harnesses (decompose/normal/vertex-path kernels compiled with the same compiler, run under Wine, outputs compared against the headless x64 exporters) and, if ever needed, the plugin_max binaries themselves. {.is-info}

Create the Wine prefix

Same conventions as the Max 9 page: a dedicated 32-bit prefix under ~/.local/share/wineprefixes/.

WINEARCH=win32 WINEPREFIX=~/.local/share/wineprefixes/vs2008/ winecfg
WINEARCH=win32 WINEPREFIX=~/.local/share/wineprefixes/vs2008/ winetricks

In Winetricks, Install a Windows DLL or component:

  • vcrun2008 (the CRT the produced binaries and the toolchain itself expect)
  • msxml6 (some SDK tools want it; harmless to have)

The .NET components are only needed if you attempt the full installer (below) — the toolchain itself does not use .NET.

Headless / scripted setup — winetricks' unattended mode makes the whole prefix reproducible from a script:

export WINEARCH=win32 WINEPREFIX=~/.local/share/wineprefixes/vs2008/
WINEDLLOVERRIDES="mscoree,mshtml=" wineboot -i   # init the prefix, skip Mono/Gecko prompts
winetricks -q vcrun2008 msxml6

On a machine with no display at all (CI, plain ssh), wrap the winetricks call in xvfb-run -a — some component installers open a window even when silenced. vcrun2008/msxml6 are reliable unattended; the dotnet35 verb (Route B only) is slow and flaky under -q, one more reason to prefer Route A.

Getting the toolchain into the prefix

Route A — copy an existing install (recommended, and the route this page assumes). The compiler does not need registry state; a working install tree is enough. From the existing local VS2008 install, copy into the prefix's drive_c:

  • Program Files/Microsoft Visual Studio 9.0/VC/bin/, include/, lib/ (x86 only; bin/amd64 etc. are irrelevant here)
  • Program Files/Microsoft Visual Studio 9.0/Common7/IDE/cl.exe loads mspdb80.dll (and friends msobj80.dll, mspdbcore.dll) from here; either keep the directory and add it to PATH, or copy those DLLs next to cl.exe
  • Program Files/Microsoft SDKs/Windows/v6.0A/Include/ and Lib/ (the Windows SDK headers/libs VS2008 shipped with)

If the local install already lives in a Wine prefix (e.g. it was used to build plugin_max), point the environment below at that prefix instead — nothing more to do.

Route B — run the installer under Wine. Known-troublesome: the VS2008 setup chain wants Windows Installer sequencing and .NET 3.5 (winetricks dotnet35 in a win32 prefix, slow and fragile), and partial-failure states are common. If the installer must be used, deselect everything except Visual C++ and expect to iterate. Route A is strictly less pain when any Windows machine or existing install is available.

Environment wrapper

Wine maps the Unix environment into the Windows process environment, so vcvars32.bat is unnecessary — export the three variables from the shell. Keep a wrapper script, e.g. ~/bin/winecl:

#!/bin/sh
export WINEPREFIX=~/.local/share/wineprefixes/vs2008/
VS='C:\Program Files\Microsoft Visual Studio 9.0'
SDK='C:\Program Files\Microsoft SDKs\Windows\v6.0A'
export INCLUDE="$VS\\VC\\include;$SDK\\Include"
export LIB="$VS\\VC\\lib;$SDK\\Lib"
export WINEPATH="$VS\\VC\\bin;$VS\\Common7\\IDE"
export WINEDEBUG=-all
exec wine "$VS\\VC\\bin\\cl.exe" "$@"

(WINEPATH appends to the Windows PATH; it is how cl.exe finds mspdb80.dll in Common7/IDE without copying DLLs around.)

Smoke test:

printf '#include <stdio.h>\nint main(){printf("%%a\\n", 1.0f/3.0f);return 0;}\n' > /tmp/t.c
winecl /nologo /O2 /Z7 /Fe:t.exe t.c   # run from the source directory
wine t.exe

Traps

  • /Z7, never /Zi. /Zi spawns mspdbsrv.exe (the PDB server process), which is unreliable under Wine and hangs builds. /Z7 embeds the debug info in the object files and never starts it. For probe harnesses just omit debug info entirely.
  • Case sensitivity. Windows-authored sources #include <WinDef.h> with arbitrary casing; the SDK tree copied onto a case-sensitive filesystem will miss them. Keeping the trees inside the prefix's drive_c and letting Wine do the path lookup handles most of it; stubborn cases want ciopfs/casefold or a lowercase-normalized copy of the include dirs.
  • Response files and long command lines work fine (cl @args.rsp); prefer them over heroic shell quoting of \-ridden paths.
  • Parallelism: cl /MP works, but each cl is a Wine process — for the small probe harnesses this page targets, plain serial compiles are simpler and fast enough.

Flags for reference-arithmetic probes

To match the Max 2010-era plugin codegen, compile probes the way the plugin was built:

  • /O2 /fp:precise (VS2008 defaults for release; no /arch:SSE* — the x87 blended default is the point of the exercise)
  • The CRT initializes the x87 control word to 53-bit precision (_PC_53); a probe that wants Max-identical behavior should leave it alone (do not call _controlfp), since the reference ran with the CRT default.
  • Link /SUBSYSTEM:CONSOLE; dump results as text (hex float bits, printf("%08x") on the bit pattern) so outputs diff cleanly against the Linux x64 exporters' dumps.

Using Max 2010 SDK code in probes

decomp_affine and the other decomp.h/geom utilities are exports of Max's own geom.dll (import library geom.lib in the Max 2010 SDK) — they are Autodesk-compiled code, not headers, which is exactly why no recompilation on the Linux side can reproduce their bits. A probe exe that links geom.lib and sits next to Max 2010's geom.dll (plus its direct dependencies; check with winedump -j import geom.dll) runs the actual reference decompose. That is the scoped experiment for the DefaultRotQuat/Scale byte-identity question (design doc §10i). Deeper Max internals (Mesh::buildRenderNormals in mesh.dll) pull progressively more of the Max runtime as dependencies — feasibility drops fast; the angle-weighted replication in pipeline_max_export_shape plus its 1e-4 verdict tier is the accepted answer there.

Troubleshooting

cl.exe exits immediately with no output

mspdb80.dll not found — verify WINEPATH includes Common7\IDE, or copy mspdb80.dll, mspdbcore.dll, msobj80.dll next to cl.exe.

C1902: Program database manager mismatch

Mixed mspdb* DLL versions between VC/bin and Common7/IDE (e.g. trees copied from different service-pack levels). Copy both directories from the same install.

LNK1104: cannot open file 'kernel32.lib'

LIB doesn't reach the Windows SDK Lib directory — the VC lib directory alone only has the CRT.

Clone this wiki locally