Skip to content

Commit

Permalink
Fixes msvc2015 detection when only vs2019 are installed. (#1955)
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Andreea Isac <[email protected]>
  • Loading branch information
lygstate authored Jul 12, 2021
1 parent 721314b commit 1aa0fb6
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 39 deletions.
137 changes: 102 additions & 35 deletions src/kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Map<string, string>|undefined> {
const fname = Math.random().toString() + '.bat';
const batfname = `vs-cmt-${fname}`;
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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;
}

Expand Down Expand Up @@ -790,25 +858,25 @@ const VsGenerators: {[key: string]: string} = {
async function varsForVSInstallation(inst: VSInstallation, hostArch: string, targetArch?: string): Promise<Map<string, string>|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 {
Expand Down Expand Up @@ -900,11 +968,10 @@ export async function scanForVSKits(pr?: ProgressReporter): Promise<Kit[]> {
const installs = await vsInstallations();
const prs = installs.map(async(inst): Promise<Kit[]> => {
const ret = [] as Kit[];
const hostArches: string[] = ['x86', 'x64'];
const targetArches: string[] = ['x86', 'x64', 'arm', 'arm64'];

const sub_prs: Promise<Kit | null>[] = [];
hostArches.forEach(hostArch => {
MSVC_HOST_ARCHES.forEach(hostArch => {
targetArches.forEach(targetArch => {
const kit: Promise<Kit | null> = tryCreateNewVCEnvironment(inst, hostArch, targetArch, pr);
if (kit) {
Expand Down
18 changes: 14 additions & 4 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`;
}
Expand Down

0 comments on commit 1aa0fb6

Please sign in to comment.