Fix Linux arm32 and arm64 cross builds (#36)

This commit is contained in:
Tyler Veness 2024-09-18 11:44:52 -07:00 committed by GitHub
parent e06eda365a
commit 287b9d939e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 736 additions and 734 deletions

View File

@ -11,12 +11,12 @@ jobs:
- container: wpilib/roborio-cross-ubuntu:2024-22.04 - container: wpilib/roborio-cross-ubuntu:2024-22.04
artifact-name: Athena artifact-name: Athena
build-options: "-Ponlylinuxathena" build-options: "-Ponlylinuxathena"
# - container: wpilib/raspbian-cross-ubuntu:bullseye-22.04 - container: wpilib/raspbian-cross-ubuntu:bullseye-22.04
# artifact-name: Arm32 artifact-name: Arm32
# build-options: "-Ponlylinuxarm32" build-options: "-Ponlylinuxarm32"
# - container: wpilib/aarch64-cross-ubuntu:bullseye-22.04 - container: wpilib/aarch64-cross-ubuntu:bullseye-22.04
# artifact-name: Arm64 artifact-name: Arm64
# build-options: "-Ponlylinuxarm64" build-options: "-Ponlylinuxarm64"
- container: wpilib/ubuntu-base:22.04 - container: wpilib/ubuntu-base:22.04
artifact-name: Linux artifact-name: Linux
build-options: "" build-options: ""

View File

@ -1,74 +1,74 @@
{ {
"fileName": "ExampleVendorJson.json", "fileName": "ExampleVendorJson.json",
"name": "ExampleVendorDep", "name": "ExampleVendorDep",
"version": "0.0.1", "version": "0.0.1",
"frcYear": "2024", "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 "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": [ "mavenUrls": [
"ThisNeedsToBeTheRootMavenUrl" "ThisNeedsToBeTheRootMavenUrl"
], ],
"jsonUrl": "InsertSomeUrlHere", "jsonUrl": "InsertSomeUrlHere",
"javaDependencies": [ "javaDependencies": [
{ {
"groupId": "com.vendor.frc", "groupId": "com.vendor.frc",
"artifactId": "Vendor-java", "artifactId": "Vendor-java",
"version": "0.0.1" "version": "0.0.1"
} }
], ],
"jniDependencies": [ "jniDependencies": [
{ {
"groupId": "com.vendor.frc", "groupId": "com.vendor.frc",
"artifactId": "Vendor-driver", "artifactId": "Vendor-driver",
"version": "0.0.1", "version": "0.0.1",
"skipInvalidPlatforms": true, "skipInvalidPlatforms": true,
"isJar": false, "isJar": false,
"validPlatforms": [ "validPlatforms": [
"windowsx86-64", "windowsx86-64",
"windowsx86", "windowsx86",
"linuxarm64", "linuxarm64",
"linuxx86-64", "linuxx86-64",
"linuxathena", "linuxathena",
"linuxarm32", "linuxarm32",
"osxuniversal" "osxuniversal"
] ]
} }
], ],
"cppDependencies": [ "cppDependencies": [
{ {
"groupId": "com.vendor.frc", "groupId": "com.vendor.frc",
"artifactId": "Vendor-cpp", "artifactId": "Vendor-cpp",
"version": "0.0.1", "version": "0.0.1",
"libName": "Vendor", "libName": "Vendor",
"headerClassifier": "headers", "headerClassifier": "headers",
"sharedLibrary": false, "sharedLibrary": false,
"skipInvalidPlatforms": true, "skipInvalidPlatforms": true,
"binaryPlatforms": [ "binaryPlatforms": [
"windowsx86-64", "windowsx86-64",
"windowsx86", "windowsx86",
"linuxarm64", "linuxarm64",
"linuxx86-64", "linuxx86-64",
"linuxathena", "linuxathena",
"linuxarm32", "linuxarm32",
"osxuniversal" "osxuniversal"
] ]
}, },
{ {
"groupId": "com.vendor.frc", "groupId": "com.vendor.frc",
"artifactId": "Vendor-driver", "artifactId": "Vendor-driver",
"version": "0.0.1", "version": "0.0.1",
"libName": "VendorDriver", "libName": "VendorDriver",
"headerClassifier": "headers", "headerClassifier": "headers",
"sharedLibrary": false, "sharedLibrary": false,
"skipInvalidPlatforms": true, "skipInvalidPlatforms": true,
"binaryPlatforms": [ "binaryPlatforms": [
"windowsx86-64", "windowsx86-64",
"windowsx86", "windowsx86",
"linuxarm64", "linuxarm64",
"linuxx86-64", "linuxx86-64",
"linuxathena", "linuxathena",
"linuxarm32", "linuxarm32",
"osxuniversal" "osxuniversal"
] ]
} }
] ]
} }

