Files
PhotonVision/photon-lib/build.gradle
Matt a0c85fc95f Create photon-targeting-JNI framework (#1428)
Initial framework for adding JNI libraries. Auto generated JNI headers and sticks native libraries into the JAR (and adds to class path for testing)
2024-09-23 22:44:09 -04:00

342 lines
12 KiB
Groovy

plugins {
id 'edu.wpi.first.WpilibTools' version '1.3.0'
}
import java.nio.file.Path
ext {
nativeName = "photonlib"
includePhotonTargeting = true
// Include the generated Version file
generatedHeaders = "src/generate/native/include"
}
apply plugin: 'cpp'
apply plugin: 'google-test-test-suite'
apply plugin: 'edu.wpi.first.NativeUtils'
apply from: "${rootDir}/shared/config.gradle"
apply from: "${rootDir}/shared/javacommon.gradle"
apply from: "${rootDir}/versioningHelper.gradle"
nativeUtils {
exportsConfigs {
"${nativeName}" {
// From https://github.com/wpilibsuite/allwpilib/blob/a32589831184969939fd3d63f449a2788a0a8542/wpimath/build.gradle#L72
// 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.
x64ExcludeSymbols = [
'_CT??_R0?AV_System_error',
'_CT??_R0?AVexception',
'_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error',
'_CT??_R0?AVsystem_error',
'_CTA5?AVfailure',
'_TI5?AVfailure',
'_CT??_R0?AVout_of_range',
'_CTA3?AVout_of_range',
'_TI3?AVout_of_range',
'_CT??_R0?AVbad_cast'
]
}
}
}
model {
components {
"${nativeName}"(NativeLibrarySpec) {
sources {
cpp {
source {
srcDirs 'src/main/native/cpp', "$buildDir/generated/source/proto/main/cpp", "src/generate/native/cpp"
include '**/*.cpp', '**/*.cc'
}
exportedHeaders {
srcDirs 'src/main/native/include', "$buildDir/generated/source/proto/main/cpp"
if (project.hasProperty('generatedHeaders')) {
srcDir generatedHeaders
}
include "**/*.h"
}
}
}
binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn generateProto
}
if(project.hasProperty('includePhotonTargeting')) {
lib project: ':photon-targeting', library: 'photontargeting', linkage: 'shared'
}
}
nativeUtils.useRequiredLibrary(it, "wpilib_shared")
nativeUtils.useRequiredLibrary(it, "apriltag_shared")
nativeUtils.useRequiredLibrary(it, "opencv_shared")
nativeUtils.useRequiredLibrary(it, "cscore_shared")
nativeUtils.useRequiredLibrary(it, "cameraserver_shared")
}
}
testSuites {
"${nativeName}Test"(GoogleTestTestSuiteSpec) {
for(NativeComponentSpec c : $.components) {
if (c.name == nativeName) {
testing c
break
}
}
sources {
cpp {
source {
srcDirs 'src/test/native/cpp'
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/test/native/include', "$buildDir/generated/source/proto/main/cpp"
}
}
}
binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn generateProto
}
if(project.hasProperty('includePhotonTargeting')) {
lib project: ':photon-targeting', library: 'photontargeting', linkage: 'shared'
}
}
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")
}
}
tasks {
def c = $.testSuites
project.tasks.create('runCpp', Exec) {
description = "Run the photon-lib executable"
def found = false
def systemArch = getCurrentArch()
c.each {
if (it in GoogleTestTestSuiteSpec && it.name == "${nativeName}Test") {
it.binaries.each {
if (!found) {
def arch = it.targetPlatform.name
if (arch == systemArch) {
dependsOn it.tasks.install
commandLine it.tasks.install.runScriptFile.get().asFile.toString()
def filePath = it.tasks.install.installDirectory.get().toString() + File.separatorChar + 'lib'
test.dependsOn it.tasks.install
test.systemProperty 'java.library.path', filePath
test.environment 'LD_LIBRARY_PATH', filePath
test.environment 'DYLD_LIBRARY_PATH', filePath
test.workingDir filePath
found = true
}
}
}
}
}
}
}
}
apply from: "${rootDir}/shared/javacpp/publish.gradle"
// Include the version file in the distributed sources
cppHeadersZip {
from('src/generate/native/include') {
into '/'
}
}
def photonlibFileInput = file("src/generate/photonlib.json.in")
ext.photonlibFileOutput = file("$buildDir/generated/vendordeps/photonlib.json")
task generateVendorJson() {
description = "Generates the vendor JSON file"
group = "PhotonVision"
outputs.file photonlibFileOutput
inputs.file photonlibFileInput
println "Writing vendor JSON ${pubVersion} to $photonlibFileOutput"
if (photonlibFileOutput.exists()) {
photonlibFileOutput.delete()
}
photonlibFileOutput.parentFile.mkdirs()
def read = photonlibFileInput.text
.replace('${photon_version}', pubVersion)
.replace('${frc_year}', frcYear)
photonlibFileOutput.text = read
outputs.upToDateWhen { false }
}
build.mustRunAfter generateVendorJson
publish.mustRunAfter generateVendorJson
task publishVendorJsonToLocalOutputs(type: Copy) {
from photonlibFileOutput
into "$allOutputsFolder/vendordeps/"
// Rename to match the name of the JSON we publish to maven to avoid user confusion
rename { String fileName ->
fileName.replace(".json", "-json-1.0.json")
}
publish.dependsOn it
}
task writeCurrentVersion {
def versionFileIn = file("${rootDir}/shared/PhotonVersion.java.in")
writePhotonVersionFile(versionFileIn, Path.of("$projectDir", "src", "main", "java", "org", "photonvision", "PhotonVersion.java"),
versionString)
versionFileIn = file("${rootDir}/shared/PhotonVersion.cpp.in")
writePhotonVersionFile(versionFileIn, Path.of("$projectDir", "src", "generate", "native", "cpp", "PhotonVersion.cpp"),
versionString)
}
build.mustRunAfter writeCurrentVersion
cppHeadersZip.dependsOn writeCurrentVersion
// Building photon-lib requires photon-targeting to generate its proto files. This technically shouldn't be required but is needed for it to build.
model {
components {
all {
it.sources.each {
it.exportedHeaders {
srcDirs "src/main/native/include"
srcDirs "src/generate/native/include"
}
}
it.binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn ":photon-targeting:generateProto"
}
}
}
}
testSuites {
all {
it.binaries.all {
it.tasks.withType(CppCompile) {
it.dependsOn ":photon-targeting:generateProto"
}
}
}
}
}
def vendorJson = artifacts.add('archives', file("$photonlibFileOutput"))
if (!project.hasProperty('copyOfflineArtifacts')) {
// Publish the vendordep json
publishing {
publications {
vendorjson(MavenPublication) {
artifact vendorJson
artifactId = "${nativeName}-json"
groupId = "org.photonvision"
version "1.0"
}
}
}
}
// Add photonversion to cpp sources zip
tasks.named('cppSourcesZip') {
dependsOn writeCurrentVersion
from("$projectDir/src/generate/native/cpp") {
into '/'
}
}
// Publish an uberzip with photon-lib and photon-targeting. This makes python binding easier to have it in one place
def zipBaseNameCombined = '_GROUP_org.photonvision_combinedcpp_ID_photonvision-combinedcpp_CLS'
task combinedCppSourcesZip(type: Zip) {
dependsOn(':photon-lib:cppSourcesZip', ':photon-targeting:cppSourcesZip')
mustRunAfter(':photon-lib:cppHeadersZip', ':photon-targeting:cppHeadersZip')
destinationDirectory = file("$buildDir/outputs")
archiveBaseName = zipBaseNameCombined
archiveClassifier = "sources"
// Include the contents of the photon-lib cppSourcesZip. Magic chatgpt nonsense
from(zipTree(project(':photon-lib').tasks.cppSourcesZip.archiveFile.get().asFile)) {
into 'photon-lib'
}
from(zipTree(project(':photon-targeting').tasks.cppSourcesZip.archiveFile.get().asFile)) {
into 'photon-targeting'
}
duplicatesStrategy = DuplicatesStrategy.FAIL
}
task combinedHeadersZip(type: Zip) {
dependsOn(':photon-lib:cppHeadersZip', ':photon-targeting:cppHeadersZip')
mustRunAfter(':photon-lib:cppHeadersZip', ':photon-targeting:cppHeadersZip')
destinationDirectory = file("$buildDir/outputs")
archiveBaseName = zipBaseNameCombined
archiveClassifier = "headers"
// Include the contents of the photon-lib cppHeadersZip. Magic chatgpt nonsense
from(zipTree(project(':photon-lib').tasks.cppHeadersZip.archiveFile.get().asFile)) {
into 'photon-lib'
}
from(zipTree(project(':photon-targeting').tasks.cppHeadersZip.archiveFile.get().asFile)) {
into 'photon-targeting'
}
duplicatesStrategy = DuplicatesStrategy.FAIL
}
// Add the uberzip to our maven publications
publishing {
publications {
// Don't publish if we're creating an offline zip
if (!project.hasProperty('copyOfflineArtifacts')) {
combinedcpp(MavenPublication) {
artifact combinedCppSourcesZip
artifact combinedHeadersZip
artifactId = "${nativeName}-combinedcpp"
groupId artifactGroupId
version pubVersion
}
}
}
}
// setup wpilib bundled native libs
wpilibTools.deps.wpilibVersion = wpi.versions.wpilibVersion.get()
def nativeConfigName = 'wpilibNatives'
def nativeConfig = configurations.create(nativeConfigName)
def nativeTasks = wpilibTools.createExtractionTasks {
configurationName = nativeConfigName
}
nativeTasks.addToSourceSetResources(sourceSets.test)
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" + wpi.frcYear.get(), wpi.versions.opencvVersion.get())