Skip to content

Commit

Permalink
Use /usr/libexec/java_home as a fallback for JAVA_HOME
Browse files Browse the repository at this point in the history
  • Loading branch information
fmeum committed Jan 12, 2022
1 parent 95cca01 commit 268a922
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 2 deletions.
6 changes: 4 additions & 2 deletions docs/targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ runtime when its first symbol is accessed. Concretely, it does the following in
1. Depend on `@fmeum_rules_jni//jni:libjvm` directly from your top-level `cc_binary`.
2. Add `#include <rules_jni.h>`.
3. Call `rules_jni_init(const char* argv0)` from your `main` function, providing `argv[0]` as the argument.

If you want this lookup to succeed also for binaries executed by other binaries that are themselves run from Bazel,
[set the environment variables required for runfiles discovery](https://github.com/bazelbuild/bazel/blob/e8a066e9e625a136363338d10f03ed14c26dedfa/tools/cpp/runfiles/runfiles_src.h#L58).

Expand All @@ -52,7 +52,9 @@ runtime when its first symbol is accessed. Concretely, it does the following in
3. If `JAVA_HOME` is set, find the `jvm` shared library relative to it at well-known locations, exiting if it cannot be
found.

4. If `PATH` is set, find the Java binary (`java` or `java.exe`) on it and try to load the `jvm` shared library from
4. (macOS only) Execute `/usr/libexec/java_home` and use its output as a replacement for `JAVA_HOME`.

5. If `PATH` is set, find the Java binary (`java` or `java.exe`) on it and try to load the `jvm` shared library from
well-known locations relative to it, exiting if it cannot be found.

To get detailed runtime logs from this location procedure, set the environment variable `RULES_JNI_TRACE` to a non-empty
Expand Down
7 changes: 7 additions & 0 deletions jni/tools/libjvm_stub/libjvm_stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ static char* find_java_executable() {
/* The returned string has to be freed by the caller. */
static char* find_java_home() {
const char* java_home_env;
char* java_home_fallback = NULL;
char* java_executable_path = NULL;
char* pos;
size_t separator_count_from_end;
Expand All @@ -205,6 +206,12 @@ static char* find_java_home() {
return res;
}

java_home_fallback = get_java_home_fallback();
if (java_home_fallback != NULL) {
trace("get_java_home_fallback() returned: %s", java_home_fallback);
return java_home_fallback;
}

java_executable_path = find_java_executable();
if (java_executable_path == NULL) {
return NULL;
Expand Down
42 changes: 42 additions & 0 deletions jni/tools/libjvm_stub/unix/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __APPLE__
#include <string.h>
#include <sys/syslimits.h>
#endif
#include <unistd.h>

static const char* JAVA_EXECUTABLE = "/java";
Expand All @@ -41,6 +45,44 @@ static const size_t MAX_CANDIDATE_PATH_LENGTH = 22;

static int executable_exists(const char* path) { return access(path, X_OK); }

#ifdef __APPLE__
static char* our_strdup(const char* src);
#endif

/* The returned string has to be freed by the caller. */
static char* get_java_home_fallback() {
#ifdef __APPLE__
char* res = NULL;
FILE* pipe = NULL;
char buffer[PATH_MAX];

/* java_home prints the JAVA_HOME of the default installation to stdout.
* Silence warnings by redirecting stderr to /dev/null. */
pipe = popen("/usr/libexec/java_home 2> /dev/null", "r");
if (pipe == NULL) {
goto cleanup;
}

res = fgets(buffer, sizeof(buffer), pipe);
if (res == NULL || strcmp(res, "") == 0) {
goto cleanup;
}

/* The output of java_home is terminated by a newline. Skip over it. */
res[strlen(res) - 1] = '\0';
res = strdup(res);

cleanup:
if (pipe != NULL) {
pclose(pipe);
}

return res;
#else
return NULL;
#endif
}

static void* load_library(const char* path) {
return dlopen(path, RTLD_LAZY | RTLD_LOCAL);
}
Expand Down
2 changes: 2 additions & 0 deletions jni/tools/libjvm_stub/windows/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ static int executable_exists(const char* path) {
return 0;
}

static char* get_java_home_fallback() { return NULL; }

static void* load_library(const char* path) { return LoadLibrary(path); }

static void* load_symbol(void* library_handle, const char* symbol) {
Expand Down
6 changes: 6 additions & 0 deletions tests/libjvm_stub/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ cc_test(
"PATH_OVERRIDE": "",
"RULES_JNI_TRACE": "1",
},
target_compatible_with = select({
# Skip on macOS since the /usr/libexec/java_home fallback means that
# a JDK will still be found without PATH and JAVA_HOME.
"@platforms//os:macos": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
deps = [
"@fmeum_rules_jni//jni:libjvm_lite",
],
Expand Down

0 comments on commit 268a922

Please sign in to comment.