google / google/error-prone

Maven multi-line <arg> does not work on Windows when <fork>ed

Open
#4,256 4 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.