Hello all

The Maven compiler plugin has an <useIncrementalCompilation> boolean parameter with `true` as the default value. This parameter has issues discussed in MCOMPILER-209 [1], which has 61 votes. In short, builds are much faster when this parameter is set to `false`, which is counter-intuitive. During the refactoring for the Maven 4 compiler plugin, by looking at the source code, I saw the following issues with the current implementation:

 * When <useIncrementalCompilation> is enabled (which is the default),
   the plugin compares the list of source files in the current build
   with a list saved after the previous build in order to detect
   changes. But it seems to me that the plugin uses relative paths in
   one case, and absolute paths in the other cases. Consequently, the
   paths do not match and the plugin always thinks that all source
   files changed. I did not double-checked or tested (maybe I missed
   some `toAbsoluteFile()` calls). But if confirmed, it would explain
   the MCOMPILER-209 issue.
 * The ways that the two lists are compared has a performance cost of
   O(N²). It could easily be O(N) instead by replacing one list by an
   hash set.
 * The plugin tries to detect changes in dependencies, but the
   algorithm works only if the compilation never fail. Consider the
   following scenario:
     o One project has 3 modules: A, B and C.
     o Module B and C depends on A.
     o Developer makes a change in A and run `mvn install`.
     o Module A compiles successfully, but B fails because of the
       change in A.
     o Developer fixes the build failure in B and run `mvn install`
       again. In this scenario, the incremental compilation will not
       see that C also needs to be rebuilt, because when
       <useIncrementalCompilation> is enabled, the plugin compares the
       JAR timestamps with the build start time. In this scenario, the
       second build start time is after the `A.jar` creation time.
       Maybe this issue was unnoticed because the issue explained in
       the first bullet point caused the plugin to always recompile
       everything anyway.

I propose to deprecate <useIncrementalCompilation> in Maven 4 and replace it by a new parameter: <incrementalCompilation>. Its value would be a comma-separated list of values instead of a single boolean flag. Those values specify which methods to use for deciding which files to recompile:

 * "sources": check for changes in source files, including whether a
   file has been deleted. This method uses a file saved by the previous
   build in the "target/maven-status"  directory (as done by the
   current implementation).
 * "classes": check whether the source file is more recent than the
   class file. This method does not need any "maven-status" file from
   the previous build, but does not detect whether a file has been
   added or removed.
 * "dependencies": check whether a dependency has changed (using a more
   robust algorithm than the current one).
 * "modules": do not specify any file to the compiler and use the
   `--module` option instead, in which case the compiler will scan the
   directories itself and decides itself which files to recompile based
   on their timestamp. This option is available for modular projects only.

The current <useIncrementalCompilation> boolean flag maps to above proposal as below:

 * `true` is approximately equivalent to "sources,dependencies", except
   that I propose to not rebuild everything when a file is added (it is
   usually not needed).
 * `false` is equivalent to "classes".

As seen from above, the current <useIncrementalCompilation> actually mixes two aspects that could be treated separately: whether to check if a dependency changed, and whether to use a list saved from the previous build for checking if a source file changed. The comma-separated value proposal would allow users to control those aspects independently.

    Martin

[1]https://issues.apache.org/jira/browse/MCOMPILER-209

Reply via email to