openjdk.ruOpenJDK на русском

JEP 247: Compile for Older Platform Versions

Компиляция для более старых версий платформы

ОтветственныйJan Lahoda
ТипFeature
ОбластьJDK
СтатусClosed / Delivered
Выпуск9
Компонентtools / javac
Обсуждениеcompiler dash dev at openjdk dot java dot net
ТрудоёмкостьM
ДлительностьL
РецензентыAlex Buckley, Brian Goetz, Jonathan Gibbons
ОдобренBrian Goetz
Создан2014/09/10 16:56
Обновлён2023/05/18 23:47
Задача8058150

Аннотация

Доработать javac, чтобы он мог компилировать программы на Java для запуска на выбранных более старых версиях платформы.

Мотивация

У javac есть два параметра командной строки, -source и -target. Первый задаёт версию языка Java, которую принимает компилятор, второй — версию создаваемых им class-файлов. Однако по умолчанию javac компилирует с API самой последней версии платформы. Поэтому скомпилированная программа может случайно использовать API, которые есть только в текущей версии платформы. Такие программы не могут работать на более старых версиях платформы, какие бы значения ни были переданы параметрам -source и -target. Это давняя проблема удобства использования: пользователи ожидают, что с этими параметрами получат class-файлы, которые могут работать на версии платформы, указанной в -target.

Описание

Вводится новый параметр командной строки --release. Он автоматически настраивает компилятор так, чтобы тот создавал class-файлы, которые будут связываться с реализацией указанной версии платформы. --release N примерно эквивалентен следующему:

  • для N < 9: -source N -target N -bootclasspath <documented-APIs-from-N>,
  • для N >= 9: -source N -target N --system <documented-APIs-from-N>.

Для N < 9 документированные API — это публичные API, которые находились в bootclasspath javac по умолчанию для JDK N.

Для N >= 9 документированные API включают (i) API, экспортируемые теми модулями образа JDK, которые входят в документацию JDK N, и (ii) API, экспортируемый модулем jdk.unsupported (описан в JEP 260). Иными словами, документированные API — это в основном API, экспортируемые пересечением множества модулей образа JDK и множества модулей, документированных для JDK N. Остальные модули образа JDK не наблюдаемы. Если используется --limit-modules, этот параметр может только дополнительно ограничить наблюдаемые модули, но не сделать наблюдаемыми другие модули. Доступ к внутреннему устройству модулей образа JDK запрещён.

Параметр --release N несовместим с другими параметрами, которые влияют на набор платформенных или системных классов. К ним относятся:

  • для N < 9: параметры -bootclasspath, -Xbootclasspath, -Xbootclasspath/a:, -Xbootclasspath/p:, -endorseddirs, -Djava.endorsed.dirs, -extdirs, -Djava.ext.dirs, задающие платформенные классы.
  • для N >= 9: параметры --system и --upgrade-module-path, задающие системные модули (то есть модули образа JDK), а также параметры --add-exports, --add-reads и --patch-module, если они изменяют системные модули. (--add-exports, --add-reads и --patch-module можно использовать для несистемных модулей, то есть модулей, которые не входят в образ JDK.)
  • для любого N: параметры -source и -target, поскольку им автоматически присваивается значение N.

Предполагается, что документированные API будут меняться только в основных выпусках. В унаследованном случае, когда JAX-WS был обновлён с 2.0 до 2.1 в промежуточном выпуске JDK 6, документированным API считается JAX-WS 2.1.

Ограничение реализации --release: при компиляции используется версия Unicode не указанной целевой платформы, а текущей.

Реализация

Для JDK N и --release M, где M < N, нужны данные о сигнатурах документированных API выпуска M платформы. Эти данные хранятся в файле $JDK_ROOT/lib/ct.sym. Он похож на одноимённый файл в JDK 8, но не совпадает с ним. Файл ct.sym — это ZIP-файл с урезанными class-файлами, соответствующими class-файлам целевых версий платформы.

Для JDK N и --release N источником class-файлов, с которыми выполняется компиляция, служит собственный образ JDK. Однако список наблюдаемых модулей ограничен документированными модулями и модулем jdk.unsupported.

Риски и допущения

Репозиторий исходного кода JDK должен содержать описание API платформы прошлых выпусков. Это описание может быть довольно объёмным, и итоговые сборки JDK станут больше. Мы постарались максимально сократить эти дополнительные затраты места.