Skip to content

Commit

Permalink
Monorepo GradleJni
Browse files Browse the repository at this point in the history
  • Loading branch information
spacey-sooty committed Jul 26, 2024
1 parent 51ac01e commit a5a305f
Show file tree
Hide file tree
Showing 47 changed files with 5,453 additions and 26 deletions.
49 changes: 37 additions & 12 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,46 @@ jobs:
run: ./gradlew publishToMavenLocal
- name: Check output
run: git --no-pager diff --exit-code HEAD
- name: InstallRioTC
run: ./gradlew installRoboRioToolchain
working-directory: testing/cpp
- name: InstallArm32Tc
run: ./gradlew installArm32Toolchain
working-directory: testing/cpp
- name: InstallArm64Tc
run: ./gradlew installArm64Toolchain
working-directory: testing/cpp
- name: Build Test

test_examples:
needs: build
strategy:
matrix:
include:
- os: windows-latest
language: cpp
- os: windows-latest
language: jni
- os: ubuntu-latest
language: cpp
- os: ubuntu-latest
language: jni
- os: macos-latest
language: cpp
- os: macos-latest
language: jni
runs-on: {{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
- uses: actions/download-artifact@v4
with:
name: Maven
path: ~/.m2/
- name: Setup Toolchains
run: |
./gradlew installRoboRioToolchain
./gradlew installArm32Toolchain
./gradlew installArm64Toolchain
- name: Test ${{ matrix.language }} Build
run: ./gradlew build
working-directory: testing/cpp
working-directory: testing/${{ matrix.language }}

publish:
needs: build
needs: [build, test-examples]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
32 changes: 32 additions & 0 deletions GradleJni/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Gradle JNI

[![CI](https://github.com/wpilibsuite/gradle-jni/actions/workflows/main.yml/badge.svg)](https://github.com/wpilibsuite/gradle-jni/actions/workflows/main.yml)

gradle-jni is a utility library for enabling easy to build JNI compatible plugins

```gradle
plugins {
id 'edu.wpi.first.GradleJni' version '0.1.6'
}
model {
components {
library(JniNativeLibrarySpec) { // Use JniNativeLibrarySpec to get a JNI library
enableCheckTask true // Set to true to enable a JNI check task. This will search all generated JNI headers, and check to ensure their symbols exist in the native library
javaCompileTasks << compileJava // set javaCompileTasks to any java compile tasks that contain your JNI classes. It is a list of tasks
jniCrossCompileOptions << JniCrossCompileOptions('athena')
// See below for more JniCrossCompileOptions
}
}
}
```

Below are the options for JniCrossCompileOptions
```
JNICrossCompileOptions('toolChainName') // Use this to match the cross compile options to a specific tool chain name
JNICrossCompileOptions('operatingSystem', 'architecture') // Use this to match the cross compile options to a specific tool chain arch and os.
// For both of these options, they take an optional last parameter of List<String> of directories
If this parameter is added, the directories passed in will be used for the include paths for the JNI headers.
If this parameter is not passed in, for any matching toolchain, a set of headers included in the plugin will be used. These headers are standard for 32 bit embedded arm toolchains.
```
19 changes: 19 additions & 0 deletions GradleJni/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
plugins {
id 'java-gradle-plugin'
id 'maven-publish'
id 'com.gradle.plugin-publish'
}

gradlePlugin {
website = 'https://github.com/wpilibsuite/gradle-jni'
vcsUrl = 'https://github.com/wpilibsuite/gradle-jni'
plugins {
GradleJni {
id = 'edu.wpi.first.GradleJni'
displayName = 'GradleJni'
implementationClass = 'edu.wpi.first.jni.GradleJni'
description = 'This plugin provides easy to use JNI support for gradle.'
tags = ['groovy', 'jni', 'utils', 'maven', 'frc', 'wpilib']
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package edu.wpi.first.jni;

import java.util.List;

import groovy.lang.Closure;

public class CreateJniCrossCompileOptions extends Closure<JniCrossCompileOptions> {

public CreateJniCrossCompileOptions() {
super(null);
}

private static final long serialVersionUID = -2465995793739686728L;

public JniCrossCompileOptions doCall(String a) {
return new JniCrossCompileOptions(a, null);
}

public JniCrossCompileOptions doCall(String a, String b) {
return new JniCrossCompileOptions(a, b, null);
}

public JniCrossCompileOptions doCall(String a, List<String> b) {
return new JniCrossCompileOptions(a, b);
}

public JniCrossCompileOptions doCall(String a, String b, List<String> c) {
return new JniCrossCompileOptions(a, b, c);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package edu.wpi.first.jni;

import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.nativeplatform.internal.DefaultNativeLibrarySpec;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultJniNativeExecutable extends DefaultNativeLibrarySpec
implements JniNativeExecutableSpec {
private List<JavaCompile> javaCompile = new ArrayList<>();
private List<JniCrossCompileOptions> crossCompileOptions = new ArrayList<>();
private Map<JavaCompile, DirectoryProperty> jniHeaderLocation = new HashMap<>();
private boolean enableCheckTask = false;
private List<String> checkSkipSymbols = new ArrayList<>();

@Override
public void setCheckSkipSymbols(List<String> checkSkipSymbols) {
this.checkSkipSymbols = checkSkipSymbols;
}

@Override
public List<String> getCheckSkipSymbols() {
return checkSkipSymbols;
}

public DefaultJniNativeExecutable() {
super();
}

@Override
public List<JavaCompile> getJavaCompileTasks() {
return javaCompile;
}

@Override
public void setJavaCompileTasks(List<JavaCompile> compile) {
javaCompile = compile;
}

@Override
public List<JniCrossCompileOptions> getJniCrossCompileOptions() {
return crossCompileOptions;
}

@Override
public void setJniCrossCompileOptions(List<JniCrossCompileOptions> options) {
crossCompileOptions = options;
}

@Override
public Map<JavaCompile, DirectoryProperty> getJniHeaderLocations() {
return jniHeaderLocation;
}

@Override
public void setJniHeaderLocations(Map<JavaCompile, DirectoryProperty> location) {
jniHeaderLocation = location;
}

@Override
public boolean getEnableCheckTask() {
return enableCheckTask;
}

@Override
public void setEnableCheckTask(boolean val) {
enableCheckTask = val;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package edu.wpi.first.jni;

import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.nativeplatform.internal.DefaultNativeLibrarySpec;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultJniNativeLibrary extends DefaultNativeLibrarySpec
implements JniNativeLibrarySpec {
private List<JavaCompile> javaCompile = new ArrayList<>();
private List<JniCrossCompileOptions> crossCompileOptions = new ArrayList<>();
private Map<JavaCompile, DirectoryProperty> jniHeaderLocation = new HashMap<>();
private boolean enableCheckTask = false;
private List<String> checkSkipSymbols = new ArrayList<>();

@Override
public void setCheckSkipSymbols(List<String> checkSkipSymbols) {
this.checkSkipSymbols = checkSkipSymbols;
}

@Override
public List<String> getCheckSkipSymbols() {
return checkSkipSymbols;
}

public DefaultJniNativeLibrary() {
super();
}

@Override
public List<JavaCompile> getJavaCompileTasks() {
return javaCompile;
}

@Override
public void setJavaCompileTasks(List<JavaCompile> compile) {
javaCompile = compile;
}

@Override
public List<JniCrossCompileOptions> getJniCrossCompileOptions() {
return crossCompileOptions;
}

@Override
public void setJniCrossCompileOptions(List<JniCrossCompileOptions> options) {
crossCompileOptions = options;
}

@Override
public Map<JavaCompile, DirectoryProperty> getJniHeaderLocations() {
return jniHeaderLocation;
}

@Override
public void setJniHeaderLocations(Map<JavaCompile, DirectoryProperty> location) {
jniHeaderLocation = location;
}

@Override
public boolean getEnableCheckTask() {
return enableCheckTask;
}

@Override
public void setEnableCheckTask(boolean val) {
enableCheckTask = val;
}
}
85 changes: 85 additions & 0 deletions GradleJni/src/main/java/edu/wpi/first/jni/ExtractJniFilesTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package edu.wpi.first.jni;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.inject.Inject;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;

public class ExtractJniFilesTask extends DefaultTask {

private final DirectoryProperty outputDirectory;

@OutputDirectory
public DirectoryProperty getOutputDirectory() {
return outputDirectory;
}

@Inject
public ExtractJniFilesTask(ObjectFactory factory) {
outputDirectory = factory.directoryProperty();
getOutputs().dir(outputDirectory);
outputDirectory.set(getProject().getLayout().getBuildDirectory().dir("embeddedJniHeaders"));
setGroup("JNI");
setDescription("Extracts the embedded JNI headers");
}

@TaskAction
public void extract() {
File mainDir = outputDirectory.getAsFile().get();
mainDir = new File(mainDir, "arm-linux-jni");
File linuxDir = new File(mainDir, "linux");
linuxDir.mkdirs();

InputStream is = ExtractJniFilesTask.class.getResourceAsStream("/arm-linux-jni/jni.h");
OutputStream os = null;

byte[] buffer = new byte[1024];
int readBytes = 0;
try {
os = new FileOutputStream(new File(mainDir, "jni.h"));
while ((readBytes = is.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
}
} catch (IOException ex) {
} finally {
try {
if (os != null) {
os.close();
}
is.close();
} catch (IOException ex) {
}
}

is = ExtractJniFilesTask.class.getResourceAsStream("/arm-linux-jni/linux/jni_md.h");
os = null;

buffer = new byte[1024];
readBytes = 0;
try {
os = new FileOutputStream(new File(linuxDir, "jni_md.h"));
while ((readBytes = is.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
}
} catch (IOException ex) {
} finally {
try {
if (os != null) {
os.close();
}
is.close();
} catch (IOException ex) {
}
}

}
}
Loading

0 comments on commit a5a305f

Please sign in to comment.