4040 * This utility helps set up a build environment for Windows users automatically.
4141 */
4242class WindowsBuildEnvironmentUtil {
43+ private static final String PROGRAM_FILES_x86_ENV_KEY = "ProgramFiles(x86)" ;
4344 private static final String VCVARSALL = "vcvarsall.bat" ;
45+ private static final String VSWHERE = "vswhere.exe" ;
4446 private static final Path VCVARSALL_SUBPATH = Paths .get ("VC" , "Auxiliary" , "Build" , VCVARSALL );
4547 // Use another static field for minimum required version because CCompilerInvoker is hosted only
4648 private static final String VISUAL_STUDIO_MINIMUM_REQUIRED_VERSION = CCompilerInvoker .VISUAL_STUDIO_MINIMUM_REQUIRED_VERSION ;
@@ -50,17 +52,13 @@ static void propagateEnv(Map<String, String> environment) {
5052 if (isCCompilerOnPath ()) {
5153 return ; // nothing to do, build environment initialized by user
5254 }
53- Path vcVarsAllLocation = findVCVarsallWithVSWhere ();
54- if (vcVarsAllLocation == null ) {
55- throw fail (String .format ("Failed to find '%s' in a Visual Studio installation." , VCVARSALL ));
56- }
55+ Path vcVarsAllLocation = findVCVarsallWithVSWhereOrFail ();
5756 Map <String , String > originalEnv = new HashMap <>();
5857 int numSeenOutputSeparators = 0 ;
5958 String outputSeparator = "!NEXTCOMMAND!" ;
6059 try {
6160 // call `set`, then `vcvarsall.bat`, and then `set` again with separators in between
62- String commandSequence = String .format ("cmd.exe /c set && echo %s && \" %s\" x64 && echo %s && set" ,
63- outputSeparator , vcVarsAllLocation , outputSeparator );
61+ String commandSequence = "cmd.exe /c set && echo %s && \" %s\" x64 && echo %s && set" .formatted (outputSeparator , vcVarsAllLocation , outputSeparator );
6462 Process p = Runtime .getRuntime ().exec (new String []{"cmd.exe" , "/c" , commandSequence });
6563 try (BufferedReader reader = new BufferedReader (new InputStreamReader (p .getInputStream ()))) {
6664 String line ;
@@ -90,37 +88,41 @@ static void propagateEnv(Map<String, String> environment) {
9088 }
9189 }
9290
93- private static Path findVCVarsallWithVSWhere () {
94- String programFilesX86 = System .getenv ("ProgramFiles(x86)" );
91+ private static Path findVCVarsallWithVSWhereOrFail () {
92+ String programFilesX86 = System .getenv (PROGRAM_FILES_x86_ENV_KEY );
9593 if (programFilesX86 == null ) {
96- return null ;
94+ throw fail ( "Variable '%s' is not defined in the system environment." . formatted ( PROGRAM_FILES_x86_ENV_KEY )) ;
9795 }
9896 /*
9997 * vswhere is included with the installer as of Visual Studio 2017 version 15.2 and later,
10098 * and can be found at the following location: `%ProgramFiles(x86)%\Microsoft Visual
10199 * Studio\Installer\vswhere.exe` (see:
102100 * https://github.com/microsoft/vswhere/blob/2717133/README.md).
103101 */
104- Path vsWhereExe = Paths .get (programFilesX86 , "Microsoft Visual Studio" , "Installer" , "vswhere.exe" );
102+ Path vsWhereExe = Paths .get (programFilesX86 , "Microsoft Visual Studio" , "Installer" , VSWHERE );
105103 if (!Files .exists (vsWhereExe )) {
106- return null ;
104+ throw fail ( "Failed to find '%s' for locating Visual Studio installations." . formatted ( VSWHERE )) ;
107105 }
108106 try {
109107 Process p = Runtime .getRuntime ().exec (new String []{vsWhereExe .toAbsolutePath ().toString (),
110108 "-version" , VISUAL_STUDIO_MINIMUM_REQUIRED_VERSION ,
109+ "-products" , "*" , /* https://github.com/microsoft/vswhere/issues/22 */
111110 "-requires" , "Microsoft.VisualStudio.Component.VC.Tools.x86.x64" ,
112111 "-property" , "installationPath" });
113112 try (BufferedReader reader = new BufferedReader (new InputStreamReader (p .getInputStream ()))) {
114- Path installationPath = Paths .get (reader .readLine ());
115- Path possibleLocation = installationPath .resolve (VCVARSALL_SUBPATH );
116- if (isRegularReadableFile (possibleLocation )) {
117- return possibleLocation ;
113+ String installationPathLine = reader .readLine ();
114+ if (installationPathLine != null ) {
115+ Path installationPath = Paths .get (installationPathLine );
116+ Path possibleLocation = installationPath .resolve (VCVARSALL_SUBPATH );
117+ if (isRegularReadableFile (possibleLocation )) {
118+ return possibleLocation ;
119+ }
118120 }
119121 }
120122 } catch (IOException e ) {
121- throw fail ("Failed to process vswhere.exe output." , e );
123+ throw fail ("Failed to process output of '%s'." . formatted ( VSWHERE ) , e );
122124 }
123- throw fail ("Failed to find suitable version of Visual Studio with vswhere.exe." );
125+ throw fail ("Failed to find a suitable version of Visual Studio with '%s'." . formatted ( VSWHERE ) );
124126 }
125127
126128 private static boolean isCCompilerOnPath () {
0 commit comments