diff --git a/commandsv2/src/dev/java/org/wpilib/commands2/DevMain.java b/commandsv2/src/dev/java/org/wpilib/commands2/DevMain.java index b88b4e7916..ec909bb1ca 100644 --- a/commandsv2/src/dev/java/org/wpilib/commands2/DevMain.java +++ b/commandsv2/src/dev/java/org/wpilib/commands2/DevMain.java @@ -6,13 +6,13 @@ package org.wpilib.commands2; import org.wpilib.hardware.hal.HALUtil; import org.wpilib.networktables.NetworkTablesJNI; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); } diff --git a/commandsv3/src/dev/java/org/wpilib/command3/DevMain.java b/commandsv3/src/dev/java/org/wpilib/command3/DevMain.java index 8b73a7b586..1baa56e513 100644 --- a/commandsv3/src/dev/java/org/wpilib/command3/DevMain.java +++ b/commandsv3/src/dev/java/org/wpilib/command3/DevMain.java @@ -6,7 +6,7 @@ package org.wpilib.command3; import org.wpilib.hardware.hal.HALUtil; import org.wpilib.networktables.NetworkTablesJNI; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; /** Dev main. */ public final class DevMain { @@ -14,7 +14,7 @@ public final class DevMain { public static void main(String[] args) { System.out.println("Commands V3 DevMain"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); } diff --git a/cscore/src/dev/java/org/wpilib/vision/camera/DevMain.java b/cscore/src/dev/java/org/wpilib/vision/camera/DevMain.java index 74549fd7b3..18b056b123 100644 --- a/cscore/src/dev/java/org/wpilib/vision/camera/DevMain.java +++ b/cscore/src/dev/java/org/wpilib/vision/camera/DevMain.java @@ -4,13 +4,13 @@ package org.wpilib.vision.camera; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main method. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); System.out.println(CameraServerJNI.getHostname()); } diff --git a/ntcore/src/dev/java/org/wpilib/networktables/DevMain.java b/ntcore/src/dev/java/org/wpilib/networktables/DevMain.java index c7b834c8ba..6413425e1a 100644 --- a/ntcore/src/dev/java/org/wpilib/networktables/DevMain.java +++ b/ntcore/src/dev/java/org/wpilib/networktables/DevMain.java @@ -4,13 +4,13 @@ package org.wpilib.networktables; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main method. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); NetworkTablesJNI.flush(NetworkTablesJNI.getDefaultInstance()); } diff --git a/romiVendordep/src/dev/java/org/wpilib/romi/DevMain.java b/romiVendordep/src/dev/java/org/wpilib/romi/DevMain.java index 4412287991..bd0a93067d 100644 --- a/romiVendordep/src/dev/java/org/wpilib/romi/DevMain.java +++ b/romiVendordep/src/dev/java/org/wpilib/romi/DevMain.java @@ -6,13 +6,13 @@ package org.wpilib.romi; import org.wpilib.hardware.hal.HALUtil; import org.wpilib.networktables.NetworkTablesJNI; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); } diff --git a/styleguide/spotbugs-exclude.xml b/styleguide/spotbugs-exclude.xml index 3cad3f3d8a..7abc2792c9 100644 --- a/styleguide/spotbugs-exclude.xml +++ b/styleguide/spotbugs-exclude.xml @@ -36,8 +36,7 @@ - - + @@ -106,10 +105,6 @@ - - - - diff --git a/wpilibj/src/dev/java/org/wpilib/DevMain.java b/wpilibj/src/dev/java/org/wpilib/DevMain.java index 26e3ec4ef4..bb04e0e7da 100644 --- a/wpilibj/src/dev/java/org/wpilib/DevMain.java +++ b/wpilibj/src/dev/java/org/wpilib/DevMain.java @@ -6,13 +6,13 @@ package org.wpilib; import org.wpilib.hardware.hal.HALUtil; import org.wpilib.networktables.NetworkTablesJNI; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); } diff --git a/wpinet/src/dev/java/org/wpilib/net/DevMain.java b/wpinet/src/dev/java/org/wpilib/net/DevMain.java index 82617988b3..210e115ef0 100644 --- a/wpinet/src/dev/java/org/wpilib/net/DevMain.java +++ b/wpinet/src/dev/java/org/wpilib/net/DevMain.java @@ -4,13 +4,13 @@ package org.wpilib.net; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); } private DevMain() {} diff --git a/wpiutil/build.gradle b/wpiutil/build.gradle index c3f40f17c1..2f587a1148 100644 --- a/wpiutil/build.gradle +++ b/wpiutil/build.gradle @@ -3,9 +3,6 @@ apply from: "${rootDir}/shared/resources.gradle" apply plugin: 'c' ext { noWpiutil = true - skipJniSymbols = [ - 'Java_org_wpilib_util_CombinedRuntimeLoader_setDllDirectory' - ] baseId = 'wpiutil' groupId = 'org.wpilib.wpiutil' diff --git a/wpiutil/src/dev/java/org/wpilib/util/DevMain.java b/wpiutil/src/dev/java/org/wpilib/util/DevMain.java index 58da26088b..dbf8c82daf 100644 --- a/wpiutil/src/dev/java/org/wpilib/util/DevMain.java +++ b/wpiutil/src/dev/java/org/wpilib/util/DevMain.java @@ -4,13 +4,13 @@ package org.wpilib.util; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); WPIUtilJNI.checkMsvcRuntime(); } diff --git a/wpiutil/src/main/java/org/wpilib/util/runtime/CombinedRuntimeLoader.java b/wpiutil/src/main/java/org/wpilib/util/runtime/CombinedRuntimeLoader.java deleted file mode 100644 index e96391b5ad..0000000000 --- a/wpiutil/src/main/java/org/wpilib/util/runtime/CombinedRuntimeLoader.java +++ /dev/null @@ -1,226 +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 org.wpilib.util.runtime; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** Loads dynamic libraries for all platforms. */ -public final class CombinedRuntimeLoader { - private CombinedRuntimeLoader() {} - - private static String extractionDirectory; - - /** - * Returns library extraction directory. - * - * @return Library extraction directory. - */ - public static synchronized String getExtractionDirectory() { - return extractionDirectory; - } - - private static synchronized void setExtractionDirectory(String directory) { - extractionDirectory = directory; - } - - private static String defaultExtractionRoot; - - /** - * Gets the default extraction root location (~/.wpilib/nativecache) for use if - * setExtractionDirectory is not set. - * - * @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; - } - - /** - * 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; - } - - private static String getLoadErrorMessage(String libraryName, UnsatisfiedLinkError ule) { - StringBuilder msg = new StringBuilder(512); - msg.append(libraryName) - .append(" could not be loaded from path\n" + "\tattempted to load for platform ") - .append(getPlatformPath()) - .append("\nLast Load Error: \n") - .append(ule.getMessage()) - .append('\n'); - 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"); - } - return msg.toString(); - } - - /** - * Extract a list of native libraries. - * - * @param The class where the resources would be located - * @param clazz The actual class object - * @param resourceName The resource name on the classpath to use for file lookup - * @return List of all libraries that were extracted - * @throws IOException Thrown if resource not found or file could not be extracted - */ - @SuppressWarnings("unchecked") - public static List extractLibraries(Class clazz, String resourceName) - throws IOException { - TypeReference> typeRef = new TypeReference<>() {}; - ObjectMapper mapper = new ObjectMapper(); - Map map; - try (var stream = clazz.getResourceAsStream(resourceName)) { - map = mapper.readValue(stream, typeRef); - } - - var platformPath = Paths.get(getPlatformPath()); - var platform = platformPath.getName(0).toString(); - var arch = platformPath.getName(1).toString(); - - var platformMap = (Map>) map.get(platform); - - var fileList = platformMap.get(arch); - - var extractionPathString = getExtractionDirectory(); - - if (extractionPathString == null) { - String hash = (String) map.get("hash"); - - var defaultExtractionRoot = getDefaultExtractionRoot(); - var extractionPath = Paths.get(defaultExtractionRoot, platform, arch, hash); - extractionPathString = extractionPath.toString(); - - setExtractionDirectory(extractionPathString); - } - - List extractedFiles = new ArrayList<>(); - - byte[] buffer = new byte[0x10000]; // 64K copy buffer - - for (var file : fileList) { - try (var stream = clazz.getResourceAsStream(file)) { - Objects.requireNonNull(stream); - - var outputFile = Paths.get(extractionPathString, new File(file).getName()); - extractedFiles.add(outputFile.toString()); - if (outputFile.toFile().exists()) { - continue; - } - var parent = outputFile.getParent(); - if (parent == null) { - throw new IOException("Output file has no parent"); - } - parent.toFile().mkdirs(); - - try (var os = Files.newOutputStream(outputFile)) { - int readBytes; - while ((readBytes = stream.read(buffer)) != -1) { // NOPMD - os.write(buffer, 0, readBytes); - } - } - } - } - - return extractedFiles; - } - - /** - * Load a single library from a list of extracted files. - * - * @param libraryName The library name to load - * @param extractedFiles The extracted files to search - * @throws IOException If library was not found - */ - public static void loadLibrary(String libraryName, List extractedFiles) - throws IOException { - String currentPath = null; - try { - for (var extractedFile : extractedFiles) { - if (extractedFile.contains(libraryName)) { - // Load it - currentPath = extractedFile; - System.load(extractedFile); - return; - } - } - throw new IOException("Could not find library " + libraryName); - } catch (UnsatisfiedLinkError ule) { - throw new IOException(getLoadErrorMessage(currentPath, ule)); - } - } - - /** - * Load a list of native libraries out of a single directory. - * - * @param The class where the resources would be located - * @param clazz The actual class object - * @param librariesToLoad List of libraries to load - * @throws IOException Throws an IOException if not found - */ - public static void loadLibraries(Class clazz, String... librariesToLoad) - throws IOException { - // Extract everything - - var extractedFiles = extractLibraries(clazz, "/ResourceInformation.json"); - - for (var library : librariesToLoad) { - loadLibrary(library, extractedFiles); - } - } -} diff --git a/wpiutil/src/main/java/org/wpilib/util/runtime/RuntimeDetector.java b/wpiutil/src/main/java/org/wpilib/util/runtime/RuntimeDetector.java deleted file mode 100644 index ec6023e1c8..0000000000 --- a/wpiutil/src/main/java/org/wpilib/util/runtime/RuntimeDetector.java +++ /dev/null @@ -1,197 +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 org.wpilib.util.runtime; - -import java.io.File; - -/** - * A utility class for detecting and providing platform-specific such as OS and CPU architecture. - * - * @deprecated platform detection is brittle and may be removed in the future. - */ -@Deprecated(since = "2025", forRemoval = true) -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/org/wpilib/util/runtime/RuntimeLoader.java b/wpiutil/src/main/java/org/wpilib/util/runtime/RuntimeLoader.java index 7b04fa81b7..1d21aacb5f 100644 --- a/wpiutil/src/main/java/org/wpilib/util/runtime/RuntimeLoader.java +++ b/wpiutil/src/main/java/org/wpilib/util/runtime/RuntimeLoader.java @@ -8,6 +8,42 @@ import java.io.IOException; /** Loads a native library at runtime. */ public final class RuntimeLoader { + /** + * Returns platform name. + * + * @return The current platform name. + * @throws IllegalStateException Thrown if the operating system is unknown. + */ + public static String getPlatformName() { + String arch = System.getProperty("os.arch"); + + boolean intel64 = "amd64".equals(arch) || "x86_64".equals(arch); + boolean arm64 = "aarch64".equals(arch) || "arm64".equals(arch); + + if (intel64) { + arch = "x86_64"; + } else if (arm64) { + arch = "arm64"; + } else { + throw new IllegalStateException("Unsupported architecture: " + arch); + } + + String osName = System.getProperty("os.name"); + + if (osName.startsWith("Windows")) { + osName = "windows"; + } else if (osName.startsWith("Mac")) { + osName = "osx"; + arch = "universal"; + } else if (osName.startsWith("Linux")) { + osName = "linux"; + } else { + throw new IllegalStateException("Unsupported operating system: " + osName); + } + + return osName + "-" + arch; + } + /** * Returns a load error message given the information in the provided UnsatisfiedLinkError. * @@ -20,7 +56,7 @@ public final class RuntimeLoader { StringBuilder msg = new StringBuilder(512); msg.append(libraryName) .append(" could not be loaded from path.\n" + "\tattempted to load for platform ") - .append(CombinedRuntimeLoader.getPlatformPath()) + .append(getPlatformName()) .append("\nLast Load Error: \n") .append(ule.getMessage()) .append('\n') diff --git a/xrpVendordep/src/dev/java/org/wpilib/xrp/DevMain.java b/xrpVendordep/src/dev/java/org/wpilib/xrp/DevMain.java index 4320336fb8..a4ae5164c0 100644 --- a/xrpVendordep/src/dev/java/org/wpilib/xrp/DevMain.java +++ b/xrpVendordep/src/dev/java/org/wpilib/xrp/DevMain.java @@ -6,13 +6,13 @@ package org.wpilib.xrp; import org.wpilib.hardware.hal.HALUtil; import org.wpilib.networktables.NetworkTablesJNI; -import org.wpilib.util.runtime.CombinedRuntimeLoader; +import org.wpilib.util.runtime.RuntimeLoader; public final class DevMain { /** Main entry point. */ public static void main(String[] args) { System.out.println("Hello World!"); - System.out.println(CombinedRuntimeLoader.getPlatformPath()); + System.out.println(RuntimeLoader.getPlatformName()); System.out.println(NetworkTablesJNI.now()); System.out.println(HALUtil.getHALRuntimeType()); }