mirror of
https://github.com/Cheviiot/Vintner.git
synced 2026-08-03 15:57:24 +00:00
Initial implementation of msvc-go-wine
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.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRewriteArg(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
sub := filepath.Join(dir, "inc")
|
||||
if err := os.Mkdir(sub, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
file := filepath.Join(sub, "foo.h")
|
||||
if err := os.WriteFile(file, nil, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{"single-letter option + abs dir", "-I" + sub, "-Iz:" + sub},
|
||||
{"two-letter option + abs file", "-Fo" + file, "-Foz:" + file},
|
||||
{"long colon option + abs file", "-MANIFESTINPUT:" + file, "-MANIFESTINPUT:z:" + file},
|
||||
{"bare absolute path", file, "z:" + file},
|
||||
{"plain flag untouched", "-nologo", "-nologo"},
|
||||
{"nonexistent dir untouched", "-I/does/not/exist/at/all", "-I/does/not/exist/at/all"},
|
||||
{"root-level bare path untouched", "/nologo", "/nologo"},
|
||||
{"relative path untouched", "test.c", "test.c"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := rewriteArg(tc.in); got != tc.want {
|
||||
t.Errorf("rewriteArg(%q) = %q, want %q", tc.in, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewriteArgsPreservesOrderAndLength(t *testing.T) {
|
||||
in := []string{"/nologo", "-c", "test.c"}
|
||||
out := RewriteArgs(in)
|
||||
if len(out) != len(in) {
|
||||
t.Fatalf("length changed: %v -> %v", in, out)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user