Компилятор Maven перекомпилирует все файлы вместо измененных

Даже если я поменяю только один из моих классов, Maven всегда перекомпилирует их все. Я использую эту конфигурацию плагина:

<plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
        <staleMillis>1</slateMillis>
        <useIncrementalCompilation>true</useIncrementalCompilation>
      </configuration>
    </plugin>
</plugins>

Это происходит с mvn compile, mvn package а также mvn install,

Конечно, это не проблема, если у вас есть 10-15 файлов. Тем не менее, у меня есть более тысячи исходных файлов, и это занимает много времени.

Есть ли в плагине компилятора Maven скрытые настройки для перекомпиляции только измененных файлов? Есть ли обходные пути?

2 ответа

Решение

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

Используйте это с болгарским обозначением (да <-> нет)

<useIncrementalCompilation>false</useIncrementalCompilation> значит правда и наоборот

Резюме

Хотя вы можете указать Maven "перекомпилировать только измененные файлы", это приведет к неверным результатам. Поведение по умолчанию - это не ошибка, а намеренное дизайнерское решение.


Какие useIncrementalCompilation действительно делает

Документация на эту тему, мягко говоря, не оптимальна. Вот что на самом деле происходит (на основе источника AbstractCompilerMojo из maven-compiler-plugin 3.3):

  • useIncrementalCompilation установлен в false (не рекомендуется)
    • Это скомпилирует только исходные файлы, которые новее, чем соответствующие им файлы классов, т.е. которые были изменены с момента последнего процесса компиляции. Как отмечает @Ivan в комментарии к другому ответу, это не перекомпилирует другие классы, которые используют измененный класс, потенциально оставляя их со ссылками на методы, которые больше не существуют, что приводит к ошибкам во время выполнения.
  • useIncrementalCompilation установлен в true (поумолчанию)
    • Чтобы решить проблему, описанную выше, в этом режиме плагин компилятора определит,
      • любые файлы JAR, от которых зависит текущий модуль, были изменены в текущем прогоне сборки, или
      • любой исходный файл был добавлен, удален или изменен с момента последней компиляции.
    • В этом случае плагин компилятора намеренно перекомпилирует все исходные файлы, печатая Changes detected - recompiling the module!

Итак, в итоге, useIncrementalCompilation всегда следует оставить по умолчанию true,


Почему это не делает что-то еще

Понятно, что можно спросить: почему плагин не определяет, какие классы затронуты изменениями, а перекомпилирует только эти классы? В комментариях к MCOMPILER-205 разработчик Maven Роберт Шольте дал краткое обоснование, а затем подтвердил следующее подробное объяснение:

Если какой-либо исходный файл был изменен или удален, все файлы будут удалены и перекомпилированы. Причина этого в том, что простая перекомпиляция всего с помощью стандартного java-компилятора довольно быстрая, вероятно, намного быстрее, чем альтернатива, которая будет выглядеть примерно так:

  1. обнаружить все измененные файлы
  2. проанализировать все исходные файлы, чтобы отобразить все отношения между классами
  3. рассчитать все затронутые файлы
  4. перекомпилировать поврежденные файлы

Однако, как пишет Роберт, перекомпиляция всего, вероятно, не является необходимой, если в проекте используется компилятор Eclipse, который выполняет этот анализ. Но для сегодняшних пользователей Maven это спорный вопрос, поскольку maven-compiler-plugin пока не меняет своего поведения в зависимости от выбора компилятора.

Вероятно, плохие новости: см. Ошибку MCOMPILER-205.

Другие вопросы по тегам