From b2260a9901893e3de0eeb1329076f8e9929bc884 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Fri, 3 Mar 2017 12:05:09 -0500 Subject: [PATCH] fix #157: detect vs2017 (vc141) and setup environment --- .gitignore | 1 + src/engine/build.bat | 8 +- src/tools/msvc.jam | 38 ++- src/tools/vc141helper/GetCLPath.ps1 | 13 + .../vc141helper/GetVS2017Configuration.cs | 267 ++++++++++++++++++ src/tools/vc141helper/cl141_path.cmd | 16 ++ 6 files changed, 334 insertions(+), 9 deletions(-) create mode 100644 src/tools/vc141helper/GetCLPath.ps1 create mode 100644 src/tools/vc141helper/GetVS2017Configuration.cs create mode 100644 src/tools/vc141helper/cl141_path.cmd diff --git a/.gitignore b/.gitignore index 500fe4bcf4..4a59be5083 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ /bin /bootstrap.log /test/test_results.txt +.tmp.json diff --git a/src/engine/build.bat b/src/engine/build.bat index 64053e3bac..c3d9a8f793 100644 --- a/src/engine/build.bat +++ b/src/engine/build.bat @@ -98,12 +98,14 @@ REM location of the found toolset. call :Clear_Error call :Test_Empty %ProgramFiles% -if not errorlevel 1 set ProgramFiles=C:\Program Files +if not errorlevel 1 set "ProgramFiles=C:\Program Files" call :Clear_Error -if NOT "_%VS150COMNTOOLS%_" == "__" ( +SET cl141cmd="%~dp0..\tools\vc141helper\cl141_path.cmd" +for /F "tokens=*" %%A IN ('cmd /D /S /C "%cl141cmd% InstallationPath"') DO if NOT "_%%A_" == "__" ( + if errorlevel 1 goto :eof set "BOOST_JAM_TOOLSET=vc1410" - set "BOOST_JAM_TOOLSET_ROOT=%VS150COMNTOOLS%..\..\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%%A\VC\" goto :eof) call :Clear_Error if EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( diff --git a/src/tools/msvc.jam b/src/tools/msvc.jam index 3f8f49e68b..2b3426cba4 100644 --- a/src/tools/msvc.jam +++ b/src/tools/msvc.jam @@ -708,6 +708,19 @@ local rule auto-detect-toolset-versions ( ) # Get installation paths from the registry. for local i in $(.known-versions) { + if $(i) = 14.10 + { + local file = [ path.make [ modules.binding $(__name__) ] ] ; + local cl141_path = [ path.native [ path.join [ path.parent $(file) ] vc141helper cl141_path.cmd ] ] ; + local shell_ret = [ SHELL $(cl141_path) ] ; + local cl_path = $(shell_ret:D) ; + if $(cl_path) + { + path = [ path.native $(cl_path) ] ; + register-configuration $(i) : $(path) ; + } + } + if $(.version-$(i)-reg) { local vc-path ; @@ -820,7 +833,16 @@ local rule generate-setup-cmd ( version : command : parent : options * : cpu : g } else { + if [ MATCH "(14.10)" : $(version) ] + { + if $(.debug-configuration) + { + ECHO 'notice: [generate-setup-cmd] $(version) is 14.10' ; + } + parent = [ path.native [ path.join $(parent) "..\\..\\..\\..\\..\\Auxiliary\\Build" ] ] ; + } setup = [ locate-default-setup $(command) : $(parent) : $(default-setup) ] ; + setup ?= [ path.join $(parent) "vcvarsall.bat" ] ; } } @@ -894,6 +916,10 @@ local rule configure-really ( version ? : options * ) local command = [ feature.get-values : $(options) ] ; + # For 14.10 we need the exact version as MS is planning rolling updates + # that will cause our `setup-cmd` to become invalid + exact-version = [ MATCH "(14\.10\.[0-9\.]+)" : $(command) ] ; + # If version is specified, we try to search first in default paths, and # only then in PATH. command = [ common.get-invocation-command msvc : cl.exe : $(command) : @@ -907,9 +933,9 @@ local rule configure-really ( version ? : options * ) # version from the path. # FIXME: We currently detect both Microsoft Visual Studio 9.0 and # 9.0express as 9.0 here. - if [ MATCH "(Microsoft Visual Studio 15)" : $(command) ] + if [ MATCH "(MSVC\\14.10)" : $(command) ] { - version = 15.0 ; + version = 14.10 ; } else if [ MATCH "(Microsoft Visual Studio 14)" : $(command) ] { @@ -1073,7 +1099,8 @@ local rule configure-really ( version ? : options * ) for local c in $(cpu) { - setup-$(c) = [ generate-setup-cmd $(version) : $(command) : $(parent) : $(options) : $(c) : $(global-setup) : $(default-global-setup-options-$(c)) : $(default-setup-$(c)) ] ; + exact-version ?= $(version) ; + setup-$(c) = [ generate-setup-cmd $(exact-version) : $(command) : $(parent) : $(options) : $(c) : $(global-setup) : $(default-global-setup-options-$(c)) : $(default-setup-$(c)) ] ; } # Windows phone has different setup scripts, located in a different directory hierarchy. @@ -1595,7 +1622,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] armv7 armv7s ; # Known toolset versions, in order of preference. -.known-versions = 15.0 14.0 12.0 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 +.known-versions = 14.10 14.0 12.0 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ; # Version aliases. @@ -1608,7 +1635,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] .version-alias-11 = 11.0 ; .version-alias-12 = 12.0 ; .version-alias-14 = 14.0 ; -.version-alias-15 = 15.0 ; +.version-alias-15 = 14.10 ; # Names of registry keys containing the Visual C++ installation path (relative # to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft"). @@ -1624,7 +1651,6 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] .version-11.0-reg = "VisualStudio\\11.0\\Setup\\VC" ; .version-12.0-reg = "VisualStudio\\12.0\\Setup\\VC" ; .version-14.0-reg = "VisualStudio\\14.0\\Setup\\VC" ; -.version-15.0-reg = "VisualStudio\\15.0\\Setup\\VC" ; # Visual C++ Toolkit 2003 does not store its installation path in the registry. # The environment variable 'VCToolkitInstallDir' and the default installation diff --git a/src/tools/vc141helper/GetCLPath.ps1 b/src/tools/vc141helper/GetCLPath.ps1 new file mode 100644 index 0000000000..3198610b15 --- /dev/null +++ b/src/tools/vc141helper/GetCLPath.ps1 @@ -0,0 +1,13 @@ +# Copyright 2017 - Refael Ackermann +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +if (-NOT (Test-Path 'Registry::HKEY_CLASSES_ROOT\CLSID\{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}')) { Exit 1 } +$jsonFile = '.tmp.json' +Invoke-Expression 'powershell -NoProfile -ExecutionPolicy Unrestricted -Command "&{ Add-Type -Path GetVS2017Configuration.cs; [VisualStudioConfiguration.Main]::Query()}"' > $jsonFile +$instPath = (Get-Content $jsonFile | ? {$_ -like "*InstallationPath*"}) -split '"' -replace '\\\\', '\' | Select-Object -skip 3 -first 1 +if ($args[0] -eq 'InstallationPath') { echo $instPath; exit } +if ($env:PROCESSOR_ARCHITEW6432 -ne $null) {$filt = '*64\x64*'} else {$filt = '*86\x86*'} +$cls = get-childitem $instPath -Include cl.exe -Recurse | ? { $_.Directory -like '*Host*' } +$cl = $cls | ? { $_.Directory -like $filt } +if ($cl -ne $null) {echo $cl.FullName} else {echo $cls[0].FullName} diff --git a/src/tools/vc141helper/GetVS2017Configuration.cs b/src/tools/vc141helper/GetVS2017Configuration.cs new file mode 100644 index 0000000000..ee26c65c36 --- /dev/null +++ b/src/tools/vc141helper/GetVS2017Configuration.cs @@ -0,0 +1,267 @@ +// Copyright 2017 - Refael Ackermann +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace VisualStudioConfiguration +{ + [Flags] + public enum InstanceState : uint + { + None = 0, + Local = 1, + Registered = 2, + NoRebootRequired = 4, + NoErrors = 8, + Complete = 4294967295, + } + + [Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface IEnumSetupInstances + { + + void Next([MarshalAs(UnmanagedType.U4), In] int celt, + [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface), Out] ISetupInstance[] rgelt, + [MarshalAs(UnmanagedType.U4)] out int pceltFetched); + + void Skip([MarshalAs(UnmanagedType.U4), In] int celt); + + void Reset(); + + [return: MarshalAs(UnmanagedType.Interface)] + IEnumSetupInstances Clone(); + } + + [Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ISetupConfiguration + { + } + + [Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ISetupConfiguration2 : ISetupConfiguration + { + + [return: MarshalAs(UnmanagedType.Interface)] + IEnumSetupInstances EnumInstances(); + + [return: MarshalAs(UnmanagedType.Interface)] + ISetupInstance GetInstanceForCurrentProcess(); + + [return: MarshalAs(UnmanagedType.Interface)] + ISetupInstance GetInstanceForPath([MarshalAs(UnmanagedType.LPWStr), In] string path); + + [return: MarshalAs(UnmanagedType.Interface)] + IEnumSetupInstances EnumAllInstances(); + } + + [Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ISetupInstance + { + } + + [Guid("89143C9A-05AF-49B0-B717-72E218A2185C")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ISetupInstance2 : ISetupInstance + { + [return: MarshalAs(UnmanagedType.BStr)] + string GetInstanceId(); + + [return: MarshalAs(UnmanagedType.Struct)] + System.Runtime.InteropServices.ComTypes.FILETIME GetInstallDate(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetInstallationName(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetInstallationPath(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetInstallationVersion(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetDisplayName([MarshalAs(UnmanagedType.U4), In] int lcid); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetDescription([MarshalAs(UnmanagedType.U4), In] int lcid); + + [return: MarshalAs(UnmanagedType.BStr)] + string ResolvePath([MarshalAs(UnmanagedType.LPWStr), In] string pwszRelativePath); + + [return: MarshalAs(UnmanagedType.U4)] + InstanceState GetState(); + + [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)] + ISetupPackageReference[] GetPackages(); + + ISetupPackageReference GetProduct(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetProductPath(); + + [return: MarshalAs(UnmanagedType.VariantBool)] + bool IsLaunchable(); + + [return: MarshalAs(UnmanagedType.VariantBool)] + bool IsComplete(); + + [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)] + ISetupPropertyStore GetProperties(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetEnginePath(); + } + + [Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ISetupPackageReference + { + + [return: MarshalAs(UnmanagedType.BStr)] + string GetId(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetVersion(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetChip(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetLanguage(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetBranch(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetType(); + + [return: MarshalAs(UnmanagedType.BStr)] + string GetUniqueId(); + + [return: MarshalAs(UnmanagedType.VariantBool)] + bool GetIsExtension(); + } + + [Guid("c601c175-a3be-44bc-91f6-4568d230fc83")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [ComImport] + public interface ISetupPropertyStore + { + + [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] + string[] GetNames(); + + object GetValue([MarshalAs(UnmanagedType.LPWStr), In] string pwszName); + } + + [Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")] + [CoClass(typeof(SetupConfigurationClass))] + [ComImport] + public interface SetupConfiguration : ISetupConfiguration2, ISetupConfiguration + { + } + + [Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")] + [ClassInterface(ClassInterfaceType.None)] + [ComImport] + public class SetupConfigurationClass + { + } + + public static class Main + { + + public static void Echo(string tmplt, params Object[] args) + { + string str = (args.Length > 0) ? String.Format(tmplt, args) : tmplt; + Console.Write(" " + str + '\n'); + } + + public static void Query() + { + ISetupConfiguration query = new SetupConfiguration(); + ISetupConfiguration2 query2 = (ISetupConfiguration2) query; + IEnumSetupInstances e = query2.EnumAllInstances(); + ISetupInstance2[] rgelt = new ISetupInstance2[1]; + int pceltFetched; + Echo("["); + e.Next(1, rgelt, out pceltFetched); + while (pceltFetched > 0) + { + PrintInstance(rgelt[0]); + e.Next(1, rgelt, out pceltFetched); + if (pceltFetched > 0) + Echo(","); + } + Echo("]"); + } + + private static void PrintInstance(ISetupInstance2 setupInstance2) + { + Echo("{"); + string[] prodParts = setupInstance2.GetProduct().GetId().Split('.'); + Array.Reverse(prodParts); + string prod = prodParts[0]; + string instPath = setupInstance2.GetInstallationPath().Replace("\\", "\\\\"); + string installationVersion = setupInstance2.GetInstallationVersion(); + bool isComplete = setupInstance2.IsComplete(); + bool isLaunchable = setupInstance2.IsLaunchable(); + Echo("\"Product\": \"{0}\",", prod); + Echo("\"Version\": \"{0}\",", installationVersion); + Echo("\"InstallationPath\": \"{0}\",", instPath); + Echo("\"IsComplete\": \"{0}\",", isComplete ? "true" : "false"); + Echo("\"IsLaunchable\": \"{0}\",", isLaunchable ? "true" : "false"); + String cmd = (instPath + "\\\\Common7\\\\Tools\\\\VsDevCmd.bat"); + Echo("\"CmdPath\": \"{0}\",", cmd); + + List packs = new List(); + string MSBuild = "false"; + string VCTools = "false"; + string Win8SDK = "0"; + string sdk10Ver = "0"; + foreach (ISetupPackageReference package in setupInstance2.GetPackages()) + { + string id = package.GetId(); + string ver = package.GetVersion(); + string detail = "{\"id\": \"" + id + "\", \"version\":\"" + ver + "\"}"; + packs.Add(" " + detail); + + if (id.Contains("Component.MSBuild")) { + MSBuild = detail; + } else if (id.Contains("VC.Tools")) { + VCTools = detail; + } else if (id.Contains("Microsoft.Windows.81SDK")) { + if (Win8SDK.CompareTo(ver) > 0) continue; + Win8SDK = ver; + } else if (id.Contains("Win10SDK_10")) { + if (sdk10Ver.CompareTo(ver) > 0) continue; + sdk10Ver = ver; + } + } + packs.Sort(); + string[] sdk10Parts = sdk10Ver.Split('.'); + sdk10Parts[sdk10Parts.Length - 1] = "0"; + Echo("\"MSBuild\": {0},", MSBuild); + Echo("\"VCTools\": {0},", VCTools); + Echo("\"SDK8\": \"{0}\",", Win8SDK); + Echo("\"SDK10\": \"{0}\",", sdk10Ver); + Echo("\"SDK\": \"{0}\",", String.Join(".", sdk10Parts)); + Echo("\"Packages\": [\n {0} \n ]", String.Join(",\n ", packs.ToArray())); + Echo("}"); + } + } + +} diff --git a/src/tools/vc141helper/cl141_path.cmd b/src/tools/vc141helper/cl141_path.cmd new file mode 100644 index 0000000000..29761347c9 --- /dev/null +++ b/src/tools/vc141helper/cl141_path.cmd @@ -0,0 +1,16 @@ +:: Copyright 2017 - Refael Ackermann +:: Distributed under the Boost Software License, Version 1.0. +:: (See accompanying file LICENSE_1_0.txt or copy at +:: http://www.boost.org/LICENSE_1_0.txt) +@IF NOT DEFINED DEBUG_GETTER @ECHO OFF +SETLOCAL +PUSHD %~dp0 +SET PROMPT=$G +SET DEBUG_GETTER= +CALL :find_CL %~dp0 %1 +POPD +GOTO :eof + +:find_CL +FOR /F "tokens=*" %%A IN ('powershell -NoProfile -ExecutionPolicy Unrestricted "%1GetCLPath.ps1" %2') DO ECHO %%A& EXIT /B +GOTO :eof \ No newline at end of file