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" licenseFile = file("LICENSE") } 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}" {} } } model { components { "${nativeName}"(NativeLibrarySpec) { sources { cpp { source { srcDirs 'src/main/native/cpp', "$buildDir/generated/source/proto/main/cpp", "$buildDir/generated/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' lib project: ':photon-targeting', library: 'photontargetingJNI', 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.dependsOn 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 copyVendorJsonToExamples { outputs.upToDateWhen { false } jar.finalizedBy it } [ "photonlib-cpp-examples", "photonlib-java-examples" ].each { exampleFolder -> file("${rootDir}/${exampleFolder}") .listFiles() .findAll { return (it.isDirectory() && !it.isHidden() && !it.name.startsWith(".") && it.toPath().resolve("build.gradle").toFile().exists()) } .collect { it.name } .each { exampleVendordepFolder -> task "copyVendorJsonTo${exampleFolder}-${exampleVendordepFolder}"(type: Copy) { from photonlibFileOutput into "${rootDir}/${exampleFolder}/${exampleVendordepFolder}/vendordeps/" outputs.upToDateWhen { false } copyVendorJsonToExamples.dependsOn it } } } clean { [ "photonlib-cpp-examples", "photonlib-java-examples" ].each { exampleFolder -> file("${rootDir}/${exampleFolder}") .listFiles() .findAll { return (it.isDirectory() && !it.isHidden() && !it.name.startsWith(".") && it.toPath().resolve("build.gradle").toFile().exists()) } .collect { it.name } .each { exampleVendordepFolder -> delete "${rootDir}/${exampleFolder}/${exampleVendordepFolder}/vendordeps/" } } } task writeCurrentVersion { doLast { def versionFileIn = file("${rootDir}/shared/PhotonVersion.java.in") writePhotonVersionFile(versionFileIn, Path.of("$buildDir", "generated", "java", "org", "photonvision", "PhotonVersion.java"), versionString) versionFileIn = file("${rootDir}/shared/PhotonVersion.cpp.in") writePhotonVersionFile(versionFileIn, Path.of("$buildDir", "generated", "native", "cpp", "PhotonVersion.cpp"), versionString) } } // https://github.com/wpilibsuite/allwpilib/blob/main/wpilibj/build.gradle#L52 sourceSets.main.java.srcDir "${buildDir}/generated/java/" compileJava.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 writeCurrentVersion 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("$buildDir/generated/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') 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') 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" + openCVYear, wpi.versions.opencvVersion.get())