Skip to content

Commit 7c4a040

Browse files
Use @argFiles for NativeImageGeneratorRunner's vm invocation on JDK9+
Fixes the issue where builder vm invocation would fail on Windows due to classpath length exceeding command line length limit.
1 parent 27c55a1 commit 7c4a040

File tree

1 file changed

+34
-22
lines changed

1 file changed

+34
-22
lines changed

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,21 +1372,24 @@ protected static List<String> createImageBuilderArgs(ArrayList<String> imageArgs
13721372
return result;
13731373
}
13741374

1375+
protected static String createVMInvocationArgumentFile(List<String> arguments) {
1376+
try {
1377+
Path argsFile = Files.createTempFile("vminvocation", ".args");
1378+
String joinedOptions = String.join("\n", arguments);
1379+
Files.write(argsFile, joinedOptions.getBytes());
1380+
argsFile.toFile().deleteOnExit();
1381+
return "@" + argsFile;
1382+
} catch (IOException e) {
1383+
throw showError(e.getMessage());
1384+
}
1385+
}
1386+
13751387
protected static String createImageBuilderArgumentFile(List<String> imageBuilderArguments) {
13761388
try {
1377-
Path argsFile = Files.createTempFile("native-image", "args");
1389+
Path argsFile = Files.createTempFile("native-image", ".args");
13781390
String joinedOptions = String.join("\0", imageBuilderArguments);
13791391
Files.write(argsFile, joinedOptions.getBytes());
1380-
Runtime.getRuntime().addShutdownHook(new Thread() {
1381-
@Override
1382-
public void run() {
1383-
try {
1384-
Files.delete(argsFile);
1385-
} catch (IOException e) {
1386-
System.err.println("Failed to delete temporary image builder arguments file: " + argsFile.toString());
1387-
}
1388-
}
1389-
});
1392+
argsFile.toFile().deleteOnExit();
13901393
return NativeImageGeneratorRunner.IMAGE_BUILDER_ARG_FILE_OPTION + argsFile.toString();
13911394
} catch (IOException e) {
13921395
throw showError(e.getMessage());
@@ -1395,37 +1398,46 @@ public void run() {
13951398

13961399
protected int buildImage(List<String> javaArgs, LinkedHashSet<Path> bcp, LinkedHashSet<Path> cp, LinkedHashSet<Path> mp, ArrayList<String> imageArgs, LinkedHashSet<Path> imagecp,
13971400
LinkedHashSet<Path> imagemp) {
1398-
/* Construct ProcessBuilder command from final arguments */
1399-
List<String> command = new ArrayList<>();
1400-
command.add(canonicalize(config.getJavaExecutable()).toString());
1401-
command.addAll(javaArgs);
1401+
List<String> arguments = new ArrayList<>();
1402+
arguments.addAll(javaArgs);
14021403
if (!bcp.isEmpty()) {
1403-
command.add(bcp.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator, "-Xbootclasspath/a:", "")));
1404+
arguments.add(bcp.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator, "-Xbootclasspath/a:", "")));
14041405
}
14051406

14061407
if (!cp.isEmpty()) {
1407-
command.addAll(Arrays.asList("-cp", cp.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator))));
1408+
arguments.addAll(Arrays.asList("-cp", cp.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator))));
14081409
}
14091410
if (!mp.isEmpty()) {
14101411
List<String> strings = Arrays.asList("--module-path", mp.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)));
1411-
command.addAll(strings);
1412+
arguments.addAll(strings);
14121413
}
14131414

14141415
if (USE_NI_JPMS) {
1415-
command.addAll(Arrays.asList("--module", DEFAULT_GENERATOR_MODULE_NAME + "/" + DEFAULT_GENERATOR_CLASS_NAME));
1416+
arguments.addAll(Arrays.asList("--module", DEFAULT_GENERATOR_MODULE_NAME + "/" + DEFAULT_GENERATOR_CLASS_NAME));
14161417
} else {
1417-
command.add(config.getGeneratorMainClass());
1418+
arguments.add(config.getGeneratorMainClass());
14181419
}
14191420
if (IS_AOT && OS.getCurrent().hasProcFS) {
14201421
/*
14211422
* GR-8254: Ensure image-building VM shuts down even if native-image dies unexpected
14221423
* (e.g. using CTRL-C in Gradle daemon mode)
14231424
*/
1424-
command.addAll(Arrays.asList(SubstrateOptions.WATCHPID_PREFIX, "" + ProcessProperties.getProcessID()));
1425+
arguments.addAll(Arrays.asList(SubstrateOptions.WATCHPID_PREFIX, "" + ProcessProperties.getProcessID()));
14251426
}
14261427
List<String> finalImageBuilderArgs = createImageBuilderArgs(imageArgs, imagecp, imagemp);
1427-
List<String> completeCommandList = Stream.concat(command.stream(), finalImageBuilderArgs.stream()).collect(Collectors.toList());
1428+
1429+
/* Construct ProcessBuilder command from final arguments */
1430+
List<String> command = new ArrayList<>();
1431+
command.add(canonicalize(config.getJavaExecutable()).toString());
1432+
List<String> completeCommandList = new ArrayList<>(command);
1433+
if (config.useJavaModules()) { // Only in JDK9+ 'java' executable supports @argFiles.
1434+
command.add(createVMInvocationArgumentFile(arguments));
1435+
} else {
1436+
command.addAll(arguments);
1437+
}
14281438
command.add(createImageBuilderArgumentFile(finalImageBuilderArgs));
1439+
1440+
completeCommandList.addAll(Stream.concat(arguments.stream(), finalImageBuilderArgs.stream()).collect(Collectors.toList()));
14291441
final String commandLine = SubstrateUtil.getShellCommandString(completeCommandList, true);
14301442
if (isDiagnostics()) {
14311443
// write to the diagnostics dir

0 commit comments

Comments
 (0)