From 1bb4783ace90e7936e5ca4b7b6d82b2dc54659b2 Mon Sep 17 00:00:00 2001 From: Isaac Turner Date: Wed, 8 May 2024 09:09:28 +0800 Subject: [PATCH] [wpiutil] Remove RuntimeLoader and RuntimeDetector Resolves https://github.com/wpilibsuite/allwpilib/issues/6598 --- .../wpi/first/apriltag/jni/AprilTagJNI.java | 7 +- .../first/apriltag/AprilTagDetectorTest.java | 7 +- .../java/edu/wpi/first/cscore/DevMain.java | 4 +- .../edu/wpi/first/cscore/CameraServerJNI.java | 12 +- .../edu/wpi/first/cscore/OpenCvLoader.java | 13 +- .../java/edu/wpi/first/hal/JNIWrapper.java | 13 +- .../java/edu/wpi/first/ntcore/DevMain.java | 4 +- .../main/java/NetworkTablesJNI.java.jinja | 11 +- .../first/networktables/NetworkTablesJNI.java | 11 +- .../edu/wpi/first/wpilibj/romi/DevMain.java | 4 +- styleguide/spotbugs-exclude.xml | 4 - .../wpi/first/wpilibj2/commands/DevMain.java | 4 +- .../java/edu/wpi/first/wpilibj/DevMain.java | 4 +- .../java/edu/wpi/first/math/WPIMathJNI.java | 13 +- .../dev/java/edu/wpi/first/net/DevMain.java | 4 +- .../java/edu/wpi/first/net/WPINetJNI.java | 12 +- .../dev/java/edu/wpi/first/util/DevMain.java | 2 +- .../wpi/first/util/CombinedRuntimeLoader.java | 54 ++++- .../edu/wpi/first/util/RuntimeDetector.java | 194 ------------------ .../edu/wpi/first/util/RuntimeLoader.java | 175 +--------------- .../java/edu/wpi/first/util/WPIUtilJNI.java | 13 +- .../edu/wpi/first/wpilibj/xrp/DevMain.java | 4 +- 22 files changed, 96 insertions(+), 473 deletions(-) delete mode 100644 wpiutil/src/main/java/edu/wpi/first/util/RuntimeDetector.java diff --git a/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java b/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java index 6aabbf9ddad..87c61e8279c 100644 --- a/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java +++ b/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java @@ -17,8 +17,6 @@ public class AprilTagJNI { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; - /** Sets whether JNI should be loaded in the static block. */ public static class Helper { private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); @@ -48,10 +46,7 @@ private Helper() {} static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "apriltagjni", RuntimeLoader.getDefaultExtractionRoot(), AprilTagJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("apriltagjni"); } catch (IOException ex) { ex.printStackTrace(); System.exit(1); diff --git a/apriltag/src/test/java/edu/wpi/first/apriltag/AprilTagDetectorTest.java b/apriltag/src/test/java/edu/wpi/first/apriltag/AprilTagDetectorTest.java index 2ace7a0ef69..475cbc0115b 100644 --- a/apriltag/src/test/java/edu/wpi/first/apriltag/AprilTagDetectorTest.java +++ b/apriltag/src/test/java/edu/wpi/first/apriltag/AprilTagDetectorTest.java @@ -29,15 +29,10 @@ class AprilTagDetectorTest { @SuppressWarnings("MemberName") AprilTagDetector detector; - static RuntimeLoader loader; - @BeforeAll static void beforeAll() { try { - loader = - new RuntimeLoader<>( - Core.NATIVE_LIBRARY_NAME, RuntimeLoader.getDefaultExtractionRoot(), Core.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME); } catch (IOException ex) { fail(ex); } diff --git a/cscore/src/dev/java/edu/wpi/first/cscore/DevMain.java b/cscore/src/dev/java/edu/wpi/first/cscore/DevMain.java index 11652f6867f..ec6468f90f9 100644 --- a/cscore/src/dev/java/edu/wpi/first/cscore/DevMain.java +++ b/cscore/src/dev/java/edu/wpi/first/cscore/DevMain.java @@ -4,13 +4,13 @@ package edu.wpi.first.cscore; -import edu.wpi.first.util.RuntimeDetector; +import edu.wpi.first.util.CombinedRuntimeLoader; public final class DevMain { /** Main method. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); System.out.println(CameraServerJNI.getHostname()); } diff --git a/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java b/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java index 0d874a7dd83..b0ac27aef53 100644 --- a/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java +++ b/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java @@ -15,8 +15,6 @@ public class CameraServerJNI { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; - /** Sets whether JNI should be loaded in the static block. */ public static class Helper { private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); @@ -46,10 +44,7 @@ private Helper() {} static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("cscorejni"); } catch (IOException ex) { ex.printStackTrace(); System.exit(1); @@ -67,10 +62,7 @@ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>( - "cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("cscorejni"); libraryLoaded = true; } diff --git a/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java b/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java index 0ca098c282c..1fb8fe65b90 100644 --- a/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java +++ b/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java @@ -14,9 +14,6 @@ public final class OpenCvLoader { @SuppressWarnings("PMD.MutableStaticState") static boolean libraryLoaded; - @SuppressWarnings("PMD.MutableStaticState") - static RuntimeLoader loader; - /** Sets whether JNI should be loaded in the static block. */ public static class Helper { private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); @@ -44,12 +41,9 @@ private Helper() {} } static { - String opencvName = Core.NATIVE_LIBRARY_NAME; if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class); - loader.loadLibraryHashed(); + RuntimeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME); } catch (IOException ex) { ex.printStackTrace(); System.exit(1); @@ -76,10 +70,7 @@ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>( - Core.NATIVE_LIBRARY_NAME, RuntimeLoader.getDefaultExtractionRoot(), Core.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME); libraryLoaded = true; } diff --git a/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java index 49bcb4a5ec8..985d30a5ee0 100644 --- a/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java +++ b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java @@ -11,7 +11,6 @@ /** Base class for all JNI wrappers. */ public class JNIWrapper { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; /** Sets whether JNI should be loaded in the static block. */ public static class Helper { @@ -42,11 +41,8 @@ private Helper() {} static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class); - loader.loadLibrary(); - } catch (IOException ex) { + RuntimeLoader.loadLibrary("wpiHaljni"); + } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } @@ -63,10 +59,7 @@ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>( - "wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("wpiHaljni"); libraryLoaded = true; } diff --git a/ntcore/src/dev/java/edu/wpi/first/ntcore/DevMain.java b/ntcore/src/dev/java/edu/wpi/first/ntcore/DevMain.java index 466731c0177..6d5e9711933 100644 --- a/ntcore/src/dev/java/edu/wpi/first/ntcore/DevMain.java +++ b/ntcore/src/dev/java/edu/wpi/first/ntcore/DevMain.java @@ -5,13 +5,13 @@ package edu.wpi.first.ntcore; import edu.wpi.first.networktables.NetworkTablesJNI; -import edu.wpi.first.util.RuntimeDetector; +import edu.wpi.first.util.CombinedRuntimeLoader; public final class DevMain { /** Main method. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); NetworkTablesJNI.flush(NetworkTablesJNI.getDefaultInstance()); } diff --git a/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja b/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja index 5c43b44e7d1..17d15c17540 100644 --- a/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja +++ b/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja @@ -17,7 +17,6 @@ import java.util.concurrent.atomic.AtomicBoolean; /** NetworkTables JNI. */ public final class NetworkTablesJNI { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; /** Sets whether JNI should be loaded in the static block. */ public static class Helper { @@ -48,10 +47,7 @@ public final class NetworkTablesJNI { static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "ntcorejni", RuntimeLoader.getDefaultExtractionRoot(), NetworkTablesJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("ntcorejni"); } catch (IOException ex) { ex.printStackTrace(); System.exit(1); @@ -69,10 +65,7 @@ public final class NetworkTablesJNI { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>( - "ntcorejni", RuntimeLoader.getDefaultExtractionRoot(), NetworkTablesJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("ntcorejni"); libraryLoaded = true; } diff --git a/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java b/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java index 4b4fa5cb6ed..4741f7642a7 100644 --- a/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java +++ b/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java @@ -17,7 +17,6 @@ /** NetworkTables JNI. */ public final class NetworkTablesJNI { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; /** Sets whether JNI should be loaded in the static block. */ public static class Helper { @@ -48,10 +47,7 @@ private Helper() {} static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "ntcorejni", RuntimeLoader.getDefaultExtractionRoot(), NetworkTablesJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("ntcorejni"); } catch (IOException ex) { ex.printStackTrace(); System.exit(1); @@ -69,10 +65,7 @@ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>( - "ntcorejni", RuntimeLoader.getDefaultExtractionRoot(), NetworkTablesJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("ntcorejni"); libraryLoaded = true; } diff --git a/romiVendordep/src/dev/java/edu/wpi/first/wpilibj/romi/DevMain.java b/romiVendordep/src/dev/java/edu/wpi/first/wpilibj/romi/DevMain.java index 846263ed5ee..aaad3f1898a 100644 --- a/romiVendordep/src/dev/java/edu/wpi/first/wpilibj/romi/DevMain.java +++ b/romiVendordep/src/dev/java/edu/wpi/first/wpilibj/romi/DevMain.java @@ -6,13 +6,13 @@ import edu.wpi.first.hal.HALUtil; import edu.wpi.first.networktables.NetworkTablesJNI; -import edu.wpi.first.util.RuntimeDetector; +import edu.wpi.first.util.CombinedRuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); } diff --git a/styleguide/spotbugs-exclude.xml b/styleguide/spotbugs-exclude.xml index e015399a7fd..d655efb9ac1 100644 --- a/styleguide/spotbugs-exclude.xml +++ b/styleguide/spotbugs-exclude.xml @@ -86,10 +86,6 @@ - - - - diff --git a/wpilibNewCommands/src/dev/java/edu/wpi/first/wpilibj2/commands/DevMain.java b/wpilibNewCommands/src/dev/java/edu/wpi/first/wpilibj2/commands/DevMain.java index 484d735ea42..5a4eff1c076 100644 --- a/wpilibNewCommands/src/dev/java/edu/wpi/first/wpilibj2/commands/DevMain.java +++ b/wpilibNewCommands/src/dev/java/edu/wpi/first/wpilibj2/commands/DevMain.java @@ -6,13 +6,13 @@ import edu.wpi.first.hal.HALUtil; import edu.wpi.first.networktables.NetworkTablesJNI; -import edu.wpi.first.util.RuntimeDetector; +import edu.wpi.first.util.CombinedRuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); } diff --git a/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java b/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java index e0db62ed0dc..2a73e481381 100644 --- a/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java +++ b/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java @@ -6,13 +6,13 @@ import edu.wpi.first.hal.HALUtil; import edu.wpi.first.networktables.NetworkTablesJNI; -import edu.wpi.first.util.RuntimeDetector; +import edu.wpi.first.util.CombinedRuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); } diff --git a/wpimath/src/main/java/edu/wpi/first/math/WPIMathJNI.java b/wpimath/src/main/java/edu/wpi/first/math/WPIMathJNI.java index 412c1b1f74b..517c13297bf 100644 --- a/wpimath/src/main/java/edu/wpi/first/math/WPIMathJNI.java +++ b/wpimath/src/main/java/edu/wpi/first/math/WPIMathJNI.java @@ -11,16 +11,12 @@ /** WPIMath JNI. */ public final class WPIMathJNI { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "wpimathjni", RuntimeLoader.getDefaultExtractionRoot(), WPIMathJNI.class); - loader.loadLibrary(); - } catch (IOException ex) { + RuntimeLoader.loadLibrary("wpimathjni"); + } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } @@ -37,10 +33,7 @@ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>( - "wpimathjni", RuntimeLoader.getDefaultExtractionRoot(), WPIMathJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("wpimathjni"); libraryLoaded = true; } diff --git a/wpinet/src/dev/java/edu/wpi/first/net/DevMain.java b/wpinet/src/dev/java/edu/wpi/first/net/DevMain.java index 7c71a457d0f..5ced60a3140 100644 --- a/wpinet/src/dev/java/edu/wpi/first/net/DevMain.java +++ b/wpinet/src/dev/java/edu/wpi/first/net/DevMain.java @@ -4,13 +4,13 @@ package edu.wpi.first.net; -import edu.wpi.first.util.RuntimeDetector; +import edu.wpi.first.util.CombinedRuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); } private DevMain() {} diff --git a/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java b/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java index 82d8e256491..084f0220f54 100644 --- a/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java +++ b/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java @@ -11,7 +11,6 @@ /** WPINet JNI. */ public class WPINetJNI { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; /** Sets whether JNI should be loaded in the static block. */ public static class Helper { @@ -42,11 +41,8 @@ private Helper() {} static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "wpinetjni", RuntimeLoader.getDefaultExtractionRoot(), WPINetJNI.class); - loader.loadLibrary(); - } catch (IOException ex) { + RuntimeLoader.loadLibrary("wpinetjni"); + } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } @@ -63,9 +59,7 @@ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>("wpinetjni", RuntimeLoader.getDefaultExtractionRoot(), WPINetJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("wpinetjni"); libraryLoaded = true; } diff --git a/wpiutil/src/dev/java/edu/wpi/first/util/DevMain.java b/wpiutil/src/dev/java/edu/wpi/first/util/DevMain.java index 3d5b1346c0f..e94fceb0c3c 100644 --- a/wpiutil/src/dev/java/edu/wpi/first/util/DevMain.java +++ b/wpiutil/src/dev/java/edu/wpi/first/util/DevMain.java @@ -8,7 +8,7 @@ public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); } private DevMain() {} diff --git a/wpiutil/src/main/java/edu/wpi/first/util/CombinedRuntimeLoader.java b/wpiutil/src/main/java/edu/wpi/first/util/CombinedRuntimeLoader.java index 8fe4839d25e..6a3cdfa91c0 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/CombinedRuntimeLoader.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/CombinedRuntimeLoader.java @@ -35,6 +35,48 @@ private static synchronized void setExtractionDirectory(String directory) { extractionDirectory = directory; } + /** + * Returns platform path. + * + * @return The current platform path. + * @throws IllegalStateException Thrown if the operating system is unknown. + */ + public static String getPlatformPath() { + String filePath; + String arch = System.getProperty("os.arch"); + + boolean intel32 = "x86".equals(arch) || "i386".equals(arch); + boolean intel64 = "amd64".equals(arch) || "x86_64".equals(arch); + + if (System.getProperty("os.name").startsWith("Windows")) { + if (intel32) { + filePath = "/windows/x86/"; + } else { + filePath = "/windows/x86-64/"; + } + } else if (System.getProperty("os.name").startsWith("Mac")) { + filePath = "/osx/universal/"; + } else if (System.getProperty("os.name").startsWith("Linux")) { + if (intel32) { + filePath = "/linux/x86/"; + } else if (intel64) { + filePath = "/linux/x86-64/"; + } else if (new File("/usr/local/frc/bin/frcRunRobot.sh").exists()) { + filePath = "/linux/athena/"; + } else if ("arm".equals(arch) || "arm32".equals(arch)) { + filePath = "/linux/arm32/"; + } else if ("aarch64".equals(arch) || "arm64".equals(arch)) { + filePath = "/linux/arm64/"; + } else { + filePath = "/linux/nativearm/"; + } + } else { + throw new IllegalStateException(); + } + + return filePath; + } + /** * Sets DLL directory. * @@ -47,11 +89,11 @@ private static String getLoadErrorMessage(String libraryName, UnsatisfiedLinkErr StringBuilder msg = new StringBuilder(512); msg.append(libraryName) .append(" could not be loaded from path\n" + "\tattempted to load for platform ") - .append(RuntimeDetector.getPlatformPath()) + .append(CombinedRuntimeLoader.getPlatformPath()) .append("\nLast Load Error: \n") .append(ule.getMessage()) .append('\n'); - if (RuntimeDetector.isWindows()) { + if (System.getProperty("os.name").startsWith("Windows")) { msg.append( "A common cause of this error is missing the C++ runtime.\n" + "Download the latest at https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads\n"); @@ -78,7 +120,7 @@ public static List extractLibraries(Class clazz, String resourceN map = mapper.readValue(stream, typeRef); } - var platformPath = Paths.get(RuntimeDetector.getPlatformPath()); + var platformPath = Paths.get(CombinedRuntimeLoader.getPlatformPath()); var platform = platformPath.getName(0).toString(); var arch = platformPath.getName(1).toString(); @@ -91,7 +133,7 @@ public static List extractLibraries(Class clazz, String resourceN if (extractionPathString == null) { String hash = (String) map.get("hash"); - var defaultExtractionRoot = RuntimeLoader.getDefaultExtractionRoot(); + var defaultExtractionRoot = CombinedRuntimeLoader.getExtractionDirectory(); var extractionPath = Paths.get(defaultExtractionRoot, platform, arch, hash); extractionPathString = extractionPath.toString(); @@ -141,7 +183,7 @@ public static void loadLibrary(String libraryName, List extractedFiles) String currentPath = null; String oldDllDirectory = null; try { - if (RuntimeDetector.isWindows()) { + if (System.getProperty("os.name").startsWith("Windows")) { var extractionPathString = getExtractionDirectory(); oldDllDirectory = setDllDirectory(extractionPathString); } @@ -180,7 +222,7 @@ public static void loadLibraries(Class clazz, String... librariesToLoad) String currentPath = ""; try { - if (RuntimeDetector.isWindows()) { + if (System.getProperty("os.name").startsWith("Windows")) { var extractionPathString = getExtractionDirectory(); // Load windows, set dll directory currentPath = Paths.get(extractionPathString, "WindowsLoaderHelper.dll").toString(); diff --git a/wpiutil/src/main/java/edu/wpi/first/util/RuntimeDetector.java b/wpiutil/src/main/java/edu/wpi/first/util/RuntimeDetector.java deleted file mode 100644 index 72593dcafc2..00000000000 --- a/wpiutil/src/main/java/edu/wpi/first/util/RuntimeDetector.java +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package edu.wpi.first.util; - -import java.io.File; - -/** - * A utility class for detecting and providing platform-specific such as OS and CPU architecture. - */ -public final class RuntimeDetector { - private static String filePrefix; - private static String fileExtension; - private static String filePath; - - private static synchronized void computePlatform() { - if (fileExtension != null && filePath != null && filePrefix != null) { - return; - } - - boolean intel32 = is32BitIntel(); - boolean intel64 = is64BitIntel(); - boolean arm64 = isArm64(); - - if (isWindows()) { - filePrefix = ""; - fileExtension = ".dll"; - if (intel32) { - filePath = "/windows/x86/"; - } else { - filePath = "/windows/x86-64/"; - } - } else if (isMac()) { - filePrefix = "lib"; - fileExtension = ".dylib"; - filePath = "/osx/universal/"; - } else if (isLinux()) { - filePrefix = "lib"; - fileExtension = ".so"; - if (intel32) { - filePath = "/linux/x86/"; - } else if (intel64) { - filePath = "/linux/x86-64/"; - } else if (isAthena()) { - filePath = "/linux/athena/"; - } else if (isArm32()) { - filePath = "/linux/arm32/"; - } else if (arm64) { - filePath = "/linux/arm64/"; - } else { - filePath = "/linux/nativearm/"; - } - } else { - throw new IllegalStateException("Failed to determine OS"); - } - } - - /** - * Get the file prefix for the current system. - * - * @return The file prefix. - */ - public static synchronized String getFilePrefix() { - computePlatform(); - - return filePrefix; - } - - /** - * Get the file extension for the current system. - * - * @return The file extension. - */ - public static synchronized String getFileExtension() { - computePlatform(); - - return fileExtension; - } - - /** - * Get the platform path for the current system. - * - * @return The platform path. - */ - public static synchronized String getPlatformPath() { - computePlatform(); - - return filePath; - } - - /** - * Get the path to the requested resource. - * - * @param libName Library name. - * @return The path to the requested resource. - */ - public static synchronized String getLibraryResource(String libName) { - computePlatform(); - - return filePath + filePrefix + libName + fileExtension; - } - - /** - * Get the path to the hash to the requested resource. - * - * @param libName Library name. - * @return The path to the hash to the requested resource. - */ - public static synchronized String getHashLibraryResource(String libName) { - computePlatform(); - - return filePath + libName + ".hash"; - } - - /** - * Check if hardware platform is Athena. - * - * @return True if hardware platform is Athena. - */ - public static boolean isAthena() { - File runRobotFile = new File("/usr/local/frc/bin/frcRunRobot.sh"); - return runRobotFile.exists(); - } - - /** - * Check if OS is Arm32. - * - * @return True if OS is Arm32. - */ - public static boolean isArm32() { - String arch = System.getProperty("os.arch"); - return "arm".equals(arch) || "arm32".equals(arch); - } - - /** - * Check if architecture is Arm64. - * - * @return if architecture is Arm64. - */ - public static boolean isArm64() { - String arch = System.getProperty("os.arch"); - return "aarch64".equals(arch) || "arm64".equals(arch); - } - - /** - * Check if OS is Linux. - * - * @return if OS is Linux. - */ - public static boolean isLinux() { - return System.getProperty("os.name").startsWith("Linux"); - } - - /** - * Check if OS is Windows. - * - * @return if OS is Windows. - */ - public static boolean isWindows() { - return System.getProperty("os.name").startsWith("Windows"); - } - - /** - * Check if OS is Mac. - * - * @return if OS is Mac. - */ - public static boolean isMac() { - return System.getProperty("os.name").startsWith("Mac"); - } - - /** - * Check if OS is 32bit Intel. - * - * @return if OS is 32bit Intel. - */ - public static boolean is32BitIntel() { - String arch = System.getProperty("os.arch"); - return "x86".equals(arch) || "i386".equals(arch); - } - - /** - * Check if OS is 64bit Intel. - * - * @return if OS is 64bit Intel. - */ - public static boolean is64BitIntel() { - String arch = System.getProperty("os.arch"); - return "amd64".equals(arch) || "x86_64".equals(arch); - } - - private RuntimeDetector() {} -} diff --git a/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java b/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java index 474666ee02f..f68313a54d3 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java @@ -4,75 +4,28 @@ package edu.wpi.first.util; -import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.DigestInputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Locale; -import java.util.Scanner; - -/** - * Loads a native library at runtime. - * - * @param The class to load. - */ -public final class RuntimeLoader { - private static String defaultExtractionRoot; - - /** - * Gets the default extraction root location (~/.wpilib/nativecache). - * - * @return The default extraction root location. - */ - public static synchronized String getDefaultExtractionRoot() { - if (defaultExtractionRoot != null) { - return defaultExtractionRoot; - } - String home = System.getProperty("user.home"); - defaultExtractionRoot = Paths.get(home, ".wpilib", "nativecache").toString(); - return defaultExtractionRoot; - } - - private final String m_libraryName; - private final Class m_loadClass; - private final String m_extractionRoot; - - /** - * Creates a new library loader. - * - * @param libraryName Name of library to load. - * @param extractionRoot Location from which to load the library. - * @param cls Class whose classpath the given library belongs. - */ - public RuntimeLoader(String libraryName, String extractionRoot, Class cls) { - m_libraryName = libraryName; - m_loadClass = cls; - m_extractionRoot = extractionRoot; - } +/** Loads a native library at runtime. */ +public final class RuntimeLoader { /** * Returns a load error message given the information in the provided UnsatisfiedLinkError. * + * @param libraryName the name of the library that failed to load. * @param ule UnsatisfiedLinkError object. * @return A load error message. */ - private String getLoadErrorMessage(UnsatisfiedLinkError ule) { + private static String getLoadErrorMessage(String libraryName, UnsatisfiedLinkError ule) { StringBuilder msg = new StringBuilder(512); - msg.append(m_libraryName) + msg.append(libraryName) .append( " could not be loaded from path or an embedded resource.\n" + "\tattempted to load for platform ") - .append(RuntimeDetector.getPlatformPath()) + .append(CombinedRuntimeLoader.getPlatformPath()) .append("\nLast Load Error: \n") .append(ule.getMessage()) .append('\n'); - if (RuntimeDetector.isWindows()) { + if (System.getProperty("os.name").startsWith("Windows")) { msg.append( "A common cause of this error is missing the C++ runtime.\n" + "Download the latest at https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads\n"); @@ -83,120 +36,14 @@ private String getLoadErrorMessage(UnsatisfiedLinkError ule) { /** * Loads a native library. * + * @param libraryName the name of the library to load. * @throws IOException if the library fails to load */ - public void loadLibrary() throws IOException { + public static void loadLibrary(String libraryName) throws IOException { try { - // First, try loading path - System.loadLibrary(m_libraryName); + System.loadLibrary(libraryName); } catch (UnsatisfiedLinkError ule) { - // Then load the hash from the resources - String hashName = RuntimeDetector.getHashLibraryResource(m_libraryName); - String resName = RuntimeDetector.getLibraryResource(m_libraryName); - try (InputStream hashIs = m_loadClass.getResourceAsStream(hashName)) { - if (hashIs == null) { - throw new IOException(getLoadErrorMessage(ule)); - } - try (Scanner scanner = new Scanner(hashIs, StandardCharsets.UTF_8)) { - String hash = scanner.nextLine(); - File jniLibrary = new File(m_extractionRoot, resName + "." + hash); - try { - // Try to load from an already extracted hash - System.load(jniLibrary.getAbsolutePath()); - } catch (UnsatisfiedLinkError ule2) { - // If extraction failed, extract - try (InputStream resIs = m_loadClass.getResourceAsStream(resName)) { - if (resIs == null) { - throw new IOException(getLoadErrorMessage(ule)); - } - - var parentFile = jniLibrary.getParentFile(); - if (parentFile == null) { - throw new IOException("JNI library has no parent file"); - } - parentFile.mkdirs(); - - try (OutputStream os = Files.newOutputStream(jniLibrary.toPath())) { - byte[] buffer = new byte[0xFFFF]; // 64K copy buffer - int readBytes; - while ((readBytes = resIs.read(buffer)) != -1) { // NOPMD - os.write(buffer, 0, readBytes); - } - } - System.load(jniLibrary.getAbsolutePath()); - } - } - } - } - } - } - - /** - * Load a native library by directly hashing the file. - * - * @throws IOException if the library failed to load - */ - public void loadLibraryHashed() throws IOException { - try { - // First, try loading path - System.loadLibrary(m_libraryName); - } catch (UnsatisfiedLinkError ule) { - // Then load the hash from the input file - String resName = RuntimeDetector.getLibraryResource(m_libraryName); - String hash; - try (InputStream is = m_loadClass.getResourceAsStream(resName)) { - if (is == null) { - throw new IOException(getLoadErrorMessage(ule)); - } - MessageDigest md; - try { - md = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException nsae) { - throw new RuntimeException("Weird Hash Algorithm?"); - } - try (DigestInputStream dis = new DigestInputStream(is, md)) { - // Read the entire buffer once to hash - byte[] buffer = new byte[0xFFFF]; - while (dis.read(buffer) > -1) {} - MessageDigest digest = dis.getMessageDigest(); - byte[] digestOutput = digest.digest(); - StringBuilder builder = new StringBuilder(); - for (byte b : digestOutput) { - builder.append(String.format("%02X", b)); - } - hash = builder.toString().toLowerCase(Locale.ENGLISH); - } - } - if (hash == null) { - throw new IOException("Weird Hash?"); - } - File jniLibrary = new File(m_extractionRoot, resName + "." + hash); - try { - // Try to load from an already extracted hash - System.load(jniLibrary.getAbsolutePath()); - } catch (UnsatisfiedLinkError ule2) { - // If extraction failed, extract - try (InputStream resIs = m_loadClass.getResourceAsStream(resName)) { - if (resIs == null) { - throw new IOException(getLoadErrorMessage(ule)); - } - - var parentFile = jniLibrary.getParentFile(); - if (parentFile == null) { - throw new IOException("JNI library has no parent file"); - } - parentFile.mkdirs(); - - try (OutputStream os = Files.newOutputStream(jniLibrary.toPath())) { - byte[] buffer = new byte[0xFFFF]; // 64K copy buffer - int readBytes; - while ((readBytes = resIs.read(buffer)) != -1) { // NOPMD - os.write(buffer, 0, readBytes); - } - } - System.load(jniLibrary.getAbsolutePath()); - } - } + throw new IOException(getLoadErrorMessage(libraryName, ule)); } } } diff --git a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java index 0bd5b2169cf..58e69c34bc2 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java @@ -11,7 +11,6 @@ /** WPIUtil JNI. */ public class WPIUtilJNI { static boolean libraryLoaded = false; - static RuntimeLoader loader = null; /** Sets whether JNI should be loaded in the static block. */ public static class Helper { @@ -42,11 +41,8 @@ private Helper() {} static { if (Helper.getExtractOnStaticLoad()) { try { - loader = - new RuntimeLoader<>( - "wpiutiljni", RuntimeLoader.getDefaultExtractionRoot(), WPIUtilJNI.class); - loader.loadLibrary(); - } catch (IOException ex) { + RuntimeLoader.loadLibrary("wpiutiljni"); + } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } @@ -63,10 +59,7 @@ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } - loader = - new RuntimeLoader<>( - "wpiutiljni", RuntimeLoader.getDefaultExtractionRoot(), WPIUtilJNI.class); - loader.loadLibrary(); + RuntimeLoader.loadLibrary("wpiutiljni"); libraryLoaded = true; } diff --git a/xrpVendordep/src/dev/java/edu/wpi/first/wpilibj/xrp/DevMain.java b/xrpVendordep/src/dev/java/edu/wpi/first/wpilibj/xrp/DevMain.java index 9b981c5666f..a9487bf9620 100644 --- a/xrpVendordep/src/dev/java/edu/wpi/first/wpilibj/xrp/DevMain.java +++ b/xrpVendordep/src/dev/java/edu/wpi/first/wpilibj/xrp/DevMain.java @@ -6,13 +6,13 @@ import edu.wpi.first.hal.HALUtil; import edu.wpi.first.networktables.NetworkTablesJNI; -import edu.wpi.first.util.RuntimeDetector; +import edu.wpi.first.util.CombinedRuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(RuntimeDetector.getPlatformPath()); + System.out.println(CombinedRuntimeLoader.getPlatformPath()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); }