View File

@ -1,25 +1,25 @@
# WPILib Vendor Template # WPILib Vendor Template
This is the base WPILib vendor template for 2023. This is the base WPILib vendor template for 2023.
## Layout ## 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. 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 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. 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 ## 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 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 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 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. For the maven artifact names, those are all in publish.gradle about 40 lines down.
## Building and editing ## 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. 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`. By default, this template builds against the latest WPILib development build. To build against the last WPILib tagged release, build with `./gradlew build -PreleaseMode`.

View File

@ -1,130 +1,130 @@
plugins { plugins {
id 'cpp' id 'cpp'
id 'java' id 'java'
id 'google-test' id 'google-test'
id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2' id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2'
id 'edu.wpi.first.NativeUtils' version '2024.7.2' id 'edu.wpi.first.NativeUtils' version '2024.7.2'
id 'edu.wpi.first.GradleJni' version '1.1.0' id 'edu.wpi.first.GradleJni' version '1.1.0'
id 'edu.wpi.first.GradleVsCode' version '2.1.0' id 'edu.wpi.first.GradleVsCode' version '2.1.0'
} }
repositories { repositories {
mavenCentral() mavenCentral()
} }
if (project.hasProperty('releaseMode')) { if (project.hasProperty('releaseMode')) {
wpilibRepositories.addAllReleaseRepositories(project) wpilibRepositories.addAllReleaseRepositories(project)
} else { } else {
wpilibRepositories.addAllDevelopmentRepositories(project) wpilibRepositories.addAllDevelopmentRepositories(project)
} }
// Apply C++ configuration // Apply C++ configuration
apply from: 'config.gradle' apply from: 'config.gradle'
// Apply Java configuration // Apply Java configuration
dependencies { dependencies {
implementation 'edu.wpi.first.cscore:cscore-java:2024.+' implementation 'edu.wpi.first.cscore:cscore-java:2024.+'
implementation 'edu.wpi.first.cameraserver:cameraserver-java:2024.+' implementation 'edu.wpi.first.cameraserver:cameraserver-java:2024.+'
implementation 'edu.wpi.first.ntcore:ntcore-java:2024.+' implementation 'edu.wpi.first.ntcore:ntcore-java:2024.+'
implementation 'edu.wpi.first.wpilibj:wpilibj-java:2024.+' implementation 'edu.wpi.first.wpilibj:wpilibj-java:2024.+'
implementation 'edu.wpi.first.wpiutil:wpiutil-java:2024.+' implementation 'edu.wpi.first.wpiutil:wpiutil-java:2024.+'
implementation 'edu.wpi.first.wpimath:wpimath-java:2024.+' implementation 'edu.wpi.first.wpimath:wpimath-java:2024.+'
implementation 'edu.wpi.first.wpiunits:wpiunits-java:2024.+' implementation 'edu.wpi.first.wpiunits:wpiunits-java:2024.+'
implementation 'edu.wpi.first.hal:hal-java:2024.+' implementation 'edu.wpi.first.hal:hal-java:2024.+'
implementation "org.ejml:ejml-simple:0.43.1" implementation "org.ejml:ejml-simple:0.43.1"
implementation "com.fasterxml.jackson.core:jackson-annotations:2.15.2" 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-core:2.15.2"
implementation "com.fasterxml.jackson.core:jackson-databind: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' implementation 'edu.wpi.first.thirdparty.frc2024.opencv:opencv-java:4.8.0-2'
} }
// Set up exports properly // Set up exports properly
nativeUtils { nativeUtils {
exportsConfigs { exportsConfigs {
// Main library is just default empty. This will export everything // Main library is just default empty. This will export everything
Vendor { Vendor {
} }
} }
privateExportsConfigs { privateExportsConfigs {
// Only export explicit symbols from driver library // Only export explicit symbols from driver library
VendorDriver { VendorDriver {
exportsFile = project.file("src/main/driver/symbols.txt") exportsFile = project.file("src/main/driver/symbols.txt")
} }
} }
} }
model { model {
components { components {
Vendor(NativeLibrarySpec) { Vendor(NativeLibrarySpec) {
sources { sources {
cpp { cpp {
source { source {
srcDirs 'src/main/native/cpp' srcDirs 'src/main/native/cpp'
include '**/*.cpp' include '**/*.cpp'
} }
exportedHeaders { exportedHeaders {
srcDirs 'src/main/native/include' srcDirs 'src/main/native/include'
} }
} }
} }
binaries.all { binaries.all {
lib library: 'VendorDriver', linkage: 'shared' lib library: 'VendorDriver', linkage: 'shared'
} }
nativeUtils.useRequiredLibrary(it, 'wpilib_shared') nativeUtils.useRequiredLibrary(it, 'wpilib_shared')
} }
VendorDriver(JniNativeLibrarySpec) { VendorDriver(JniNativeLibrarySpec) {
enableCheckTask true enableCheckTask true
javaCompileTasks << compileJava javaCompileTasks << compileJava
jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio) jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio)
// Leave these for future proofing // Leave these for future proofing
jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32) jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm32)
jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm64) jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.linuxarm64)
sources { sources {
cpp { cpp {
source { source {
srcDirs 'src/main/driver/cpp' srcDirs 'src/main/driver/cpp'
include '**/*.cpp' include '**/*.cpp'
} }
exportedHeaders { exportedHeaders {
srcDirs 'src/main/driver/include' srcDirs 'src/main/driver/include'
} }
} }
} }
nativeUtils.useRequiredLibrary(it, "driver_shared") nativeUtils.useRequiredLibrary(it, "driver_shared")
} }
} }
testSuites { testSuites {
VendorTest { VendorTest {
sources.cpp { sources.cpp {
source { source {
srcDir 'src/test/native/cpp' srcDir 'src/test/native/cpp'
include '**/*.cpp' include '**/*.cpp'
} }
} }
binaries.all { binaries.all {
lib library: 'VendorDriver', linkage: 'shared' lib library: 'VendorDriver', linkage: 'shared'
} }
nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static") nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static")
} }
VendorDriverTest { VendorDriverTest {
sources.cpp { sources.cpp {
source { source {
srcDir 'src/test/driver/cpp' srcDir 'src/test/driver/cpp'
include '**/*.cpp' include '**/*.cpp'
} }
} }
nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static") nativeUtils.useRequiredLibrary(it, "wpilib_executable_shared", "googletest_static")
} }
} }
} }
apply from: 'publish.gradle' apply from: 'publish.gradle'
wrapper { wrapper {
gradleVersion '8.5' gradleVersion '8.5'
} }

