-
Notifications
You must be signed in to change notification settings - Fork 326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
--jvm tries to find Java executable system-wide. #11500
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The --jvm option now tries to find java executable from JAVA_HOME and from PATH. If that is not found, the distribution manager's runtimes are used as a fallback.
I'd say that this is the wrong order. The target audience of Enso users is unlikely to have proper JVM installed in the system. Searching for a system JVM is good for us, developers, but not for our target audience.
trying to find the java executable from the distribution manager's runtime (on my system located in ~/.local/share/enso/runtime) and it used the first runtime found. But the first runtime on my system is JDK 17.
It is good we have such a failing example! What is the layout of your Enso JVM runtimes? That is an important information for your #11274 bug report.
Anyway, the enso
launcher should:
- search managed runtimes (in
~/.local/share/enso/runtime
) first - ignore the outdated ones - e.g. having JVM spec version lower than
21
(right now) - select the exact match, if found
- select acceptable match (e.g. newer JDK), if found - probably with some warning printed
- if no match found among managed runtimes, fallback to system JVM - with some warning printed, if the JDK isn't exactly the one we expect
Would the above steps work for your system setup, Pavel?
That is a good point.
Certainly. Sounds like a good plan. I will see what I can do. |
It would be great, if we selected the same JDK as used for the build (however that's
DistributionManager shall do most of the selection logic. CCing @radeusgd to give us an expert guidance. |
…m runtime-version-manager
/** | ||
* Tries to find {@code java} executable on the system. If a system-wide JDK is not found, tries | ||
* to find it in the {@link DistributionManager distribution} runtimes. | ||
* | ||
* @return null if cannot be found. Otherwise, returns the absolute path to the executable, or | ||
* simply {@code java} if it is on the {@code PATH}. | ||
*/ | ||
static String findJavaExecutable() { | ||
var javaHome = System.getenv("JAVA_HOME"); | ||
if (javaHome != null) { | ||
var java = new File(javaHome, "bin/java").getAbsoluteFile(); | ||
if (java.exists()) { | ||
return java.getAbsolutePath(); | ||
} | ||
} | ||
if (isJavaOnPath()) { | ||
return "java"; | ||
} | ||
var javaInRuntime = findJavaExecutableInDistributionRuntimes(); | ||
if (javaInRuntime != null) { | ||
return javaInRuntime.toAbsolutePath().toString(); | ||
} | ||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the precedence should actually look into distribution first and only afterwards use system JVM.
The whole purpose of ensoup
was to manage JVMs related to the engine versions, so that the engine is run with the right compatible JVM and not a random version that may be incompatible with it (I guess it used to be more important before Truffle 'got unchained').
I think ideally we should first to run the JVM version required by the engine if it's found in the distribution. Then we can fallback to using the logic of searching JAVA_HOME
and Path
.
Ideally I'd also check the JVM version and log a warning if the version required by engine does not match the version that has been found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JVMs related to the engine versions
This version is stored in the engine's manifest - see for example built-distribution/enso-engine-0.0.0-dev-windows-amd64/enso-0.0.0-dev/manifest.yaml
.
It contains fields: graal-vm-version
and graal-java-version
.
You can see lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/Manifest.scala
for the logic of loading the manifest and extracting the GraalVMVersion
from it.
We have a GraalCEReleaseProvider
which translates this GraalVMVersion
into a strategy for downloading it from GitHub - but you probably don't need this.
The function graalDirectoryForVersion
in RuntimeVersionManager
takes GraalVMVersion
and gives you back the directory name under which this JVM version will be sitting in the $ENSO_DATA_DIRECTORY/runtime
(installed by ensoup
).
I guess you could factor out the Manifest
and graalDirectoryForVersion
utilities to a common package and you could use it to figure out the JVM version tied to the engine.
Btw. the manifest also contains a jvm-options
field. I'd be very happy if we could keep the (sometimes changing) options in a single place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess if you want to check if the JVM version is correct you need to call java --version
and somehow parse its output and compare with graal-java-version
.
e.g. I get
openjdk 21.0.2 2024-01-16
OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)
I guess I want to extract the second word from the first line. At least for now that seems to work. But we can update the logic whenever the version format of expected JVM changes - unexpected format just means it's not the JVM we expect :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly better way than parsing output of java -version
is to run a small program on the JVM:
public static void main(String... args) {
System.out.prinltn(System.getProperty("java.vm.version"));
// etc.
}
and just read the output line by line without the need to parse words.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool - that indeed sounds better, I didn't think of that
As of 586fc73:
Only when there is no newer runtime found in the managed distribution runtimes, |
...ion-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
Windows CI does not have
|
What about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit surprised this fails Windows PR check. What's the reason?
logger.warn("Falling back to java on PATH: {}", javaExe); | ||
return javaExe; | ||
} | ||
logger.warn("No JDK found on PATH. Cannot start the runtime."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't you be checking ENSO_JVM_PATH
as well?
return null; | ||
} | ||
|
||
private static boolean isOnWindows() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could just use OS.isWindows()
instead? It's already a dependency, right?
try { | ||
ProcessBuilder processBuilder; | ||
if (isOnWindows()) { | ||
processBuilder = new ProcessBuilder("java.exe", "-h"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
processBuilder = new ProcessBuilder("java.exe", "-h"); | |
processBuilder = new ProcessBuilder("java.exe", "-v"); |
if (isOnWindows()) { | ||
processBuilder = new ProcessBuilder("java.exe", "-h"); | ||
} else { | ||
processBuilder = new ProcessBuilder("java", "-h"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
processBuilder = new ProcessBuilder("java", "-h"); | |
processBuilder = new ProcessBuilder("java", "-v"); |
Congratulation to getting thru CI checks. |
Fixes `--jvm` option, given to the native image. This was failing on my machine, because when given `--jvm` option, the runner was trying to find the `java` executable from the distribution manager's runtime (on my system located in `~/.local/share/enso/runtime`) and it used the first runtime found. But the first runtime on my system is JDK 17. The `--jvm` option now tries to: - Find a JDK from the distribution manager that has the same version as the JDK used for building the engine. - If there is not an exact version match, it tries to find a runtime from distribution manager that is *newer*. - If none, fallback to system-wide search - System-wide search tries to find `java` from `$JAVA_HOME` and from `$PATH`. But this is just a fallback. # Important Notes - Added test to Engine CI jobs that pass `--jvm` argument to a native image of engine-runner - ea3af5f - `runtime-version-manager` sbt project migrated to a JPMS module - `engine-runner` now depends on `runtime-version-manager`. - Removed unnecessary stuff in `runtime-version-manager` dealing with outdated `gu` Graal Updater utility. - Extracted [GraalVersionManager](https://github.com/enso-org/enso/blob/1455b025cb8e5141409ea96b75577e8884265a70/lib/scala/runtime-version-manager/src/main/java/org/enso/runtimeversionmanager/components/GraalVersionManager.java) from [RuntimeVersionManager](https://github.com/enso-org/enso/blob/d2e8994700fd36228f7873f040668013e643190a/lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/RuntimeVersionManager.scala)
Fixes #11274
Pull Request Description
Fixes
--jvm
option, given to the native image. This was failing on my machine, because when given--jvm
option, the runner was trying to find thejava
executable from the distribution manager's runtime (on my system located in~/.local/share/enso/runtime
) and it used the first runtime found. But the first runtime on my system is JDK 17.The
--jvm
option now tries to:java
from$JAVA_HOME
and from$PATH
. But this is just a fallback.Important Notes
--jvm
argument to a native image of engine-runnerruntime-version-manager
sbt project migrated to a JPMS moduleengine-runner
now depends onruntime-version-manager
.runtime-version-manager
dealing with outdatedgu
Graal Updater utility.Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java,
TypeScript,
and
Rust
style guides. In case you are using a language not listed above, follow the Rust style guide.
or the Snowflake database integration, a run of the Extra Tests has been scheduled.