5050import java .util .Map ;
5151import java .util .Optional ;
5252import java .util .Properties ;
53+ import java .util .StringJoiner ;
5354import java .util .function .BiConsumer ;
5455import java .util .function .BiFunction ;
5556import java .util .function .Consumer ;
@@ -996,7 +997,7 @@ private int completeImageBuild() {
996997 if (config .useJavaModules ()) {
997998 config .getBuilderModulePath ().forEach (this ::addImageBuilderModulePath );
998999 String upgradeModulePath = config .getBuilderUpgradeModulePath ().stream ()
999- .map (p -> canonicalize (p ). toString ( ))
1000+ .map (p -> shellPath ( canonicalize (p )))
10001001 .collect (Collectors .joining (File .pathSeparator ));
10011002 if (!upgradeModulePath .isEmpty ()) {
10021003 addImageBuilderJavaArgs (Arrays .asList ("--upgrade-module-path" , upgradeModulePath ));
@@ -1005,7 +1006,7 @@ private int completeImageBuild() {
10051006 config .getBuilderJVMCIClasspath ().forEach ((Consumer <? super Path >) this ::addImageBuilderClasspath );
10061007 if (!config .getBuilderJVMCIClasspathAppend ().isEmpty ()) {
10071008 String builderJavaArg = config .getBuilderJVMCIClasspathAppend ()
1008- .stream ().map (path -> canonicalize (path ). toString ( ))
1009+ .stream ().map (path -> shellPath ( canonicalize (path )))
10091010 .collect (Collectors .joining (File .pathSeparator , "-Djvmci.class.path.append=" , "" ));
10101011 addImageBuilderJavaArgs (builderJavaArg );
10111012 }
@@ -1019,7 +1020,7 @@ private int completeImageBuild() {
10191020
10201021 String clibrariesPath = (targetPlatform != null ) ? targetPlatform : platform ;
10211022 String clibrariesBuilderArg = config .getBuilderCLibrariesPaths ().stream ()
1022- .map (path -> canonicalize (path .resolve (clibrariesPath )). toString ( ))
1023+ .map (path -> shellPath ( canonicalize (path .resolve (clibrariesPath ))))
10231024 .collect (Collectors .joining ("," , oHCLibraryPath , "" ));
10241025 addPlainImageBuilderArg (clibrariesBuilderArg );
10251026
@@ -1235,7 +1236,7 @@ private List<String> getAgentArguments() {
12351236 if (!agentOptions .isEmpty ()) {
12361237 args .add ("-agentlib:native-image-diagnostics-agent=" + agentOptions );
12371238 }
1238- args .add ("-javaagent:" + config .getAgentJAR (). toAbsolutePath ( ) + (agentOptions .isEmpty () ? "" : "=" + agentOptions ));
1239+ args .add ("-javaagent:" + shellPath ( config .getAgentJAR ()) + (agentOptions .isEmpty () ? "" : "=" + agentOptions ));
12391240 return args ;
12401241 }
12411242
@@ -1301,7 +1302,14 @@ protected static List<String> createImageBuilderArgs(ArrayList<String> imageArgs
13011302 protected static String createVMInvocationArgumentFile (List <String > arguments ) {
13021303 try {
13031304 Path argsFile = Files .createTempFile ("vminvocation" , ".args" );
1304- String joinedOptions = String .join ("\n " , arguments );
1305+ StringJoiner joiner = new StringJoiner ("\n " );
1306+ for (String arg : arguments ) {
1307+ // Options in @argfile need to be properly quoted as
1308+ // this relies on the JDK's @argfile parsing when the
1309+ // native image generator is being launched.
1310+ joiner .add (SubstrateUtil .quoteShellArg (arg ));
1311+ }
1312+ String joinedOptions = joiner .toString ();
13051313 Files .write (argsFile , joinedOptions .getBytes ());
13061314 argsFile .toFile ().deleteOnExit ();
13071315 return "@" + argsFile ;
@@ -1327,14 +1335,14 @@ protected int buildImage(List<String> javaArgs, LinkedHashSet<Path> bcp, LinkedH
13271335 List <String > arguments = new ArrayList <>();
13281336 arguments .addAll (javaArgs );
13291337 if (!bcp .isEmpty ()) {
1330- arguments .add (bcp .stream ().map (Path :: toString ).collect (Collectors .joining (File .pathSeparator , "-Xbootclasspath/a:" , "" )));
1338+ arguments .add (bcp .stream ().map (NativeImage :: shellPath ).collect (Collectors .joining (File .pathSeparator , "-Xbootclasspath/a:" , "" )));
13311339 }
13321340
13331341 if (!cp .isEmpty ()) {
1334- arguments .addAll (Arrays .asList ("-cp" , cp .stream ().map (Path :: toString ).collect (Collectors .joining (File .pathSeparator ))));
1342+ arguments .addAll (Arrays .asList ("-cp" , cp .stream ().map (NativeImage :: shellPath ).collect (Collectors .joining (File .pathSeparator ))));
13351343 }
13361344 if (!mp .isEmpty ()) {
1337- List <String > strings = Arrays .asList ("--module-path" , mp .stream ().map (Path :: toString ).collect (Collectors .joining (File .pathSeparator )));
1345+ List <String > strings = Arrays .asList ("--module-path" , mp .stream ().map (NativeImage :: shellPath ).collect (Collectors .joining (File .pathSeparator )));
13381346 arguments .addAll (strings );
13391347 }
13401348
@@ -1399,6 +1407,17 @@ protected int buildImage(List<String> javaArgs, LinkedHashSet<Path> bcp, LinkedH
13991407 return exitStatus ;
14001408 }
14011409
1410+ // Since path variables get used in @argumenet files and '\' is an unsafe shell
1411+ // character, be sure to escape backslashes in paths so they can get interpreted correctly
1412+ // in @argument files when they are quoted. I.e. 'C:\foo\bar' => 'C:\\foo\\bar'
1413+ private static String shellPath (Path path ) {
1414+ String retval = path .toString ();
1415+ if (OS .getCurrent () == OS .WINDOWS ) {
1416+ return retval .replace ("\\ " , "\\ \\ " );
1417+ }
1418+ return retval ;
1419+ }
1420+
14021421 private static final Function <BuildConfiguration , NativeImage > defaultNativeImageProvider = config -> new NativeImage (config );
14031422
14041423 public static void main (String [] args ) {
0 commit comments