View File

@ -1,177 +1,179 @@
import org.gradle.internal.os.OperatingSystem import org.gradle.internal.os.OperatingSystem
nativeUtils.addWpiNativeUtils() nativeUtils.addWpiNativeUtils()
nativeUtils.withCrossRoboRIO() nativeUtils.withCrossRoboRIO()
nativeUtils.withCrossLinuxArm32()
nativeUtils { nativeUtils.withCrossLinuxArm64()
wpi {
configureDependencies { nativeUtils {
wpiVersion = "2024.+" wpi {
opencvYear = "frc2024" configureDependencies {
googleTestYear = "frc2024" wpiVersion = "2024.+"
niLibVersion = "2024.2.1" opencvYear = "frc2024"
opencvVersion = "4.8.0-2" googleTestYear = "frc2024"
googleTestVersion = "1.14.0-1" niLibVersion = "2024.2.1"
} opencvVersion = "4.8.0-2"
} googleTestVersion = "1.14.0-1"
} }
}
nativeUtils.wpi.addWarnings() }
nativeUtils.wpi.addWarningsAsErrors()
nativeUtils.wpi.addWarnings()
nativeUtils.setSinglePrintPerPlatform() nativeUtils.wpi.addWarningsAsErrors()
model { nativeUtils.setSinglePrintPerPlatform()
// Uncomment this, and remove lines below it to enable builds for just roborio
// components { model {
// all { // Uncomment this, and remove lines below it to enable builds for just roborio
// targetPlatform nativeUtils.wpi.platforms.roborio // components {
// } // all {
// } // targetPlatform nativeUtils.wpi.platforms.roborio
components { // }
all { // }
nativeUtils.useAllPlatforms(it) components {
} all {
} nativeUtils.useAllPlatforms(it)
binaries { }
withType(NativeBinarySpec).all { }
nativeUtils.usePlatformArguments(it) binaries {
} withType(NativeBinarySpec).all {
} nativeUtils.usePlatformArguments(it)
} }
}
ext.appendDebugPathToBinaries = { binaries-> }
binaries.withType(StaticLibraryBinarySpec) {
if (it.buildType.name.contains('debug')) { ext.appendDebugPathToBinaries = { binaries->
def staticFileDir = it.staticLibraryFile.parentFile binaries.withType(StaticLibraryBinarySpec) {
def staticFileName = it.staticLibraryFile.name if (it.buildType.name.contains('debug')) {
def staticFileExtension = staticFileName.substring(staticFileName.lastIndexOf('.')) def staticFileDir = it.staticLibraryFile.parentFile
staticFileName = staticFileName.substring(0, staticFileName.lastIndexOf('.')) def staticFileName = it.staticLibraryFile.name
staticFileName = staticFileName + 'd' + staticFileExtension def staticFileExtension = staticFileName.substring(staticFileName.lastIndexOf('.'))
def newStaticFile = new File(staticFileDir, staticFileName) staticFileName = staticFileName.substring(0, staticFileName.lastIndexOf('.'))
it.staticLibraryFile = newStaticFile 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 binaries.withType(SharedLibraryBinarySpec) {
def sharedFileName = it.sharedLibraryFile.name if (it.buildType.name.contains('debug')) {
def sharedFileExtension = sharedFileName.substring(sharedFileName.lastIndexOf('.')) def sharedFileDir = it.sharedLibraryFile.parentFile
sharedFileName = sharedFileName.substring(0, sharedFileName.lastIndexOf('.')) def sharedFileName = it.sharedLibraryFile.name
sharedFileName = sharedFileName + 'd' + sharedFileExtension def sharedFileExtension = sharedFileName.substring(sharedFileName.lastIndexOf('.'))
def newSharedFile = new File(sharedFileDir, sharedFileName) sharedFileName = sharedFileName.substring(0, sharedFileName.lastIndexOf('.'))
sharedFileName = sharedFileName + 'd' + sharedFileExtension
def sharedLinkFileDir = it.sharedLibraryLinkFile.parentFile def newSharedFile = new File(sharedFileDir, sharedFileName)
def sharedLinkFileName = it.sharedLibraryLinkFile.name
def sharedLinkFileExtension = sharedLinkFileName.substring(sharedLinkFileName.lastIndexOf('.')) def sharedLinkFileDir = it.sharedLibraryLinkFile.parentFile
sharedLinkFileName = sharedLinkFileName.substring(0, sharedLinkFileName.lastIndexOf('.')) def sharedLinkFileName = it.sharedLibraryLinkFile.name
sharedLinkFileName = sharedLinkFileName + 'd' + sharedLinkFileExtension def sharedLinkFileExtension = sharedLinkFileName.substring(sharedLinkFileName.lastIndexOf('.'))
def newLinkFile = new File(sharedLinkFileDir, sharedLinkFileName) sharedLinkFileName = sharedLinkFileName.substring(0, sharedLinkFileName.lastIndexOf('.'))
sharedLinkFileName = sharedLinkFileName + 'd' + sharedLinkFileExtension
it.sharedLibraryLinkFile = newLinkFile def newLinkFile = new File(sharedLinkFileDir, sharedLinkFileName)
it.sharedLibraryFile = newSharedFile
} it.sharedLibraryLinkFile = newLinkFile
} it.sharedLibraryFile = newSharedFile
} }
}
ext.createComponentZipTasks = { components, names, base, type, project, func -> }
def stringNames = names.collect {it.toString()}
def configMap = [:] ext.createComponentZipTasks = { components, names, base, type, project, func ->
components.each { def stringNames = names.collect {it.toString()}
if (it in NativeLibrarySpec && stringNames.contains(it.name)) { def configMap = [:]
it.binaries.each { components.each {
if (!it.buildable) return if (it in NativeLibrarySpec && stringNames.contains(it.name)) {
def target = nativeUtils.getPublishClassifier(it) it.binaries.each {
if (configMap.containsKey(target)) { if (!it.buildable) return
configMap.get(target).add(it) def target = nativeUtils.getPublishClassifier(it)
} else { if (configMap.containsKey(target)) {
configMap.put(target, []) configMap.get(target).add(it)
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 taskList = []
def task = project.tasks.create(base + "-${key}", type) { def outputsFolder = file("$project.buildDir/outputs")
description = 'Creates component archive for platform ' + key configMap.each { key, value ->
destinationDirectory = outputsFolder def task = project.tasks.create(base + "-${key}", type) {
archiveClassifier = key description = 'Creates component archive for platform ' + key
archiveBaseName = '_M_' + base destinationDirectory = outputsFolder
duplicatesStrategy = 'exclude' archiveClassifier = key
archiveBaseName = '_M_' + base
from(licenseFile) { duplicatesStrategy = 'exclude'
into '/'
} from(licenseFile) {
into '/'
func(it, value) }
}
taskList.add(task) func(it, value)
}
project.build.dependsOn task taskList.add(task)
project.artifacts { project.build.dependsOn task
task
} project.artifacts {
addTaskToCopyAllOutputs(task) task
} }
return taskList addTaskToCopyAllOutputs(task)
} }
return taskList
ext.createAllCombined = { list, name, base, type, project -> }
def outputsFolder = file("$project.buildDir/outputs")
ext.createAllCombined = { list, name, base, type, project ->
def task = project.tasks.create(base + "-all", type) { def outputsFolder = file("$project.buildDir/outputs")
description = "Creates component archive for all classifiers"
destinationDirectory = outputsFolder def task = project.tasks.create(base + "-all", type) {
classifier = "all" description = "Creates component archive for all classifiers"
archiveBaseName = base destinationDirectory = outputsFolder
duplicatesStrategy = 'exclude' classifier = "all"
archiveBaseName = base
list.each { duplicatesStrategy = 'exclude'
if (it.name.endsWith('debug')) return
from project.zipTree(it.archiveFile) list.each {
dependsOn it if (it.name.endsWith('debug')) return
} from project.zipTree(it.archiveFile)
} dependsOn it
}
project.build.dependsOn task }
project.artifacts { project.build.dependsOn task
task
} project.artifacts {
task
return task }
} return task
ext.includeStandardZipFormat = { task, value -> }
value.each { binary ->
if (binary.buildable) { ext.includeStandardZipFormat = { task, value ->
if (binary instanceof SharedLibraryBinarySpec) { value.each { binary ->
task.dependsOn binary.tasks.link if (binary.buildable) {
task.from(new File(binary.sharedLibraryFile.absolutePath + ".debug")) { if (binary instanceof SharedLibraryBinarySpec) {
into nativeUtils.getPlatformPath(binary) + '/shared' task.dependsOn binary.tasks.link
} task.from(new File(binary.sharedLibraryFile.absolutePath + ".debug")) {
def sharedPath = binary.sharedLibraryFile.absolutePath into nativeUtils.getPlatformPath(binary) + '/shared'
sharedPath = sharedPath.substring(0, sharedPath.length() - 4) }
def sharedPath = binary.sharedLibraryFile.absolutePath
task.from(new File(sharedPath + '.pdb')) { sharedPath = sharedPath.substring(0, sharedPath.length() - 4)
into nativeUtils.getPlatformPath(binary) + '/shared'
} task.from(new File(sharedPath + '.pdb')) {
task.from(binary.sharedLibraryFile) { into nativeUtils.getPlatformPath(binary) + '/shared'
into nativeUtils.getPlatformPath(binary) + '/shared' }
} task.from(binary.sharedLibraryFile) {
task.from(binary.sharedLibraryLinkFile) { into nativeUtils.getPlatformPath(binary) + '/shared'
into nativeUtils.getPlatformPath(binary) + '/shared' }
} task.from(binary.sharedLibraryLinkFile) {
} else if (binary instanceof StaticLibraryBinarySpec) { into nativeUtils.getPlatformPath(binary) + '/shared'
task.dependsOn binary.tasks.createStaticLib }
task.from(binary.staticLibraryFile) { } else if (binary instanceof StaticLibraryBinarySpec) {
into nativeUtils.getPlatformPath(binary) + '/static' task.dependsOn binary.tasks.createStaticLib
} task.from(binary.staticLibraryFile) {
} into nativeUtils.getPlatformPath(binary) + '/static'
} }
} }
} }
}
}

View File

@ -1,205 +1,205 @@
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
ext.licenseFile = files("$rootDir/LICENSE.txt") ext.licenseFile = files("$rootDir/LICENSE.txt")
def pubVersion = '0.0.1' def pubVersion = '0.0.1'
def outputsFolder = file("$buildDir/outputs") def outputsFolder = file("$buildDir/outputs")
def versionFile = file("$outputsFolder/version.txt") def versionFile = file("$outputsFolder/version.txt")
task outputVersions() { task outputVersions() {
description = 'Prints the versions of wpilib to a file for use by the downstream packaging project' description = 'Prints the versions of wpilib to a file for use by the downstream packaging project'
group = 'Build' group = 'Build'
outputs.files(versionFile) outputs.files(versionFile)
doFirst { doFirst {
buildDir.mkdir() buildDir.mkdir()
outputsFolder.mkdir() outputsFolder.mkdir()
} }
doLast { doLast {
versionFile.write pubVersion versionFile.write pubVersion
} }
} }
task libraryBuild() {} task libraryBuild() {}
build.dependsOn outputVersions build.dependsOn outputVersions
task copyAllOutputs(type: Copy) { task copyAllOutputs(type: Copy) {
destinationDir file("$buildDir/allOutputs") destinationDir file("$buildDir/allOutputs")
from versionFile from versionFile
dependsOn outputVersions dependsOn outputVersions
} }
build.dependsOn copyAllOutputs build.dependsOn copyAllOutputs
copyAllOutputs.dependsOn outputVersions copyAllOutputs.dependsOn outputVersions
ext.addTaskToCopyAllOutputs = { task -> ext.addTaskToCopyAllOutputs = { task ->
copyAllOutputs.dependsOn task copyAllOutputs.dependsOn task
copyAllOutputs.inputs.file task.archiveFile copyAllOutputs.inputs.file task.archiveFile
copyAllOutputs.from task.archiveFile copyAllOutputs.from task.archiveFile
} }
def artifactGroupId = 'com.vendor.frc' def artifactGroupId = 'com.vendor.frc'
def baseArtifactId = 'Vendor' def baseArtifactId = 'Vendor'
def driverZipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-driver_CLS" def driverZipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-driver_CLS"
def zipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-cpp_CLS" def zipBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-cpp_CLS"
def javaBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-java_CLS" def javaBaseName = "_GROUP_com_vendor_frc_ID_${baseArtifactId}-java_CLS"
task cppHeadersZip(type: Zip) { task cppHeadersZip(type: Zip) {
destinationDirectory = outputsFolder destinationDirectory = outputsFolder
archiveBaseName = zipBaseName archiveBaseName = zipBaseName
archiveClassifier = "headers" archiveClassifier = "headers"
from(licenseFile) { from(licenseFile) {
into '/' into '/'
} }
from('src/main/native/include') { from('src/main/native/include') {
into '/' into '/'
} }
} }
task cppSourceZip(type: Zip) { task cppSourceZip(type: Zip) {
destinationDirectory = outputsFolder destinationDirectory = outputsFolder
archiveBaseName = zipBaseName archiveBaseName = zipBaseName
archiveClassifier = "sources" archiveClassifier = "sources"
from(licenseFile) { from(licenseFile) {
into '/' into '/'
} }
from('src/main/native/cpp') { from('src/main/native/cpp') {
into '/' into '/'
} }
} }
task cppDriverHeadersZip(type: Zip) { task cppDriverHeadersZip(type: Zip) {
destinationDirectory = outputsFolder destinationDirectory = outputsFolder
archiveBaseName = driverZipBaseName archiveBaseName = driverZipBaseName
archiveClassifier = "headers" archiveClassifier = "headers"
from(licenseFile) { from(licenseFile) {
into '/' into '/'
} }
from('src/main/driver/include') { from('src/main/driver/include') {
into '/' into '/'
} }
} }
build.dependsOn cppHeadersZip build.dependsOn cppHeadersZip
addTaskToCopyAllOutputs(cppHeadersZip) addTaskToCopyAllOutputs(cppHeadersZip)
build.dependsOn cppSourceZip build.dependsOn cppSourceZip
addTaskToCopyAllOutputs(cppSourceZip) addTaskToCopyAllOutputs(cppSourceZip)
build.dependsOn cppDriverHeadersZip build.dependsOn cppDriverHeadersZip
addTaskToCopyAllOutputs(cppDriverHeadersZip) addTaskToCopyAllOutputs(cppDriverHeadersZip)
task sourcesJar(type: Jar, dependsOn: classes) { task sourcesJar(type: Jar, dependsOn: classes) {
archiveClassifier = 'sources' archiveClassifier = 'sources'
from sourceSets.main.allSource from sourceSets.main.allSource
} }
task javadocJar(type: Jar, dependsOn: javadoc) { task javadocJar(type: Jar, dependsOn: javadoc) {
archiveClassifier = 'javadoc' archiveClassifier = 'javadoc'
from javadoc.destinationDir from javadoc.destinationDir
} }
task outputJar(type: Jar, dependsOn: classes) { task outputJar(type: Jar, dependsOn: classes) {
archiveBaseName = javaBaseName archiveBaseName = javaBaseName
destinationDirectory = outputsFolder destinationDirectory = outputsFolder
from sourceSets.main.output from sourceSets.main.output
} }
task outputSourcesJar(type: Jar, dependsOn: classes) { task outputSourcesJar(type: Jar, dependsOn: classes) {
archiveBaseName = javaBaseName archiveBaseName = javaBaseName
destinationDirectory = outputsFolder destinationDirectory = outputsFolder
archiveClassifier = 'sources' archiveClassifier = 'sources'
from sourceSets.main.allSource from sourceSets.main.allSource
} }
task outputJavadocJar(type: Jar, dependsOn: javadoc) { task outputJavadocJar(type: Jar, dependsOn: javadoc) {
archiveBaseName = javaBaseName archiveBaseName = javaBaseName
destinationDirectory = outputsFolder destinationDirectory = outputsFolder
archiveClassifier = 'javadoc' archiveClassifier = 'javadoc'
from javadoc.destinationDir from javadoc.destinationDir
} }
artifacts { artifacts {
archives sourcesJar archives sourcesJar
archives javadocJar archives javadocJar
archives outputJar archives outputJar
archives outputSourcesJar archives outputSourcesJar
archives outputJavadocJar archives outputJavadocJar
} }
addTaskToCopyAllOutputs(outputSourcesJar) addTaskToCopyAllOutputs(outputSourcesJar)
addTaskToCopyAllOutputs(outputJavadocJar) addTaskToCopyAllOutputs(outputJavadocJar)
addTaskToCopyAllOutputs(outputJar) addTaskToCopyAllOutputs(outputJar)
build.dependsOn outputSourcesJar build.dependsOn outputSourcesJar
build.dependsOn outputJavadocJar build.dependsOn outputJavadocJar
build.dependsOn outputJar build.dependsOn outputJar
libraryBuild.dependsOn build libraryBuild.dependsOn build
def releasesRepoUrl = "$buildDir/repos/releases" def releasesRepoUrl = "$buildDir/repos/releases"
publishing { publishing {
repositories { repositories {
maven { maven {
url = releasesRepoUrl url = releasesRepoUrl
} }
} }
} }
task cleanReleaseRepo(type: Delete) { task cleanReleaseRepo(type: Delete) {
delete releasesRepoUrl delete releasesRepoUrl
} }
tasks.matching {it != cleanReleaseRepo}.all {it.dependsOn cleanReleaseRepo} tasks.matching {it != cleanReleaseRepo}.all {it.dependsOn cleanReleaseRepo}
model { model {
publishing { publishing {
def taskList = createComponentZipTasks($.components, ['Vendor'], zipBaseName, Zip, project, includeStandardZipFormat) def taskList = createComponentZipTasks($.components, ['Vendor'], zipBaseName, Zip, project, includeStandardZipFormat)
def driverTaskList = createComponentZipTasks($.components, ['VendorDriver'], driverZipBaseName, Zip, project, includeStandardZipFormat) def driverTaskList = createComponentZipTasks($.components, ['VendorDriver'], driverZipBaseName, Zip, project, includeStandardZipFormat)
publications { publications {
cpp(MavenPublication) { cpp(MavenPublication) {
taskList.each { taskList.each {
artifact it artifact it
} }
artifact cppHeadersZip artifact cppHeadersZip
artifact cppSourceZip artifact cppSourceZip
artifactId = "${baseArtifactId}-cpp" artifactId = "${baseArtifactId}-cpp"
groupId artifactGroupId groupId artifactGroupId
version pubVersion version pubVersion
} }
driver(MavenPublication) { driver(MavenPublication) {
driverTaskList.each { driverTaskList.each {
artifact it artifact it
} }
artifact cppDriverHeadersZip artifact cppDriverHeadersZip
artifactId = "${baseArtifactId}-driver" artifactId = "${baseArtifactId}-driver"
groupId artifactGroupId groupId artifactGroupId
version pubVersion version pubVersion
} }
java(MavenPublication) { java(MavenPublication) {
artifact jar artifact jar
artifact sourcesJar artifact sourcesJar
artifact javadocJar artifact javadocJar
artifactId = "${baseArtifactId}-java" artifactId = "${baseArtifactId}-java"
groupId artifactGroupId groupId artifactGroupId
version pubVersion version pubVersion
} }
} }
} }
} }

View File

@ -1,22 +1,22 @@
#include "jni.h" #include "jni.h"
#include "com_vendor_jni_VendorJNI.h" #include "com_vendor_jni_VendorJNI.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
// Check to ensure the JNI version is valid // Check to ensure the JNI version is valid
JNIEnv* env; JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
return JNI_ERR; return JNI_ERR;
// In here is also where you store things like class references // In here is also where you store things like class references
// if they are ever needed // if they are ever needed
return JNI_VERSION_1_6; return JNI_VERSION_1_6;
} }
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {} JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {}
JNIEXPORT jint JNICALL Java_com_vendor_jni_VendorJNI_initialize JNIEXPORT jint JNICALL Java_com_vendor_jni_VendorJNI_initialize
(JNIEnv *, jclass) { (JNIEnv *, jclass) {
return 0; return 0;
} }

View File

@ -1,7 +1,7 @@
#include "driverheader.h" #include "driverheader.h"
extern "C" { extern "C" {
void c_doThing() { void c_doThing() {
} }
} }

View File

@ -1,11 +1,11 @@
#pragma once #pragma once
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
void c_doThing(); void c_doThing();
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -1,60 +1,60 @@
package com.vendor.jni; package com.vendor.jni;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* Demo class for loading the driver via JNI. * Demo class for loading the driver via JNI.
*/ */
public class VendorJNI { public class VendorJNI {
static boolean libraryLoaded = false; static boolean libraryLoaded = false;
/** /**
* Helper class for determining whether or not to load the driver on static initialization. * Helper class for determining whether or not to load the driver on static initialization.
*/ */
public static class Helper { public static class Helper {
private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
/** /**
* Get whether to load the driver on static init. * Get whether to load the driver on static init.
* @return true if the driver will load on static init * @return true if the driver will load on static init
*/ */
public static boolean getExtractOnStaticLoad() { public static boolean getExtractOnStaticLoad() {
return extractOnStaticLoad.get(); return extractOnStaticLoad.get();
} }
/** /**
* Set whether to load the driver on static init. * Set whether to load the driver on static init.
* @param load the new value * @param load the new value
*/ */
public static void setExtractOnStaticLoad(boolean load) { public static void setExtractOnStaticLoad(boolean load) {
extractOnStaticLoad.set(load); extractOnStaticLoad.set(load);
} }
} }
static { static {
if (Helper.getExtractOnStaticLoad()) { if (Helper.getExtractOnStaticLoad()) {
System.loadLibrary("VendorDriver"); System.loadLibrary("VendorDriver");
libraryLoaded = true; libraryLoaded = true;
} }
} }
/** /**
* Force load the library. * Force load the library.
*/ */
public static synchronized void forceLoad() { public static synchronized void forceLoad() {
if (libraryLoaded) { if (libraryLoaded) {
return; return;
} }
System.loadLibrary("VendorDriver"); System.loadLibrary("VendorDriver");
libraryLoaded = true; libraryLoaded = true;
} }
/** /**
* Tells the driver to initialize. * Tells the driver to initialize.
* This is a demo of a native JNI method from the driver. * This is a demo of a native JNI method from the driver.
* *
* @return the int returned by the driver * @return the int returned by the driver
* @see "VendorJNI.cpp" * @see "VendorJNI.cpp"
*/ */
public static native int initialize(); public static native int initialize();
} }

View File

@ -1,6 +1,6 @@
#include "header.h" #include "header.h"
#include "driverheader.h" #include "driverheader.h"
void func() { void func() {
c_doThing(); c_doThing();
} }

View File

@ -1,6 +1,6 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
int main(int argc, char** argv) { int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

View File

@ -1,6 +1,6 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
int main(int argc, char** argv) { int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }