Prompted by a real incident: an MSBuild node-reuse worker (its own
/nodeReuse:true default) survived a build getting interrupted, came
back deadlocked, and got reused by the next `msbuild` invocation -
which then failed with a confusing, unrelated-looking
`System.TypeLoadException` on Microsoft.VisualStudio.Telemetry on
every call for hours, until the stale process was killed by hand.
That's exactly the "unrelated blocker" noted in this repo's own
earlier session notes (CLAUDE.md) while debugging a real project's
build - it wasn't a missing dependency, it was a corrupted reused
process.
Two changes:
- vintner now forces /nodeReuse:false on every msbuild invocation
(unless the caller already passed their own /nodeReuse or /nr
switch), so a wedged worker can never poison a later, unrelated
build in the first place. Costs each invocation the couple-hundred-
ms/node startup time node reuse exists to save.
- VINTNER_TIMEOUT (a duration string, e.g. "30m") bounds how long any
single tool invocation is allowed to run, for the case something
wedges that isn't MSBuild-specific. Every exec.Command site in
internal/wrapper now goes through a shared newToolCommand
constructor that, when the timeout is set, kills the *whole*
process group (not just the immediate `wine` process - a wedged
child surviving under it is exactly the scenario this needs to
reach) via a context deadline, and reports a clear "timed out after
Xm" message (exit 124, matching the timeout(1) convention) instead
of a bare "signal: killed". Unset by default - every real build
observed stays unbounded, matching Windows' own behavior.
Verified end-to-end, not just at the unit level: a real `sleep 30`
through the `cmd` native wrapper with VINTNER_TIMEOUT=1s was killed
within the deadline and reported the timeout clearly (exit 124); a
real `cl` invocation with the same 1s timeout finished normally
(0.26s) without being mistaken for a hang.
download --with-dxsdk fetches the DirectX SDK (June 2010) - the last
standalone release of D3DX9/10/11, XInput and XAudio2, dropped from
the Windows SDK entirely once D3DX was deprecated, but still needed
by plenty of legacy code. Like the WDK, it isn't part of the VS
installer manifest, so this is its own self-contained fetch+unpack
path: the installer is a self-extracting CAB, unpacked directly via
cabextract (already a prerequisite for the WinSDK .msi payloads) with
its -F filter restricting extraction to just Include/ and Lib/ -
about 21MB out of the installer's 1.2GB uncompressed payload.
Verified against the real installer: real d3dx9.h and d3dx9.lib
(x86 and x64) extracted correctly and linked into an actual legacy
game client build.
The old version restated "independently implemented"/"original to
this project" in three separate places, which reads as protesting
too much rather than as confidence. Credits the msvc-wine inspiration
once, plainly, and drops the rest. Also split several overlong
comma-chained sentences, fixed the WDK section (a sentence was cut in
half by its own code block), and cleaned up the license paragraph's
phrasing. Content is unchanged - verified the two claims most worth
double-checking (the clang-cl/lld-link path, and that `stplr install
nivora/vintner` actually resolves) rather than just rewording them.
vintner completion bash|zsh prints a completion script meant to be
sourced (source <(vintner completion bash)); completes subcommands
(including short aliases), download's flags, and directory arguments
for install/env --bin. Mentioned in the top-level usage text and
documented in the README.
The Nivora package doesn't auto-install these system-wide yet - it'd
need Stapler's install-completion helper, whose calling convention
isn't documented anywhere in this repo or Nivora's other packages, so
guessing at it risked a broken package build for a nice-to-have.
source <(vintner completion bash) works today regardless of install
method (Nivora, prebuilt binary, or from source).
Adds the two installation options that now actually exist (Nivora
package, prebuilt GitHub Release binary) alongside building from
source, a table of contents, CI/release/license badges, and a
Language section for VINTNER_LANG. Moves the more implementation-
focused toolrelay.exe/compatibility-patches explanations into
collapsible sections so the top of the page stays focused on using
the tool rather than how it's built.
Renamed the GitHub repo, Go module path, binary, and default install
directory from msvc-go-wine to vintner. Updated every user-facing
string (usage text, error prefixes, README, LICENSE, CI/release
workflow) and the embedded compatibility patches' own header text to
match; the VINTNER_LANG env var replaces VSMC_GO_WINE_LANG.
Also fixes a real bug found while re-verifying the rename end-to-end:
Microsoft.Cpp.WindowsSDK.props.patch had LF-only line endings in its
hunk body while the real Microsoft-shipped file it targets is CRLF,
so `git apply` silently failed on every real install and the SDK
detection fix it's meant to provide was never actually taking effect.
Restored matching CRLF endings in the hunk (checked against the other
five patches, which already had this right). Left the patch's
internal MsvcGoWine_ExtraSdkRoots MSBuild property name alone rather
than renaming it too - changing hunk content, even just an identifier,
breaks reverse-apply idempotency for anyone re-running download
against an already-patched tree, which the fix above depends on. Added
a .remove marker so an existing install's old-named props file gets
cleaned up on the next download.
Re-verified end-to-end after the rename: general MSBuild/cl/link
still work, and a real KMDF driver build (compile, link, INF stamping,
Inf2Cat signability check) still succeeds under the renamed binary.
README also gets an accuracy pass: WDK support and the download/env
CLI flags it lists were out of date (WDK was previously listed under
"Known gaps" despite being implemented and verified), the full tool
list was missing mc/cmd/findstr, and the new command aliases and
VINTNER_LANG option are now documented.
- download --list-workloads / --list-components print every workload or
component id (with its manifest title) without downloading anything, for
discovering what to pass as a package id or --with-* toggle.
- download --print-deps-tree prints the dependency tree of whatever the
current flags would actually select, sharing the exact same
arch/--ignore/Optional/Recommended filtering ExpandSelection uses so the
output matches a real download; diamond dependencies are shown once and
referenced as "(see above)" afterwards to keep it finite.
- Fixed --manifest (offline/predownloaded manifest testing) never having
worked at all: it builds a "file:" URL but the shared http.Client had no
handler registered for that scheme.
- Added a CI workflow running gofmt/vet/build/test on every push and PR;
previously only the tag-triggered release workflow existed.
--dest (download) and the positional dir (install) were previously
required, forcing every user to pick and remember a location. Both now
default to a single hidden ~/.msvc-go-wine, matching the convention most
CLI tools use for their own data dir - still overridable for anyone who
wants a different location.
A single-binary Go tool for cross compiling with the real MSVC toolchain
on Linux via Wine. Behaves as cl/link/lib/rc/midl/mt/dumpbin/msbuild/
nmake/ml/ml64/armasm/armasm64/cmd/findstr depending on the name it's
invoked as, plus download/install/env/version management subcommands.
- download: fetches the MSVC/WinSDK installer manifest, resolves package
selection and dependencies, downloads and verifies payloads, unpacks
VSIX/MSI packages, and applies a handful of compatibility patches so
VsDevCmd.bat and MSBuild's SDK detection work without a Windows
Registry (which doesn't exist under Wine).
- install: locates the installed toolchain/SDK versions, normalizes
header/library name casing, lays out per-architecture tool symlinks
with an env.json config each, and compiles a small native launcher
(toolrelay.exe) that lets mt.exe's CMake-compatibility exit code
survive Wine's own exit-code truncation.
- The wrapper runtime rewrites absolute unix paths in tool arguments into
Wine's z:\... form, runs the real .exe under wine, and rewrites the
tool's output back to plain unix paths.
Verified end-to-end against a real MSVC/WinSDK download: cl, link, mt and
the resulting hello.exe all work under Wine, including through the
toolrelay.exe relay path and with paths containing non-ASCII characters.
Offline unit tests cover the wrapper's path-rewrite/output-filter logic,
install-time header lowercasing, and download package-selection/
dependency-resolution.