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,59 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Argument path rewriting: MSVC/Wine sometimes fails to resolve relative-
|
||||
// looking includes passed as plain unix absolute paths (see
|
||||
// https://bugs.winehq.org/show_bug.cgi?id=55200); the fix is to rewrite
|
||||
// `-I/abs/path` into `-Iz:/abs/path` and similar, trying each option-prefix
|
||||
// shape in priority order until one matches.
|
||||
var (
|
||||
reOpt1 = regexp.MustCompile(`^[-/][A-Za-z](/.*)$`) // -I/path, /I/path
|
||||
reOpt2 = regexp.MustCompile(`^[-/][A-Za-z][A-Za-z](/.*)$`) // -Fo/path
|
||||
reOpt3 = regexp.MustCompile(`^[-/][A-Za-z][A-Za-z][A-Za-z]*:(/.*)$`) // -MANIFESTINPUT:/path
|
||||
reBare = regexp.MustCompile(`^(/.*)$`) // /abs/path alone
|
||||
)
|
||||
|
||||
// RewriteArgs rewrites absolute unix paths embedded in tool arguments into
|
||||
// "z:/abs/path" form, only when the path's parent directory actually exists
|
||||
// on disk and isn't "/" - matching the original bash's `[ -d "$(dirname ..)" ]`
|
||||
// guard, which keeps short flags like "/P" or "/D" untouched.
|
||||
func RewriteArgs(args []string) []string {
|
||||
out := make([]string, len(args))
|
||||
for i, a := range args {
|
||||
out[i] = rewriteArg(a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func rewriteArg(a string) string {
|
||||
var path string
|
||||
switch {
|
||||
case reOpt1.MatchString(a):
|
||||
path = reOpt1.FindStringSubmatch(a)[1]
|
||||
case reOpt2.MatchString(a):
|
||||
path = reOpt2.FindStringSubmatch(a)[1]
|
||||
case reOpt3.MatchString(a):
|
||||
path = reOpt3.FindStringSubmatch(a)[1]
|
||||
case reBare.MatchString(a):
|
||||
path = reBare.FindStringSubmatch(a)[1]
|
||||
default:
|
||||
return a
|
||||
}
|
||||
|
||||
dir := filepath.Dir(path)
|
||||
if dir == "/" {
|
||||
return a
|
||||
}
|
||||
fi, err := os.Stat(dir)
|
||||
if err != nil || !fi.IsDir() {
|
||||
return a
|
||||
}
|
||||
|
||||
prefix := a[:len(a)-len(path)]
|
||||
return prefix + "z:" + path
|
||||
}
|
||||
Reference in New Issue
Block a user