Rebrand project to vintner

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.
This commit is contained in:
Cheviiot
2026-07-25 03:55:22 +10:00
parent 23ea620ce2
commit a1743e4435
28 changed files with 183 additions and 160 deletions
+1 -1
View File
@@ -186,7 +186,7 @@ var httpClient = &http.Client{Timeout: 5 * time.Minute}
func init() {
// --manifest points at a local file, fetched through this same client
// via a "file:" URL (see cmd/msvc-go-wine's runDownload) - so it needs a
// via a "file:" URL (see cmd/vintner's runDownload) - so it needs a
// registered "file" handler alongside the default http/https transport.
t := http.DefaultTransport.(*http.Transport).Clone()
t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/")))
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"path/filepath"
"strings"
"github.com/Cheviiot/msvc-go-wine/assets"
"github.com/Cheviiot/vintner/assets"
)
// ApplyCompatibilityFixes applies the embedded Wine compatibility patches
@@ -63,7 +63,7 @@ func applyGitPatch(dest, embeddedPath, target string) error {
return err
}
tmp, err := os.CreateTemp("", "msvc-go-wine-*.patch")
tmp, err := os.CreateTemp("", "vintner-*.patch")
if err != nil {
return err
}
+1 -1
View File
@@ -50,7 +50,7 @@ type Options struct {
// selection - unlike everything else it depends on, it's opt-in via
// --with-wdk, since the actual driver headers/libs come from a separate
// NuGet package download handled outside ExpandSelection entirely (see
// wdk.go and cmd/msvc-go-wine's runDownload).
// wdk.go and cmd/vintner's runDownload).
WithWDK bool
}
+33 -33
View File
@@ -1,4 +1,4 @@
// Package i18n provides minimal message localization for msvc-go-wine's own
// Package i18n provides minimal message localization for vintner's own
// CLI chrome (usage text, progress lines, prompts). It does not localize
// error messages bubbled up from deeper packages - those stay in English,
// matching how most cross-platform dev tools keep diagnostic text technical
@@ -20,13 +20,13 @@ const (
var current = detect()
// detect picks the active language from MSVC_GO_WINE_LANG (checked first, so
// detect picks the active language from VINTNER_LANG (checked first, so
// it always overrides the locale), falling back to the POSIX locale
// variables in their usual priority order (LC_ALL, LC_MESSAGES, LANG). Any
// value starting with "ru" (case-insensitive) selects Russian; anything else
// falls back to English.
func detect() Lang {
for _, key := range []string{"MSVC_GO_WINE_LANG", "LC_ALL", "LC_MESSAGES", "LANG"} {
for _, key := range []string{"VINTNER_LANG", "LC_ALL", "LC_MESSAGES", "LANG"} {
v := os.Getenv(key)
if v == "" {
continue
@@ -65,55 +65,55 @@ func T(key string, args ...any) string {
var catalog = map[string]map[Lang]string{
"main.usage": {
EN: `msvc-go-wine - cross compile with MSVC on Linux via Wine
EN: `vintner - cross compile with MSVC on Linux via Wine
Usage:
msvc-go-wine download (dl) --accept-license [--dest <dir>] [options]
fetch and unpack MSVC/WinSDK/WDK
msvc-go-wine install (i) [dir] wire up wrappers for a downloaded MSVC
msvc-go-wine env (e) --bin <dir/bin/arch> print INCLUDE/LIB for native clang-cl/lld-link use
msvc-go-wine version (v) print the version
msvc-go-wine help (h) show this message
vintner download (dl) --accept-license [--dest <dir>] [options]
fetch and unpack MSVC/WinSDK/WDK
vintner install (i) [dir] wire up wrappers for a downloaded MSVC
vintner env (e) --bin <dir/bin/arch> print INCLUDE/LIB for native clang-cl/lld-link use
vintner version (v) print the version
vintner help (h) show this message
Run "msvc-go-wine <command> --help" for that command's own options - download
Run "vintner <command> --help" for that command's own options - download
has many, including --with-wdk, --list-workloads, --list-components and
--print-deps-tree.
--dest/[dir] default to ~/.msvc-go-wine if omitted.
Language: set MSVC_GO_WINE_LANG=ru (or LANG=ru_RU...) for Russian output.
--dest/[dir] default to ~/.vintner if omitted.
Language: set VINTNER_LANG=ru (or LANG=ru_RU...) for Russian output.
Once installed, add <dir>/bin/<arch> to PATH and invoke the tools directly:
cl, link, lib, ml, ml64, mc, midl, mt, rc, dumpbin, msbuild, nmake, armasm, armasm64, cmd, findstr
`,
RU: `msvc-go-wine — кросс-компиляция настоящим MSVC на Linux через Wine
RU: `vintner — кросс-компиляция настоящим MSVC на Linux через Wine
Использование:
msvc-go-wine download (dl) --accept-license [--dest <каталог>] [опции]
скачать и распаковать MSVC/WinSDK/WDK
msvc-go-wine install (i) [каталог] настроить обёртки для скачанного MSVC
msvc-go-wine env (e) --bin <dir/bin/arch> вывести INCLUDE/LIB для clang-cl/lld-link напрямую
msvc-go-wine version (v) показать версию
msvc-go-wine help (h) показать эту справку
vintner download (dl) --accept-license [--dest <каталог>] [опции]
скачать и распаковать MSVC/WinSDK/WDK
vintner install (i) [каталог] настроить обёртки для скачанного MSVC
vintner env (e) --bin <dir/bin/arch> вывести INCLUDE/LIB для clang-cl/lld-link напрямую
vintner version (v) показать версию
vintner help (h) показать эту справку
Запустите «msvc-go-wine <команда> --help» для параметров конкретной команды —
Запустите «vintner <команда> --help» для параметров конкретной команды —
у download их много, включая --with-wdk, --list-workloads, --list-components
и --print-deps-tree.
--dest/[каталог] по умолчанию — ~/.msvc-go-wine.
Язык: установите MSVC_GO_WINE_LANG=en (или LANG=en_US...) для вывода на английском.
--dest/[каталог] по умолчанию — ~/.vintner.
Язык: установите VINTNER_LANG=en (или LANG=en_US...) для вывода на английском.
После установки добавьте <dir>/bin/<arch> в PATH и вызывайте инструменты напрямую:
cl, link, lib, ml, ml64, mc, midl, mt, rc, dumpbin, msbuild, nmake, armasm, armasm64, cmd, findstr
`,
},
"main.unknown_subcommand": {
EN: "msvc-go-wine: unknown subcommand %q\n\n",
RU: "msvc-go-wine: неизвестная подкоманда %q\n\n",
EN: "vintner: unknown subcommand %q\n\n",
RU: "vintner: неизвестная подкоманда %q\n\n",
},
"install.usage": {
EN: "usage: msvc-go-wine install (i) [dest] (default: ~/.msvc-go-wine)",
RU: "использование: msvc-go-wine install (i) [каталог] (по умолчанию: ~/.msvc-go-wine)",
EN: "usage: vintner install (i) [dest] (default: ~/.vintner)",
RU: "использование: vintner install (i) [каталог] (по умолчанию: ~/.vintner)",
},
"install.default_dir": {
EN: "No directory given, using default: %s",
@@ -125,12 +125,12 @@ Once installed, add <dir>/bin/<arch> to PATH and invoke the tools directly:
},
"env.usage": {
EN: "usage: msvc-go-wine env (e) --bin <dest>/bin/<arch>",
RU: "использование: msvc-go-wine env (e) --bin <dest>/bin/<arch>",
EN: "usage: vintner env (e) --bin <dest>/bin/<arch>",
RU: "использование: vintner env (e) --bin <dest>/bin/<arch>",
},
"env.unknown_arch": {
EN: "msvc-go-wine env: unknown arch %q\n",
RU: "msvc-go-wine env: неизвестная архитектура %q\n",
EN: "vintner env: unknown arch %q\n",
RU: "vintner env: неизвестная архитектура %q\n",
},
"download.host_arch": {
@@ -146,8 +146,8 @@ Once installed, add <dir>/bin/<arch> to PATH and invoke the tools directly:
RU: "--dest не указан, используется значение по умолчанию: %s",
},
"download.done": {
EN: "Done. Next: msvc-go-wine install %s",
RU: "Готово. Далее: msvc-go-wine install %s",
EN: "Done. Next: vintner install %s",
RU: "Готово. Далее: vintner install %s",
},
"download.wdk_skip": {
EN: "--with-wdk: no x64/arm64 target architecture selected, skipping (no WDK package exists for x86/arm)",
+13 -13
View File
@@ -1,4 +1,4 @@
// Package install wires up a downloaded MSVC/WinSDK tree so the msvc-go-wine
// Package install wires up a downloaded MSVC/WinSDK tree so the vintner
// wrapper commands can find it: locating the installed toolchain/SDK
// versions, fixing up header/library name casing, laying out the
// per-architecture tool symlinks, and building the toolrelay helper.
@@ -14,16 +14,16 @@ import (
"sort"
"strings"
"github.com/Cheviiot/msvc-go-wine/assets"
"github.com/Cheviiot/msvc-go-wine/internal/wineenv"
"github.com/Cheviiot/vintner/assets"
"github.com/Cheviiot/vintner/internal/wineenv"
)
var archs = []string{"x86", "x64", "arm", "arm64"}
// Install wires up dest (a directory previously populated by
// `msvc-go-wine download --dest dest`) with the tool wrapper symlinks and
// `vintner download --dest dest`) with the tool wrapper symlinks and
// env.json config the wrapper runtime expects. selfBinary is the path to
// the currently running msvc-go-wine executable, copied into dest/bin so
// the currently running vintner executable, copied into dest/bin so
// the arch-specific tool symlinks have something to point at.
func Install(dest, selfBinary string) error {
dest, err := filepath.Abs(dest)
@@ -86,7 +86,7 @@ func Install(dest, selfBinary string) error {
kits10 := filepath.Join(dest, "kits", "10")
if !isDir(kits10) {
return fmt.Errorf("%s not found - expected a Windows SDK already unpacked by `msvc-go-wine download`", kits10)
return fmt.Errorf("%s not found - expected a Windows SDK already unpacked by `vintner download`", kits10)
}
if err := lnS("Lib", filepath.Join(kits10, "lib")); err != nil {
return err
@@ -148,7 +148,7 @@ func Install(dest, selfBinary string) error {
if err := os.MkdirAll(destBin, 0o755); err != nil {
return err
}
sharedBinary := filepath.Join(destBin, "msvc-go-wine")
sharedBinary := filepath.Join(destBin, "vintner")
if err := copyFile(selfBinary, sharedBinary, 0o755); err != nil {
return fmt.Errorf("installing shared binary: %w", err)
}
@@ -288,7 +288,7 @@ func renameHostDirs(binDir string) error {
}
// setupWrapperDir creates <destBin>/<arch> with its own local copy of the
// msvc-go-wine binary (not a symlink to the shared one in destBin), and
// vintner binary (not a symlink to the shared one in destBin), and
// symlinks every tool name to that LOCAL copy.
//
// This matters: the wrapper runtime locates its own install root via
@@ -297,23 +297,23 @@ func renameHostDirs(binDir string) error {
// PATH-resolved absolute path as argv[0] (some just pass the bare command
// name, e.g. "cl", which would make a naive argv[0]-based lookup resolve
// against the caller's cwd instead of the install dir). A same-directory
// symlink (cl -> msvc-go-wine) resolves to a binary that's still in the
// right arch dir; a symlink to a binary one level up (cl -> ../msvc-go-wine)
// symlink (cl -> vintner) resolves to a binary that's still in the
// right arch dir; a symlink to a binary one level up (cl -> ../vintner)
// would not be.
func setupWrapperDir(destBin, selfBinary, arch, host, dotnetHost, msvcVer, sdkVer string) error {
archDir := filepath.Join(destBin, arch)
if err := os.MkdirAll(archDir, 0o755); err != nil {
return err
}
localBinary := filepath.Join(archDir, "msvc-go-wine")
localBinary := filepath.Join(archDir, "vintner")
if err := copyFile(selfBinary, localBinary, 0o755); err != nil {
return fmt.Errorf("installing per-arch binary: %w", err)
}
for name := range toolNames {
if err := lnS("msvc-go-wine", filepath.Join(archDir, name)); err != nil {
if err := lnS("vintner", filepath.Join(archDir, name)); err != nil {
return err
}
if err := lnS("msvc-go-wine", filepath.Join(archDir, name+".exe")); err != nil {
if err := lnS("vintner", filepath.Join(archDir, name+".exe")); err != nil {
return err
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ import (
)
// ConfigFileName is the per-architecture config dropped next to the tool
// symlinks by `msvc-go-wine install`.
// symlinks by `vintner install`.
const ConfigFileName = "env.json"
// Config is the per-architecture info generated at install time.
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"regexp"
"strings"
"github.com/Cheviiot/msvc-go-wine/internal/wineenv"
"github.com/Cheviiot/vintner/internal/wineenv"
)
var reToolsetDir = regexp.MustCompile(`^v(\d+)$`)
+21 -21
View File
@@ -12,7 +12,7 @@ import (
"syscall"
"time"
"github.com/Cheviiot/msvc-go-wine/internal/wineenv"
"github.com/Cheviiot/vintner/internal/wineenv"
)
// pipeDrainGrace bounds how long we wait for a tool's stdout/stderr copy
@@ -24,7 +24,7 @@ import (
// `| tail`, CI log capture) long after the actual build finished.
const pipeDrainGrace = 500 * time.Millisecond
// toolRelayName is where `msvc-go-wine install` places the compiled
// toolRelayName is where `vintner install` places the compiled
// toolrelay.exe helper, shared across all arch bin dirs.
const toolRelayName = "toolrelay.exe"
@@ -37,7 +37,7 @@ func Run(tool string, args []string) int {
s, ok := Tools[tool]
if !ok {
fmt.Fprintf(os.Stderr, "msvc-go-wine: unknown tool %q\n", tool)
fmt.Fprintf(os.Stderr, "vintner: unknown tool %q\n", tool)
return 127
}
@@ -50,19 +50,19 @@ func Run(tool string, args []string) int {
// <dest>/bin/<arch>, not <dest>/bin.
exePath, err := os.Executable()
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
scriptDir := filepath.Dir(exePath)
cfg, err := wineenv.Load(scriptDir)
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine: loading install config:", err)
fmt.Fprintln(os.Stderr, "vintner: loading install config:", err)
return 1
}
baseUnix, err := wineenv.FindBaseUnix(scriptDir)
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine: locating installation root:", err)
fmt.Fprintln(os.Stderr, "vintner: locating installation root:", err)
return 1
}
paths := wineenv.NewPaths(cfg, baseUnix)
@@ -71,7 +71,7 @@ func Run(tool string, args []string) int {
wineBin, err := wineenv.FindWine()
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
@@ -119,17 +119,17 @@ func Run(tool string, args []string) int {
// observes the real 32-bit exit code via Win32 before translating and
// re-exiting with a value that fits in a byte.
func runViaToolRelay(wineBin, relayExe, exePath string, args []string, paths *wineenv.Paths, stdoutF, stderrF lineFilter) int {
stdoutFifo := filepath.Join(os.TempDir(), fmt.Sprintf("msvc-go-wine.stdout.%d", os.Getpid()))
stderrFifo := filepath.Join(os.TempDir(), fmt.Sprintf("msvc-go-wine.stderr.%d", os.Getpid()))
stdoutFifo := filepath.Join(os.TempDir(), fmt.Sprintf("vintner.stdout.%d", os.Getpid()))
stderrFifo := filepath.Join(os.TempDir(), fmt.Sprintf("vintner.stderr.%d", os.Getpid()))
os.Remove(stdoutFifo)
os.Remove(stderrFifo)
if err := syscall.Mkfifo(stdoutFifo, 0o600); err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
defer os.Remove(stdoutFifo)
if err := syscall.Mkfifo(stderrFifo, 0o600); err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
defer os.Remove(stderrFifo)
@@ -144,7 +144,7 @@ func runViaToolRelay(wineBin, relayExe, exePath string, args []string, paths *wi
}
if err := cmd.Start(); err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
@@ -176,7 +176,7 @@ func runViaToolRelay(wineBin, relayExe, exePath string, args []string, paths *wi
if exitErr, ok := err.(*exec.ExitError); ok {
return exitErr.ExitCode()
}
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
return 0
@@ -191,17 +191,17 @@ func runViaToolRelay(wineBin, relayExe, exePath string, args []string, paths *wi
func runRawStdout(cmd *exec.Cmd) int {
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
stderr, err := cmd.StderrPipe()
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
if err := cmd.Start(); err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
@@ -218,7 +218,7 @@ func runRawStdout(cmd *exec.Cmd) int {
if exitErr, ok := err.(*exec.ExitError); ok {
return exitErr.ExitCode()
}
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
return 0
@@ -265,17 +265,17 @@ func buildEnv(p *wineenv.Paths) []string {
func runFiltered(cmd *exec.Cmd, stdoutF, stderrF lineFilter) int {
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
stderr, err := cmd.StderrPipe()
if err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
if err := cmd.Start(); err != nil {
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
@@ -292,7 +292,7 @@ func runFiltered(cmd *exec.Cmd, stdoutF, stderrF lineFilter) int {
if exitErr, ok := err.(*exec.ExitError); ok {
return exitErr.ExitCode()
}
fmt.Fprintln(os.Stderr, "msvc-go-wine:", err)
fmt.Fprintln(os.Stderr, "vintner:", err)
return 1
}
return 0
+1 -1
View File
@@ -4,7 +4,7 @@
// filtering its output.
package wrapper
import "github.com/Cheviiot/msvc-go-wine/internal/wineenv"
import "github.com/Cheviiot/vintner/internal/wineenv"
// dirKind selects which install directory a tool's real .exe lives in.
type dirKind int