mirror of
https://github.com/Cheviiot/Vintner.git
synced 2026-08-03 15:57:24 +00:00
vintner only ever downloads one compiler generation, but real-world .vcxproj files are pinned to whichever PlatformToolset they were last saved under - v142 (VS2019) for anything not actively maintained is extremely common. MSBuild checks toolset "installed-ness" (MSB8020) by testing whether MSBuild/Microsoft/VC/v<schema>/Platforms/<arch>/ PlatformToolsets/<toolset>/ exists on disk - a plain file lookup our downloaded MSBuild package only satisfies for the exact generation it shipped. `install` now symlinks every historical numeric PlatformToolset name (v90 through v143) onto whichever real toolset directory is actually present, so any of them resolves transparently; Toolset.props/ .targets don't hardcode a version number, so aliasing is correct, not just a workaround. Three more MSBuild property/environment issues came with it, all found building a real years-old project against the one modern toolchain vintner installs: - VCInstallDir_<N>/VCToolsInstallDir_<N> needed a third numbering source (PlatformToolset short names from Microsoft.VCToolsVersion. v<N>.default.props) alongside the existing MSBuild schema-version and known-toolset lists, so the env-var-driven half of toolset resolution covers the same names the on-disk alias does. - VCToolsVersion must be a real version string: left unset, it falls back to a literal placeholder that then hits an unconditional version-string comparison elsewhere in Microsoft.CppBuild.targets (MSB4184). Setting it to the real installed version in turn requires CheckMSVCComponents=false, since CheckVCToolsetVersion (MSB8052) otherwise rejects an aliased PlatformToolset whenever its numeric generation doesn't match VCToolsVersion's - exactly the case aliasing creates on purpose. Everything else CheckMSVCComponents gates is diagnostic-only (MFC/ATL/Spectre presence warnings), so disabling it costs nothing else. - WindowsTargetPlatformVersion needed to become an explicit /p: global property on the msbuild command line, not just an env var: legacy .vcxproj files commonly hardcode this in a PropertyGroup, and an explicit project assignment always wins over an inherited environment variable of the same name. A command-line global property is the one thing a project file can't override. Only injected when the caller hasn't already pinned it themselves.
107 lines
3.4 KiB
Go
107 lines
3.4 KiB
Go
package install
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/Cheviiot/vintner/internal/wineenv"
|
|
)
|
|
|
|
func TestAliasPlatformToolsetsAliasesRealToolset(t *testing.T) {
|
|
dest := t.TempDir()
|
|
toolsetsDir := filepath.Join(dest, "MSBuild", "Microsoft", "VC", "v180", "Platforms", "x64", "PlatformToolsets")
|
|
realDir := filepath.Join(toolsetsDir, "v145")
|
|
if err := os.MkdirAll(realDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(realDir, "Toolset.props"), []byte("<Project/>"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// A WDK toolset entry alongside it - must not be mistaken for the real
|
|
// numeric toolset or itself get aliased over.
|
|
if err := os.MkdirAll(filepath.Join(toolsetsDir, "WindowsKernelModeDriver10.0"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := aliasPlatformToolsets(dest); err != nil {
|
|
t.Fatalf("aliasPlatformToolsets: %v", err)
|
|
}
|
|
|
|
for _, n := range wineenv.KnownPlatformToolsets {
|
|
alias := filepath.Join(toolsetsDir, "v"+n)
|
|
fi, err := os.Lstat(alias)
|
|
if err != nil {
|
|
t.Errorf("expected v%s alias to exist: %v", n, err)
|
|
continue
|
|
}
|
|
if fi.Mode()&os.ModeSymlink == 0 {
|
|
t.Errorf("v%s should be a symlink, got mode %v", n, fi.Mode())
|
|
continue
|
|
}
|
|
target, err := os.Readlink(alias)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if target != "v145" {
|
|
t.Errorf("v%s symlink target = %q, want \"v145\"", n, target)
|
|
}
|
|
// Follow the alias and confirm it actually reaches the real content.
|
|
if !isFile(filepath.Join(toolsetsDir, "v"+n, "Toolset.props")) {
|
|
t.Errorf("v%s/Toolset.props not reachable through the alias", n)
|
|
}
|
|
}
|
|
|
|
if exists(filepath.Join(toolsetsDir, "WindowsKernelModeDriver10.0", "v"+wineenv.KnownPlatformToolsets[0])) {
|
|
t.Error("WDK toolset directory should not have been touched")
|
|
}
|
|
}
|
|
|
|
func TestAliasPlatformToolsetsDoesNotOverwriteExisting(t *testing.T) {
|
|
dest := t.TempDir()
|
|
toolsetsDir := filepath.Join(dest, "MSBuild", "Microsoft", "VC", "v180", "Platforms", "x64", "PlatformToolsets")
|
|
if err := os.MkdirAll(filepath.Join(toolsetsDir, "v145"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// v142 already genuinely installed (e.g. a real VS install with several
|
|
// side-by-side toolsets) - must be left alone, not replaced with an alias.
|
|
real142 := filepath.Join(toolsetsDir, "v142")
|
|
if err := os.MkdirAll(real142, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(real142, "Toolset.props"), []byte("<!-- real v142 -->"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := aliasPlatformToolsets(dest); err != nil {
|
|
t.Fatalf("aliasPlatformToolsets: %v", err)
|
|
}
|
|
|
|
fi, err := os.Lstat(real142)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if fi.Mode()&os.ModeSymlink != 0 {
|
|
t.Error("pre-existing v142 directory should not have been replaced with a symlink")
|
|
}
|
|
}
|
|
|
|
func TestAliasPlatformToolsetsNoNumericToolset(t *testing.T) {
|
|
dest := t.TempDir()
|
|
// Only a WDK-style toolset present, nothing numeric to alias from.
|
|
toolsetsDir := filepath.Join(dest, "MSBuild", "Microsoft", "VC", "v180", "Platforms", "x64", "PlatformToolsets")
|
|
if err := os.MkdirAll(filepath.Join(toolsetsDir, "WindowsUserModeDriver10.0"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := aliasPlatformToolsets(dest); err != nil {
|
|
t.Fatalf("aliasPlatformToolsets: %v", err)
|
|
}
|
|
|
|
for _, n := range wineenv.KnownPlatformToolsets {
|
|
if exists(filepath.Join(toolsetsDir, "v"+n)) {
|
|
t.Errorf("v%s should not have been created with no real numeric toolset present", n)
|
|
}
|
|
}
|
|
}
|