Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
commonquail opened this issue Jan 21, 2024 · 3 comments
Open

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

commonquail opened this issue Jan 21, 2024 · 3 comments

Comments

@commonquail
Copy link

https://errorprone.info/docs/flags#maven 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. <fork>true</fork>) 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:

> 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, <arg>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:

...\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 version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>example.multi-line-fork-crash</groupId>
  <artifactId>y-u-no-compile</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <maven.compiler.release>21</maven.compiler.release>
    <maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
    <error-prone.version>2.24.1</error-prone.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.12.1</version>
        <configuration>
          <compilerArgs>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
            <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
            <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
            <arg>-XDcompilePolicy=simple</arg>
            <arg>
              -Xplugin:ErrorProne \
              -Xep:DeadException:WARN \
              -Xep:GuardedBy:OFF</arg>
          </compilerArgs>
          <annotationProcessorPaths>
            <path>
              <groupId>com.google.errorprone</groupId>
              <artifactId>error_prone_core</artifactId>
              <version>${error-prone.version}</version>
            </path>
          </annotationProcessorPaths>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

.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:

public class T { }
@cushon
Copy link
Collaborator

cushon commented Jan 22, 2024

Thanks for the investigation, adding a disclaimer to https://errorprone.info/docs/flags#maven sounds good to me.

Would you be willing to also report the bug against maven, if you haven't already, since it sounds like the underlying problem is a maven-compiler-plugin bug?

@commonquail
Copy link
Author

adding a disclaimer [...]

Incidentally, I would offer to do that, too, but legally speaking that's a bit difficult.

Would you be willing to also report the bug against maven [...]

Yes. I want to see if I can identify the source first but I will report it either way.

@commonquail
Copy link
Author

commonquail commented Jan 24, 2024

Upstream tickets:

It is perhaps worth mentioning to any passers-by that the in-process compiler supports multi-line arguments both with and without the line terminating \ but javac supports only \.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants