diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8acf4c8..a3651b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,12 +11,12 @@ jobs: - container: wpilib/roborio-cross-ubuntu:2024-22.04 artifact-name: Athena build-options: "-Ponlylinuxathena" - # - container: wpilib/raspbian-cross-ubuntu:bullseye-22.04 - # artifact-name: Arm32 - # build-options: "-Ponlylinuxarm32" - # - container: wpilib/aarch64-cross-ubuntu:bullseye-22.04 - # artifact-name: Arm64 - # build-options: "-Ponlylinuxarm64" + - container: wpilib/raspbian-cross-ubuntu:bullseye-22.04 + artifact-name: Arm32 + build-options: "-Ponlylinuxarm32" + - container: wpilib/aarch64-cross-ubuntu:bullseye-22.04 + artifact-name: Arm64 + build-options: "-Ponlylinuxarm64" - container: wpilib/ubuntu-base:22.04 artifact-name: Linux build-options: "" diff --git a/ExampleVendorJson.json b/ExampleVendorJson.json index e5188c9..af4d453 100644 --- a/ExampleVendorJson.json +++ b/ExampleVendorJson.json @@ -1,74 +1,74 @@ -{ - "fileName": "ExampleVendorJson.json", - "name": "ExampleVendorDep", - "version": "0.0.1", - "frcYear": "2024", - "uuid": "Generate A Unique GUID https://guidgenerator.com/online-guid-generator.aspx and insert it here", This line is to purposely make this fail to parse - "mavenUrls": [ - "ThisNeedsToBeTheRootMavenUrl" - ], - "jsonUrl": "InsertSomeUrlHere", - "javaDependencies": [ - { - "groupId": "com.vendor.frc", - "artifactId": "Vendor-java", - "version": "0.0.1" - } - ], - "jniDependencies": [ - { - "groupId": "com.vendor.frc", - "artifactId": "Vendor-driver", - "version": "0.0.1", - "skipInvalidPlatforms": true, - "isJar": false, - "validPlatforms": [ - "windowsx86-64", - "windowsx86", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - } - ], - "cppDependencies": [ - { - "groupId": "com.vendor.frc", - "artifactId": "Vendor-cpp", - "version": "0.0.1", - "libName": "Vendor", - "headerClassifier": "headers", - "sharedLibrary": false, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "windowsx86", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - }, - { - "groupId": "com.vendor.frc", - "artifactId": "Vendor-driver", - "version": "0.0.1", - "libName": "VendorDriver", - "headerClassifier": "headers", - "sharedLibrary": false, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "windowsx86", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - } - ] -} +{ + "fileName": "ExampleVendorJson.json", + "name": "ExampleVendorDep", + "version": "0.0.1", + "frcYear": "2024", + "uuid": "Generate A Unique GUID https://guidgenerator.com/online-guid-generator.aspx and insert it here", This line is to purposely make this fail to parse + "mavenUrls": [ + "ThisNeedsToBeTheRootMavenUrl" + ], + "jsonUrl": "InsertSomeUrlHere", + "javaDependencies": [ + { + "groupId": "com.vendor.frc", + "artifactId": "Vendor-java", + "version": "0.0.1" + } + ], + "jniDependencies": [ + { + "groupId": "com.vendor.frc", + "artifactId": "Vendor-driver", + "version": "0.0.1", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "windowsx86", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.vendor.frc", + "artifactId": "Vendor-cpp", + "version": "0.0.1", + "libName": "Vendor", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "windowsx86", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.vendor.frc", + "artifactId": "Vendor-driver", + "version": "0.0.1", + "libName": "VendorDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "windowsx86", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} diff --git a/README.md b/README.md index 0ebfba8..1d531c2 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,25 @@ -# WPILib Vendor Template - -This is the base WPILib vendor template for 2023. - -## Layout - -The build is split into 3 libraries. A java library is built. This has access to all of wpilib, and also can JNI load the driver library. - -A driver library is built. This should contain all low level code you want to access from both C++, Java and any other text based language. This will not work with LabVIEW. This library has access to the WPILib HAL and wpiutil. This library can only export C symbols. It cannot export C++ symbols at all, and all C symbols must be explicitly listed in the symbols.txt file in the driver folder. JNI symbols must be listed in this file as well. This library however can be written in C++. If you attempt to change this library to have access to all of wpilib, you will break JNI access and it will no longer work. - -A native C++ library is built. This has access to all of wpilib, and access to the driver library. This should implment the standard wpilib interfaces. - -## Customizing -For Java, the library name will be the folder name the build is started from, so rename the folder to the name of your choosing. - -For the native impl, you need to change the library name in the exportsConfigs block of build.gradle, the components block of build.gradle, and the taskList input array name in publish.gradle. - -For the driver, change the library name in privateExportsConfigs, the driver name in components, and the driverTaskList input array name. In addition, you'll need to change the `lib library` in the native C++ impl component, and the JNI library name in the JNI java class. - -For the maven artifact names, those are all in publish.gradle about 40 lines down. - -## Building and editing -This uses gradle, and uses the same base setup as a standard GradleRIO robot project. This means you build with `./gradlew build`, and can install the native toolchain with `./gradlew installRoboRIOToolchain`. If you open this project in VS Code with the wpilib extension installed, you will get intellisense set up for both C++ and Java. - +# WPILib Vendor Template + +This is the base WPILib vendor template for 2023. + +## Layout + +The build is split into 3 libraries. A java library is built. This has access to all of wpilib, and also can JNI load the driver library. + +A driver library is built. This should contain all low level code you want to access from both C++, Java and any other text based language. This will not work with LabVIEW. This library has access to the WPILib HAL and wpiutil. This library can only export C symbols. It cannot export C++ symbols at all, and all C symbols must be explicitly listed in the symbols.txt file in the driver folder. JNI symbols must be listed in this file as well. This library however can be written in C++. If you attempt to change this library to have access to all of wpilib, you will break JNI access and it will no longer work. + +A native C++ library is built. This has access to all of wpilib, and access to the driver library. This should implment the standard wpilib interfaces. + +## Customizing +For Java, the library name will be the folder name the build is started from, so rename the folder to the name of your choosing. + +For the native impl, you need to change the library name in the exportsConfigs block of build.gradle, the components block of build.gradle, and the taskList input array name in publish.gradle. + +For the driver, change the library name in privateExportsConfigs, the driver name in components, and the driverTaskList input array name. In addition, you'll need to change the `lib library` in the native C++ impl component, and the JNI library name in the JNI java class. + +For the maven artifact names, those are all in publish.gradle about 40 lines down. + +## Building and editing +This uses gradle, and uses the same base setup as a standard GradleRIO robot project. This means you build with `./gradlew build`, and can install the native toolchain with `./gradlew installRoboRIOToolchain`. If you open this project in VS Code with the wpilib extension installed, you will get intellisense set up for both C++ and Java. + By default, this template builds against the latest WPILib development build. To build against the last WPILib tagged release, build with `./gradlew build -PreleaseMode`. \ No newline at end of file diff --git a/build.gradle b/build.gradle index bb4238b..9d19665 100644 --- a/build.gradle +++ b/build.gradle @@ -1,130 +1,130 @@ -plugins { - id 'cpp' - id 'java' - id 'google-test' - id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2' - id 'edu.wpi.first.NativeUtils' version '2024.7.2' - id 'edu.wpi.first.GradleJni' version '1.1.0' - id 'edu.wpi.first.GradleVsCode' version '2.1.0' -} - -repositories { - mavenCentral() -} -if (project.hasProperty('releaseMode')) { - wpilibRepositories.addAllReleaseRepositories(project) -} else { - wpilibRepositories.addAllDevelopmentRepositories(project) -} - -// Apply C++ configuration -apply from: 'config.gradle' - -// Apply Java configuration -dependencies { - implementation 'edu.wpi.first.cscore:cscore-java:2024.+' - implementation 'edu.wpi.first.cameraserver:cameraserver-java:2024.+' - implementation 'edu.wpi.first.ntcore:ntcore-java:2024.+' - implementation 'edu.wpi.first.wpilibj:wpilibj-java:2024.+' - implementation 'edu.wpi.first.wpiutil:wpiutil-java:2024.+' - implementation 'edu.wpi.first.wpimath:wpimath-java:2024.+' - implementation 'edu.wpi.first.wpiunits:wpiunits-java:2024.+' - implementation 'edu.wpi.first.hal:hal-java:2024.+' - implementation "org.ejml:ejml-simple:0.43.1" - implementation "com.fasterxml.jackson.core:jackson-annotations:2.15.2" - implementation "com.fasterxml.jackson.core:jackson-core:2.15.2" - implementation "com.fasterxml.jackson.core:jackson-databind:2.15.2" - implementation 'edu.wpi.first.thirdparty.frc2024.opencv:opencv-java:4.8.0-2' -} - -// Set up exports properly -nativeUtils { - exportsConfigs { - // Main library is just default empty. This will export everything - Vendor { - } - } - privateExportsConfigs { - // Only export explicit symbols from driver library - VendorDriver { - exportsFile = project.file("src/main/driver/symbols.txt") - } - } -} - -model { - components { - Vendor(NativeLibrarySpec) { - sources { - cpp { - source { - srcDirs 'src/main/native/cpp' - include '**/*.cpp' - } - exportedHeaders { - srcDirs 'src/main/native/include' - } - } - } - binaries.all { - lib library: 'VendorDriver', linkage: 'shared' - } - nativeUtils.useRequiredLibrary(it, 'wpilib_shared') - } - - VendorDriver(JniNativeLibrarySpec) { - enableCheckTask true - javaCompileTasks << compileJava - jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio) - // Leave these for future proofing - jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32) - jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm64) - sources { - cpp { - source { - srcDirs 'src/main/driver/cpp' - include '**/*.cpp' - } - exportedHeaders { - srcDirs 'src/main/driver/include' - } - } - } - - nativeUtils.useRequiredLibrary(it, "driver_shared") - } - } - testSuites { - VendorTest { - sources.cpp { - source { - srcDir 'src/test/native/cpp' - include '**/*.cpp' - } - } - - binaries.all { - lib library: 'VendorDriver', linkage: 'shared' - } - - nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static") - } - - VendorDriverTest { - sources.cpp { - source { - srcDir 'src/test/driver/cpp' - include '**/*.cpp' - } - } - - nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static") - } - } -} - -apply from: 'publish.gradle' - -wrapper { - gradleVersion '8.5' -} +plugins { + id 'cpp' + id 'java' + id 'google-test' + id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2' + id 'edu.wpi.first.NativeUtils' version '2024.7.2' + id 'edu.wpi.first.GradleJni' version '1.1.0' + id 'edu.wpi.first.GradleVsCode' version '2.1.0' +} + +repositories { + mavenCentral() +} +if (project.hasProperty('releaseMode')) { + wpilibRepositories.addAllReleaseRepositories(project) +} else { + wpilibRepositories.addAllDevelopmentRepositories(project) +} + +// Apply C++ configuration +apply from: 'config.gradle' + +// Apply Java configuration +dependencies { + implementation 'edu.wpi.first.cscore:cscore-java:2024.+' + implementation 'edu.wpi.first.cameraserver:cameraserver-java:2024.+' + implementation 'edu.wpi.first.ntcore:ntcore-java:2024.+' + implementation 'edu.wpi.first.wpilibj:wpilibj-java:2024.+' + implementation 'edu.wpi.first.wpiutil:wpiutil-java:2024.+' + implementation 'edu.wpi.first.wpimath:wpimath-java:2024.+' + implementation 'edu.wpi.first.wpiunits:wpiunits-java:2024.+' + implementation 'edu.wpi.first.hal:hal-java:2024.+' + implementation "org.ejml:ejml-simple:0.43.1" + implementation "com.fasterxml.jackson.core:jackson-annotations:2.15.2" + implementation "com.fasterxml.jackson.core:jackson-core:2.15.2" + implementation "com.fasterxml.jackson.core:jackson-databind:2.15.2" + implementation 'edu.wpi.first.thirdparty.frc2024.opencv:opencv-java:4.8.0-2' +} + +// Set up exports properly +nativeUtils { + exportsConfigs { + // Main library is just default empty. This will export everything + Vendor { + } + } + privateExportsConfigs { + // Only export explicit symbols from driver library + VendorDriver { + exportsFile = project.file("src/main/driver/symbols.txt") + } + } +} + +model { + components { + Vendor(NativeLibrarySpec) { + sources { + cpp { + source { + srcDirs 'src/main/native/cpp' + include '**/*.cpp' + } + exportedHeaders { + srcDirs 'src/main/native/include' + } + } + } + binaries.all { + lib library: 'VendorDriver', linkage: 'shared' + } + nativeUtils.useRequiredLibrary(it, 'wpilib_shared') + } + + VendorDriver(JniNativeLibrarySpec) { + enableCheckTask true + javaCompileTasks << compileJava + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio) + // Leave these for future proofing + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32) + jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm64) + sources { + cpp { + source { + srcDirs 'src/main/driver/cpp' + include '**/*.cpp' + } + exportedHeaders { + srcDirs 'src/main/driver/include' + } + } + } + + nativeUtils.useRequiredLibrary(it, "driver_shared") + } + } + testSuites { + VendorTest { + sources.cpp { + source { + srcDir 'src/test/native/cpp' + include '**/*.cpp' + } + } + + binaries.all { + lib library: 'VendorDriver', linkage: 'shared' + } + + nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static") + } + + VendorDriverTest { + sources.cpp { + source { + srcDir 'src/test/driver/cpp' + include '**/*.cpp' + } + } + + nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static") + } + } +} + +apply from: 'publish.gradle' + +wrapper { + gradleVersion '8.5' +} diff --git a/config.gradle b/config.gradle index 0c88342..cebc9c7 100644 --- a/config.gradle +++ b/config.gradle @@ -1,177 +1,179 @@ -import org.gradle.internal.os.OperatingSystem - -nativeUtils.addWpiNativeUtils() -nativeUtils.withCrossRoboRIO() - -nativeUtils { - wpi { - configureDependencies { - wpiVersion = "2024.+" - opencvYear = "frc2024" - googleTestYear = "frc2024" - niLibVersion = "2024.2.1" - opencvVersion = "4.8.0-2" - googleTestVersion = "1.14.0-1" - } - } -} - -nativeUtils.wpi.addWarnings() -nativeUtils.wpi.addWarningsAsErrors() - -nativeUtils.setSinglePrintPerPlatform() - -model { - // Uncomment this, and remove lines below it to enable builds for just roborio - // components { - // all { - // targetPlatform nativeUtils.wpi.platforms.roborio - // } - // } - components { - all { - nativeUtils.useAllPlatforms(it) - } - } - binaries { - withType(NativeBinarySpec).all { - nativeUtils.usePlatformArguments(it) - } - } -} - -ext.appendDebugPathToBinaries = { binaries-> - binaries.withType(StaticLibraryBinarySpec) { - if (it.buildType.name.contains('debug')) { - def staticFileDir = it.staticLibraryFile.parentFile - def staticFileName = it.staticLibraryFile.name - def staticFileExtension = staticFileName.substring(staticFileName.lastIndexOf('.')) - staticFileName = staticFileName.substring(0, staticFileName.lastIndexOf('.')) - staticFileName = staticFileName + 'd' + staticFileExtension - def newStaticFile = new File(staticFileDir, staticFileName) - it.staticLibraryFile = newStaticFile - } - } - binaries.withType(SharedLibraryBinarySpec) { - if (it.buildType.name.contains('debug')) { - def sharedFileDir = it.sharedLibraryFile.parentFile - def sharedFileName = it.sharedLibraryFile.name - def sharedFileExtension = sharedFileName.substring(sharedFileName.lastIndexOf('.')) - sharedFileName = sharedFileName.substring(0, sharedFileName.lastIndexOf('.')) - sharedFileName = sharedFileName + 'd' + sharedFileExtension - def newSharedFile = new File(sharedFileDir, sharedFileName) - - def sharedLinkFileDir = it.sharedLibraryLinkFile.parentFile - def sharedLinkFileName = it.sharedLibraryLinkFile.name - def sharedLinkFileExtension = sharedLinkFileName.substring(sharedLinkFileName.lastIndexOf('.')) - sharedLinkFileName = sharedLinkFileName.substring(0, sharedLinkFileName.lastIndexOf('.')) - sharedLinkFileName = sharedLinkFileName + 'd' + sharedLinkFileExtension - def newLinkFile = new File(sharedLinkFileDir, sharedLinkFileName) - - it.sharedLibraryLinkFile = newLinkFile - it.sharedLibraryFile = newSharedFile - } - } -} - -ext.createComponentZipTasks = { components, names, base, type, project, func -> - def stringNames = names.collect {it.toString()} - def configMap = [:] - components.each { - if (it in NativeLibrarySpec && stringNames.contains(it.name)) { - it.binaries.each { - if (!it.buildable) return - def target = nativeUtils.getPublishClassifier(it) - if (configMap.containsKey(target)) { - configMap.get(target).add(it) - } else { - configMap.put(target, []) - configMap.get(target).add(it) - } - } - } - } - def taskList = [] - def outputsFolder = file("$project.buildDir/outputs") - configMap.each { key, value -> - def task = project.tasks.create(base + "-${key}", type) { - description = 'Creates component archive for platform ' + key - destinationDirectory = outputsFolder - archiveClassifier = key - archiveBaseName = '_M_' + base - duplicatesStrategy = 'exclude' - - from(licenseFile) { - into '/' - } - - func(it, value) - } - taskList.add(task) - - project.build.dependsOn task - - project.artifacts { - task - } - addTaskToCopyAllOutputs(task) - } - return taskList -} - -ext.createAllCombined = { list, name, base, type, project -> - def outputsFolder = file("$project.buildDir/outputs") - - def task = project.tasks.create(base + "-all", type) { - description = "Creates component archive for all classifiers" - destinationDirectory = outputsFolder - classifier = "all" - archiveBaseName = base - duplicatesStrategy = 'exclude' - - list.each { - if (it.name.endsWith('debug')) return - from project.zipTree(it.archiveFile) - dependsOn it - } - } - - project.build.dependsOn task - - project.artifacts { - task - } - - return task - -} - -ext.includeStandardZipFormat = { task, value -> - value.each { binary -> - if (binary.buildable) { - if (binary instanceof SharedLibraryBinarySpec) { - task.dependsOn binary.tasks.link - task.from(new File(binary.sharedLibraryFile.absolutePath + ".debug")) { - into nativeUtils.getPlatformPath(binary) + '/shared' - } - def sharedPath = binary.sharedLibraryFile.absolutePath - sharedPath = sharedPath.substring(0, sharedPath.length() - 4) - - task.from(new File(sharedPath + '.pdb')) { - into nativeUtils.getPlatformPath(binary) + '/shared' - } - task.from(binary.sharedLibraryFile) { - into nativeUtils.getPlatformPath(binary) + '/shared' - } - task.from(binary.sharedLibraryLinkFile) { - into nativeUtils.getPlatformPath(binary) + '/shared' - } - } else if (binary instanceof StaticLibraryBinarySpec) { - task.dependsOn binary.tasks.createStaticLib - task.from(binary.staticLibraryFile) { - into nativeUtils.getPlatformPath(binary) + '/static' - } - } - } - } -} +import org.gradle.internal.os.OperatingSystem + +nativeUtils.addWpiNativeUtils() +nativeUtils.withCrossRoboRIO() +nativeUtils.withCrossLinuxArm32() +nativeUtils.withCrossLinuxArm64() + +nativeUtils { + wpi { + configureDependencies { + wpiVersion = "2024.+" + opencvYear = "frc2024" + googleTestYear = "frc2024" + niLibVersion = "2024.2.1" + opencvVersion = "4.8.0-2" + googleTestVersion = "1.14.0-1" + } + } +} + +nativeUtils.wpi.addWarnings() +nativeUtils.wpi.addWarningsAsErrors() + +nativeUtils.setSinglePrintPerPlatform() + +model { + // Uncomment this, and remove lines below it to enable builds for just roborio + // components { + // all { + // targetPlatform nativeUtils.wpi.platforms.roborio + // } + // } + components { + all { + nativeUtils.useAllPlatforms(it) + } + } + binaries { + withType(NativeBinarySpec).all { + nativeUtils.usePlatformArguments(it) + } + } +} + +ext.appendDebugPathToBinaries = { binaries-> + binaries.withType(StaticLibraryBinarySpec) { + if (it.buildType.name.contains('debug')) { + def staticFileDir = it.staticLibraryFile.parentFile + def staticFileName = it.staticLibraryFile.name + def staticFileExtension = staticFileName.substring(staticFileName.lastIndexOf('.')) + staticFileName = staticFileName.substring(0, staticFileName.lastIndexOf('.')) + staticFileName = staticFileName + 'd' + staticFileExtension + def newStaticFile = new File(staticFileDir, staticFileName) + it.staticLibraryFile = newStaticFile + } + } + binaries.withType(SharedLibraryBinarySpec) { + if (it.buildType.name.contains('debug')) { + def sharedFileDir = it.sharedLibraryFile.parentFile + def sharedFileName = it.sharedLibraryFile.name + def sharedFileExtension = sharedFileName.substring(sharedFileName.lastIndexOf('.')) + sharedFileName = sharedFileName.substring(0, sharedFileName.lastIndexOf('.')) + sharedFileName = sharedFileName + 'd' + sharedFileExtension + def newSharedFile = new File(sharedFileDir, sharedFileName) + + def sharedLinkFileDir = it.sharedLibraryLinkFile.parentFile + def sharedLinkFileName = it.sharedLibraryLinkFile.name + def sharedLinkFileExtension = sharedLinkFileName.substring(sharedLinkFileName.lastIndexOf('.')) + sharedLinkFileName = sharedLinkFileName.substring(0, sharedLinkFileName.lastIndexOf('.')) + sharedLinkFileName = sharedLinkFileName + 'd' + sharedLinkFileExtension + def newLinkFile = new File(sharedLinkFileDir, sharedLinkFileName) + + it.sharedLibraryLinkFile = newLinkFile + it.sharedLibraryFile = newSharedFile + } + } +} + +ext.createComponentZipTasks = { components, names, base, type, project, func -> + def stringNames = names.collect {it.toString()} + def configMap = [:] + components.each { + if (it in NativeLibrarySpec && stringNames.contains(it.name)) { + it.binaries.each { + if (!it.buildable) return + def target = nativeUtils.getPublishClassifier(it) + if (configMap.containsKey(target)) { + configMap.get(target).add(it) + } else { + configMap.put(target, []) + configMap.get(target).add(it) + } + } + } + } + def taskList = [] + def outputsFolder = file("$project.buildDir/outputs") + configMap.each { key, value -> + def task = project.tasks.create(base + "-${key}", type) { + description = 'Creates component archive for platform ' + key + destinationDirectory = outputsFolder + archiveClassifier = key + archiveBaseName = '_M_' + base + duplicatesStrategy = 'exclude' + + from(licenseFile) { + into '/' + } + + func(it, value) + } + taskList.add(task) + + project.build.dependsOn task + + project.artifacts { + task + } + addTaskToCopyAllOutputs(task) + } + return taskList +} + +ext.createAllCombined = { list, name, base, type, project -> + def outputsFolder = file("$project.buildDir/outputs") + + def task = project.tasks.create(base + "-all", type) { + description = "Creates component archive for all classifiers" + destinationDirectory = outputsFolder + classifier = "all" + archiveBaseName = base + duplicatesStrategy = 'exclude' + + list.each { + if (it.name.endsWith('debug')) return + from project.zipTree(it.archiveFile) + dependsOn it + } + } + + project.build.dependsOn task + + project.artifacts { + task + } + + return task + +} + +ext.includeStandardZipFormat = { task, value -> + value.each { binary -> + if (binary.buildable) { + if (binary instanceof SharedLibraryBinarySpec) { + task.dependsOn binary.tasks.link + task.from(new File(binary.sharedLibraryFile.absolutePath + ".debug")) { + into nativeUtils.getPlatformPath(binary) + '/shared' + } + def sharedPath = binary.sharedLibraryFile.absolutePath + sharedPath = sharedPath.substring(0, sharedPath.length() - 4) + + task.from(new File(sharedPath + '.pdb')) { + into nativeUtils.getPlatformPath(binary) + '/shared' + } + task.from(binary.sharedLibraryFile) { + into nativeUtils.getPlatformPath(binary) + '/shared' + } + task.from(binary.sharedLibraryLinkFile) { + into nativeUtils.getPlatformPath(binary) + '/shared' + } + } else if (binary instanceof StaticLibraryBinarySpec) { + task.dependsOn binary.tasks.createStaticLib + task.from(binary.staticLibraryFile) { + into nativeUtils.getPlatformPath(binary) + '/static' + } + } + } + } +} diff --git a/publish.gradle b/publish.gradle index 477455a..59c6f5e 100644 --- a/publish.gradle +++ b/publish.gradle @@ -1,205 +1,205 @@ -apply plugin: 'maven-publish' - -ext.licenseFile = files("$rootDir/LICENSE.txt") - -def pubVersion = '0.0.1' - -def outputsFolder = file("$buildDir/outputs") - -def versionFile = file("$outputsFolder/version.txt") - -task outputVersions() { - description = 'Prints the versions of wpilib to a file for use by the downstream packaging project' - group = 'Build' - outputs.files(versionFile) - - doFirst { - buildDir.mkdir() - outputsFolder.mkdir() - } - - doLast { - versionFile.write pubVersion - } -} - -task libraryBuild() {} - -build.dependsOn outputVersions - -task copyAllOutputs(type: Copy) { - destinationDir file("$buildDir/allOutputs") - from versionFile - dependsOn outputVersions -} - -build.dependsOn copyAllOutputs -copyAllOutputs.dependsOn outputVersions - -ext.addTaskToCopyAllOutputs = { task -> - copyAllOutputs.dependsOn task - copyAllOutputs.inputs.file task.archiveFile - copyAllOutputs.from task.archiveFile -} - -def artifactGroupId = 'com.vendor.frc' -def baseArtifactId = 'Vendor' -def driverZipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-driver_CLS" -def zipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-cpp_CLS" -def javaBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-java_CLS" - -task cppHeadersZip(type: Zip) { - destinationDirectory = outputsFolder - archiveBaseName = zipBaseName - archiveClassifier = "headers" - - from(licenseFile) { - into '/' - } - - from('src/main/native/include') { - into '/' - } -} - -task cppSourceZip(type: Zip) { - destinationDirectory = outputsFolder - archiveBaseName = zipBaseName - archiveClassifier = "sources" - - from(licenseFile) { - into '/' - } - - from('src/main/native/cpp') { - into '/' - } -} - -task cppDriverHeadersZip(type: Zip) { - destinationDirectory = outputsFolder - archiveBaseName = driverZipBaseName - archiveClassifier = "headers" - - from(licenseFile) { - into '/' - } - - from('src/main/driver/include') { - into '/' - } -} - -build.dependsOn cppHeadersZip -addTaskToCopyAllOutputs(cppHeadersZip) -build.dependsOn cppSourceZip -addTaskToCopyAllOutputs(cppSourceZip) -build.dependsOn cppDriverHeadersZip -addTaskToCopyAllOutputs(cppDriverHeadersZip) - -task sourcesJar(type: Jar, dependsOn: classes) { - archiveClassifier = 'sources' - from sourceSets.main.allSource -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - archiveClassifier = 'javadoc' - from javadoc.destinationDir -} - -task outputJar(type: Jar, dependsOn: classes) { - archiveBaseName = javaBaseName - destinationDirectory = outputsFolder - from sourceSets.main.output -} - -task outputSourcesJar(type: Jar, dependsOn: classes) { - archiveBaseName = javaBaseName - destinationDirectory = outputsFolder - archiveClassifier = 'sources' - from sourceSets.main.allSource -} - -task outputJavadocJar(type: Jar, dependsOn: javadoc) { - archiveBaseName = javaBaseName - destinationDirectory = outputsFolder - archiveClassifier = 'javadoc' - from javadoc.destinationDir -} - -artifacts { - archives sourcesJar - archives javadocJar - archives outputJar - archives outputSourcesJar - archives outputJavadocJar -} - -addTaskToCopyAllOutputs(outputSourcesJar) -addTaskToCopyAllOutputs(outputJavadocJar) -addTaskToCopyAllOutputs(outputJar) - -build.dependsOn outputSourcesJar -build.dependsOn outputJavadocJar -build.dependsOn outputJar - -libraryBuild.dependsOn build - -def releasesRepoUrl = "$buildDir/repos/releases" - -publishing { - repositories { - maven { - - url = releasesRepoUrl - } - } -} - -task cleanReleaseRepo(type: Delete) { - delete releasesRepoUrl -} - -tasks.matching {it != cleanReleaseRepo}.all {it.dependsOn cleanReleaseRepo} - -model { - publishing { - def taskList = createComponentZipTasks($.components, ['Vendor'], zipBaseName, Zip, project, includeStandardZipFormat) - - def driverTaskList = createComponentZipTasks($.components, ['VendorDriver'], driverZipBaseName, Zip, project, includeStandardZipFormat) - - publications { - cpp(MavenPublication) { - taskList.each { - artifact it - } - artifact cppHeadersZip - artifact cppSourceZip - - artifactId = "${baseArtifactId}-cpp" - groupId artifactGroupId - version pubVersion - } - driver(MavenPublication) { - driverTaskList.each { - artifact it - } - artifact cppDriverHeadersZip - - artifactId = "${baseArtifactId}-driver" - groupId artifactGroupId - version pubVersion - } - - java(MavenPublication) { - artifact jar - artifact sourcesJar - artifact javadocJar - - artifactId = "${baseArtifactId}-java" - groupId artifactGroupId - version pubVersion - } - } - } -} +apply plugin: 'maven-publish' + +ext.licenseFile = files("$rootDir/LICENSE.txt") + +def pubVersion = '0.0.1' + +def outputsFolder = file("$buildDir/outputs") + +def versionFile = file("$outputsFolder/version.txt") + +task outputVersions() { + description = 'Prints the versions of wpilib to a file for use by the downstream packaging project' + group = 'Build' + outputs.files(versionFile) + + doFirst { + buildDir.mkdir() + outputsFolder.mkdir() + } + + doLast { + versionFile.write pubVersion + } +} + +task libraryBuild() {} + +build.dependsOn outputVersions + +task copyAllOutputs(type: Copy) { + destinationDir file("$buildDir/allOutputs") + from versionFile + dependsOn outputVersions +} + +build.dependsOn copyAllOutputs +copyAllOutputs.dependsOn outputVersions + +ext.addTaskToCopyAllOutputs = { task -> + copyAllOutputs.dependsOn task + copyAllOutputs.inputs.file task.archiveFile + copyAllOutputs.from task.archiveFile +} + +def artifactGroupId = 'com.vendor.frc' +def baseArtifactId = 'Vendor' +def driverZipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-driver_CLS" +def zipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-cpp_CLS" +def javaBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-java_CLS" + +task cppHeadersZip(type: Zip) { + destinationDirectory = outputsFolder + archiveBaseName = zipBaseName + archiveClassifier = "headers" + + from(licenseFile) { + into '/' + } + + from('src/main/native/include') { + into '/' + } +} + +task cppSourceZip(type: Zip) { + destinationDirectory = outputsFolder + archiveBaseName = zipBaseName + archiveClassifier = "sources" + + from(licenseFile) { + into '/' + } + + from('src/main/native/cpp') { + into '/' + } +} + +task cppDriverHeadersZip(type: Zip) { + destinationDirectory = outputsFolder + archiveBaseName = driverZipBaseName + archiveClassifier = "headers" + + from(licenseFile) { + into '/' + } + + from('src/main/driver/include') { + into '/' + } +} + +build.dependsOn cppHeadersZip +addTaskToCopyAllOutputs(cppHeadersZip) +build.dependsOn cppSourceZip +addTaskToCopyAllOutputs(cppSourceZip) +build.dependsOn cppDriverHeadersZip +addTaskToCopyAllOutputs(cppDriverHeadersZip) + +task sourcesJar(type: Jar, dependsOn: classes) { + archiveClassifier = 'sources' + from sourceSets.main.allSource +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + archiveClassifier = 'javadoc' + from javadoc.destinationDir +} + +task outputJar(type: Jar, dependsOn: classes) { + archiveBaseName = javaBaseName + destinationDirectory = outputsFolder + from sourceSets.main.output +} + +task outputSourcesJar(type: Jar, dependsOn: classes) { + archiveBaseName = javaBaseName + destinationDirectory = outputsFolder + archiveClassifier = 'sources' + from sourceSets.main.allSource +} + +task outputJavadocJar(type: Jar, dependsOn: javadoc) { + archiveBaseName = javaBaseName + destinationDirectory = outputsFolder + archiveClassifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives sourcesJar + archives javadocJar + archives outputJar + archives outputSourcesJar + archives outputJavadocJar +} + +addTaskToCopyAllOutputs(outputSourcesJar) +addTaskToCopyAllOutputs(outputJavadocJar) +addTaskToCopyAllOutputs(outputJar) + +build.dependsOn outputSourcesJar +build.dependsOn outputJavadocJar +build.dependsOn outputJar + +libraryBuild.dependsOn build + +def releasesRepoUrl = "$buildDir/repos/releases" + +publishing { + repositories { + maven { + + url = releasesRepoUrl + } + } +} + +task cleanReleaseRepo(type: Delete) { + delete releasesRepoUrl +} + +tasks.matching {it != cleanReleaseRepo}.all {it.dependsOn cleanReleaseRepo} + +model { + publishing { + def taskList = createComponentZipTasks($.components, ['Vendor'], zipBaseName, Zip, project, includeStandardZipFormat) + + def driverTaskList = createComponentZipTasks($.components, ['VendorDriver'], driverZipBaseName, Zip, project, includeStandardZipFormat) + + publications { + cpp(MavenPublication) { + taskList.each { + artifact it + } + artifact cppHeadersZip + artifact cppSourceZip + + artifactId = "${baseArtifactId}-cpp" + groupId artifactGroupId + version pubVersion + } + driver(MavenPublication) { + driverTaskList.each { + artifact it + } + artifact cppDriverHeadersZip + + artifactId = "${baseArtifactId}-driver" + groupId artifactGroupId + version pubVersion + } + + java(MavenPublication) { + artifact jar + artifact sourcesJar + artifact javadocJar + + artifactId = "${baseArtifactId}-java" + groupId artifactGroupId + version pubVersion + } + } + } +} diff --git a/src/main/driver/cpp/VendorJNI.cpp b/src/main/driver/cpp/VendorJNI.cpp index 0a3ce66..e38b850 100644 --- a/src/main/driver/cpp/VendorJNI.cpp +++ b/src/main/driver/cpp/VendorJNI.cpp @@ -1,22 +1,22 @@ -#include "jni.h" -#include "com_vendor_jni_VendorJNI.h" - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { - // Check to ensure the JNI version is valid - - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) - return JNI_ERR; - - // In here is also where you store things like class references - // if they are ever needed - - return JNI_VERSION_1_6; -} - -JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {} - -JNIEXPORT jint JNICALL Java_com_vendor_jni_VendorJNI_initialize - (JNIEnv *, jclass) { - return 0; -} +#include "jni.h" +#include "com_vendor_jni_VendorJNI.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { + // Check to ensure the JNI version is valid + + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) + return JNI_ERR; + + // In here is also where you store things like class references + // if they are ever needed + + return JNI_VERSION_1_6; +} + +JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {} + +JNIEXPORT jint JNICALL Java_com_vendor_jni_VendorJNI_initialize + (JNIEnv *, jclass) { + return 0; +} diff --git a/src/main/driver/cpp/driversource.cpp b/src/main/driver/cpp/driversource.cpp index 15716a4..ded85c2 100644 --- a/src/main/driver/cpp/driversource.cpp +++ b/src/main/driver/cpp/driversource.cpp @@ -1,7 +1,7 @@ -#include "driverheader.h" - -extern "C" { -void c_doThing() { - -} -} +#include "driverheader.h" + +extern "C" { +void c_doThing() { + +} +} diff --git a/src/main/driver/include/driverheader.h b/src/main/driver/include/driverheader.h index 5aeff00..1758c27 100644 --- a/src/main/driver/include/driverheader.h +++ b/src/main/driver/include/driverheader.h @@ -1,11 +1,11 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -void c_doThing(); - -#ifdef __cplusplus -} // extern "C" -#endif +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void c_doThing(); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/main/java/com/vendor/jni/VendorJNI.java b/src/main/java/com/vendor/jni/VendorJNI.java index 9ee6fe1..753288d 100644 --- a/src/main/java/com/vendor/jni/VendorJNI.java +++ b/src/main/java/com/vendor/jni/VendorJNI.java @@ -1,60 +1,60 @@ -package com.vendor.jni; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Demo class for loading the driver via JNI. - */ -public class VendorJNI { - static boolean libraryLoaded = false; - - /** - * Helper class for determining whether or not to load the driver on static initialization. - */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); - - /** - * Get whether to load the driver on static init. - * @return true if the driver will load on static init - */ - public static boolean getExtractOnStaticLoad() { - return extractOnStaticLoad.get(); - } - - /** - * Set whether to load the driver on static init. - * @param load the new value - */ - public static void setExtractOnStaticLoad(boolean load) { - extractOnStaticLoad.set(load); - } - } - - static { - if (Helper.getExtractOnStaticLoad()) { - System.loadLibrary("VendorDriver"); - libraryLoaded = true; - } - } - - /** - * Force load the library. - */ - public static synchronized void forceLoad() { - if (libraryLoaded) { - return; - } - System.loadLibrary("VendorDriver"); - libraryLoaded = true; - } - - /** - * Tells the driver to initialize. - * This is a demo of a native JNI method from the driver. - * - * @return the int returned by the driver - * @see "VendorJNI.cpp" - */ - public static native int initialize(); -} +package com.vendor.jni; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Demo class for loading the driver via JNI. + */ +public class VendorJNI { + static boolean libraryLoaded = false; + + /** + * Helper class for determining whether or not to load the driver on static initialization. + */ + public static class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + + /** + * Get whether to load the driver on static init. + * @return true if the driver will load on static init + */ + public static boolean getExtractOnStaticLoad() { + return extractOnStaticLoad.get(); + } + + /** + * Set whether to load the driver on static init. + * @param load the new value + */ + public static void setExtractOnStaticLoad(boolean load) { + extractOnStaticLoad.set(load); + } + } + + static { + if (Helper.getExtractOnStaticLoad()) { + System.loadLibrary("VendorDriver"); + libraryLoaded = true; + } + } + + /** + * Force load the library. + */ + public static synchronized void forceLoad() { + if (libraryLoaded) { + return; + } + System.loadLibrary("VendorDriver"); + libraryLoaded = true; + } + + /** + * Tells the driver to initialize. + * This is a demo of a native JNI method from the driver. + * + * @return the int returned by the driver + * @see "VendorJNI.cpp" + */ + public static native int initialize(); +} diff --git a/src/main/native/cpp/source.cpp b/src/main/native/cpp/source.cpp index 3990d40..378ac38 100644 --- a/src/main/native/cpp/source.cpp +++ b/src/main/native/cpp/source.cpp @@ -1,6 +1,6 @@ -#include "header.h" -#include "driverheader.h" - -void func() { - c_doThing(); -} +#include "header.h" +#include "driverheader.h" + +void func() { + c_doThing(); +} diff --git a/src/test/driver/cpp/main.cpp b/src/test/driver/cpp/main.cpp index d0e7d22..a62216b 100644 --- a/src/test/driver/cpp/main.cpp +++ b/src/test/driver/cpp/main.cpp @@ -1,6 +1,6 @@ -#include "gtest/gtest.h" - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +#include "gtest/gtest.h" + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/test/native/cpp/main.cpp b/src/test/native/cpp/main.cpp index d0e7d22..a62216b 100644 --- a/src/test/native/cpp/main.cpp +++ b/src/test/native/cpp/main.cpp @@ -1,6 +1,6 @@ -#include "gtest/gtest.h" - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} +#include "gtest/gtest.h" + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}