diff --git a/photon-core/build.gradle b/photon-core/build.gradle index 684c329b2..6e9c99c1f 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -8,24 +8,26 @@ apply from: "${rootDir}/shared/common.gradle" wpilibTools.deps.wpilibVersion = wpi.versions.wpilibVersion.get() def nativeConfigName = 'wpilibNatives' -def nativeConfig = configurations.create(nativeConfigName) - +configurations { + wpilibNatives +} def nativeTasks = wpilibTools.createExtractionTasks { configurationName = nativeConfigName } nativeTasks.addToSourceSetResources(sourceSets.main) -nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpimath") -nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpinet") -nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpiutil") -nativeConfig.dependencies.add wpilibTools.deps.wpilib("ntcore") -nativeConfig.dependencies.add wpilibTools.deps.wpilib("cscore") -nativeConfig.dependencies.add wpilibTools.deps.wpilib("apriltag") -nativeConfig.dependencies.add wpilibTools.deps.wpilib("hal") -nativeConfig.dependencies.add wpilibTools.deps.wpilibOpenCv("frc" + openCVYear, wpi.versions.opencvVersion.get()) - dependencies { + wpilibNatives project(path: ':photon-targeting', configuration: 'wpilibNatives') + wpilibNatives wpilibTools.deps.wpilib("wpimath") + wpilibNatives wpilibTools.deps.wpilib("wpinet") + wpilibNatives wpilibTools.deps.wpilib("wpiutil") + wpilibNatives wpilibTools.deps.wpilib("ntcore") + wpilibNatives wpilibTools.deps.wpilib("cscore") + wpilibNatives wpilibTools.deps.wpilib("apriltag") + wpilibNatives wpilibTools.deps.wpilib("hal") + wpilibNatives wpilibTools.deps.wpilibOpenCv("frc" + openCVYear, wpi.versions.opencvVersion.get()) + // Zip implementation 'org.zeroturnaround:zt-zip:1.14' diff --git a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/TimeSyncManager.java b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/TimeSyncManager.java index 050a28e50..a85010936 100644 --- a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/TimeSyncManager.java +++ b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/TimeSyncManager.java @@ -25,7 +25,6 @@ import org.photonvision.common.configuration.NetworkConfig; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; import org.photonvision.common.util.TimedTaskManager; -import org.photonvision.jni.PhotonTargetingJniLoader; import org.photonvision.jni.TimeSyncClient; import org.photonvision.jni.TimeSyncServer; @@ -43,10 +42,6 @@ public class TimeSyncManager { IntegerPublisher m_lastPongTimePub; public TimeSyncManager(NetworkTable kRootTable) { - if (!PhotonTargetingJniLoader.isWorking) { - logger.error("PhotonTargetingJNI was not loaded! Cannot do time-sync"); - } - this.ntInstance = kRootTable.getInstance(); // Need this subtable to be unique per coprocessor. TODO: consider using MAC address or @@ -65,18 +60,10 @@ public class TimeSyncManager { // Since we're spinning off tasks in a new thread, be careful and start it seperately public void start() { - if (!PhotonTargetingJniLoader.isWorking) { - logger.error("PhotonTargetingJNI was not loaded! Cannot start"); - } - TimedTaskManager.getInstance().addTask("TimeSyncManager::tick", this::tick, 1000); } public synchronized long getOffset() { - if (!PhotonTargetingJniLoader.isWorking) { - return 0; - } - // if we're a client, return the offset to server time if (m_client != null) return m_client.getOffset(); // if we're a server, our time (nt::Now) is the same as network time @@ -88,10 +75,6 @@ public class TimeSyncManager { } synchronized void setConfig(NetworkConfig config) { - if (!PhotonTargetingJniLoader.isWorking) { - return; - } - if (m_client == null && m_server == null) { throw new RuntimeException("Neither client nor server are null?"); } diff --git a/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java b/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java index cf29d613b..eeef84d49 100644 --- a/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java +++ b/photon-core/src/main/java/org/photonvision/common/util/TestUtils.java @@ -26,14 +26,14 @@ import java.io.IOException; import java.nio.file.Path; import org.opencv.core.Mat; import org.opencv.highgui.HighGui; -import org.photonvision.jni.WpilibLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.vision.calibration.CameraCalibrationCoefficients; import org.photonvision.vision.pipeline.result.CVPipelineResult; import org.photonvision.vision.target.TrackedTarget; public class TestUtils { public static boolean loadLibraries() { - return WpilibLoader.loadLibraries(); + return LibraryLoader.loadWpiLibraries() && LibraryLoader.loadTargeting(); } @SuppressWarnings("unused") diff --git a/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java b/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java index f5fa86cbe..2d822f1f7 100644 --- a/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java +++ b/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java @@ -20,7 +20,6 @@ package org.photonvision.hardware; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; import org.junit.jupiter.api.Test; import org.photonvision.common.hardware.GPIO.CustomGPIO; import org.photonvision.common.hardware.GPIO.GPIOBase; @@ -28,17 +27,11 @@ import org.photonvision.common.hardware.GPIO.pi.PigpioPin; import org.photonvision.common.hardware.Platform; import org.photonvision.common.hardware.metrics.MetricsManager; import org.photonvision.common.util.TestUtils; -import org.photonvision.jni.PhotonTargetingJniLoader; public class HardwareTest { @Test public void testHardware() { - try { - TestUtils.loadLibraries(); - PhotonTargetingJniLoader.load(); - } catch (UnsatisfiedLinkError | IOException e) { - e.printStackTrace(); - } + TestUtils.loadLibraries(); MetricsManager mm = new MetricsManager(); if (!Platform.isRaspberryPi()) return; diff --git a/photon-core/src/test/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumerTest.java b/photon-core/src/test/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumerTest.java index 606e1d4f7..0595d8b2f 100644 --- a/photon-core/src/test/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumerTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/frame/consumer/FileSaveFrameConsumerTest.java @@ -41,24 +41,20 @@ import org.junitpioneer.jupiter.cartesian.CartesianTest.Values; import org.photonvision.common.configuration.ConfigManager; import org.photonvision.common.dataflow.networktables.NetworkTablesManager; import org.photonvision.common.util.TestUtils; -import org.photonvision.jni.PhotonTargetingJniLoader; -import org.photonvision.jni.WpilibLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.vision.frame.provider.FileFrameProvider; public class FileSaveFrameConsumerTest { NetworkTableInstance inst = null; @BeforeAll - public static void init() throws UnsatisfiedLinkError, IOException { - if (!WpilibLoader.loadLibraries()) { + public static void init() throws IOException { + if (!LibraryLoader.loadWpiLibraries()) { fail(); } - try { - if (!PhotonTargetingJniLoader.load()) fail(); - } catch (UnsatisfiedLinkError | IOException e) { - e.printStackTrace(); - fail(e); + if (!LibraryLoader.loadTargeting()) { + fail(); } } diff --git a/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java b/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java index d71866677..355131da5 100644 --- a/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/processes/VisionModuleManagerTest.java @@ -22,7 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import edu.wpi.first.cscore.VideoMode; -import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -32,7 +31,7 @@ import org.photonvision.common.configuration.CameraConfiguration; import org.photonvision.common.configuration.ConfigManager; import org.photonvision.common.dataflow.CVPipelineResultConsumer; import org.photonvision.common.util.TestUtils; -import org.photonvision.jni.PhotonTargetingJniLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.vision.camera.PVCameraInfo; import org.photonvision.vision.camera.QuirkyCamera; import org.photonvision.vision.camera.USBCameras.USBCameraSource; @@ -48,12 +47,7 @@ public class VisionModuleManagerTest { System.out.print(classpathStr); TestUtils.loadLibraries(); - try { - if (!PhotonTargetingJniLoader.load()) fail(); - } catch (UnsatisfiedLinkError | IOException e) { - e.printStackTrace(); - fail(e); - } + if (!LibraryLoader.loadTargeting()) fail(); } private static class TestSource extends VisionSource { diff --git a/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java b/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java index 06cd97b10..6d3a9e51b 100644 --- a/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java @@ -17,7 +17,6 @@ package org.photonvision.vision.processes; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -33,7 +32,6 @@ import org.photonvision.common.configuration.CameraConfiguration; import org.photonvision.common.configuration.ConfigManager; import org.photonvision.common.util.TestUtils; import org.photonvision.common.util.file.JacksonUtils; -import org.photonvision.jni.PhotonTargetingJniLoader; import org.photonvision.vision.camera.PVCameraInfo; public class VisionSourceManagerTest { @@ -59,9 +57,7 @@ public class VisionSourceManagerTest { @BeforeAll public static void loadLibraries() { - TestUtils.loadLibraries(); - assertDoesNotThrow(PhotonTargetingJniLoader::load); - assertTrue(PhotonTargetingJniLoader.isWorking); + assertTrue(TestUtils.loadLibraries()); // Broadcast all still calls into configmanager (ew) so set that up here ConfigManager.getInstance().load(); diff --git a/photon-lib/build.gradle b/photon-lib/build.gradle index 0ff5278df..a06fc532e 100644 --- a/photon-lib/build.gradle +++ b/photon-lib/build.gradle @@ -363,6 +363,9 @@ def nativeTasks = wpilibTools.createExtractionTasks { nativeTasks.addToSourceSetResources(sourceSets.test) +dependencies { + wpilibNatives project(":photon-targeting") +} nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpimath") nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpinet") nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpiutil") diff --git a/photon-lib/src/main/java/org/photonvision/timesync/TimeSyncSingleton.java b/photon-lib/src/main/java/org/photonvision/timesync/TimeSyncSingleton.java index c1d7e5826..968ec8e97 100644 --- a/photon-lib/src/main/java/org/photonvision/timesync/TimeSyncSingleton.java +++ b/photon-lib/src/main/java/org/photonvision/timesync/TimeSyncSingleton.java @@ -24,8 +24,8 @@ package org.photonvision.timesync; +import edu.wpi.first.util.RuntimeLoader; import java.io.IOException; -import org.photonvision.jni.PhotonTargetingJniLoader; import org.photonvision.jni.TimeSyncServer; /** Helper to hold a single TimeSyncServer instance with some default config */ @@ -35,12 +35,11 @@ public class TimeSyncSingleton { public static boolean load() { if (INSTANCE == null) { try { - if (!PhotonTargetingJniLoader.load()) { - return false; - } - } catch (UnsatisfiedLinkError | IOException e) { + RuntimeLoader.loadLibrary("photontargetingJNI"); + } catch (IOException e) { + // Don't want to return early. We want to create the TimeSyncServer so the program crashes + // because we need it in order to function. e.printStackTrace(); - return false; } INSTANCE = new TimeSyncServer(5810); diff --git a/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java b/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java index d2080a6f5..9a2f69dd4 100644 --- a/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java +++ b/photon-lib/src/test/java/org/photonvision/PhotonCameraTest.java @@ -35,6 +35,7 @@ import edu.wpi.first.hal.HAL; import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.networktables.NetworkTableInstance; import edu.wpi.first.networktables.NetworkTablesJNI; +import edu.wpi.first.util.RuntimeLoader; import edu.wpi.first.wpilibj.DataLogManager; import edu.wpi.first.wpilibj.Timer; import edu.wpi.first.wpilibj.simulation.SimHooks; @@ -55,9 +56,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.photonvision.common.dataflow.structures.Packet; -import org.photonvision.jni.PhotonTargetingJniLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.jni.TimeSyncClient; -import org.photonvision.jni.WpilibLoader; import org.photonvision.simulation.PhotonCameraSim; import org.photonvision.targeting.PhotonPipelineMetadata; import org.photonvision.targeting.PhotonPipelineResult; @@ -68,8 +68,9 @@ class PhotonCameraTest { NetworkTableInstance inst = null; @BeforeAll - public static void load_wpilib() { - WpilibLoader.loadLibraries(); + public static void load() throws IOException { + LibraryLoader.loadWpiLibraries(); + RuntimeLoader.loadLibrary("photontargetingJNI"); } @BeforeEach @@ -111,9 +112,6 @@ class PhotonCameraTest { @Test @Order(3) public void testTimeSyncServerWithPhotonCamera() throws InterruptedException, IOException { - load_wpilib(); - PhotonTargetingJniLoader.load(); - inst.stopClient(); inst.startServer(); diff --git a/photon-lib/src/test/java/org/photonvision/PhotonPoseEstimatorTest.java b/photon-lib/src/test/java/org/photonvision/PhotonPoseEstimatorTest.java index 2f4603a16..0449d7e15 100644 --- a/photon-lib/src/test/java/org/photonvision/PhotonPoseEstimatorTest.java +++ b/photon-lib/src/test/java/org/photonvision/PhotonPoseEstimatorTest.java @@ -48,6 +48,7 @@ import edu.wpi.first.math.geometry.Transform3d; import edu.wpi.first.math.geometry.Translation2d; import edu.wpi.first.math.geometry.Translation3d; import edu.wpi.first.math.util.Units; +import edu.wpi.first.util.RuntimeLoader; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -59,8 +60,7 @@ import org.junit.jupiter.api.Test; import org.photonvision.PhotonPoseEstimator.ConstrainedSolvepnpParams; import org.photonvision.PhotonPoseEstimator.PoseStrategy; import org.photonvision.estimation.TargetModel; -import org.photonvision.jni.PhotonTargetingJniLoader; -import org.photonvision.jni.WpilibLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.simulation.PhotonCameraSim; import org.photonvision.simulation.SimCameraProperties; import org.photonvision.simulation.VisionTargetSim; @@ -76,13 +76,11 @@ class PhotonPoseEstimatorTest { @AutoClose final PhotonCameraInjector cameraOne = new PhotonCameraInjector(); @BeforeAll - public static void init() throws UnsatisfiedLinkError, IOException { - if (!WpilibLoader.loadLibraries()) { - fail(); - } - if (!PhotonTargetingJniLoader.load()) { + public static void init() throws IOException { + if (!LibraryLoader.loadWpiLibraries()) { fail(); } + RuntimeLoader.loadLibrary("photontargetingJNI"); HAL.initialize(1000, 0); diff --git a/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java b/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java index 44f119aef..3d85c4825 100644 --- a/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java +++ b/photon-lib/src/test/java/org/photonvision/VisionSystemSimTest.java @@ -28,7 +28,6 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static org.photonvision.UnitTestUtils.waitForSequenceNumber; import edu.wpi.first.apriltag.AprilTag; @@ -44,6 +43,7 @@ import edu.wpi.first.math.geometry.Translation2d; import edu.wpi.first.math.geometry.Translation3d; import edu.wpi.first.math.util.Units; import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.util.RuntimeLoader; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import java.io.IOException; import java.util.ArrayList; @@ -59,8 +59,7 @@ import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import org.photonvision.estimation.TargetModel; import org.photonvision.estimation.VisionEstimation; -import org.photonvision.jni.PhotonTargetingJniLoader; -import org.photonvision.jni.WpilibLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.simulation.PhotonCameraSim; import org.photonvision.simulation.VisionSystemSim; import org.photonvision.simulation.VisionTargetSim; @@ -72,15 +71,9 @@ class VisionSystemSimTest { NetworkTableInstance inst; @BeforeAll - public static void setUp() { - assertTrue(WpilibLoader.loadLibraries()); - - try { - assertTrue(PhotonTargetingJniLoader.load()); - } catch (UnsatisfiedLinkError | IOException e) { - e.printStackTrace(); - fail(e); - } + public static void setUp() throws IOException { + assertTrue(LibraryLoader.loadWpiLibraries()); + RuntimeLoader.loadLibrary("photontargetingJNI"); OpenCvLoader.forceStaticLoad(); } diff --git a/photon-server/src/main/java/org/photonvision/Main.java b/photon-server/src/main/java/org/photonvision/Main.java index 442fdb6d0..130bd25ba 100644 --- a/photon-server/src/main/java/org/photonvision/Main.java +++ b/photon-server/src/main/java/org/photonvision/Main.java @@ -38,7 +38,7 @@ import org.photonvision.common.logging.Logger; import org.photonvision.common.logging.PvCSCoreLogger; import org.photonvision.common.networking.NetworkManager; import org.photonvision.common.util.TestUtils; -import org.photonvision.jni.PhotonTargetingJniLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.jni.RknnDetectorJNI; import org.photonvision.jni.RubikDetectorJNI; import org.photonvision.mrcal.MrCalJNILoader; @@ -205,7 +205,7 @@ public class Main { logger.info("WPI JNI libraries loaded."); try { - boolean success = PhotonTargetingJniLoader.load(); + boolean success = LibraryLoader.loadTargeting(); if (!success) { logger.error("Failed to load native libraries! Giving up :("); diff --git a/photon-targeting/build.gradle b/photon-targeting/build.gradle index 08963f56a..eef9fa9a0 100644 --- a/photon-targeting/build.gradle +++ b/photon-targeting/build.gradle @@ -23,20 +23,6 @@ nativeUtils { sourceSets.main.java.srcDir "${projectDir}/src/generated/main/java" -// Folder whose contents will be included in the final jar -def outputsFolder = file("$buildDir/extra_resources") - -// Sync task: like the copy task, but all files that exist in the destination directory will be deleted before copying files -task syncOutputsFolder(type: Sync) { - into outputsFolder -} - -// And package our outputs folder into the final jar -jar { - from outputsFolder - dependsOn syncOutputsFolder -} - model { components { "${nativeName}"(NativeLibrarySpec) { @@ -115,21 +101,6 @@ model { platName = "osxuniversal"; realWpilibName = "osxuniversal"; } - - if (binary.targetPlatform.name == platName) { - // only include release binaries (hard coded for now) - def isDebug = binary.buildType.name.contains('debug') - if (!isDebug) { - syncOutputsFolder { - // Just shove the shared library into the root of the jar output by photon-targeting:jar - from(binary.sharedLibraryFile) { - into "nativelibraries/${realWpilibName}/" - } - // And (not sure if this is a hack) make the jar task depend on the build task - dependsOn binary.identifier.projectScopedName - } - } - } } } } @@ -202,27 +173,6 @@ model { apply from: "${rootDir}/shared/javacpp/publish.gradle" -// quickly hack our raw jar into publishing -def rawjavaJar = tasks.register("rawjavaJar", Jar) { - dependsOn classes - includeEmptyDirs = false - from sourceSets.main.output - archiveClassifier = 'raw' -} - -publishing { - publications { - rawjava(MavenPublication) { - artifact (rawjavaJar) { - classifier = null - } - artifactId = "${nativeName}-rawjava" - groupId = artifactGroupId - version = pubVersion - } - } -} - // Add photon serde headers to our published sources cppHeadersZip { from('src/generated/main/native/include') { @@ -230,12 +180,6 @@ cppHeadersZip { } } -// make sure native libraries can be loaded in tests -test { - classpath += files(outputsFolder) - dependsOn syncOutputsFolder -} - // setup wpilib bundled native libs wpilibTools.deps.wpilibVersion = wpi.versions.wpilibVersion.get() diff --git a/photon-targeting/src/main/java/org/photonvision/jni/WpilibLoader.java b/photon-targeting/src/main/java/org/photonvision/jni/LibraryLoader.java similarity index 69% rename from photon-targeting/src/main/java/org/photonvision/jni/WpilibLoader.java rename to photon-targeting/src/main/java/org/photonvision/jni/LibraryLoader.java index ccaf03cef..0572711fd 100644 --- a/photon-targeting/src/main/java/org/photonvision/jni/WpilibLoader.java +++ b/photon-targeting/src/main/java/org/photonvision/jni/LibraryLoader.java @@ -29,11 +29,12 @@ import edu.wpi.first.util.WPIUtilJNI; import java.io.IOException; import org.opencv.core.Core; -public class WpilibLoader { - private static boolean has_loaded = false; +public class LibraryLoader { + private static boolean hasWpiLoaded = false; + private static boolean hasTargetingLoaded = false; - public static boolean loadLibraries() { - if (has_loaded) return true; + public static boolean loadWpiLibraries() { + if (hasWpiLoaded) return true; NetworkTablesJNI.Helper.setExtractOnStaticLoad(false); WPIUtilJNI.Helper.setExtractOnStaticLoad(false); @@ -45,10 +46,10 @@ public class WpilibLoader { AprilTagJNI.Helper.setExtractOnStaticLoad(false); try { // Need to load wpiutil first before checking if the MSVC runtime is valid - CombinedRuntimeLoader.loadLibraries(WpilibLoader.class, "wpiutiljni"); + CombinedRuntimeLoader.loadLibraries(LibraryLoader.class, "wpiutiljni"); WPIUtilJNI.checkMsvcRuntime(); CombinedRuntimeLoader.loadLibraries( - WpilibLoader.class, + LibraryLoader.class, "wpimathjni", "ntcorejni", "wpinetjni", @@ -56,13 +57,25 @@ public class WpilibLoader { "cscorejni", "apriltagjni"); - CombinedRuntimeLoader.loadLibraries(WpilibLoader.class, Core.NATIVE_LIBRARY_NAME); - has_loaded = true; + CombinedRuntimeLoader.loadLibraries(LibraryLoader.class, Core.NATIVE_LIBRARY_NAME); + hasWpiLoaded = true; } catch (IOException e) { e.printStackTrace(); - has_loaded = false; + hasWpiLoaded = false; } - return has_loaded; + return hasWpiLoaded; + } + + public static boolean loadTargeting() { + if (hasTargetingLoaded) return true; + try { + CombinedRuntimeLoader.loadLibraries(LibraryLoader.class, "photontargetingJNI"); + hasTargetingLoaded = true; + } catch (IOException e) { + e.printStackTrace(); + hasTargetingLoaded = false; + } + return hasTargetingLoaded; } } diff --git a/photon-targeting/src/main/java/org/photonvision/jni/PhotonTargetingJniLoader.java b/photon-targeting/src/main/java/org/photonvision/jni/PhotonTargetingJniLoader.java deleted file mode 100644 index 32ef1abf6..000000000 --- a/photon-targeting/src/main/java/org/photonvision/jni/PhotonTargetingJniLoader.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) Photon Vision. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.photonvision.jni; - -import edu.wpi.first.util.RuntimeLoader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.util.List; -import org.photonvision.common.hardware.Platform; - -public class PhotonTargetingJniLoader { - public static boolean isWorking = false; - - public static boolean load() throws IOException, UnsatisfiedLinkError { - if (isWorking) return true; - isWorking = load_(); - return isWorking; - } - - public static boolean load_() throws IOException, UnsatisfiedLinkError { - // We always extract the shared object (we could hash each so, but that's a lot - // of work) - String arch_name = Platform.getNativeLibraryFolderName(); - var clazz = PhotonTargetingJniLoader.class; - - for (var libraryName : List.of("photontargeting", "photontargetingJNI")) { - try { - RuntimeLoader.loadLibrary(libraryName); - continue; - } catch (Exception e) { - System.out.println("Direct library load failed; falling back to extraction"); - } - - var nativeLibName = System.mapLibraryName(libraryName); - var path = "/nativelibraries/" + arch_name + "/" + nativeLibName; - var in = clazz.getResourceAsStream(path); - - if (in == null) { - System.err.println("Could not get resource at path " + path); - return false; - } - - // It's important that we don't mangle the names of these files on Windows at - // least - var tempfolder = Files.createTempDirectory("nativeextract"); - File temp = new File(tempfolder.toAbsolutePath().toString(), nativeLibName); - System.out.println(temp.getAbsolutePath().toString()); - FileOutputStream fos = new FileOutputStream(temp); - - int read = -1; - byte[] buffer = new byte[1024]; - while ((read = in.read(buffer)) != -1) { - fos.write(buffer, 0, read); - } - fos.close(); - in.close(); - - try { - System.load(temp.getAbsolutePath()); - } catch (Throwable t) { - System.err.println("Unable to System.load " + temp.getName() + " : " + t.getMessage()); - t.printStackTrace(); - return false; - } - - System.out.println("Successfully loaded shared object " + temp.getName()); - } - - return true; - } -} diff --git a/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java b/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java index 40acdf2a9..2a2e611f8 100644 --- a/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java +++ b/photon-targeting/src/test/java/ConstrainedSolvepnpTest.java @@ -21,24 +21,22 @@ import static org.junit.jupiter.api.Assertions.fail; import edu.wpi.first.hal.HAL; import edu.wpi.first.math.MatBuilder; import edu.wpi.first.math.Nat; +import edu.wpi.first.util.RuntimeLoader; import java.io.IOException; import java.util.Arrays; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.photonvision.jni.ConstrainedSolvepnpJni; -import org.photonvision.jni.PhotonTargetingJniLoader; -import org.photonvision.jni.WpilibLoader; +import org.photonvision.jni.LibraryLoader; public class ConstrainedSolvepnpTest { @BeforeAll - public static void load_wpilib() throws UnsatisfiedLinkError, IOException { - if (!WpilibLoader.loadLibraries()) { - fail(); - } - if (!PhotonTargetingJniLoader.load()) { + public static void load() throws IOException { + if (!LibraryLoader.loadWpiLibraries()) { fail(); } + RuntimeLoader.loadLibrary("photontargetingJNI"); HAL.initialize(1000, 0); } diff --git a/photon-targeting/src/test/java/jni/CscoreExtrasTest.java b/photon-targeting/src/test/java/jni/CscoreExtrasTest.java index 1c5e8ea48..1efb15122 100644 --- a/photon-targeting/src/test/java/jni/CscoreExtrasTest.java +++ b/photon-targeting/src/test/java/jni/CscoreExtrasTest.java @@ -28,23 +28,21 @@ import edu.wpi.first.cscore.UsbCamera; import edu.wpi.first.hal.HAL; import edu.wpi.first.util.PixelFormat; import edu.wpi.first.util.RawFrame; +import edu.wpi.first.util.RuntimeLoader; import java.io.IOException; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.opencv.core.Mat; import org.photonvision.jni.CscoreExtras; -import org.photonvision.jni.PhotonTargetingJniLoader; -import org.photonvision.jni.WpilibLoader; +import org.photonvision.jni.LibraryLoader; public class CscoreExtrasTest { @BeforeAll - public static void load_wpilib() throws UnsatisfiedLinkError, IOException { - if (!WpilibLoader.loadLibraries()) { - fail(); - } - if (!PhotonTargetingJniLoader.load()) { + public static void load() throws IOException { + if (!LibraryLoader.loadWpiLibraries()) { fail(); } + RuntimeLoader.loadLibrary("photontargetingJNI"); HAL.initialize(1000, 0); } diff --git a/photon-targeting/src/test/java/jni/FileLoggerTest.java b/photon-targeting/src/test/java/jni/FileLoggerTest.java index f974825b3..fe2f129f8 100644 --- a/photon-targeting/src/test/java/jni/FileLoggerTest.java +++ b/photon-targeting/src/test/java/jni/FileLoggerTest.java @@ -21,24 +21,22 @@ import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assumptions.assumeTrue; import edu.wpi.first.hal.HAL; +import edu.wpi.first.util.RuntimeLoader; import java.io.IOException; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.photonvision.common.hardware.Platform; -import org.photonvision.jni.PhotonTargetingJniLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.jni.QueuedFileLogger; -import org.photonvision.jni.WpilibLoader; public class FileLoggerTest { @BeforeAll - public static void load_wpilib() throws UnsatisfiedLinkError, IOException { - if (!WpilibLoader.loadLibraries()) { - fail(); - } - if (!PhotonTargetingJniLoader.load()) { + public static void load() throws IOException { + if (!LibraryLoader.loadWpiLibraries()) { fail(); } + RuntimeLoader.loadLibrary("photontargetingJNI"); HAL.initialize(1000, 0); } diff --git a/photon-targeting/src/test/java/net/TimeSyncTest.java b/photon-targeting/src/test/java/net/TimeSyncTest.java index a5fd7b4cc..2234ee50a 100644 --- a/photon-targeting/src/test/java/net/TimeSyncTest.java +++ b/photon-targeting/src/test/java/net/TimeSyncTest.java @@ -17,25 +17,21 @@ package net; -import static org.junit.jupiter.api.Assertions.fail; - import edu.wpi.first.hal.HAL; +import edu.wpi.first.util.RuntimeLoader; import java.io.IOException; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.photonvision.jni.PhotonTargetingJniLoader; +import org.photonvision.jni.LibraryLoader; import org.photonvision.jni.TimeSyncClient; import org.photonvision.jni.TimeSyncServer; -import org.photonvision.jni.WpilibLoader; public class TimeSyncTest { @BeforeAll - public static void load_wpilib() throws UnsatisfiedLinkError, IOException { - WpilibLoader.loadLibraries(); - if (!PhotonTargetingJniLoader.load()) { - fail(); - } + public static void load() throws IOException { + LibraryLoader.loadWpiLibraries(); + RuntimeLoader.loadLibrary("photontargetingJNI"); HAL.initialize(1000, 0); } diff --git a/shared/config.gradle b/shared/config.gradle index 90e8aa206..71cb2ca21 100644 --- a/shared/config.gradle +++ b/shared/config.gradle @@ -127,8 +127,14 @@ ext.createComponentZipTasks = { components, names, base, type, project, func -> project.build.dependsOn task - project.artifacts { - task + // If the zip artifact matches the platform we're building for (either host or whatever the ArchOverride is), and it's a shared library built in release mode, add it to the list of artifacts the project exposes for use + if (key.contains(wpilibTools.getPlatformMapper().getWpilibClassifier()) && !key.contains("debug") && !key.contains("static")) { + // For more information, see https://docs.gradle.org/current/userguide/variant_model.html and the outgoingVariants task + project.artifacts.add("wpilibNatives", task) + } else { + project.artifacts { + task + } } addTaskToCopyAllOutputs(task) }