001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package org.wpilib.util.runtime;
006
007import java.io.IOException;
008
009/** Loads a native library at runtime. */
010public final class RuntimeLoader {
011  /**
012   * Returns platform name.
013   *
014   * @return The current platform name.
015   * @throws IllegalStateException Thrown if the operating system is unknown.
016   */
017  public static String getPlatformName() {
018    String arch = System.getProperty("os.arch");
019
020    boolean intel64 = "amd64".equals(arch) || "x86_64".equals(arch);
021    boolean arm64 = "aarch64".equals(arch) || "arm64".equals(arch);
022
023    if (intel64) {
024      arch = "x86_64";
025    } else if (arm64) {
026      arch = "arm64";
027    } else {
028      throw new IllegalStateException("Unsupported architecture: " + arch);
029    }
030
031    String osName = System.getProperty("os.name");
032
033    if (osName.startsWith("Windows")) {
034      osName = "windows";
035    } else if (osName.startsWith("Mac")) {
036      osName = "osx";
037      arch = "universal";
038    } else if (osName.startsWith("Linux")) {
039      osName = "linux";
040    } else {
041      throw new IllegalStateException("Unsupported operating system: " + osName);
042    }
043
044    return osName + "-" + arch;
045  }
046
047  /**
048   * Returns a load error message given the information in the provided UnsatisfiedLinkError.
049   *
050   * @param libraryName the name of the library that failed to load.
051   * @param ule UnsatisfiedLinkError object.
052   * @return A load error message.
053   */
054  private static String getLoadErrorMessage(String libraryName, UnsatisfiedLinkError ule) {
055    String jvmLocation = ProcessHandle.current().info().command().orElse("Unknown");
056    StringBuilder msg = new StringBuilder(512);
057    msg.append(libraryName)
058        .append(" could not be loaded from path.\n" + "\tattempted to load for platform ")
059        .append(getPlatformName())
060        .append("\nLast Load Error: \n")
061        .append(ule.getMessage())
062        .append('\n')
063        .append(String.format("JVM Location: %s\n", jvmLocation));
064    if (System.getProperty("os.name").startsWith("Windows")) {
065      msg.append(
066          "A common cause of this error is using a JVM with an incorrect MSVC runtime.\n"
067              + "Ensure you are using the WPILib JVM (The current running JVM is listed above)\n"
068              + "See https://wpilib.org/jvmruntime for more information\n");
069    }
070    return msg.toString();
071  }
072
073  /**
074   * Loads a native library.
075   *
076   * @param libraryName the name of the library to load.
077   * @throws IOException if the library fails to load
078   */
079  public static void loadLibrary(String libraryName) throws IOException {
080    try {
081      System.loadLibrary(libraryName);
082    } catch (UnsatisfiedLinkError ule) {
083      throw new IOException(getLoadErrorMessage(libraryName, ule));
084    }
085  }
086
087  private RuntimeLoader() {
088    throw new IllegalStateException("This class shouldn't be instantiated");
089  }
090}