Компилятор 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-компилятора довольно быстрая, вероятно, намного быстрее, чем альтернатива, которая будет выглядеть примерно так:
- обнаружить все измененные файлы
- проанализировать все исходные файлы, чтобы отобразить все отношения между классами
- рассчитать все затронутые файлы
- перекомпилировать поврежденные файлы
Однако, как пишет Роберт, перекомпиляция всего, вероятно, не является необходимой, если в проекте используется компилятор Eclipse, который выполняет этот анализ. Но для сегодняшних пользователей Maven это спорный вопрос, поскольку maven-compiler-plugin
пока не меняет своего поведения в зависимости от выбора компилятора.