40
40
* This utility helps set up a build environment for Windows users automatically.
41
41
*/
42
42
class WindowsBuildEnvironmentUtil {
43
+ private static final String PROGRAM_FILES_x86_ENV_KEY = "ProgramFiles(x86)" ;
43
44
private static final String VCVARSALL = "vcvarsall.bat" ;
45
+ private static final String VSWHERE = "vswhere.exe" ;
44
46
private static final Path VCVARSALL_SUBPATH = Paths .get ("VC" , "Auxiliary" , "Build" , VCVARSALL );
45
47
// Use another static field for minimum required version because CCompilerInvoker is hosted only
46
48
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) {
50
52
if (isCCompilerOnPath ()) {
51
53
return ; // nothing to do, build environment initialized by user
52
54
}
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 ();
57
56
Map <String , String > originalEnv = new HashMap <>();
58
57
int numSeenOutputSeparators = 0 ;
59
58
String outputSeparator = "!NEXTCOMMAND!" ;
60
59
try {
61
60
// 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 );
64
62
Process p = Runtime .getRuntime ().exec (new String []{"cmd.exe" , "/c" , commandSequence });
65
63
try (BufferedReader reader = new BufferedReader (new InputStreamReader (p .getInputStream ()))) {
66
64
String line ;
@@ -90,37 +88,41 @@ static void propagateEnv(Map<String, String> environment) {
90
88
}
91
89
}
92
90
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 );
95
93
if (programFilesX86 == null ) {
96
- return null ;
94
+ throw fail ( "Variable '%s' is not defined in the system environment." . formatted ( PROGRAM_FILES_x86_ENV_KEY )) ;
97
95
}
98
96
/*
99
97
* vswhere is included with the installer as of Visual Studio 2017 version 15.2 and later,
100
98
* and can be found at the following location: `%ProgramFiles(x86)%\Microsoft Visual
101
99
* Studio\Installer\vswhere.exe` (see:
102
100
* https://github.com/microsoft/vswhere/blob/2717133/README.md).
103
101
*/
104
- Path vsWhereExe = Paths .get (programFilesX86 , "Microsoft Visual Studio" , "Installer" , "vswhere.exe" );
102
+ Path vsWhereExe = Paths .get (programFilesX86 , "Microsoft Visual Studio" , "Installer" , VSWHERE );
105
103
if (!Files .exists (vsWhereExe )) {
106
- return null ;
104
+ throw fail ( "Failed to find '%s' for locating Visual Studio installations." . formatted ( VSWHERE )) ;
107
105
}
108
106
try {
109
107
Process p = Runtime .getRuntime ().exec (new String []{vsWhereExe .toAbsolutePath ().toString (),
110
108
"-version" , VISUAL_STUDIO_MINIMUM_REQUIRED_VERSION ,
109
+ "-products" , "*" , /* https://github.com/microsoft/vswhere/issues/22 */
111
110
"-requires" , "Microsoft.VisualStudio.Component.VC.Tools.x86.x64" ,
112
111
"-property" , "installationPath" });
113
112
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
+ }
118
120
}
119
121
}
120
122
} 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 );
122
124
}
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 ) );
124
126
}
125
127
126
128
private static boolean isCCompilerOnPath () {
0 commit comments