Skip to content

Commit

Permalink
Ask the found JDK for its version instead of relying on wonky path sp…
Browse files Browse the repository at this point in the history
…litting (TheInfiniteKind#87)
  • Loading branch information
Vampire committed Nov 20, 2023
1 parent 928566b commit a4d5efb
Showing 1 changed file with 68 additions and 83 deletions.
151 changes: 68 additions & 83 deletions appbundler/native/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ typedef int (JNICALL *JLI_Launch_t)(int argc, char ** argv,
NSString * findJava (NSString *, bool, bool, bool);
NSString * findJRE (int, bool);
NSString * findJDK (int, bool);
bool checkJavaVersionCompatibility (NSString *, int, bool);
int extractMajorVersion (NSString *);
NSString * convertRelativeFilePath(NSString *);
NSString * addDirectoryToSystemArguments(NSUInteger, NSSearchPathDomainMask, NSString *, NSMutableArray *);
Expand Down Expand Up @@ -792,16 +793,31 @@ int launch(char *commandName, int progargc, char *progargv[]) {
int jvmRequired,
bool exactMatch)
{
// Try the "java -version" shell command and see if we get a response and
// if so whether the version is acceptable.
// Note that for unknown but ancient reasons, the result is output to stderr
// rather than to stdout.
if (checkJavaVersionCompatibility(@JAVA_RUNTIME, jvmRequired, exactMatch))
{
return @JAVA_RUNTIME;
}
else
{
return nil;
}
}

// Having failed to find a JRE in the usual location, see if a JDK is installed
// (probably in /Library/Java/JavaVirtualMachines).
/**
* Searches for a JDK of the specified version or optionally later.
*/
NSString * findJDK (
int jvmRequired,
bool exactMatch)
{
@try
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:[@JAVA_RUNTIME stringByAppendingPathComponent:@"bin/java"]];
[task setLaunchPath:@"/usr/libexec/java_home"];

NSArray *args = [NSArray arrayWithObjects: @"-version", nil];
NSArray *args = [NSArray arrayWithObjects: @"-v", [NSString stringWithFormat:@"1.%i%@", jvmRequired, exactMatch?@"":@"+"], nil];
[task setArguments:args];

NSPipe *stdout = [NSPipe pipe];
Expand All @@ -827,55 +843,49 @@ int launch(char *commandName, int progargc, char *progargv[]) {
NSString *errRead = [[NSString alloc] initWithData:data2
encoding:NSUTF8StringEncoding];

// Found something in errRead. Parse it for a Java version string and
// try to extract a major version number.
if (errRead != nil) {
int version = 0;

// The result of the version command is 'java version "1.x"' or 'java version "9"' or 'openjdk version "1.x" or 'openjdk version "12.x.y"'
NSRange vrange = [errRead rangeOfString:@"java version \""];

if (vrange.location != NSNotFound) {
NSString *vstring = [errRead substringFromIndex:(vrange.location + 14)];

vrange = [vstring rangeOfString:@"\""];
vstring = [vstring substringToIndex:vrange.location];

version = extractMajorVersion(vstring);
// If matching JDK not found, outRead will include something like
// "Unable to find any JVMs matching version "1.X"."
if ( errRead != nil
&& [errRead rangeOfString:@"Unable"].location != NSNotFound )
{
Log(@"No matching JDK found.");
return nil;
}

Log(@"Found a Java %@ JRE", vstring);
Log(@"Looks like major version %d", extractMajorVersion(vstring));
}
NSString *javaHome = [outRead stringByTrimmingCharactersInSet:[NSCharacterSet
whitespaceAndNewlineCharacterSet]];

if ( (version >= jvmRequired && !exactMatch) || (version == jvmRequired && exactMatch) ) {
Log(@"JRE version qualifies");
return @JAVA_RUNTIME;
}
if (checkJavaVersionCompatibility(javaHome, jvmRequired, exactMatch))
{
return javaHome;
}
}
@catch (NSException *exception)
{
Log(@"JRE search exception: '%@'", [exception reason]);
Log(@"JDK search exception: '%@'", [exception reason]);
}

return nil;
}

// Having failed to find a JRE in the usual location, see if a JDK is installed
// (probably in /Library/Java/JavaVirtualMachines).
/**
* Searches for a JDK of the specified version or later.
* Checks the version of a Java home for compatibility.
*/
NSString * findJDK (
int jvmRequired,
bool exactMatch)
bool checkJavaVersionCompatibility (
NSString *javaHome,
int jvmRequired,
bool exactMatch)
{
// Try the "java -version" shell command and see if we get a response and
// if so whether the version is acceptable.
// Note that for unknown but ancient reasons, the result is output to stderr
// rather than to stdout.
@try
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/usr/libexec/java_home"];
[task setLaunchPath:[javaHome stringByAppendingPathComponent:@"bin/java"]];

NSArray *args = [NSArray arrayWithObjects: @"-v", [NSString stringWithFormat:@"1.%i%@", jvmRequired, exactMatch?@"":@"+"], nil];
NSArray *args = [NSArray arrayWithObjects: @"-version", nil];
[task setArguments:args];

NSPipe *stdout = [NSPipe pipe];
Expand All @@ -901,68 +911,43 @@ int launch(char *commandName, int progargc, char *progargv[]) {
NSString *errRead = [[NSString alloc] initWithData:data2
encoding:NSUTF8StringEncoding];

// If matching JDK not found, outRead will include something like
// "Unable to find any JVMs matching version "1.X"."
if ( errRead != nil
&& [errRead rangeOfString:@"Unable"].location != NSNotFound )
// Found something in errRead. Parse it for a Java version string and
// try to extract a major version number.
if (errRead != nil)
{
Log(@"No matching JDK found.");
return nil;
}

int version = 0;

// ... and outRead will include something like
// "/Library/Java/JavaVirtualMachines/jdk-12.0.1.jdk/Contents/Home" or
// "/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home"

NSRange vrange = [outRead rangeOfString:@"jdk1."];
if (vrange.location == NSNotFound) {
// try the changed version layout from version 9 (e.g., jdk-9, zulu-12)
vrange = [outRead rangeOfString:@"-"];
vrange.location += 1;
} else {
// otherwise remove the leading jdk
vrange.location += 3;
}

if (vrange.location != NSNotFound) {
NSString *vstring = [outRead substringFromIndex:(vrange.location)];

vrange = [vstring rangeOfString:@"/"];
vstring = [vstring substringToIndex:vrange.location];
int version = 0;

version = extractMajorVersion(vstring);
// The result of the version command is 'java version "1.x"' or 'java version "9"' or 'openjdk version "1.x" or 'openjdk version "12.x.y"'
NSRange vrange = [errRead rangeOfString:@"version \""];

Log(@"Found a Java %@ JDK", vstring);
Log(@"Looks like major version %d", extractMajorVersion(vstring));
}
if (vrange.location != NSNotFound)
{
NSString *vstring = [errRead substringFromIndex:(vrange.location + 9)];

if ( (version >= jvmRequired && !exactMatch) || (version == jvmRequired && exactMatch) ) {
Log(@"JDK version qualifies");
vrange = [vstring rangeOfString:@"\""];
vstring = [vstring substringToIndex:vrange.location];

NSString *outread2 = [outRead stringByTrimmingCharactersInSet:[NSCharacterSet
whitespaceAndNewlineCharacterSet]];
version = extractMajorVersion(vstring);

// Return location where LIBJLI_DY_LIB is located. Note that the path was
// shortemed between JDK 8 and JDK 9.
if (version > 8) {
return outread2;
Log(@"Found a Java %@", vstring);
Log(@"Looks like major version %d", version);
}
else {
return [outread2 stringByAppendingPathComponent:@"jre"];

if ( ((version >= jvmRequired) && !exactMatch) || ((version == jvmRequired) && exactMatch) )
{
Log(@"Java version qualifies");
return true;
}
}
}
@catch (NSException *exception)
{
Log(@"JDK search exception: '%@'", [exception reason]);
Log(@"Java version check exception: '%@'", [exception reason]);
}

return nil;
return false;
}


/**
* Extract the Java major version number from a string. We expect the input
* to look like either either "1.X", "1.X.Y_ZZ" or "X.Y.ZZ", and the
Expand Down

0 comments on commit a4d5efb

Please sign in to comment.