Bug 259468 - java/javavmwrapper: Add a java_home command
Summary: java/javavmwrapper: Add a java_home command
Status: Open
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: --- Affects Some People
Assignee: Greg Lewis
Keywords: needs-qa
Depends on:
Reported: 2021-10-26 23:47 UTC by Thomas Hurst
Modified: 2022-11-23 20:21 UTC (History)
2 users (show)

See Also:
bugzilla: maintainer-feedback? (glewis)
koobs: merge-quarterly?

Initial implementation attempt (5.57 KB, patch)
2021-10-27 15:40 UTC, Thomas Hurst
no flags Details | Diff
Minor tweak to initial implementation (5.57 KB, patch)
2021-10-27 15:46 UTC, Thomas Hurst
no flags Details | Diff
Updated patch (5.15 KB, patch)
2021-10-28 14:59 UTC, Thomas Hurst
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Hurst 2021-10-26 23:47:04 UTC
JRuby's launchers currently attempt to determine JAVA_HOME by resolving symlinks - it uses this mechanism to determine if the JVM has modules support, which necessitates calling java with various `--add-opens` flags for fully-featured operation.

This obviously doesn't work on FreeBSD, as it just resolves to /usr/local/bin: https://github.com/jruby/jruby/issues/6905

Manually setting JAVA_HOME works around this, but is obviously not an ideal solution.

The best fix would seem to be for javavmwrapper to offer a mechanism to determine the configured JAVA_HOME, and there seems to be precedent for such a feature on other platforms which offer similar functionality in the form of a `java_home` command: https://medium.com/notes-for-geeks/java-home-and-java-home-on-macos-f246cab643bd

>       java_home - return a value for $JAVA_HOME
> -v or --version  version
>    Filters the returned JVMs by the major platform version in "JVMVersion" form.
>    Example versions: "1.5+", or "1.6*".

> -V or --verbose
>    Prints the matching list of JVMs and architectures to stderr.

> --exec  command ...
>    Executes the command at $JAVA_HOME/bin/<command> and passes the remaining arguments. 
>    Any arguments to select which $JAVA_HOME to use must precede the --exec option.

For JRuby's purposes only the most basic functionality would be required, with the rest perhaps a nice-to-have.

This might also be nice for heavy Java users - manually setting JAVA_HOME cuts out most of javavmwrapper's overheads (in my case, 95ms becomes 15ms), and this would allow it to be set without manually hardcoding it.

Does this seem reasonable?
Comment 1 Kubilay Kocak freebsd_committer freebsd_triage 2021-10-26 23:54:56 UTC
What is the user impact with this resolution mechanism missing? Some subset of java software cannot be built/installed (they fail?)

Are there precedents/examples for a standard mechanism in the packages for other OS's we can reference & use?
Comment 2 Thomas Hurst 2021-10-27 01:14:12 UTC
It basically means a user unaware of how to work around the problem will struggle to install recent versions of JRuby - a `rbenv install jruby-` will fail with an obscure "Bad file descriptor" error when attempting to build jruby-launcher, which ruby-build considers fatal.

A manual attempt might run into issues like:

> javavm: warning: The use of 'javavm' as a synonym for 'java' is deprecated
> 2021-10-27T00:27:59.661Z [main] WARN FilenoUtil : Native subprocess control requires open access to the JDK IO subsystem
> Pass '--add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED' to enable.

symlink chasing results in calling a deprecated name for javavmwrapper, and incorrect JAVA_HOME guessing results in a failure to detect a modularized JVM giving strange warnings and limited functionality.

This is also the reason I haven't updated the port - I'm not sure how to actually make it work reliably in the general case.

As far as I can tell the java_home command is specific to macOS, and other platforms tend to just go for a single version blessed by symlinks.
Comment 3 Thomas Hurst 2021-10-27 15:40:43 UTC
Created attachment 229074 [details]
Initial implementation attempt

Here's a quick implementation of such a command, supporting only short options.

❯ java_home
❯ java_home -v 13
java_home: error: no suitable JavaVMs found
❯ java_home -v 13+
❯ java_home -v 13+ -o linux
java_home: error: no suitable JavaVMs found
❯ java_home -v 13+ -e java -version
openjdk version "14.0.2" 2020-07-14
Comment 4 Thomas Hurst 2021-10-27 15:46:11 UTC
Created attachment 229075 [details]
Minor tweak to initial implementation

Remove a vestigial -: from getopts which was from an aborted attempt to support long options.
Comment 5 Thomas Hurst 2021-10-28 14:59:15 UTC
Created attachment 229096 [details]
Updated patch

Tidy up argument handling, fix some default variable handling, and add a -V option for setting JAVA_VENDOR.

This does diverge from the macOS implementation with a different meaning for -V, but it seems unlikely anyone's going to use that in a script.
Comment 6 Michael Osipov 2021-10-29 07:54:28 UTC
FWIW, I have removed all Java discovery logic from Maven 4 because it was brittle and never complete. Jruby and others suffer from the same problem: applying to much discovery magic.
Comment 7 Greg Lewis freebsd_committer 2021-11-09 04:17:33 UTC
Hi Thomas,

Thanks for taking the time to submit this bug report and patch.  I'd like to compare what you've got to the MacOS version but java_home doesn't appear to exist on my MacOS box (running Mojave).  Do you know when it was introduced?  I can potentially run a newer version in a VM and check it out that way.

-- Greg
Comment 8 Thomas Hurst 2021-11-09 12:06:54 UTC
It's /usr/libexec/java_home on macOS, and dates all the way back to 10.5 (Leopard).
Comment 9 Greg Lewis freebsd_committer 2021-11-10 06:43:20 UTC
Thanks!  /usr/libexec was not in my path, but I do see it there.  I'll give the man page a read and try it out a bit and compare.
Comment 10 Thomas Hurst 2022-11-23 20:21:39 UTC
(In reply to Greg Lewis from comment #9)

Did you get a chance to look at this?