From f07f82c501de5598b31fcc58d99c5416b6871a0d Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Tue, 28 Jan 2025 10:37:43 +0200 Subject: [PATCH 1/9] fix: JAVA_HOME should be pointing at JDK directory, instead points to JRE directory --- src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index db9b754..e8986a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,6 +195,7 @@ fn do_locate_java_home() -> Result { // Here we should have found ourselves in a directory like /usr/lib/jvm/java-8-oracle/jre/bin/java home_path.pop(); home_path.pop(); + home_path.pop(); home_path .into_os_string() @@ -276,4 +277,10 @@ mod unit_tests { fn locate_java_from_exec_test() { println!("do_locate_java_home: {}", do_locate_java_home().unwrap()); } + + #[test] + fn jni_headers_test() { + let java_home = do_locate_java_home().unwrap(); + assert!(PathBuf::from(java_home).join("include").join("jni.h").exists()); + } } From 1fd5a97a4452a4cda22cef855d706ca4493c3363 Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Tue, 28 Jan 2025 10:38:36 +0200 Subject: [PATCH 2/9] chore: Update actions --- .github/workflows/ci-workflow.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index e04180c..f9c2b99 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -18,9 +18,9 @@ jobs: os: [ ubuntu-latest, macos-latest, windows-latest ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'adopt' From e05d08ce3974617f3814f83a9afc9dbccafdbfd2 Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Tue, 28 Jan 2025 11:05:04 +0200 Subject: [PATCH 3/9] feature flag --- Cargo.toml | 3 ++- src/lib.rs | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c99373a..1576447 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,4 +26,5 @@ glob = "0.3" docopt = { version = "1.1", optional = true } [features] -build-binary = ["docopt"] \ No newline at end of file +build-binary = ["docopt"] +legacy-java-compat = [] diff --git a/src/lib.rs b/src/lib.rs index e8986a0..e4108d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -195,7 +195,17 @@ fn do_locate_java_home() -> Result { // Here we should have found ourselves in a directory like /usr/lib/jvm/java-8-oracle/jre/bin/java home_path.pop(); home_path.pop(); - home_path.pop(); + + // Java 8(aka 1.8) has a slightly different directory structure, + // where java is in the ${JAVA_HOME}/jre/bin/java directory, and ${JAVA_HOME}/bin/java is just a symlink. + // Since we recursively follow symlinks, we end up in the wrong directory, + // so we need to pop one more time. + #[cfg(feature = "legacy-java-compat")] + if let Some(last_section) = home_path.file_name() { + if last_section == "jre" { + home_path.pop(); + } + } home_path .into_os_string() From f15d0fadfcc47658573c1c5c343907d94afb8abf Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Tue, 28 Jan 2025 11:12:43 +0200 Subject: [PATCH 4/9] Add legacy test --- .github/workflows/ci-workflow.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index f9c2b99..c23ec15 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -27,4 +27,17 @@ jobs: - name: Build Rust with Cargo run: cargo build --verbose - name: Test Rust with Cargo - run: cargo test --verbose -- --nocapture \ No newline at end of file + run: cargo test --verbose -- --nocapture + + test-legacy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 8 + uses: actions/setup-java@v4 + with: + java-version: '8' + distribution: 'temurin' + - name: Test Rust with Cargo + run: JAVAM_HOME="" cargo test --features=legacy-java-compat --verbose -- --nocapture \ No newline at end of file From c3ff3b32ae0b31cfd056d72c4541a35af79d2114 Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Tue, 28 Jan 2025 11:16:35 +0200 Subject: [PATCH 5/9] newline --- .github/workflows/ci-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index c23ec15..a56186f 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -40,4 +40,4 @@ jobs: java-version: '8' distribution: 'temurin' - name: Test Rust with Cargo - run: JAVAM_HOME="" cargo test --features=legacy-java-compat --verbose -- --nocapture \ No newline at end of file + run: JAVAM_HOME="" cargo test --features=legacy-java-compat --verbose -- --nocapture From 5faa4bff284a8c4c1f4854021f125e370e4e29db Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Tue, 28 Jan 2025 13:12:46 +0200 Subject: [PATCH 6/9] fix typo --- .github/workflows/ci-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index a56186f..a226794 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -40,4 +40,4 @@ jobs: java-version: '8' distribution: 'temurin' - name: Test Rust with Cargo - run: JAVAM_HOME="" cargo test --features=legacy-java-compat --verbose -- --nocapture + run: JAVA_HOME="" cargo test --features=legacy-java-compat --verbose -- --nocapture From cb11989617ba7b1cb04ef9fcda67fd5cf542b9f1 Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Tue, 28 Jan 2025 16:22:50 +0200 Subject: [PATCH 7/9] fmt --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e4108d9..c7b0942 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -291,6 +291,9 @@ mod unit_tests { #[test] fn jni_headers_test() { let java_home = do_locate_java_home().unwrap(); - assert!(PathBuf::from(java_home).join("include").join("jni.h").exists()); + assert!(PathBuf::from(java_home) + .join("include") + .join("jni.h") + .exists()); } } From 5532531d1a7f8b252867624cc6fc182a1c8dd461 Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Thu, 30 Jan 2025 10:17:08 +0200 Subject: [PATCH 8/9] Update to new fix implementation --- .github/workflows/ci-workflow.yml | 6 ++-- Cargo.toml | 2 +- src/lib.rs | 57 +++++++++++++++++++------------ 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index a226794..03ac950 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -29,9 +29,9 @@ jobs: - name: Test Rust with Cargo run: cargo test --verbose -- --nocapture - test-legacy: + # This is a good test for the locate-jdk-only feature, as the JRE is in a different path on JDK 8 + test-locate-jdk: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 - name: Set up JDK 8 @@ -40,4 +40,4 @@ jobs: java-version: '8' distribution: 'temurin' - name: Test Rust with Cargo - run: JAVA_HOME="" cargo test --features=legacy-java-compat --verbose -- --nocapture + run: JAVA_HOME="" cargo test --features=locate-jdk-only --verbose -- --nocapture diff --git a/Cargo.toml b/Cargo.toml index 1576447..45a35e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,4 +27,4 @@ docopt = { version = "1.1", optional = true } [features] build-binary = ["docopt"] -legacy-java-compat = [] +locate-jdk-only = [] diff --git a/src/lib.rs b/src/lib.rs index c7b0942..be04554 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,12 +78,18 @@ The latter two commands should return something like: > /usr/lib/jvm/java-11-openjdk-amd64/lib +## Extra Features + +* `locate-jdk-only`: Attempts to locate the JDK first by searching for the Java compiler. \ +If this fails, it falls back to locating the JRE by searching for the Java runtime. +This solves issues in JDK 8 where the JRE resides in a subdirectory and not in the JDK root. + ## License At your option, under: -* Apache License, Version 2.0, (http://www.apache.org/licenses/LICENSE-2.0) -* MIT license (http://opensource.org/licenses/MIT) +* Apache License, Version 2.0, () +* MIT license () */ @@ -96,6 +102,9 @@ use glob::{glob, Pattern}; pub mod errors; +const JAVA_BINARY: &str = "java"; +const JAVAC_BINARY: &str = "javac"; + /// Returns the name of the jvm dynamic library: /// /// * libjvm.so for Linux @@ -120,16 +129,26 @@ pub fn get_jvm_dyn_lib_file_name() -> &'static str { /// If `JAVA_HOME` is not defined, the function tries to locate it using the `java` executable. pub fn locate_java_home() -> Result { match &env::var("JAVA_HOME") { - Ok(s) if s.is_empty() => do_locate_java_home(), + Ok(s) if s.is_empty() => locate_java_home_with_fallback(), Ok(java_home_env_var) => Ok(java_home_env_var.clone()), - Err(_) => do_locate_java_home(), + Err(_) => locate_java_home_with_fallback(), + } +} + +fn locate_java_home_with_fallback() -> Result { + if cfg!(feature = "locate-jdk-only") { + // Try locating the JDK first by searching for the Java compiler + // If this fails, fallback to locating the JRE, by locating the Java runtime + do_locate_java_home(JAVAC_BINARY).or_else(|_| do_locate_java_home(JAVA_BINARY)) + } else { + do_locate_java_home(JAVA_BINARY) } } #[cfg(target_os = "windows")] -fn do_locate_java_home() -> Result { +fn do_locate_java_home(binary: &str) -> Result { let output = Command::new("where") - .arg("java") + .arg(binary) .output() .map_err(|e| JavaLocatorError::new(format!("Failed to run command `where` ({e})")))?; @@ -182,9 +201,9 @@ fn do_locate_java_home() -> Result { } #[cfg(not(any(target_os = "windows", target_os = "macos")))] // Unix -fn do_locate_java_home() -> Result { +fn do_locate_java_home(binary: &str) -> Result { let output = Command::new("which") - .arg("java") + .arg(binary) .output() .map_err(|e| JavaLocatorError::new(format!("Failed to run command `which` ({e})")))?; let java_exec_path = std::str::from_utf8(&output.stdout)?.trim(); @@ -196,17 +215,6 @@ fn do_locate_java_home() -> Result { home_path.pop(); home_path.pop(); - // Java 8(aka 1.8) has a slightly different directory structure, - // where java is in the ${JAVA_HOME}/jre/bin/java directory, and ${JAVA_HOME}/bin/java is just a symlink. - // Since we recursively follow symlinks, we end up in the wrong directory, - // so we need to pop one more time. - #[cfg(feature = "legacy-java-compat")] - if let Some(last_section) = home_path.file_name() { - if last_section == "jre" { - home_path.pop(); - } - } - home_path .into_os_string() .into_string() @@ -285,12 +293,19 @@ mod unit_tests { #[test] fn locate_java_from_exec_test() { - println!("do_locate_java_home: {}", do_locate_java_home().unwrap()); + println!( + "do_locate_java_home: {}", + do_locate_java_home(JAVA_BINARY).unwrap() + ); + println!( + "do_locate_java_home: {}", + do_locate_java_home(JAVAC_BINARY).unwrap() + ); } #[test] fn jni_headers_test() { - let java_home = do_locate_java_home().unwrap(); + let java_home = locate_java_home_with_fallback().unwrap(); assert!(PathBuf::from(java_home) .join("include") .join("jni.h") From aae2c9f59975024930c42c325357863ba77287cd Mon Sep 17 00:00:00 2001 From: Emily Matheys Date: Thu, 30 Jan 2025 11:24:18 +0200 Subject: [PATCH 9/9] No fallback to JRE, missed the macos tests, update documentation to reflect the new approach. --- src/lib.rs | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index be04554..14c870d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,9 +80,10 @@ The latter two commands should return something like: ## Extra Features -* `locate-jdk-only`: Attempts to locate the JDK first by searching for the Java compiler. \ -If this fails, it falls back to locating the JRE by searching for the Java runtime. -This solves issues in JDK 8 where the JRE resides in a subdirectory and not in the JDK root. +* `locate-jdk-only`: Attempts to locate the JDK by searching for the Java compiler, + as opposed to searching for the runtime. + This solves issues in JDK 8 where the JRE resides in a subdirectory and not in the JDK root, + so development files are not found in JAVA_HOME as would be expected. ## License @@ -102,8 +103,10 @@ use glob::{glob, Pattern}; pub mod errors; -const JAVA_BINARY: &str = "java"; -const JAVAC_BINARY: &str = "javac"; +#[cfg(not(feature = "locate-jdk-only"))] +const LOCATE_BINARY: &str = "java"; +#[cfg(feature = "locate-jdk-only")] +const LOCATE_BINARY: &str = "javac"; /// Returns the name of the jvm dynamic library: /// @@ -129,26 +132,16 @@ pub fn get_jvm_dyn_lib_file_name() -> &'static str { /// If `JAVA_HOME` is not defined, the function tries to locate it using the `java` executable. pub fn locate_java_home() -> Result { match &env::var("JAVA_HOME") { - Ok(s) if s.is_empty() => locate_java_home_with_fallback(), + Ok(s) if s.is_empty() => do_locate_java_home(), Ok(java_home_env_var) => Ok(java_home_env_var.clone()), - Err(_) => locate_java_home_with_fallback(), - } -} - -fn locate_java_home_with_fallback() -> Result { - if cfg!(feature = "locate-jdk-only") { - // Try locating the JDK first by searching for the Java compiler - // If this fails, fallback to locating the JRE, by locating the Java runtime - do_locate_java_home(JAVAC_BINARY).or_else(|_| do_locate_java_home(JAVA_BINARY)) - } else { - do_locate_java_home(JAVA_BINARY) + Err(_) => do_locate_java_home(), } } #[cfg(target_os = "windows")] -fn do_locate_java_home(binary: &str) -> Result { +fn do_locate_java_home() -> Result { let output = Command::new("where") - .arg(binary) + .arg(LOCATE_BINARY) .output() .map_err(|e| JavaLocatorError::new(format!("Failed to run command `where` ({e})")))?; @@ -201,9 +194,9 @@ fn do_locate_java_home() -> Result { } #[cfg(not(any(target_os = "windows", target_os = "macos")))] // Unix -fn do_locate_java_home(binary: &str) -> Result { +fn do_locate_java_home() -> Result { let output = Command::new("which") - .arg(binary) + .arg(LOCATE_BINARY) .output() .map_err(|e| JavaLocatorError::new(format!("Failed to run command `which` ({e})")))?; let java_exec_path = std::str::from_utf8(&output.stdout)?.trim(); @@ -293,19 +286,12 @@ mod unit_tests { #[test] fn locate_java_from_exec_test() { - println!( - "do_locate_java_home: {}", - do_locate_java_home(JAVA_BINARY).unwrap() - ); - println!( - "do_locate_java_home: {}", - do_locate_java_home(JAVAC_BINARY).unwrap() - ); + println!("do_locate_java_home: {}", do_locate_java_home().unwrap()); } #[test] fn jni_headers_test() { - let java_home = locate_java_home_with_fallback().unwrap(); + let java_home = do_locate_java_home().unwrap(); assert!(PathBuf::from(java_home) .join("include") .join("jni.h")