Иногда может возникнуть необходимость использовать какую-то определенную версию Java для вашего проекта. Мы тоже в Surf с таким столкнулись при работе над одним из Flutter приложений-долгожителей. Решение нашлось в виде использования менеджера версий Java. Рассказываем, что за инструмент и как с ним базово работать на MacOS.
Что такое jenv
jenv — это менеджер для удобного управления версиями Java на локальной машине. Он позволяет легко переключаться между различными версиями Java, проводит разделение между глобальной версией Java и локальными версиями для использования в разных проектах, а также позволяет управлять переменными окружения Java в системе.
Возможности jenv
Управление версиями Java: jenv позволяет установить и использовать несколько версий Java на одной машине.
Поддержка различных ОС: jenv может использоваться на macOS, Linux и Windows;
Управление переменными окружения Java: jenv может автоматически установить переменные окружения Java;
Управление настройками JVM: jenv позволяет настраивать параметры JVM для каждой версии Java, такие как размер кучи, аргументы командной строки и т. д.
Применение для MacOS
Установка jenv
Устанавливать jenv на macOS рекомендую через brew.
$ brew install jenv
После установки прописываем jenv в ~/.zshrc через команды:
$ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
$ echo 'eval "$(jenv init -)"' >> ~/.zshrc
После выполнения этих команд надо удостовериться, что в ~/.zshrc есть строки:
export PATH="$HOME/.jenv/bin:$PATH"
eval "$(jenv init -)"
Проверить установку можно через команду:
jenv doctor
Вывод может быть таким:
[OK] No JAVA_HOME set
[ERROR] Java binary in path is not in the jenv shims.
[ERROR] Please check your path, or try using ...
[OK] Jenv is correctly loaded
Ничего страшного, если есть ошибки, главное: Jenv is correctly loaded.
Установка Java
Получить список всех доступных JVM можно командой:
/usr/libexec/java_home -V
Если есть доступные JVM, то можно увидеть их список:
Matching Java Virtual Machines (6):
20.0.1 (arm64) "Oracle Corporation" - "OpenJDK 20.0.1" /Users/martynov/Library/Java/JavaVirtualMachines/openjdk-20.0.1/Contents/Home
17.0.8 (arm64) "JetBrains s.r.o." - "JBR-17.0.8+7-1000.8-nomod 17.0.8" /Users/martynov/Library/Java/JavaVirtualMachines/jbr-17.0.8/Contents/Home
15.0.10 (arm64) "Azul Systems, Inc." - "Zulu 15.46.17" /Users/martynov/Library/Java/JavaVirtualMachines/azul-15.0.10/Contents/Home
13.0.14 (arm64) "Azul Systems, Inc." - "Zulu 13.54.17" /Users/martynov/Library/Java/JavaVirtualMachines/azul-13.0.14/Contents/Home
11.0.19 (arm64) "Amazon.com Inc." - "Amazon Corretto 11" /Users/martynov/Library/Java/JavaVirtualMachines/corretto-11.0.19/Contents/Home
1.8.0_372 (arm64) "Amazon" - "Amazon Corretto 8" /Users/martynov/Library/Java/JavaVirtualMachines/corretto-1.8.0_372/Contents/Home
/Users/martynov/Library/Java/JavaVirtualMachines/openjdk-20.0.1/Contents/Home
Если список пуст или нет нужной версии Java, то ее можно установить так:
# Установка текущей версии:
brew install openjdk
# Установка нужной версии:
brew install openjdk@17
После установки, нужно выполнить несколько команд, которые предлагаются в Caveats (предостережениях):
sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk
echo 'export PATH="/usr/local/opt/openjdk/bin:$PATH"' >> ~/.zshrc
export CPPFLAGS="-I/usr/local/opt/openjdk/include"
Добавление Java в jenv
Для добавления Java в jenv надо выполнить следующую команду (путь можно взять из списка доступных JVM выше):
jenv add /Users/martynov/Library/Java/JavaVirtualMachines/corretto-11.0.19/Contents/Home
Результат с подтверждением добавления:
corretto64-11.0.19 added
11.0.19 added
11.0 added
11.0.19 already present, skip installation
Список всех добавленных JVM можно посмотреть через команду:
Список всех добавленных JVM можно посмотреть через команду:
Результат будет примерно таким:
* system (set by /Users/martynov/.jenv/version)
11.0
11.0.19
15.0
15.0.10
17.0
17.0.8
corretto64-11.0.19
jetbrains64-17.0.8
zulu64-15.0.10
Использование различных версий Java через jenv
Глобальная версия
Для установки глобальной версии java нужно выполнить команду по аналогии с этой:
jenv global 15.0
После чего можно проверить версию командой:
java -version
Которая должна отразить выбранную версию:
openjdk version "15.0.1" 2020-10-20
OpenJDK Runtime Environment (build 15.0.1+9)
OpenJDK 64-Bit Server VM (build 15.0.1+9, mixed mode, sharing)
Локальная версия
Перед установкой нужной версии локально нужно перейти в папку с проектом.Для Flutter проекта это может быть папка /android.
Для установки локальной версии используется команда с нужной версией Java:
jenv local 17.0
Будет добавлен файл android/.java-version с выбранной версией внутри: 17.0. После проверяем установку локальной версии через команду:
jenv versions:
system
11.0
11.0.19
15.0
15.0.10
* 17.0 (set by /Users/martynov/Surf/flutter-project/android/.java-version)
17.0.8
corretto64-11.0.19
jetbrains64-17.0.8
zulu64-15.0.10
Еще можно на всякий случай проверить по другому.Перейти в папку в папку android и вызвать команду:
./gradlew -version
Убедиться, что используется нужная версия:
------------------------------------------------------------
Gradle 7.2
------------------------------------------------------------
Build time: 2021-08-17 09:59:03 UTC
Revision: a773786b58bb28710e3dc96c4d1a7063628952ad
Kotlin: 1.5.21
Groovy: 3.0.8
Ant: Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM: 17.0.8 (JetBrains s.r.o. 17.0.8+7-b1000.8)
OS: Mac OS X 13.4.1 aarch64
Источник: https://www.jenv.be – официальный сайт jenv.
Больше интересного контента для разработчиков → в телеграм‑канале Surf Flutter Team
П.с там публикуем кейсы, лучшие практики, новости и вакансии Surf, а также проводим прямые эфиры.
Комментарии (12)
b00
29.09.2023 14:23+2Выглядит излишне сложно, по сравнению с
curl -s "https://get.sdkman.io" | bash
Да ещё и JVM надо сначала установить отдельно, насколько я понял.
Lioshik
29.09.2023 14:23+1Добрый день, у jenv есть хорошая альтернатива - SDKman - https://sdkman.io. Он по запросу выкачивает и устанавливает как JDK, так и такие инструменты как maven, gradle. Так же можно в разных каталогах использовать разные JVM.
Не холивара ради а только для разнообразия.
BugM
Просто запускать нужную джаву по полному пути или по нужному симлинку слишком просто?
avost
Запустить по полному пути несложно. И даже подменять каждый раз JAVA_HOME и дюжину симлинков не то, чтобы сложно, но изрядно геморройно. А подменять надо, поскольку вы ведь не хотите лезть в кишки того же gradle, чтобы полменить пути там внутри. Ну, вот эта утиль, собственно, и подменяет то, что нужно. Впрочем, довольно хреново - мне так и не удалось нё запинать. jenv пишет, что переключилась на одну версию, а java -v показазывает другую... :(
BugM
Наверно в самом кровавом энтерпрайзе это еще и нужно. Но где энтерпрайз и где Homebrew. А обычный современный софт давно уже ничего не требует. java -jar service.jar -big_config.yaml и поехали.
avost
В энтерпрайзе это не нужно. А вот при разработке в том числе для энтерпрайза версии менять приходится. И кроме вашего java -jar в каталоге JAVA_HOME/bin есть ещё дюжина бинарников, а ещё рантайм, экстёрнал либы, сертификаты. И всё это для разных окружений разное и их тоже надо подменять даже в вашем простейшем хелловорде. И ещё раз внимательнее - я говорил для примера про грэдл. Где у него java -jar service.jar -big_config.yaml ?
BugM
Очень давно не использовал, но первая ссылка Гугла говорит что одной строкой в конфиге все делается.
Вот это и используется в кровавых энтерпрайзах. Современная разработка перешла на более простые варианты.
avost
Да, разумеется. Одной строкой в конфиге гредла, одной строкой в конфиге мавена, одной строкой в конфиге анта и тд и тп. Возможно, кому-то доставляет удовольствие при каждом переключении вручную менять десятки конфигов, но я слишком ленив для этого. Мне бы одной командой.
Ээээ? Вы можете продемонстрировать что именно более простое используется в "современной разработке", чем явский рантайм, явский компилятор, установленный набор сертификатов и набор библиотек? Я, по видимому, отстал от "современной разработки", слишком стар для того, чтобы постоянно менять строчки в десятках конфигов и пропустил момент когда ява отказалась от использования рантаймов, сторонних библиотек и компиляторов.
BugM
Профили давно везде есть. Шаблоны и переменные давно поддерживаются во всех конфигах. Все уже решено. Меняется по кнопке. Если вы что-то делаете даже в двух местах, то пора посмотреть подумать и исправить это. Точно есть какое-то стандартное решение.
Ну да. Компилятор вызывается из системы сборки, рантайм работает сам просто кого вызовешь. Сертификаты из стандартного хранилища подхватываются сами. Ну вот отсюда вызвал, оно из того же jdk и подхватилось Сторонние библиотеки приезжают в сборку какие укажешь в системе сборки.
Джава хороша своей огромной экосистемой. Все проблемы о которых вы даже не задумывались решены. И не просто решены, а есть типовое решение. Проверенное всем миром. Никто давно ничего в 10 местах не меняет. Даже в одном менять не стоит. Все делается просто по кнопке.
avost
То есть всёртаки не надо менять вручную строчки в конфиге? Ну, надо же! А вы говорили, что запросто меняете каждый раз...
Серьёзно? А как же строчка в конфиге? Но я вам даже больше скажу - одно из этих решений называется jenv. Внезапно.
В которой надо строчку в конфиге поменять, как вы сами сказали.
Неа. Вы бы хоть попробовали :)...
Вы же их не используете, они же неудобные. И, нет, это работает иначе.
Niet :)
Это же та которой надо строку в конфиге поменять? Или не надо?
Зачем же вы сказали, что надо поменять в конфиге?
(Сходил за попкорном) ну, так назовите уже эту кнопку! "Имя, сестра, имя" (ц)
aleksandy
Так а кнопку-то кто будет настраивать? И, главное, как? Смысл подобных инструментов как раз в том, что они суть есть эта волшебная кнопка.
Тут ниже уже написали про
sdkman
. С ним вообще можно один раз у проект настроить.