diff --git a/.ado/VSComponentList.ps1 b/.ado/VSComponentList.ps1 new file mode 100644 index 00000000000..bd27aca3c19 --- /dev/null +++ b/.ado/VSComponentList.ps1 @@ -0,0 +1,24 @@ +$dir = $env:temp +if ($env:Agent_TempDirectory -ne $null) +{ + $dir = $env:Agent_TempDirectory +} + +$installerPath = 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\' +$installationPath = . $installerPath\vswhere.exe -latest -property installationPath +$vsconfig = "$dir\vsconfig" +Write-Host "VSConfig will be at $vsconfig" + +Invoke-WebRequest -Uri 'https://download.visualstudio.microsoft.com/download/pr/c4fef23e-cc45-4836-9544-70e213134bc8/1ee5717e9a1e05015756dff77eb27d554a79a6db91f2716d836df368381af9a1/vs_Enterprise.exe' -OutFile $dir\vs_enterprise.exe +$p = Start-Process -PassThru $dir\vs_enterprise.exe -RedirectStandardError $dir\err -RedirectStandardOutput $dir\out -ArgumentList "export --installpath `"$installationPath`" --quiet --config $vsconfig" +$p.WaitForExit() +$x = [Datetime]::Now.AddSeconds(60) +while (!(Test-Path $vsconfig) -and ([datetime]::Now -lt $x)) +{ + Sleep 5 + Write-Host "Waiting for vsconfig file..." +} + +Get-Content $dir\err +Get-Content $dir\out +Get-Content $vsconfig \ No newline at end of file diff --git a/.ado/windows-vs-pr.yml b/.ado/windows-vs-pr.yml index aa4a649d5c8..602a9f187cb 100644 --- a/.ado/windows-vs-pr.yml +++ b/.ado/windows-vs-pr.yml @@ -473,7 +473,7 @@ jobs: vmImage: windows-2019 BuildPlatform: x64 UseRNFork: true - vsComponents: Microsoft.VisualStudio.Component.VC.v141.x86.x64 + vsComponents: Microsoft.VisualStudio.Component.VC.v141.x86.x64, Microsoft.VisualStudio.ComponentGroup.UWP.VC.v141 - job: RNWNugetPR displayName: Build and Pack Nuget diff --git a/change/react-native-windows-2019-10-15-18-17-54-v141path.json b/change/react-native-windows-2019-10-15-18-17-54-v141path.json new file mode 100644 index 00000000000..68e72d8c7b0 --- /dev/null +++ b/change/react-native-windows-2019-10-15-18-17-54-v141path.json @@ -0,0 +1,9 @@ +{ + "type": "none", + "comment": "Don't hardcode the path to v141 platform toolset", + "packageName": "react-native-windows", + "email": "asklar@winse.microsoft.com", + "commit": "5259e65b49ff7d0131cc7d731ca7bd3438b03776", + "date": "2019-10-16T01:17:54.674Z", + "file": "F:\\rnw\\change\\react-native-windows-2019-10-15-18-17-54-v141path.json" +} \ No newline at end of file diff --git a/vnext/local-cli/runWindows/utils/build.js b/vnext/local-cli/runWindows/utils/build.js index 102abe2b70f..48354bfccf2 100644 --- a/vnext/local-cli/runWindows/utils/build.js +++ b/vnext/local-cli/runWindows/utils/build.js @@ -25,14 +25,14 @@ async function buildSolution(slnFile, buildType, buildArch, verbose) { ); } - const msBuildTools = MSBuildTools.findAvailableVersion(); + const msBuildTools = MSBuildTools.findAvailableVersion(buildArch, verbose); await msBuildTools.buildProject(slnFile, buildType, buildArch, null, verbose); } -async function nugetRestore(nugetPath, slnFile, verbose) { +async function nugetRestore(nugetPath, slnFile, verbose, msbuildVersion) { const text = 'Restoring NuGets'; const spinner = newSpinner(text); - + console.log(nugetPath); await commandWithProgress( spinner, text, @@ -43,6 +43,8 @@ async function nugetRestore(nugetPath, slnFile, verbose) { '-NonInteractive', '-Verbosity', verbose ? 'normal' : 'quiet', + '-MSBuildVersion', + msbuildVersion, ], verbose, ); @@ -68,7 +70,13 @@ async function restoreNuGetPackages(options, slnFile, verbose) { } ensureNugetSpinner.succeed('Found NuGet Binary'); - await nugetRestore(nugetPath, slnFile, verbose); + const msbuildTools = MSBuildTools.findAvailableVersion('x86', verbose); + await nugetRestore( + nugetPath, + slnFile, + verbose, + msbuildTools.installationVersion, + ); } function getSolutionFile(options) { diff --git a/vnext/local-cli/runWindows/utils/msbuildtools.js b/vnext/local-cli/runWindows/utils/msbuildtools.js index 7149f6af4d6..e955dda5910 100644 --- a/vnext/local-cli/runWindows/utils/msbuildtools.js +++ b/vnext/local-cli/runWindows/utils/msbuildtools.js @@ -5,7 +5,6 @@ */ // @ts-check 'use strict'; - const EOL = require('os').EOL; const fs = require('fs'); const path = require('path'); @@ -25,16 +24,20 @@ const { const MSBUILD_VERSIONS = ['16.0', '15.0', '14.0', '12.0', '4.0']; class MSBuildTools { - constructor(version, localPath) { + // version is something like 16.0 for 2019 + // localPath is the path to MSBuild.exe (x86) + // installationVersion is the full version e.g. 16.3.29411.108 + constructor(version, localPath, installationVersion) { this.version = version; this.path = localPath; + this.installationVersion = installationVersion; } cleanProject(slnFile) { const cmd = `"${path.join( this.path, 'msbuild.exe', - )}" "${slnFile}" t/:Clean`; + )}" "${slnFile}" /t:Clean`; const results = child_process .execSync(cmd) .toString() @@ -57,19 +60,13 @@ class MSBuildTools { '/p:AppxBundle=Never', ]; + args.push('/p:PlatformToolset=v141'); + // Set platform toolset for VS 2017 (this way we can keep the base sln file working for VS 2015) if (this.version === '15.0') { - args.push('/p:PlatformToolset=v141'); args.push('/p:VisualStudioVersion=15.0'); - } - - // Set platform toolset for VS 2019 - if (this.version === '16.0') { - args.push('/p:PlatformToolset=v141'); + } else if (this.version === '16.0') { args.push('/p:VisualStudioVersion=16.0'); - args.push( - '/p:VCTargetsPath=C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Microsoft\\VC\\v150\\', - ); } if (config) { @@ -85,6 +82,8 @@ class MSBuildTools { return; } + console.log(`Running MSBuild with args ${args.join(' ')}`); + const progressName = 'Building Solution'; const spinner = newSpinner(progressName); await commandWithProgress( @@ -97,9 +96,7 @@ class MSBuildTools { } } -function checkMSBuildVersion(version) { - let toolsPath = null; - +function VSWhere(requires, version, property) { // This path is maintained and VS has promised to keep it valid. const vsWherePath = path.join( process.env['ProgramFiles(x86)'], @@ -110,70 +107,142 @@ function checkMSBuildVersion(version) { if (fs.existsSync(vsWherePath)) { const vsPath = child_process .execSync( - `"${vsWherePath}" -latest -products * Microsoft.Component.MSBuild -property installationPath`, + `"${vsWherePath}" -version [${version},${Number(version) + + 1}) -products * -requires ${requires} -property ${property}`, ) .toString() .split(EOL)[0]; - - // VS 2019 changed path naming convention - const vsVersion = version === '16.0' ? 'Current' : version; - - // look for the specified version of msbuild - const msBuildPath = path.join( - vsPath, - 'MSBuild', - vsVersion, - 'Bin/MSBuild.exe', - ); - - toolsPath = fs.existsSync(msBuildPath) ? path.dirname(msBuildPath) : null; + return vsPath; } else { const query = `reg query HKLM\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\${version} /s /v MSBuildToolsPath`; + let toolsPath = null; // Try to get the MSBuild path using registry try { const output = child_process.execSync(query).toString(); let toolsPathOutput = /MSBuildToolsPath\s+REG_SZ\s+(.*)/i.exec(output); if (toolsPathOutput) { - toolsPathOutput = toolsPathOutput[1]; + let toolsPathOutputStr = toolsPathOutput[1]; // Win10 on .NET Native uses x86 arch compiler, if using x64 Node, use x86 tools if ( version === '15.0' || - (version === '14.0' && toolsPath.indexOf('amd64') > -1) + (version === '14.0' && toolsPathOutputStr.indexOf('amd64') > -1) ) { - toolsPathOutput = path.resolve(toolsPathOutput, '..'); + toolsPathOutputStr = path.resolve(toolsPathOutputStr, '..'); } - toolsPath = toolsPathOutput; + toolsPath = toolsPathOutputStr; } } catch (e) { toolsPath = null; } + return toolsPath; + } +} + +function getVC141Component(version, buildArch) { + if (version === '16.0') { + switch (buildArch.toLowerCase()) { + case 'x86': + case 'x64': + return 'Microsoft.VisualStudio.Component.VC.v141.x86.x64'; + case 'arm': + return 'Microsoft.VisualStudio.Component.VC.v141.ARM'; + case 'arm64': + return 'Microsoft.VisualStudio.Component.VC.v141.ARM64'; + } + } else { + switch (buildArch.toLowerCase()) { + case 'x86': + case 'x64': + return 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64'; + case 'arm': + return 'Microsoft.VisualStudio.Component.VC.Tools.ARM'; + case 'arm64': + return 'Microsoft.VisualStudio.Component.VC.Tools.ARM64'; + } } +} + +function checkMSBuildVersion(version, buildArch, verbose) { + let toolsPath = null; + if (verbose) { + console.log('Searching for MSBuild version ' + version); + } + + // https://aka.ms/vs/workloads + const requires16 = [ + 'Microsoft.Component.MSBuild', + getVC141Component(version, buildArch), + 'Microsoft.VisualStudio.ComponentGroup.UWP.VC.v141', + ]; + const requires15 = [ + 'Microsoft.Component.MSBuild', + getVC141Component(version, buildArch), + 'Microsoft.VisualStudio.ComponentGroup.UWP.VC', + ]; + + const requires = version === '16.0' ? requires16 : requires15; + + const vsPath = VSWhere(requires.join(' '), version, 'installationPath'); + const installationVersion = VSWhere( + requires.join(' '), + version, + 'installationVersion', + ); + // VS 2019 changed path naming convention + const vsVersion = version === '16.0' ? 'Current' : version; + + // look for the specified version of msbuild + const msBuildPath = path.join( + vsPath, + 'MSBuild', + vsVersion, + 'Bin/MSBuild.exe', + ); + + toolsPath = fs.existsSync(msBuildPath) ? path.dirname(msBuildPath) : null; // We found something so return MSBuild Tools. if (toolsPath) { - newSuccess(`Found MSBuild v${version} at ${toolsPath}`); - return new MSBuildTools(version, toolsPath); + newSuccess( + `Found MSBuild v${version} at ${toolsPath} (${installationVersion})`, + ); + return new MSBuildTools(version, toolsPath, installationVersion); } else { return null; } } -module.exports.findAvailableVersion = function() { - const versions = MSBUILD_VERSIONS.map(checkMSBuildVersion); +module.exports.findAvailableVersion = function(buildArch, verbose) { + const versions = + process.env.VisualStudioVersion != null + ? [ + checkMSBuildVersion( + process.env.VisualStudioVersion, + buildArch, + verbose, + ), + ] + : MSBUILD_VERSIONS.map(function(value) { + return checkMSBuildVersion(value, buildArch, verbose); + }); const msbuildTools = versions.find(Boolean); if (!msbuildTools) { - throw new Error('MSBuild tools not found'); + if (process.env.VisualStudioVersion != null) { + throw new Error( + `MSBuild tools not found for version ${ + process.env.VisualStudioVersion + } (from environment). Make sure all required components have been installed (e.g. v141 support)`, + ); + } else { + throw new Error( + 'MSBuild tools not found. Make sure all required components have been installed (e.g. v141 support)', + ); + } } - return msbuildTools; }; -module.exports.findAllAvailableVersions = function() { - console.log(chalk.green('Searching for available MSBuild versions...')); - return MSBUILD_VERSIONS.map(checkMSBuildVersion).filter(item => !!item); -}; - module.exports.getAllAvailableUAPVersions = function() { const results = [];