-
Notifications
You must be signed in to change notification settings - Fork 64
[Java.Interop.BootstrapTasks] Support single-digit versions #327
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
[Java.Interop.BootstrapTasks] Support single-digit versions #327
Conversation
9a4c98c to
efcea05
Compare
jonathanpeppers
left a comment
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.
Ok, I think I see one other thing that could break here.
If we hit any of the null cases here: https://github.com/xamarin/java.interop/blob/ca27edd23f4dfa2700cf28deaabfe2d74fc72a93/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs#L105-L115
Like if there was a random directory in there with no numbers.
I think we need a null check for Version somewhere in this LINQ expression: https://github.com/xamarin/java.interop/blob/ca27edd23f4dfa2700cf28deaabfe2d74fc72a93/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs#L168-L175
Yup, that's correct. There's another, closely related, problem: What should we do about ties? The original comment lays out the scenario, but doesn't ask (or answer!) the question: Given this directory: Which directory should be preferred, by default? I posed this question to @grendello, and he suggested using The pre- 4bd9297 answer was to use the directory with the most recent timestamp: https://github.com/xamarin/java.interop/blob/4bd9297f311b3e0fb3e07335507a38278b83d255^/build-tools/scripts/jdk.mk#L81: (This was why we used I suspect we should return to this behavior of preferring the directory with the most recent timestamp. |
|
It's good you already have LINQ: I think picking the highest version, then timestamp should still be doable. |
|
For equal versions, the most recent timestamps sounds good to me. BTW, various linuxes differ and on my dated Fedora I see this: So using |
|
@radekdoulik: can you do the The regex we use for sorting only looks at the first match in a filename. As such, there will be 6 matches for Do the We might also want to filter out directories which don't fulfill the requirements. |
|
I assume we use ctime here: The |
|
I find the "use the latest timestamp" approach to choose between Oracle Java and OpenJDK a bit dangerous. They are supposed to be compatible but, as we know from experience, they're not. Maybe we should, in this case, apply a simple check - look for |
efcea05 to
b01878e
Compare
|
New And Improved™! Current version now tries the output of We also add a "JDK Validation" method to ensure that not only does e.g. |
| Log.LogMessage (MessageImportance.Low, $" Skipping JAVA_HOME default value of `{java_home}` as it does not contain an `include` subdirectory."); | ||
| java_home = null; | ||
| } | ||
| if (java_home != 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.
the java_home != null check is redundant, since ValidateJdkPath repeats it. It might look neater if the null check is completely removed
| bool ValidateJdkPath (Version maxVersion, string java_home) | ||
| { | ||
| return ValidateJdkPath (maxVersion, java_home, | ||
| out var jar, out var javac, out var jdk, out var include); |
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 like a perfect place to use C#7 discards :)
| Log.LogMessage (MessageImportance.Low, $" {e.Data}"); | ||
| path = e.Data; | ||
| }); | ||
| return path; |
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.
/etc/alternatives/java points to the java executable, not home path:
$ readlink /etc/alternatives/java
/usr/lib/jvm/java-8-oracle/jre/bin/javaso more processing is necessary here to match output from e.g. macOS java_home
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.
After the force-push update, this comment is now on the wrong method. ;-)
It has been addressed, by sending the output of readlink /etc/alternatives/java through GetJavaHomePathFromJava(), which runs java -XshowSettings:properties ....
The `<JdkInfo/>` task sorts preferred JDK versions based on the version number embedded into the directory name. This unfortunately requires that the version number embedded into the directory name contain two or more version parts. This is true on macOS and Windows: # macOS $ ls -1tr /Library/Java/JavaVirtualMachines/ 1.6.0_65-b14-462.jdk jdk1.8.0_77.jdk jdk-9.0.4.jdk But this is not necessarily the case on Linux: $ ls -1 /usr/lib/jvm java-8-openjdk-amd64 java-8-oracle Single-part version numbers aren't supported by `Version.TryParse()`, so when `$(JI_MAX_JDK)` is set -- causing `maxVersion` to be non-null -- while the version *isn't* extracted from the directory name, the [comparison can fail][0]: [0]: https://jenkins.mono-project.com/job/xamarin-anroid-linux-pr-builder/2917/console The "JdkInfo" task failed unexpectedly. System.ArgumentNullException: Value cannot be null. Parameter name: v1 at System.Version.op_LessThanOrEqual (System.Version v1, System.Version v2) [0x00003] in <2f83d2ff70e3444cb3582fe4e97bad63>:0 at Java.Interop.BootstrapTasks.JdkInfo+<>c__DisplayClass31_0.<GetJavaHomePathFromMachine>b__2 (<>f__AnonymousType0`2[<Path>j__TPar,<Version>j__TPar] v) [0x00000] in …/xamarin-android/external/Java.Interop/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs:172 ... at Java.Interop.BootstrapTasks.JdkInfo.GetJavaHomePathFromMachine (System.Version maxVersion) [0x00015] in …/xamarin-android/external/Java.Interop/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs:163 at Java.Interop.BootstrapTasks.JdkInfo.Execute () [0x00176] in …/xamarin-android/external/Java.Interop/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs:56 Fix this by allowing extraction of Version numbers from single-part version codes as seen on Linux, allowing us to perform comparisons against non-null versions. If multiple directories *still* have matching version numbers, then we sort the output so that the location with the most recent write time is used. Additionally, check some OS-specific preferred locations: * On macOS, `/usr/libexec/java_home`, which is a program which prints out the preferred JDK location to stdout. * On Linux, `/usr/alternatives/java` is a symlink to the preferred JDK location, which we can read using `readlink`. Treat the OS-specific locations similar to `$JAVA_HOME`, and check them *before* attempting the `JdkInfo.JdksRoot` children.
b01878e to
d03ff8c
Compare
jonathanpeppers
left a comment
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.
So much code, to just "find java" on three platforms...
My only suggestion at this point might be to somehow move this code to a single cs file that could be reused in other projects without a dependency on MSBuild. Then, for example, I could add java.interop as a submodule to something like Embeddinator-4000 and even use the code within a Cake script. This could be done later, too.
radekdoulik
left a comment
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 like the idea of extracting the code later to own class/source file. I guess it will be handy later when running jinmarshalmethod-gen.exe on Windows.
|
In the interest of getting things ready for branching, we're merging now that it's green. :-) That said:
I don't think this would be useful; xamarin-android already has that information. We simply need to provide that information to |
|
Does XA have it when installed at a user machine, ie. not XA build time? What I remembered was that we need to introduce a way to get it at runtime. Maybe I remembered it wrong then. Where in the XA do we have it? |
The The Xamarin.Android |
The
<JdkInfo/>task sorts preferred JDK versions based on theversion number embedded into the directory name.
This unfortunately requires that the version number embedded into the
directory name contain two or more version parts. This is true on
macOS and Windows:
But this is not necessarily the case on Linux:
Single-part version numbers aren't supported by
Version.TryParse(),so when
$(JI_MAX_JDK)is set -- causingmaxVersionto be non-null-- while the version isn't extracted from the directory name, the
comparison can fail:
Fix this by allowing extraction of Version numbers from single-part
version codes as seen on Linux, allowing us to perform comparisons
against non-null versions.