How do I pass javac multiple command-line argument

2019-02-17 13:37发布

问题:

I want to make my Maven build fail when I forget to declare serialVersionUIDs in a Serializable class. With javac, that's easy:

$ javac -Xlint:serial -Werror Source.java

Directly translating that to Maven doesn't work:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <compilerArgument>-Xlint:serial -Werror</compilerArgument>
            </configuration>
        </plugin>

The compilerArgument is quoted, so javac receives only one argument, containing -Xlint:serial -Werror, instead of -Xlint:serial and -Werror as separate arguments. So you read the docs, and find compilerArguments:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <compilerArguments>
                    <Xlint:serial />
                    <Werror />
                </compilerArguments>
            </configuration>
        </plugin>

This looks weird - the colon makes serial element in the Xlint namespace, which isn't declared anywhere - but it works... until you want to do a release:

$ mvn release:prepare

org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.3.2:prepare (default-cli) on project my-project: Error reading POM: Error on line 58: The prefix "Xlint" for element "Xlint:serial" is not bound.

Apparently, the regular POM reader handles XML namespaces in another way than the one used by the release plugin.

So how do I pass javac multiple command-line switches when some of those switches contain characters which aren't valid for plain XML elements, without breaking the release plugin?

回答1:

See http://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#compilerArgs

and http://maven.apache.org/plugins/maven-compiler-plugin/examples/pass-compiler-arguments.html

Maven 3.1 or later

                        <source>1.6</source>
                        <target>1.6</target>
                        <showDeprecation>true</showDeprecation>
                        <showWarnings>true</showWarnings>
                        </processors>
                        <compilerArgs>
                          <arg>-verbose</arg>
                          <arg>-Aeclipselink.persistencexml=src/main/resources/META-INF/persistence.xml</arg>
                        </compilerArgs>

or Maven 3.0 or older

      <compilerArguments>
        <verbose />
      </compilerArguments>
      <compilerArgument>-Aeclipselink.persistencexml=src/main/resources/META-INF/persistence.xml</compilerArgument>


回答2:

I think it's a bug in maven-compiler-plugin, I submitted an issue to developers: MCOMPILER-178



回答3:

It seems that while spaces are escaped in compilerArgument, the same isn't true for quotes. So, if you surround the spaces in the argument with quotes, you get two arguments:

<compilerArgument>-Xlint:serial" "-Werror</compilerArgument>

This invokes javac "-Xlint:serial" "-Werror" rather than javac "-Xlint:serial -Werror".

There's nothing in the docs about this that I can find.



回答4:

In relation to Kalpesh Soni's answer:

Note for Maven 3.1 or later according to the example from http://maven.apache.org/plugins/maven-compiler-plugin/examples/pass-compiler-arguments.html:

<compilerArgs>
    <arg>-verbose</arg>
    <arg>-Xlint:all,-options,-path</arg>
</compilerArgs>

The above is great unless you want to pass an additional param that requires space character. In my case it was -bootclasspath /path/to/custom/rt.jar. In such a case you have to split this string on every space and pass every part as a new <arg /> in order not to get Fatal error compiling: invalid flag: ... So the working example is:

<compilerArgs>
    <arg>-verbose</arg>
    <arg>-Xlint:all,-options,-path</arg>
    <arg>-bootclasspath</arg><arg>/path/to/custom/rt.jar</arg>
</compilerArgs>