From 3b737565fa87b2d9b23f8395a741877b0f92cd75 Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Sun, 27 Jun 2021 01:31:15 +0800 Subject: [PATCH] Fixes msvc2015 detection when only vs2019 are installed. Currently msvc2015 detection will detected without proper Windows SDK path so fixes it by patching the Windows SDK path Also by the help of Andreea Isac, fix arm/aarch64 detection Signed-off-by: Yonggang Luo Signed-off-by: Andreea Isac --- src/kit.ts | 137 ++++++++++++++++++++++++++++++++++++++-------------- src/util.ts | 18 +++++-- 2 files changed, 116 insertions(+), 39 deletions(-) diff --git a/src/kit.ts b/src/kit.ts index 58ce43039..3d17d50a8 100644 --- a/src/kit.ts +++ b/src/kit.ts @@ -554,41 +554,86 @@ export function kitHostTargetArch(hostArch: string, targetArch?: string, amd64Al } /** + * Possible msvc host architectures + */ +export const MSVC_HOST_ARCHES: string[] = ['x86', 'x64']; + +/* * List of environment variables required for Visual C++ to run as expected for * a VS installation. + * The diff of vcvarsall.bat output env and system env: + DevEnvDir=C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\ + Framework40Version=v4.0 + FrameworkDir=C:\Windows\Microsoft.NET\Framework\ + FrameworkDIR32=C:\Windows\Microsoft.NET\Framework\ + FrameworkVersion=v4.0.30319 + FrameworkVersion32=v4.0.30319 + INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ATLMFC\INCLUDE;C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\ucrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\winrt; + LIB=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\ARM;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ATLMFC\LIB\ARM;C:\Program Files (x86)\Windows Kits\10\lib\10.0.14393.0\ucrt\ARM;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\lib\um\ARM;C:\Program Files (x86)\Windows Kits\10\lib\10.0.14393.0\um\ARM; + LIBPATH=C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\ARM;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ATLMFC\LIB\ARM;C:\Program Files (x86)\Windows Kits\10\UnionMetadata;C:\Program Files (x86)\Windows Kits\10\References;\Microsoft.VCLibs\14.0\References\CommonConfiguration\neutral; + NETFXSDKDir=C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\ + Path=C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files (x86)\MSBuild\14.0\bin;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_ARM;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools;C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\VCPackages;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Performance Tools;C:\Program Files (x86)\Windows Kits\10\bin\x86;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\Microsoft VS Code\bin;C:\Program Files\CMake\bin;C:\Program Files\Git\cmd;C:\Program Files\TortoiseGit\bin;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\ + Platform=ARM + UCRTVersion=10.0.14393.0 + UniversalCRTSdkDir=C:\Program Files (x86)\Windows Kits\10\ + user_inputversion=10.0.14393.0 + VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\ + VisualStudioVersion=14.0 + VSINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio 14.0\ + WindowsLibPath=C:\Program Files (x86)\Windows Kits\10\UnionMetadata;C:\Program Files (x86)\Windows Kits\10\References + WindowsSdkDir=C:\Program Files (x86)\Windows Kits\10\ + WindowsSDKLibVersion=10.0.14393.0\ + WindowsSDKVersion=10.0.14393.0\ + WindowsSDK_ExecutablePath_x64=C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\ + WindowsSDK_ExecutablePath_x86=C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\ + * */ const MSVC_ENVIRONMENT_VARIABLES = [ - 'CL', - '_CL_', + /* These is the diff of vcvarsall.bat generated env and original system env */ + 'DevEnvDir', + 'Framework40Version', + 'FrameworkDir', + 'FrameworkDIR32', + 'FrameworkDIR64', + 'FrameworkVersion', + 'FrameworkVersion32', + 'FrameworkVersion64', 'INCLUDE', + 'LIB', 'LIBPATH', + 'NETFXSDKDir', + 'Path', + 'Platform', + 'UCRTVersion', + 'UniversalCRTSdkDir', + 'user_inputversion', + 'VCINSTALLDIR', + 'VisualStudioVersion', + 'VSINSTALLDIR', + 'WindowsLibPath', + 'WindowsSdkDir', + 'WindowsSDKLibVersion', + 'WindowsSDKVersion', + 'WindowsSDK_ExecutablePath_x64', + 'WindowsSDK_ExecutablePath_x86', + + /* These are special also need to be cached */ + 'CL', + '_CL_', 'LINK', '_LINK_', - 'LIB', - 'PATH', 'TMP', - 'FRAMEWORKDIR', - 'FRAMEWORKDIR64', - 'FRAMEWORKVERSION', - 'FRAMEWORKVERSION64', 'UCRTCONTEXTROOT', - 'UCRTVERSION', - 'UNIVERSALCRTSDKDIR', - 'VCINSTALLDIR', - 'VCTARGETSPATH', - 'WINDOWSLIBPATH', - 'WINDOWSSDKDIR', - 'WINDOWSSDKLIBVERSION', - 'WINDOWSSDKVERSION', - 'VISUALSTUDIOVERSION' + 'VCTARGETSPATH' ]; /** * Get the environment variables corresponding to a VS dev batch file. + * @param hostArch Host arch used to find the proper Windows SDK path * @param devbat Path to a VS environment batch file * @param args List of arguments to pass to the batch file */ -async function collectDevBatVars(devbat: string, args: string[], major_version: number, common_dir: string): +async function collectDevBatVars(hostArch: string, devbat: string, args: string[], major_version: number, common_dir: string): Promise|undefined> { const fname = Math.random().toString() + '.bat'; const batfname = `vs-cmt-${fname}`; @@ -603,7 +648,7 @@ async function collectDevBatVars(devbat: string, args: string[], major_version: `cd /d "%~dp0"` /* Switch back to original drive */ ]; for (const envvar of MSVC_ENVIRONMENT_VARIABLES) { - bat.push(`echo ${envvar} := %${envvar}% >> ${envfname}`); + bat.push(`if DEFINED ${envvar} echo ${envvar} := %${envvar}% >> ${envfname}`); } // writeFile and unlink don't need quotes (they work just fine with an unquoted path with space) @@ -651,11 +696,8 @@ async function collectDevBatVars(devbat: string, args: string[], major_version: await fs.unlink(envpath); } catch (error) { log.error(error); } - if (!env || env === '') { - log.error(localize('script.run.error', - 'Error running:{0} with args:{1}\nOutput are:\n{2}\nBat content are:\n{3}', - devbat, args.join(' '), output, batContent)); - return; + if (!env) { + env = ''; } const vars @@ -668,13 +710,39 @@ async function collectDevBatVars(devbat: string, args: string[], major_version: } return acc; }, new Map()); - if (vars.get('INCLUDE') === '') { + const include_env = vars.get('INCLUDE') ?? ''; + if (include_env === '') { log.error(localize('script.run.error.check', - 'Error running:{0} with args:{1}\nCannot find INCLUDE within:\n{2}\nBat content are:\n{3}', - devbat, args.join(' '), env, batContent)); + 'Error running:{0} with args:{1}\nCannot find INCLUDE within:\n{2}\nBat content are:\n{3}\nExecute output are:\n{4}\n', + devbat, args.join(' '), env, batContent, output)); return; } - log.debug(localize('ok.running', 'OK running {0} {1}, env vars: {2}', devbat, args.join(' '), JSON.stringify([...vars]))); + + let WindowsSDKVersionParsed: util.Version = { + major: 0, + minor: 0, + patch: 0 + }; + const WindowsSDKVersion = vars.get('WindowsSDKVersion') ?? '0.0.0'; + try { + WindowsSDKVersionParsed = util.parseVersion(WindowsSDKVersion); + } catch (err) { + log.error(`Parse '${WindowsSDKVersion}' failed`); + } + if (util.compareVersion(WindowsSDKVersionParsed, {major: 10, minor: 0, patch: 14393}) >= 0) { + const WindowsSdkDir = vars.get('WindowsSdkDir') ?? ''; + const existPath = vars.get('PATH') ?? ''; + const oldWinSdkBinPath = path.join(WindowsSdkDir, 'bin', hostArch); + const newWinSdkBinPath = path.join(WindowsSdkDir, 'bin', WindowsSDKVersion, hostArch); + if (existPath.toLowerCase().indexOf(oldWinSdkBinPath.toLowerCase()) >= 0 + && existPath.toLowerCase().indexOf(newWinSdkBinPath.toLowerCase()) < 0) { + log.info(localize('windows.sdk.path.patch', 'Patch Windows SDK bin path from {0} to {1} for {2}', + oldWinSdkBinPath, newWinSdkBinPath, devbat)); + vars.set('PATH', `${newWinSdkBinPath};${existPath}`); + } + } + log.debug(localize('ok.running', 'OK running {0} {1}, env vars: {2}', + devbat, args.join(' '), JSON.stringify([...vars], null, 2))); return vars; } @@ -790,25 +858,25 @@ const VsGenerators: {[key: string]: string} = { async function varsForVSInstallation(inst: VSInstallation, hostArch: string, targetArch?: string): Promise|null> { console.log(`varsForVSInstallation path:'${inst.installationPath}' version:${inst.installationVersion} host arch:${hostArch} - target arch:${targetArch}`); const common_dir = path.join(inst.installationPath, 'Common7', 'Tools'); + const majorVersion = parseInt(inst.installationVersion); let vcvarsScript: string = 'vcvarsall.bat'; if (targetArch === "arm" || targetArch === "arm64") { // The arm(64) vcvars filename for x64 hosted toolset is using the 'amd64' alias. vcvarsScript = `vcvars${kitHostTargetArch(hostArch, targetArch, true)}.bat`; } - - let devbat = path.join(inst.installationPath, 'VC', 'Auxiliary', 'Build', vcvarsScript); - const majorVersion = parseInt(inst.installationVersion); + let devBatFolder = path.join(inst.installationPath, 'VC', 'Auxiliary', 'Build'); if (majorVersion < 15) { - devbat = path.join(inst.installationPath, 'VC', vcvarsScript); + devBatFolder = path.join(inst.installationPath, 'VC'); } + const devbat = path.join(devBatFolder, vcvarsScript); // The presence of vcvars[hostArch][targetArch].bat indicates whether targetArch is included // in the given VS installation. if (!await fs.exists(devbat)) { return null; } - const variables = await collectDevBatVars(devbat, [kitHostTargetArch(hostArch, targetArch, majorVersion < 15)], majorVersion, common_dir); + const variables = await collectDevBatVars(hostArch, devbat, [kitHostTargetArch(hostArch, targetArch, majorVersion < 15)], majorVersion, common_dir); if (!variables) { return null; } else { @@ -900,11 +968,10 @@ export async function scanForVSKits(pr?: ProgressReporter): Promise { const installs = await vsInstallations(); const prs = installs.map(async(inst): Promise => { const ret = [] as Kit[]; - const hostArches: string[] = ['x86', 'x64']; const targetArches: string[] = ['x86', 'x64', 'arm', 'arm64']; const sub_prs: Promise[] = []; - hostArches.forEach(hostArch => { + MSVC_HOST_ARCHES.forEach(hostArch => { targetArches.forEach(targetArch => { const kit: Promise = tryCreateNewVCEnvironment(inst, hostArch, targetArch, pr); if (kit) { diff --git a/src/util.ts b/src/util.ts index 77a7ae805..3d9263071 100644 --- a/src/util.ts +++ b/src/util.ts @@ -325,19 +325,29 @@ export interface Version { patch: number; } export function parseVersion(str: string): Version { - const version_re = /(\d+)\.(\d+)\.(\d+)/; + const version_re = /(\d+)\.(\d+)\.(\d+)(.*)/; const mat = version_re.exec(str); if (!mat) { throw new InvalidVersionString(localize('invalid.version.string', 'Invalid version string {0}', str)); } const [, major, minor, patch] = mat; return { - major: parseInt(major), - minor: parseInt(minor), - patch: parseInt(patch) + major: parseInt(major ?? '0'), + minor: parseInt(minor ?? '0'), + patch: parseInt(patch ?? '0') }; } +export function compareVersion(va: Version, vb: Version) { + if (va.major !== vb.major) { + return va.major - vb.major; + } + if (va.minor !== vb.minor) { + return va.minor - vb.minor; + } + return va.patch - vb.patch; +} + export function versionToString(ver: Version): string { return `${ver.major}.${ver.minor}.${ver.patch}`; }