Maven multi-line <arg> does not work on Windows when <fork>ed
- Dominant language
- Java
- Stars
- 7.2k
- Forks
- 820
- Avg merge
- 5h 9m
- Merged PRs (30d)
- 50
Description
discusses limitations of configuring Error Prone in Maven and demonstrates a way to split arguments across multiple lines. However, while that example works outside of Windows it does not work on Windows iff the compiler was forked, and I can find no variant that does work.
**This is not a defect of Error Prone, however, Error Prone's documentation ought perhaps to expand its disclaimer** -- especially because peculiarities of the error make it difficult to troubleshoot.
The error manifests in Maven 3.9.6 with `maven-compiler-plugin` 3.10.0 through 3.12.1, current latest, independently of whether Maven Wrapper is used. The error manifests only when forking the compiler (e.g. `true`) and appears to be an artifact of how Maven orchestrates forking on Windows. I'm sure that other versions of Maven are also affected.
The sample POM below minimally reproduces the issue together with Error Prone, such that simply toggling the user property `maven.compiler.fork` causes compilation to fail:
```powershell
> foreach ($fork in 'false', 'true') {
.\mvnw.cmd clean compile -X "-Dmaven.compiler.fork=$fork"
}
```
```
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] error: invalid flag: -Xep:DeadException:WARN
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.823 s
[INFO] Finished at: 2024-01-21T12:16:07+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.12.1:compile (default-compile) on project y-u-no-compile: Compilation failure
[ERROR] error: invalid flag: -Xep:DeadException:WARN
[ERROR]
[ERROR] -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.12.1:compile (default-compile) on project y-u-no-compile: Compilation failure
error: invalid flag: -Xep:DeadException:WARN
at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:333)
at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:73)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:53)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:118)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:261)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:173)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:101)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:906)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:283)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:206)
at jdk.internal.reflect.DirectMethodHandleAccessor.invoke (DirectMethodHandleAccessor.java:103)
at java.lang.reflect.Method.invoke (Method.java:580)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:283)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:226)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:407)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:348)
at jdk.internal.reflect.DirectMethodHandleAccessor.invoke (DirectMethodHandleAccessor.java:103)
at java.lang.reflect.Method.invoke (Method.java:580)
at org.apache.maven.wrapper.BootstrapMainStarter.start (BootstrapMainStarter.java:52)
at org.apache.maven.wrapper.WrapperExecutor.execute (WrapperExecutor.java:161)
at org.apache.maven.wrapper.MavenWrapperMain.main (MavenWrapperMain.java:73)
Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compilation failure
```
The defect can easily be shown without Error Prone but a successful compilation is a good contrast and is easier to show with Error Prone.
When compiling with `-X`, whether in-process or forked, Maven always reports that its compiler arguments include instructions like
```
... -XDcompilePolicy=simple -Xplugin:ErrorProne \
-Xep:DeadException:WARN \
-Xep:GuardedBy:OFF
```
That is, ``s contents verbatim.
Under the right circumstances the `-X` argument will also generate a `target/javac.bat` file and a sibling file that contains (some of the) `javac` arguments. These files are generated only when `maven-compiler-plugin` progresses a forked build far enough -- in-process builds never generate these files, and forked builds can encounter failures early enough in the process that the files are not generated.
From the generated arguments file we can see that what the forked compiler actually executes is
```
"-XDcompilePolicy=simple"
"-Xplugin:ErrorProne /
-Xep:DeadException:WARN /
-Xep:GuardedBy:OFF"
```
That is, `\` has been replaced with `/`. This looks suspiciously like an errant path separator normalization! We can also manually restore the original `\`s inside the arguments file and observe that compilation then succeeds:
```batch
...\target> .\javac.bat
...\target>cmd.exe /X /C "..."
...\src\main\java\T.java:1: warning: [DefaultPackage] Java classes shouldn't use default package
public class T { }
^
(see https://errorprone.info/bugpattern/DefaultPackage)
1 warning
```
**POM:**
```xml
4.0.0
example.multi-line-fork-crash
y-u-no-compile
1.0-SNAPSHOT
21
3.12.1
2.24.1
org.apache.maven.plugins
maven-compiler-plugin
3.12.1
-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
-XDcompilePolicy=simple
-Xplugin:ErrorProne \
-Xep:DeadException:WARN \
-Xep:GuardedBy:OFF
com.google.errorprone
error_prone_core
${error-prone.version}
```
**.mvn/jvm.confg:**
```
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
```
**src/main/java/T.java:**
```java
public class T { }
```
Contributor guide
Assessment
This issue has not been assessed yet.