From 4a7de52e8c552ce143b032c75e98e623fa6623d1 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 23 Dec 2023 15:53:08 -0800 Subject: [PATCH 01/11] Copy lots of JNI stuff from allwpilib --- build.gradle | 6 ++ photon-core/build.gradle | 26 ++++++ photon-core/src/dev/native/cpp/devmain.cpp | 16 ++++ .../org/photonvision/raspi/LibCameraJNI.java | 2 +- .../src/main/native/cpp/jni/TestJni.cpp | 8 ++ photon-core/src/main/native/cpp/test.cpp | 16 ++++ photon-core/src/main/native/include/test.h | 2 + photon-core/src/test/native/cpp/devmain.cpp | 7 ++ photon-lib/build.gradle | 15 ++++ photon-targeting/build.gradle | 15 ++++ shared/javacpp/setupBuild.gradle | 90 +++++++++++++++++-- 11 files changed, 196 insertions(+), 7 deletions(-) create mode 100644 photon-core/src/dev/native/cpp/devmain.cpp create mode 100644 photon-core/src/main/native/cpp/jni/TestJni.cpp create mode 100644 photon-core/src/main/native/cpp/test.cpp create mode 100644 photon-core/src/main/native/include/test.h create mode 100644 photon-core/src/test/native/cpp/devmain.cpp diff --git a/build.gradle b/build.gradle index 3c00130fd5..f4c8281fd4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id "com.diffplug.spotless" version "6.22.0" id "edu.wpi.first.NativeUtils" version "2024.6.1" apply false + id 'edu.wpi.first.GradleJni' version '1.1.0' id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2" id "edu.wpi.first.GradleRIO" version "2024.1.1-beta-4" id 'edu.wpi.first.WpilibTools' version '1.3.0' @@ -90,3 +91,8 @@ spotless { wrapper { gradleVersion '8.4' } + +import edu.wpi.first.toolchain.NativePlatforms +ext.getCurrentArch = { + return NativePlatforms.desktop +} diff --git a/photon-core/build.gradle b/photon-core/build.gradle index d5de014915..48bc192dc7 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -1,7 +1,31 @@ +plugins { + id 'edu.wpi.first.WpilibTools' version '1.3.0' +} + import java.nio.file.Path apply from: "${rootDir}/shared/common.gradle" +ext { + nativeName = "photoncore" + + main_native_libs = [ + "opencv_shared" + ] + + test_native_libs = [ + "opencv_static" + ] + + dev_native_libs = [ + "opencv_static", + ] +} + +def sharedCvConfigs = [photoncore: []] +def staticCvConfigs = [:] + + dependencies { // JOGL stuff (currently we only distribute for aarch64, which is Pi 4) implementation "org.jogamp.gluegen:gluegen-rt:$joglVersion" @@ -22,3 +46,5 @@ task writeCurrentVersion { } build.dependsOn writeCurrentVersion + +apply from: "${rootDir}/shared/javacpp/setupBuild.gradle" diff --git a/photon-core/src/dev/native/cpp/devmain.cpp b/photon-core/src/dev/native/cpp/devmain.cpp new file mode 100644 index 0000000000..69f8136930 --- /dev/null +++ b/photon-core/src/dev/native/cpp/devmain.cpp @@ -0,0 +1,16 @@ +#include "test.h" + +#include +#include +#include + +#include + +int main() { + + cv::Mat mat = cv::imread("/home/matt/Documents/GitHub/photonvision/test-resources/testimages/2022/WPI/FarLaunchpad13ft10in.png"); + + printf("DevMain! mat size %i %i\n", mat.rows, mat.cols); + + return 1; +} \ No newline at end of file diff --git a/photon-core/src/main/java/org/photonvision/raspi/LibCameraJNI.java b/photon-core/src/main/java/org/photonvision/raspi/LibCameraJNI.java index 8a12aeabfa..a243a47967 100644 --- a/photon-core/src/main/java/org/photonvision/raspi/LibCameraJNI.java +++ b/photon-core/src/main/java/org/photonvision/raspi/LibCameraJNI.java @@ -116,7 +116,7 @@ public static boolean isSupported() { * * @param width Camera video mode width in pixels * @param height Camera video mode height in pixels - * @param fps Camera video mode FPS + * @param rotation Asdf * @return success of creating a camera object */ public static native boolean createCamera(int width, int height, int rotation); diff --git a/photon-core/src/main/native/cpp/jni/TestJni.cpp b/photon-core/src/main/native/cpp/jni/TestJni.cpp new file mode 100644 index 0000000000..6e8f36bd5a --- /dev/null +++ b/photon-core/src/main/native/cpp/jni/TestJni.cpp @@ -0,0 +1,8 @@ +#include + +extern "C" { + JNIEXPORT jint JNICALL + some_native_function() { + return 0; + } +} \ No newline at end of file diff --git a/photon-core/src/main/native/cpp/test.cpp b/photon-core/src/main/native/cpp/test.cpp new file mode 100644 index 0000000000..203a2f8f8e --- /dev/null +++ b/photon-core/src/main/native/cpp/test.cpp @@ -0,0 +1,16 @@ +#include "test.h" + +#include +#include +#include + +#include + +int some_test() { + + cv::Mat mat = cv::imread("/home/matt/Documents/GitHub/photonvision/test-resources/testimages/2022/WPI/FarLaunchpad13ft10in.png"); + + printf("mat size %i %i\n", mat.rows, mat.cols); + + return 1; +} \ No newline at end of file diff --git a/photon-core/src/main/native/include/test.h b/photon-core/src/main/native/include/test.h new file mode 100644 index 0000000000..4e3098346f --- /dev/null +++ b/photon-core/src/main/native/include/test.h @@ -0,0 +1,2 @@ +#pragma once +int some_test(); diff --git a/photon-core/src/test/native/cpp/devmain.cpp b/photon-core/src/test/native/cpp/devmain.cpp new file mode 100644 index 0000000000..b003512ea7 --- /dev/null +++ b/photon-core/src/test/native/cpp/devmain.cpp @@ -0,0 +1,7 @@ +#include "test.h" +#include + +int main(int argc, char** argv) { + printf("hello!\n"); + return some_test(); +} \ No newline at end of file diff --git a/photon-lib/build.gradle b/photon-lib/build.gradle index 099308f470..6b6cec8dec 100644 --- a/photon-lib/build.gradle +++ b/photon-lib/build.gradle @@ -11,6 +11,21 @@ ext { includePhotonTargeting = true // Include the generated Version file generatedHeaders = "src/generate/native/include" + + test_native_libs = [ + "cscore_shared", + "cameraserver_shared", + "wpilib_executable_shared", + "googletest_static", + "apriltag_shared", + "opencv_shared", + ] + + main_native_libs = [ + "wpilib_shared", "apriltag_shared", "opencv_shared" + ] + + dev_native_libs = [] } apply from: "${rootDir}/shared/javacpp/setupBuild.gradle" diff --git a/photon-targeting/build.gradle b/photon-targeting/build.gradle index 4238e951e6..5e8af89ee4 100644 --- a/photon-targeting/build.gradle +++ b/photon-targeting/build.gradle @@ -4,6 +4,21 @@ plugins { ext { nativeName = "photontargeting" + + main_native_libs = [ + "wpilib_shared", "apriltag_shared", "opencv_shared" + ] + + test_native_libs = [ + "cscore_shared", + "cameraserver_shared", + "wpilib_executable_shared", + "googletest_static", + "apriltag_shared", + "opencv_shared", + ] + + dev_native_libs = [] } apply from: "${rootDir}/shared/javacpp/setupBuild.gradle" diff --git a/shared/javacpp/setupBuild.gradle b/shared/javacpp/setupBuild.gradle index dd8a5bec32..6ebc1dfcbb 100644 --- a/shared/javacpp/setupBuild.gradle +++ b/shared/javacpp/setupBuild.gradle @@ -1,6 +1,7 @@ apply plugin: 'cpp' apply plugin: 'google-test-test-suite' apply plugin: 'edu.wpi.first.NativeUtils' +apply plugin: 'edu.wpi.first.GradleJni' apply from: "${rootDir}/shared/config.gradle" apply from: "${rootDir}/shared/javacommon.gradle" @@ -60,6 +61,86 @@ model { nativeUtils.useRequiredLibrary(it, "wpilib_shared") nativeUtils.useRequiredLibrary(it, "apriltag_shared") nativeUtils.useRequiredLibrary(it, "opencv_shared") + main_native_libs.each { name -> + nativeUtils.useRequiredLibrary(it, name) + } + } + // By default, a development executable will be generated. This is to help the case of + // testing specific functionality of the library. + "${nativeName}Dev"(NativeExecutableSpec) { + targetBuildTypes 'debug' + sources { + cpp { + source { + srcDirs 'src/dev/native/cpp' + include '**/*.cpp' + } + exportedHeaders { + srcDir 'src/main/native/include' + if (project.hasProperty('generatedHeaders')) { + srcDir generatedHeaders + } + } + } + } + binaries.all { + lib library: nativeName, linkage: 'shared' + it.tasks.withType(CppCompile) { + // it.dependsOn generateProto + } + if (project.hasProperty('exeSplitSetup')) { + exeSplitSetup(it) + } + } + dev_native_libs.each { name -> + nativeUtils.useRequiredLibrary(it, name) + } + } + "${nativeName}JNI"(JniNativeLibrarySpec) { + baseName = nativeName + 'jni' + + enableCheckTask !project.hasProperty('skipJniCheck') + javaCompileTasks << compileJava + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio) + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32) + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm64) + + sources { + cpp { + source { + srcDirs 'src/main/native/cpp' + if (project.hasProperty('generatedSources')) { + srcDir generatedSources + } + include '**/jni/**/*.cpp' + } + exportedHeaders { + srcDir 'src/main/native/include' + if (project.hasProperty('generatedHeaders')) { + srcDir generatedHeaders + } + include '**/*.h' + } + } + } + + binaries.all { + if (it instanceof StaticLibraryBinarySpec) { + it.buildable = false + return + } + lib library: "${nativeName}", linkage: 'shared' + if (!project.hasProperty('noWpiutil')) { + lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + } + if (project.hasProperty('jniSplitSetup')) { + jniSplitSetup(it) + } + } + + if(project.hasProperty("jni_native_libs")) jni_native_libs.each { name -> + nativeUtils.useRequiredLibrary(it, name) + } } } testSuites { @@ -88,12 +169,9 @@ model { } } - nativeUtils.useRequiredLibrary(it, "cscore_shared") - nativeUtils.useRequiredLibrary(it, "cameraserver_shared") - nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared") - nativeUtils.useRequiredLibrary(it, "googletest_static") - nativeUtils.useRequiredLibrary(it, "apriltag_shared") - nativeUtils.useRequiredLibrary(it, "opencv_shared") + test_native_libs.each { name -> + nativeUtils.useRequiredLibrary(it, name) + } } } } From 70b732c391a872ca54f9dbceeb9fe1f1bb913f49 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 23 Dec 2023 16:11:12 -0800 Subject: [PATCH 02/11] Yeet JNI --- build.gradle | 1 - shared/javacpp/setupBuild.gradle | 47 -------------------------------- 2 files changed, 48 deletions(-) diff --git a/build.gradle b/build.gradle index f4c8281fd4..c6c9ca2915 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,6 @@ plugins { id "com.diffplug.spotless" version "6.22.0" id "edu.wpi.first.NativeUtils" version "2024.6.1" apply false - id 'edu.wpi.first.GradleJni' version '1.1.0' id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2" id "edu.wpi.first.GradleRIO" version "2024.1.1-beta-4" id 'edu.wpi.first.WpilibTools' version '1.3.0' diff --git a/shared/javacpp/setupBuild.gradle b/shared/javacpp/setupBuild.gradle index 6ebc1dfcbb..8128daa677 100644 --- a/shared/javacpp/setupBuild.gradle +++ b/shared/javacpp/setupBuild.gradle @@ -1,7 +1,6 @@ apply plugin: 'cpp' apply plugin: 'google-test-test-suite' apply plugin: 'edu.wpi.first.NativeUtils' -apply plugin: 'edu.wpi.first.GradleJni' apply from: "${rootDir}/shared/config.gradle" apply from: "${rootDir}/shared/javacommon.gradle" @@ -96,52 +95,6 @@ model { nativeUtils.useRequiredLibrary(it, name) } } - "${nativeName}JNI"(JniNativeLibrarySpec) { - baseName = nativeName + 'jni' - - enableCheckTask !project.hasProperty('skipJniCheck') - javaCompileTasks << compileJava - jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio) - jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32) - jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm64) - - sources { - cpp { - source { - srcDirs 'src/main/native/cpp' - if (project.hasProperty('generatedSources')) { - srcDir generatedSources - } - include '**/jni/**/*.cpp' - } - exportedHeaders { - srcDir 'src/main/native/include' - if (project.hasProperty('generatedHeaders')) { - srcDir generatedHeaders - } - include '**/*.h' - } - } - } - - binaries.all { - if (it instanceof StaticLibraryBinarySpec) { - it.buildable = false - return - } - lib library: "${nativeName}", linkage: 'shared' - if (!project.hasProperty('noWpiutil')) { - lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' - } - if (project.hasProperty('jniSplitSetup')) { - jniSplitSetup(it) - } - } - - if(project.hasProperty("jni_native_libs")) jni_native_libs.each { name -> - nativeUtils.useRequiredLibrary(it, name) - } - } } testSuites { "${nativeName}Test"(GoogleTestTestSuiteSpec) { From dd8b65034664aa45e951f2046bbd7fd557848d68 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 23 Dec 2023 16:15:53 -0800 Subject: [PATCH 03/11] gih --- build.gradle | 1 + photon-core/build.gradle | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/build.gradle b/build.gradle index c6c9ca2915..b571df5302 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ plugins { id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2" id "edu.wpi.first.GradleRIO" version "2024.1.1-beta-4" id 'edu.wpi.first.WpilibTools' version '1.3.0' + id 'edu.wpi.first.GradleJni' version '1.1.0' } allprojects { diff --git a/photon-core/build.gradle b/photon-core/build.gradle index 48bc192dc7..a93e094586 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -48,3 +48,55 @@ task writeCurrentVersion { build.dependsOn writeCurrentVersion apply from: "${rootDir}/shared/javacpp/setupBuild.gradle" + +apply plugin: 'edu.wpi.first.GradleJni' +model { + components { + "${nativeName}JNI"(JniNativeLibrarySpec) { + baseName = nativeName + 'jni' + + enableCheckTask !project.hasProperty('skipJniCheck') + javaCompileTasks << compileJava + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio) + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32) + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm64) + + sources { + cpp { + source { + srcDirs 'src/main/native/cpp' + if (project.hasProperty('generatedSources')) { + srcDir generatedSources + } + include '**/jni/**/*.cpp' + } + exportedHeaders { + srcDir 'src/main/native/include' + if (project.hasProperty('generatedHeaders')) { + srcDir generatedHeaders + } + include '**/*.h' + } + } + } + + binaries.all { + if (it instanceof StaticLibraryBinarySpec) { + it.buildable = false + return + } + lib library: "${nativeName}", linkage: 'shared' + if (!project.hasProperty('noWpiutil')) { + lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + } + if (project.hasProperty('jniSplitSetup')) { + jniSplitSetup(it) + } + } + + if(project.hasProperty("jni_native_libs")) jni_native_libs.each { name -> + nativeUtils.useRequiredLibrary(it, name) + } + } + } +} From 5ac9f688931a22a126b6d30fee75e3512ac21046 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 23 Dec 2023 18:01:51 -0800 Subject: [PATCH 04/11] Create test-jni --- build.gradle | 2 + photon-core/build.gradle | 17 +++----- .../src/main/native/{cpp => }/jni/TestJni.cpp | 0 shared/javacpp/publish.gradle | 39 ++++++++++++++++++- 4 files changed, 45 insertions(+), 13 deletions(-) rename photon-core/src/main/native/{cpp => }/jni/TestJni.cpp (100%) diff --git a/build.gradle b/build.gradle index b571df5302..47453850bc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,6 @@ plugins { + id "java" + id "cpp" id "com.diffplug.spotless" version "6.22.0" id "edu.wpi.first.NativeUtils" version "2024.6.1" apply false id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2" diff --git a/photon-core/build.gradle b/photon-core/build.gradle index a93e094586..46dd210111 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -9,16 +9,12 @@ apply from: "${rootDir}/shared/common.gradle" ext { nativeName = "photoncore" - main_native_libs = [ - "opencv_shared" - ] + main_native_libs = ["opencv_shared"] - test_native_libs = [ - "opencv_static" - ] + test_native_libs = ["opencv_shared"] dev_native_libs = [ - "opencv_static", + "opencv_shared", ] } @@ -64,11 +60,11 @@ model { sources { cpp { source { - srcDirs 'src/main/native/cpp' + srcDirs 'src/main/native/jni' if (project.hasProperty('generatedSources')) { srcDir generatedSources } - include '**/jni/**/*.cpp' + include '**/*.cpp' } exportedHeaders { srcDir 'src/main/native/include' @@ -86,9 +82,6 @@ model { return } lib library: "${nativeName}", linkage: 'shared' - if (!project.hasProperty('noWpiutil')) { - lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' - } if (project.hasProperty('jniSplitSetup')) { jniSplitSetup(it) } diff --git a/photon-core/src/main/native/cpp/jni/TestJni.cpp b/photon-core/src/main/native/jni/TestJni.cpp similarity index 100% rename from photon-core/src/main/native/cpp/jni/TestJni.cpp rename to photon-core/src/main/native/jni/TestJni.cpp diff --git a/shared/javacpp/publish.gradle b/shared/javacpp/publish.gradle index 22389e2342..6f5fa80813 100644 --- a/shared/javacpp/publish.gradle +++ b/shared/javacpp/publish.gradle @@ -1,3 +1,5 @@ +import java.security.MessageDigest + apply plugin: 'maven-publish' def outputsFolder = file("$buildDir/outputs") @@ -5,6 +7,7 @@ def outputsFolder = file("$buildDir/outputs") def baseArtifactId = nativeName def artifactGroupId = 'org.photonvision' def zipBaseName = "_GROUP_org_photonvision_${baseArtifactId}_ID_${baseArtifactId}-cpp_CLS" +def jniBaseName = "_GROUP_org_photonvision_${nativeName}_ID_${nativeName}-jni_CLS" def licenseFile = file("$rootDir/LICENCE") @@ -52,7 +55,32 @@ addTaskToCopyAllOutputs(cppHeadersZip) model { publishing { - def taskList = createComponentZipTasks($.components, [nativeName], zipBaseName, Zip, project, includeStandardZipFormat) + def taskList = createComponentZipTasks($.components, [ + nativeName, + "${nativeName}JNI" + ], zipBaseName, Zip, project, includeStandardZipFormat) + + def jniTaskList = createComponentZipTasks($.components, ["${nativeName}JNI"], jniBaseName, Jar, project, { task, value -> + value.each { binary -> + if (binary.buildable) { + if (binary instanceof SharedLibraryBinarySpec) { + task.dependsOn binary.tasks.link + def hashFile = new File(binary.sharedLibraryFile.parentFile.absolutePath, "${binary.component.baseName}.hash") + task.outputs.file(hashFile) + task.inputs.file(binary.sharedLibraryFile) + task.from(hashFile) { + into nativeUtils.getPlatformPath(binary) + } + task.doFirst { + hashFile.text = MessageDigest.getInstance("MD5").digest(binary.sharedLibraryFile.bytes).encodeHex().toString() + } + task.from(binary.sharedLibraryFile) { + into nativeUtils.getPlatformPath(binary) + } + } + } + } + }) publications { cpp(MavenPublication) { @@ -66,6 +94,15 @@ model { groupId artifactGroupId version pubVersion } + jni(MavenPublication) { + jniTaskList.each { + artifact it + } + + artifactId = "${baseArtifactId}-jni" + groupId artifactGroupId + version pubVersion + } } repositories { From 804099360e274220fcdf0b68701e5b6240a419f1 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 23 Dec 2023 18:02:15 -0800 Subject: [PATCH 05/11] Run lint --- photon-core/src/dev/native/cpp/devmain.cpp | 32 ++++++++++++++++----- photon-core/src/main/native/cpp/test.cpp | 32 ++++++++++++++++----- photon-core/src/main/native/include/test.h | 17 +++++++++++ photon-core/src/main/native/jni/TestJni.cpp | 24 ++++++++++++---- photon-core/src/test/native/cpp/devmain.cpp | 26 ++++++++++++++--- photon-lib/build.gradle | 4 ++- photon-targeting/build.gradle | 4 ++- 7 files changed, 114 insertions(+), 25 deletions(-) diff --git a/photon-core/src/dev/native/cpp/devmain.cpp b/photon-core/src/dev/native/cpp/devmain.cpp index 69f8136930..5b4065a1d7 100644 --- a/photon-core/src/dev/native/cpp/devmain.cpp +++ b/photon-core/src/dev/native/cpp/devmain.cpp @@ -1,16 +1,34 @@ -#include "test.h" +/* + * 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 . + */ + +#include #include #include #include -#include +#include "test.h" int main() { - - cv::Mat mat = cv::imread("/home/matt/Documents/GitHub/photonvision/test-resources/testimages/2022/WPI/FarLaunchpad13ft10in.png"); + cv::Mat mat = cv::imread( + "/home/matt/Documents/GitHub/photonvision/test-resources/testimages/2022/" + "WPI/FarLaunchpad13ft10in.png"); - printf("DevMain! mat size %i %i\n", mat.rows, mat.cols); + std::printf("DevMain! mat size %i %i\n", mat.rows, mat.cols); - return 1; -} \ No newline at end of file + return 1; +} diff --git a/photon-core/src/main/native/cpp/test.cpp b/photon-core/src/main/native/cpp/test.cpp index 203a2f8f8e..e42ed323cc 100644 --- a/photon-core/src/main/native/cpp/test.cpp +++ b/photon-core/src/main/native/cpp/test.cpp @@ -1,16 +1,34 @@ +/* + * 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 . + */ + #include "test.h" +#include + #include #include #include -#include - int some_test() { - - cv::Mat mat = cv::imread("/home/matt/Documents/GitHub/photonvision/test-resources/testimages/2022/WPI/FarLaunchpad13ft10in.png"); + cv::Mat mat = cv::imread( + "/home/matt/Documents/GitHub/photonvision/test-resources/testimages/2022/" + "WPI/FarLaunchpad13ft10in.png"); - printf("mat size %i %i\n", mat.rows, mat.cols); + std::printf("mat size %i %i\n", mat.rows, mat.cols); - return 1; -} \ No newline at end of file + return 1; +} diff --git a/photon-core/src/main/native/include/test.h b/photon-core/src/main/native/include/test.h index 4e3098346f..ae673c990a 100644 --- a/photon-core/src/main/native/include/test.h +++ b/photon-core/src/main/native/include/test.h @@ -1,2 +1,19 @@ +/* + * 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 . + */ + #pragma once int some_test(); diff --git a/photon-core/src/main/native/jni/TestJni.cpp b/photon-core/src/main/native/jni/TestJni.cpp index 6e8f36bd5a..38da552c57 100644 --- a/photon-core/src/main/native/jni/TestJni.cpp +++ b/photon-core/src/main/native/jni/TestJni.cpp @@ -1,8 +1,22 @@ +/* + * 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 . + */ + #include extern "C" { - JNIEXPORT jint JNICALL - some_native_function() { - return 0; - } -} \ No newline at end of file +JNIEXPORT jint JNICALL some_native_function(void) { return 0; } +} // extern "C" diff --git a/photon-core/src/test/native/cpp/devmain.cpp b/photon-core/src/test/native/cpp/devmain.cpp index b003512ea7..8384921a68 100644 --- a/photon-core/src/test/native/cpp/devmain.cpp +++ b/photon-core/src/test/native/cpp/devmain.cpp @@ -1,7 +1,25 @@ +/* + * 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 . + */ + +#include + #include "test.h" -#include int main(int argc, char** argv) { - printf("hello!\n"); - return some_test(); -} \ No newline at end of file + std::printf("hello!\n"); + return some_test(); +} diff --git a/photon-lib/build.gradle b/photon-lib/build.gradle index 6b6cec8dec..02b468d11b 100644 --- a/photon-lib/build.gradle +++ b/photon-lib/build.gradle @@ -22,7 +22,9 @@ ext { ] main_native_libs = [ - "wpilib_shared", "apriltag_shared", "opencv_shared" + "wpilib_shared", + "apriltag_shared", + "opencv_shared" ] dev_native_libs = [] diff --git a/photon-targeting/build.gradle b/photon-targeting/build.gradle index 5e8af89ee4..0d14b6737f 100644 --- a/photon-targeting/build.gradle +++ b/photon-targeting/build.gradle @@ -6,7 +6,9 @@ ext { nativeName = "photontargeting" main_native_libs = [ - "wpilib_shared", "apriltag_shared", "opencv_shared" + "wpilib_shared", + "apriltag_shared", + "opencv_shared" ] test_native_libs = [ From 4f6850c8ea35cd7814e77bbcaacf5330c1d60248 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 24 Dec 2023 10:27:10 -0800 Subject: [PATCH 06/11] still can't make java depend on native? --- photon-core/build.gradle | 57 +++++++++++++++++++++++++++++++- shared/javacpp/setupBuild.gradle | 8 +++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/photon-core/build.gradle b/photon-core/build.gradle index 46dd210111..c0871fd4be 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -46,12 +46,17 @@ build.dependsOn writeCurrentVersion apply from: "${rootDir}/shared/javacpp/setupBuild.gradle" apply plugin: 'edu.wpi.first.GradleJni' + +def nativeOutputDir = file("$buildDir/${nativeName}_outs") +def taskFoo = null; +println("Saving to $nativeOutputDir") + model { components { "${nativeName}JNI"(JniNativeLibrarySpec) { baseName = nativeName + 'jni' - enableCheckTask !project.hasProperty('skipJniCheck') + enableCheckTask project.hasProperty('doJniCheck') javaCompileTasks << compileJava jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio) jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32) @@ -90,6 +95,56 @@ model { if(project.hasProperty("jni_native_libs")) jni_native_libs.each { name -> nativeUtils.useRequiredLibrary(it, name) } + + appendDebugPathToBinaries(binaries) + } + } + + tasks { + def ts = $.components + project.tasks.register('copyPhotonCoreNative') { testTask-> + // println("Hello!") + def systemArch = getCurrentArch() + def sharedLibs = [] + ts.each { + // println("=========") + // println it.baseName + it.binaries.each { + def arch = it.targetPlatform.name + if (arch == systemArch && it.buildType.name == 'release' && it instanceof SharedLibraryBinarySpec) { + testTask.dependsOn it.tasks.build + + // println it.tasks + // println it.getSharedLibraryFile() + // println it.tasks.build.class + // def f = it.sharedLibraryFile.parentFile; + + + sharedLibs << it + } + } + } + + doLast { + sharedLibs.each { so -> + def arch = so.targetPlatform.architecture.name + def os = so.targetPlatform.operatingSystem.name + + copy { + from so.sharedLibraryFile + // We know all should be shared libs only at this point + into file("$buildDir/${nativeName}_outs/${nativeUtils.getPlatformPath(so)}/shared") + } + } + } + + $.tasks.jar.dependsOn testTask + // taskFoo = testTask; } } } + +// Make sure our files get added to resources, and that build happens before JAR does +// println taskFoo +sourceSets.main.resources.srcDirs += nativeOutputDir +// jar.dependsOn { taskFoo } diff --git a/shared/javacpp/setupBuild.gradle b/shared/javacpp/setupBuild.gradle index 8128daa677..5f0a921b55 100644 --- a/shared/javacpp/setupBuild.gradle +++ b/shared/javacpp/setupBuild.gradle @@ -57,12 +57,11 @@ model { } } - nativeUtils.useRequiredLibrary(it, "wpilib_shared") - nativeUtils.useRequiredLibrary(it, "apriltag_shared") - nativeUtils.useRequiredLibrary(it, "opencv_shared") main_native_libs.each { name -> nativeUtils.useRequiredLibrary(it, name) } + + appendDebugPathToBinaries(binaries) } // By default, a development executable will be generated. This is to help the case of // testing specific functionality of the library. @@ -91,9 +90,12 @@ model { exeSplitSetup(it) } } + dev_native_libs.each { name -> nativeUtils.useRequiredLibrary(it, name) } + + appendDebugPathToBinaries(binaries) } } testSuites { From a71b1e3b6205e6f755a2c12f94620d6cfc9d8c19 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 24 Dec 2023 11:30:14 -0800 Subject: [PATCH 07/11] Make jar depend on JNI build --- photon-core/build.gradle | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/photon-core/build.gradle b/photon-core/build.gradle index c0871fd4be..9ffbc26242 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -48,7 +48,6 @@ apply from: "${rootDir}/shared/javacpp/setupBuild.gradle" apply plugin: 'edu.wpi.first.GradleJni' def nativeOutputDir = file("$buildDir/${nativeName}_outs") -def taskFoo = null; println("Saving to $nativeOutputDir") model { @@ -133,18 +132,29 @@ model { copy { from so.sharedLibraryFile // We know all should be shared libs only at this point - into file("$buildDir/${nativeName}_outs/${nativeUtils.getPlatformPath(so)}/shared") + into file(nativeOutputDir.path + "/${nativeUtils.getPlatformPath(so)}/shared") } } } - $.tasks.jar.dependsOn testTask + // $.tasks.jar.dependsOn testTask // taskFoo = testTask; } } } +// yay misdirection +tasks.register('testDesktop') { + dependsOn copyPhotonCoreNative +} +jar.dependsOn tasks.named('testDesktop') + +jar { + from nativeOutputDir + println("Adding to JAR $nativeOutputDir") +} + + // Make sure our files get added to resources, and that build happens before JAR does -// println taskFoo -sourceSets.main.resources.srcDirs += nativeOutputDir -// jar.dependsOn { taskFoo } +// sourceSets.main.resources.srcDirs += nativeOutputDir +// println sourceSets.main.resources.srcDirs From 8640609669975f8d2433225cc1e9686be311272e Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 24 Dec 2023 13:18:55 -0800 Subject: [PATCH 08/11] It works! --- README.md | 5 +++++ photon-core/build.gradle | 8 ++++---- photon-core/src/dev/native/cpp/devmain.cpp | 7 ++----- .../java/org/photonvision/jni/CalibrationHelper.java | 11 +++++++++++ 4 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java diff --git a/README.md b/README.md index 556043437a..d847683de2 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Note that these are case sensitive! * x86 - `-PtgtIp`: Specifies where `./gradlew deploy` should try to copy the fat JAR to - `-Pprofile`: enables JVM profiling +- `doJniCheck`: Enables checking JNI symbol matching between Java/C++ ## Building @@ -59,6 +60,10 @@ To run them, use the commands listed below. Photonlib must first be published to ~/photonvision/photonlib-cpp-examples$ ./gradlew :simulateNative ``` +## Installing cross-toolchains + +Install cross toolchains using `./gradlew installArm64Toolchain`/`./gradlew installRoboRioToolchain`. Needed for building for arm64 or rio targets. + ## Acknowledgments PhotonVision was forked from [Chameleon Vision](https://github.com/Chameleon-Vision/chameleon-vision/). Thank you to everyone who worked on the original project. diff --git a/photon-core/build.gradle b/photon-core/build.gradle index 9ffbc26242..3ff56423d4 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -103,16 +103,18 @@ model { def ts = $.components project.tasks.register('copyPhotonCoreNative') { testTask-> // println("Hello!") - def systemArch = getCurrentArch() + def systemArch = wpilibTools.getCurrentPlatform().platformName def sharedLibs = [] ts.each { // println("=========") // println it.baseName it.binaries.each { def arch = it.targetPlatform.name + // println("checking $arch against $systemArch") if (arch == systemArch && it.buildType.name == 'release' && it instanceof SharedLibraryBinarySpec) { testTask.dependsOn it.tasks.build + println "Selecting ${it}" // println it.tasks // println it.getSharedLibraryFile() // println it.tasks.build.class @@ -120,6 +122,7 @@ model { sharedLibs << it + testTask.dependsOn it } } } @@ -136,9 +139,6 @@ model { } } } - - // $.tasks.jar.dependsOn testTask - // taskFoo = testTask; } } } diff --git a/photon-core/src/dev/native/cpp/devmain.cpp b/photon-core/src/dev/native/cpp/devmain.cpp index 5b4065a1d7..c98cb86d51 100644 --- a/photon-core/src/dev/native/cpp/devmain.cpp +++ b/photon-core/src/dev/native/cpp/devmain.cpp @@ -17,6 +17,7 @@ #include +// Includes to test opencv linkage #include #include #include @@ -24,11 +25,7 @@ #include "test.h" int main() { - cv::Mat mat = cv::imread( - "/home/matt/Documents/GitHub/photonvision/test-resources/testimages/2022/" - "WPI/FarLaunchpad13ft10in.png"); - - std::printf("DevMain! mat size %i %i\n", mat.rows, mat.cols); + // Just empty to check library linking happens return 1; } diff --git a/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java b/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java new file mode 100644 index 0000000000..805ba04f56 --- /dev/null +++ b/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java @@ -0,0 +1,11 @@ +package org.photonvision.jni; + +public class CalibrationHelper { + public static class CalResult { + + } + + public static native long Create(int width, int height, long overlayMatPtr, double tolerance); + public static native long Destroy(); + public static native CalResult Detect(long inputImg, long outputImg); +} From 22a4f5b79f7ac3e339d53f1b4f8ac65de32217a2 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 24 Dec 2023 13:21:48 -0800 Subject: [PATCH 09/11] Working JNI example --- .../java/org/photonvision/jni/CalibrationHelper.java | 5 +++++ .../src/main/native/jni/CalibrationHelperJni.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 photon-core/src/main/native/jni/CalibrationHelperJni.cpp diff --git a/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java b/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java index 805ba04f56..dc04dbde7d 100644 --- a/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java +++ b/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java @@ -8,4 +8,9 @@ public static class CalResult { public static native long Create(int width, int height, long overlayMatPtr, double tolerance); public static native long Destroy(); public static native CalResult Detect(long inputImg, long outputImg); + + public static void main(String[] args) { + System.load("/home/matt/Documents/GitHub/photonvision/photon-core/build/libs/photoncoreJNI/shared/linuxx86-64/release/libphotoncorejni.so"); + System.out.println(Create(1, 2, 3, 4)); + } } diff --git a/photon-core/src/main/native/jni/CalibrationHelperJni.cpp b/photon-core/src/main/native/jni/CalibrationHelperJni.cpp new file mode 100644 index 0000000000..b875a41e28 --- /dev/null +++ b/photon-core/src/main/native/jni/CalibrationHelperJni.cpp @@ -0,0 +1,10 @@ +#include + +extern "C" { + +JNIEXPORT jlong JNICALL Java_org_photonvision_jni_CalibrationHelper_Create + (JNIEnv *, jclass, jint, jint, jlong, jdouble) { + return 0; +} + +} From a14ea485eed6febcf1703a7a9f588e94edf2851d Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 24 Dec 2023 13:23:17 -0800 Subject: [PATCH 10/11] Run lint --- photon-core/build.gradle | 2 +- .../photonvision/jni/CalibrationHelper.java | 26 ++++++++++++--- .../main/native/jni/CalibrationHelperJni.cpp | 32 ++++++++++++++++--- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/photon-core/build.gradle b/photon-core/build.gradle index 3ff56423d4..77a9d1ccc7 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -131,7 +131,7 @@ model { sharedLibs.each { so -> def arch = so.targetPlatform.architecture.name def os = so.targetPlatform.operatingSystem.name - + copy { from so.sharedLibraryFile // We know all should be shared libs only at this point diff --git a/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java b/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java index dc04dbde7d..230ca72b8e 100644 --- a/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java +++ b/photon-core/src/main/java/org/photonvision/jni/CalibrationHelper.java @@ -1,16 +1,34 @@ +/* + * 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; public class CalibrationHelper { - public static class CalResult { - - } + public static class CalResult {} public static native long Create(int width, int height, long overlayMatPtr, double tolerance); + public static native long Destroy(); + public static native CalResult Detect(long inputImg, long outputImg); public static void main(String[] args) { - System.load("/home/matt/Documents/GitHub/photonvision/photon-core/build/libs/photoncoreJNI/shared/linuxx86-64/release/libphotoncorejni.so"); + System.load( + "/home/matt/Documents/GitHub/photonvision/photon-core/build/libs/photoncoreJNI/shared/linuxx86-64/release/libphotoncorejni.so"); System.out.println(Create(1, 2, 3, 4)); } } diff --git a/photon-core/src/main/native/jni/CalibrationHelperJni.cpp b/photon-core/src/main/native/jni/CalibrationHelperJni.cpp index b875a41e28..d5766cf4bd 100644 --- a/photon-core/src/main/native/jni/CalibrationHelperJni.cpp +++ b/photon-core/src/main/native/jni/CalibrationHelperJni.cpp @@ -1,10 +1,34 @@ +/* + * 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 . + */ + #include extern "C" { -JNIEXPORT jlong JNICALL Java_org_photonvision_jni_CalibrationHelper_Create - (JNIEnv *, jclass, jint, jint, jlong, jdouble) { - return 0; +/* + * Class: org_photonvision_jni_CalibrationHelper + * Method: Create + * Signature: (IIJD)J + */ +JNIEXPORT jlong JNICALL +Java_org_photonvision_jni_CalibrationHelper_Create + (JNIEnv*, jclass, jint, jint, jlong, jdouble) +{ + return 0; } -} +} // extern "C" From 3640fae69d0f2a418da6aab49c98887eeaefeac1 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 25 Dec 2023 11:46:40 -0800 Subject: [PATCH 11/11] Publish to maven-local ugh --- photon-core/build.gradle | 20 ++++++++++---------- photon-core/src/main/native/jni/TestJni.cpp | 3 ++- photon-server/build.gradle | 3 +++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/photon-core/build.gradle b/photon-core/build.gradle index 77a9d1ccc7..059ada791d 100644 --- a/photon-core/build.gradle +++ b/photon-core/build.gradle @@ -85,7 +85,7 @@ model { it.buildable = false return } - lib library: "${nativeName}", linkage: 'shared' + lib library: "${nativeName}", linkage: 'static' if (project.hasProperty('jniSplitSetup')) { jniSplitSetup(it) } @@ -144,15 +144,15 @@ model { } // yay misdirection -tasks.register('testDesktop') { - dependsOn copyPhotonCoreNative -} -jar.dependsOn tasks.named('testDesktop') - -jar { - from nativeOutputDir - println("Adding to JAR $nativeOutputDir") -} +// tasks.register('testDesktop') { +// dependsOn copyPhotonCoreNative +// } +// jar.dependsOn tasks.named('testDesktop') + +// jar { +// from nativeOutputDir +// println("Adding to JAR $nativeOutputDir") +// } // Make sure our files get added to resources, and that build happens before JAR does diff --git a/photon-core/src/main/native/jni/TestJni.cpp b/photon-core/src/main/native/jni/TestJni.cpp index 38da552c57..69de712e6c 100644 --- a/photon-core/src/main/native/jni/TestJni.cpp +++ b/photon-core/src/main/native/jni/TestJni.cpp @@ -16,7 +16,8 @@ */ #include +#include "test.h" extern "C" { -JNIEXPORT jint JNICALL some_native_function(void) { return 0; } +JNIEXPORT jint JNICALL some_native_function(void) { return some_test(); } } // extern "C" diff --git a/photon-server/build.gradle b/photon-server/build.gradle index c60c441760..124544988f 100644 --- a/photon-server/build.gradle +++ b/photon-server/build.gradle @@ -13,6 +13,9 @@ dependencies { // Needed for Javalin Runtime Logging implementation "org.slf4j:slf4j-simple:2.0.7" + + // implementation "org.photonvision:photoncore-cpp:${pubVersion}:" + jniPlatform + "@zip" + implementation "org.photonvision:photoncore-jni:${pubVersion}:" + jniPlatform; } group 'org.photonvision'