Rewrite README prose: cut repeated self-assurance, tighten sentences

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.
This commit is contained in:
Cheviiot
2026-07-25 10:55:01 +10:00
parent fc20b2fb15
commit c049274626
+83 -91
View File
@@ -4,17 +4,16 @@
[![Release](https://img.shields.io/github/v/release/Cheviiot/vintner)](https://github.com/Cheviiot/vintner/releases/latest) [![Release](https://img.shields.io/github/v/release/Cheviiot/vintner)](https://github.com/Cheviiot/vintner/releases/latest)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
**vintner** cross compiles with the real MSVC toolchain on Linux, using Wine vintner cross-compiles with the real MSVC toolchain on Linux, using Wine.
a single Go binary, inspired by [mstorsjo/msvc-wine](https://github.com/mstorsjo/msvc-wine)'s One Go binary drops in as `cl`, `link`, `lib`, `rc`, `midl`, `mc`, `mt`,
approach (download the actual MSVC/WinSDK, wrap the compiler under Wine) and `dumpbin`, `msbuild`, `nmake`, `ml`, `ml64`, `armasm`, `armasm64`, plus
implemented independently. `cmd`/`findstr` shims, so once installed you invoke the real Microsoft
tools exactly like on Windows. It handles full MSBuild projects, and with
Once installed, you invoke the real Microsoft toolchain exactly like on
Windows: `cl`, `link`, `lib`, `rc`, `midl`, `mc`, `mt`, `dumpbin`, `msbuild`,
`nmake`, `ml`, `ml64`, `armasm`, `armasm64`, plus trivial `cmd`/`findstr`
shims, all work from your `PATH` — including full MSBuild projects and, with
`--with-wdk`, real KMDF/UMDF Windows drivers. `--with-wdk`, real KMDF/UMDF Windows drivers.
Inspired by [mstorsjo/msvc-wine](https://github.com/mstorsjo/msvc-wine)'s
approach: download the real MSVC/WinSDK, wrap the compiler under Wine.
## Contents ## Contents
- [How it works](#how-it-works) - [How it works](#how-it-works)
@@ -25,35 +24,37 @@ shims, all work from your `PATH` — including full MSBuild projects and, with
- [Language](#language) - [Language](#language)
- [Shell completion](#shell-completion) - [Shell completion](#shell-completion)
- [Using clang-cl/lld-link instead of Wine](#using-clang-cllld-link-instead-of-wine) - [Using clang-cl/lld-link instead of Wine](#using-clang-cllld-link-instead-of-wine)
- [toolrelay.exe](#toolrelayexe)
- [Compatibility patches](#compatibility-patches)
- [Building from source](#building-from-source) - [Building from source](#building-from-source)
- [How the pieces fit together](#how-the-pieces-fit-together)
- [License](#license) - [License](#license)
## How it works ## How it works
`vintner` is one Go binary that behaves differently depending on the name vintner is a multi-call binary, like busybox: it behaves differently
it's invoked as (a "multi-call binary", like busybox): depending on the name it's invoked as.
- Invoked as `cl`, `link`, `lib`, ... → it loads a small per-architecture - As `cl`, `link`, `lib`, and the rest: it loads a per-architecture
`env.json`, builds the `INCLUDE`/`LIB`/`WINEPATH` environment Wine needs, `env.json`, sets `INCLUDE`/`LIB`/`WINEPATH`, and rewrites absolute Unix
rewrites absolute unix paths in the arguments into Wine's `z:\...` form paths in the arguments to Wine's `z:\...` form (Wine and cl.exe
(working around [a Wine/cl.exe include-path bug](https://bugs.winehq.org/show_bug.cgi?id=55200)), otherwise mishandle relative includes — see
runs the real `.exe` under `wine`/`wine64`, and rewrites the tool's output [winehq bug 55200](https://bugs.winehq.org/show_bug.cgi?id=55200)). It
back from `z:\...` paths to plain unix paths so your build system's error then runs the real `.exe` under `wine`/`wine64`, and rewrites `z:\...`
paths back to Unix paths in the output, so your build system's error
parsing keeps working. parsing keeps working.
- Invoked as `vintner` it exposes the `download`, `install`, `env` and - As `vintner`: it exposes the `download`, `install`, `env`, `version`
`version` management subcommands described below (short aliases: `dl`, and `completion` subcommands below (short aliases: `dl`, `i`, `e`, `v`;
`i`, `e`, `v`; `help`/`h` prints usage). `help`/`h` prints usage).
## Installation ## Installation
**On ALT Linux, via [Nivora](https://github.com/Cheviiot/Nivora):** On ALT Linux, via [Nivora](https://github.com/Cheviiot/Nivora):
```bash ```bash
stplr install nivora/vintner stplr install nivora/vintner
``` ```
**Prebuilt binary**, from the [latest release](https://github.com/Cheviiot/vintner/releases/latest): Prebuilt binary, from the [latest release](https://github.com/Cheviiot/vintner/releases/latest):
```bash ```bash
curl -fLo vintner "https://github.com/Cheviiot/vintner/releases/latest/download/vintner-linux-$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')" curl -fLo vintner "https://github.com/Cheviiot/vintner/releases/latest/download/vintner-linux-$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')"
@@ -61,18 +62,18 @@ chmod +x vintner
sudo install vintner /usr/local/bin/vintner sudo install vintner /usr/local/bin/vintner
``` ```
**From source** see [Building from source](#building-from-source). From source: see [Building from source](#building-from-source).
Either way, `wine`/`wine64`, `msitools` (for `msiextract`) and `git` need to Either way, `wine`/`wine64`, `msitools` (for `msiextract`) and `git` need
be on `PATH` at run time (see [Prerequisites](#prerequisites) below); Nivora to be on `PATH` at run time. Nivora installs pull these in automatically
installs already pull these in as package dependencies. as package dependencies.
### Prerequisites ### Prerequisites
- `wine` (or `wine64`) — runs the real `cl.exe`/`link.exe`/etc. - `wine` (or `wine64`) — runs the real `cl.exe`/`link.exe`/etc.
- `msitools` (`msiextract`) — unpacks the `.msi` payloads MSVC/WinSDK ship as. - `msitools` (`msiextract`) — unpacks the `.msi` payloads MSVC/WinSDK ship as.
- `git` used to apply the small compatibility patches bundled with - `git` — applies the compatibility patches bundled with `download` (see
`download` (see [Compatibility patches](#compatibility-patches) below). [Compatibility patches](#compatibility-patches)).
On ALT Linux: On ALT Linux:
@@ -83,9 +84,9 @@ pkcon install wine msitools git
## Quick start ## Quick start
```bash ```bash
# 1. Download and unpack MSVC + Windows SDK into ~/.vintner (requires # 1. Download and unpack MSVC + Windows SDK into ~/.vintner (accepts
# accepting Microsoft's Visual Studio Build Tools license). Pass # Microsoft's Visual Studio Build Tools license). Pass --dest <dir>
# --dest <dir> for a different location. # for a different location.
vintner download --accept-license vintner download --accept-license
# 2. Wire up the tool wrappers # 2. Wire up the tool wrappers
@@ -119,38 +120,40 @@ vintner completion bash|zsh print a shell
`vintner download -h` for the full list with descriptions. `vintner download -h` for the full list with descriptions.
`--list-workloads`/`--list-components` print every workload/component id `--list-workloads`/`--list-components` print every workload/component id
(with its human-readable title) available in the fetched manifest and exit and its human-readable title from the fetched manifest, then exit
without downloading anything — useful for discovering what to pass as a bare without downloading anything. Useful for finding what to pass as a bare
package id or via `--with-*`. `--print-deps-tree` prints the dependency tree package id or through `--with-*`. `--print-deps-tree` prints the
of whatever would actually be selected (honoring every other flag), also dependency tree of whatever would actually be selected honoring every
without downloading. other flag — without downloading anything.
## Building drivers (WDK) ## Building drivers (WDK)
`--with-wdk` also fetches the Windows Driver Kit: headers, import libs,
and the MSBuild `WindowsKernelModeDriver10.0`/`WindowsUserModeDriver10.0`
PlatformToolsets.
```bash ```bash
vintner download --accept-license --with-wdk vintner download --accept-license --with-wdk
``` ```
additionally fetches the Windows Driver Kit (headers, import libs, and the With it, `msbuild` builds real KMDF/UMDF drivers — compiling, linking,
MSBuild `WindowsKernelModeDriver10.0`/`WindowsUserModeDriver10.0` INF stamping, and the `Inf2Cat` signability check (`SignMode=off`) all
PlatformToolsets) so `msbuild` can build real KMDF/UMDF drivers — work under Wine. Tested against a real sample driver from
compiling, linking, INF stamping and the `Inf2Cat` signability check (with
`SignMode=off`) all work under Wine. Verified end-to-end against a real
sample driver from
[microsoft/Windows-driver-samples](https://github.com/microsoft/Windows-driver-samples). [microsoft/Windows-driver-samples](https://github.com/microsoft/Windows-driver-samples).
Only x64 and arm64 targets have a WDK package upstream (no x86/arm). Only x64 and arm64 targets have a WDK package upstream; there's no x86 or
arm one.
## Language ## Language
CLI messages (usage text, progress lines, prompts) default to English. Set CLI text (usage, progress lines, prompts) defaults to English. Set
`VINTNER_LANG=ru` (or have a `ru`-prefixed `LC_ALL`/`LC_MESSAGES`/`LANG`, `VINTNER_LANG=ru` (or a `ru`-prefixed `LC_ALL`/`LC_MESSAGES`/`LANG`, e.g.
e.g. `ru_RU.UTF-8`) for Russian: `ru_RU.UTF-8`) for Russian:
```bash ```bash
VINTNER_LANG=ru vintner help VINTNER_LANG=ru vintner help
``` ```
Deeper error text bubbled up from internal packages stays in English. Error text from internal packages stays in English regardless.
## Shell completion ## Shell completion
@@ -159,13 +162,13 @@ source <(vintner completion bash) # or add to ~/.bashrc
source <(vintner completion zsh) # or add to ~/.zshrc source <(vintner completion zsh) # or add to ~/.zshrc
``` ```
Completes subcommands (including the short aliases), `download`'s flags, Completes subcommands, including the short aliases, `download`'s flags,
and directory arguments for `install`/`env --bin`. and directory arguments for `install`/`env --bin`.
## Using clang-cl/lld-link instead of Wine ## Using clang-cl/lld-link instead of Wine
You don't need Wine at all if you drive the (nonredistributable) MSVC/WinSDK The MSVC/WinSDK headers and libraries work directly with Clang/LLD in
headers and libraries with Clang/LLD in MSVC-compatible mode: MSVC-compatible mode. No Wine needed:
```bash ```bash
eval "$(vintner env --bin ~/.vintner/bin/x64)" eval "$(vintner env --bin ~/.vintner/bin/x64)"
@@ -173,55 +176,44 @@ clang-cl -c hello.c
lld-link hello.obj -out:hello.exe lld-link hello.obj -out:hello.exe
``` ```
## toolrelay.exe
`install` compiles `assets/vendor/toolrelay.cpp`, a small native Windows
launcher, with the freshly-installed host-arch `cl.exe`. This is
best-effort: if `wine` isn't available yet, or the compile fails, install
still succeeds, and tool invocations just skip it. When present, every
non-MSBuild tool call is routed through it via two named FIFOs.
That's what lets `mt.exe`'s CMake-compatibility exit code
(`0x41020001``0xbb`) survive Wine's own exit-code truncation: a native
Windows process can read the real 32-bit exit code via
`GetExitCodeProcess()` before Wine collapses it to a single byte on the
way back to Unix.
## Compatibility patches
`download` applies a few small patches (`assets/patches`) to the
downloaded MSVC/WinSDK tree, so `VsDevCmd.bat` and MSBuild's
SDK-detection props work without a Windows Registry, which doesn't exist
under Wine. They look up the SDK directly under the VS install root
instead of querying the registry, skip telemetry, and don't fail devcmd
setup when an optional component (ConnectionManagerExe, bundled
CMake/Ninja) is missing.
## Building from source ## Building from source
```bash ```bash
go build -o vintner ./cmd/vintner go build -o vintner ./cmd/vintner
```
Go 1.23+ is all you need to build it; `wine`/`msitools` are only needed at
run time (`install`/tool invocation and `download` respectively).
```bash
go vet ./... go vet ./...
go test ./... go test ./...
``` ```
## How the pieces fit together Go 1.23+ builds it. `wine`/`msitools` are only needed at run time, for
`install`/tool invocation and `download` respectively.
<details>
<summary><strong>toolrelay.exe</strong> — surviving Wine's exit-code truncation</summary>
`install` compiles `assets/vendor/toolrelay.cpp` (a small native Windows
launcher, original to this project) with the freshly-installed host-arch
`cl.exe` (best-effort: if `wine` isn't present yet, or the compile fails,
install still succeeds and the wrapper runtime just falls back to invoking
tools directly through wine). When present, every non-MSBuild tool
invocation is routed through it via two named FIFOs. This is what lets
`mt.exe`'s CMake-compatibility exit-code translation (`0x41020001``0xbb`)
survive Wine's own exit-code truncation: only a native Windows process
observing the untranslated code via `GetExitCodeProcess()` can catch it
before Wine marshals the process exit back to Unix and drops everything but
the low byte.
</details>
<details>
<summary><strong>Compatibility patches</strong> — making MSBuild work without a Windows Registry</summary>
`download` applies a handful of small patches (`assets/patches`) to the
downloaded MSVC/WinSDK tree — independently written for this project — that
make `VsDevCmd.bat` and MSBuild's SDK-detection props work without a
Windows Registry (which doesn't exist under Wine): they check the SDK
directly under the VS install root instead of querying the registry, skip
telemetry, and don't hard-fail devcmd setup when an optional component
(ConnectionManagerExe, bundled CMake/Ninja) wasn't downloaded.
</details>
## License ## License
MIT, see [LICENSE.txt](LICENSE.txt) — covers vintner's own source only. The MIT (see [LICENSE.txt](LICENSE.txt)) for vintner's own source. The MSVC
MSVC Build Tools / Windows SDK / WDK that `download` fetches remain governed Build Tools, Windows SDK, and WDK that `download` fetches stay under
by Microsoft's own license (accepted via `--accept-license`), same as with Microsoft's own license (accepted via `--accept-license`), same as with
any other way of obtaining them. any other way of obtaining them.