Skip to content

Commit c9935a1

Browse files
committed
Monorepo GradleJni
1 parent 51ac01e commit c9935a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+5453
-26
lines changed

.github/workflows/main.yml

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,46 @@ jobs:
2020
run: ./gradlew publishToMavenLocal
2121
- name: Check output
2222
run: git --no-pager diff --exit-code HEAD
23-
- name: InstallRioTC
24-
run: ./gradlew installRoboRioToolchain
25-
working-directory: testing/cpp
26-
- name: InstallArm32Tc
27-
run: ./gradlew installArm32Toolchain
28-
working-directory: testing/cpp
29-
- name: InstallArm64Tc
30-
run: ./gradlew installArm64Toolchain
31-
working-directory: testing/cpp
32-
- name: Build Test
23+
24+
test_examples:
25+
needs: build
26+
strategy:
27+
matrix:
28+
include:
29+
- os: windows-latest
30+
language: cpp
31+
- os: windows-latest
32+
language: jni
33+
- os: ubuntu-latest
34+
language: cpp
35+
- os: ubuntu-latest
36+
language: jni
37+
- os: macos-latest
38+
language: cpp
39+
- os: macos-latest
40+
language: jni
41+
runs-on: ${{ matrix.os }}
42+
steps:
43+
- uses: actions/checkout@v4
44+
- uses: actions/setup-java@v4
45+
with:
46+
java-version: 17
47+
distribution: temurin
48+
- uses: actions/download-artifact@v4
49+
with:
50+
name: Maven
51+
path: ~/.m2/
52+
- name: Setup Toolchains
53+
run: |
54+
./gradlew installRoboRioToolchain
55+
./gradlew installArm32Toolchain
56+
./gradlew installArm64Toolchain
57+
- name: Test ${{ matrix.language }} Build
3358
run: ./gradlew build
34-
working-directory: testing/cpp
59+
working-directory: testing/${{ matrix.language }}
3560

3661
publish:
37-
needs: build
62+
needs: [build, test-examples]
3863
runs-on: ubuntu-latest
3964
steps:
4065
- uses: actions/checkout@v4

GradleJni/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Gradle JNI
2+
3+
[![CI](https://github.com/wpilibsuite/gradle-jni/actions/workflows/main.yml/badge.svg)](https://github.com/wpilibsuite/gradle-jni/actions/workflows/main.yml)
4+
5+
gradle-jni is a utility library for enabling easy to build JNI compatible plugins
6+
7+
```gradle
8+
plugins {
9+
id 'edu.wpi.first.GradleJni' version '0.1.6'
10+
}
11+
12+
model {
13+
components {
14+
library(JniNativeLibrarySpec) { // Use JniNativeLibrarySpec to get a JNI library
15+
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
16+
javaCompileTasks << compileJava // set javaCompileTasks to any java compile tasks that contain your JNI classes. It is a list of tasks
17+
jniCrossCompileOptions << JniCrossCompileOptions('athena')
18+
// See below for more JniCrossCompileOptions
19+
}
20+
}
21+
}
22+
```
23+
24+
Below are the options for JniCrossCompileOptions
25+
```
26+
JNICrossCompileOptions('toolChainName') // Use this to match the cross compile options to a specific tool chain name
27+
JNICrossCompileOptions('operatingSystem', 'architecture') // Use this to match the cross compile options to a specific tool chain arch and os.
28+
29+
// For both of these options, they take an optional last parameter of List<String> of directories
30+
If this parameter is added, the directories passed in will be used for the include paths for the JNI headers.
31+
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.
32+
```

GradleJni/build.gradle

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
plugins {
2+
id 'java-gradle-plugin'
3+
id 'maven-publish'
4+
id 'com.gradle.plugin-publish'
5+
}
6+
7+
gradlePlugin {
8+
website = 'https://github.com/wpilibsuite/gradle-jni'
9+
vcsUrl = 'https://github.com/wpilibsuite/gradle-jni'
10+
plugins {
11+
GradleJni {
12+
id = 'edu.wpi.first.GradleJni'
13+
displayName = 'GradleJni'
14+
implementationClass = 'edu.wpi.first.jni.GradleJni'
15+
description = 'This plugin provides easy to use JNI support for gradle.'
16+
tags = ['groovy', 'jni', 'utils', 'maven', 'frc', 'wpilib']
17+
}
18+
}
19+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package edu.wpi.first.jni;
2+
3+
import java.util.List;
4+
5+
import groovy.lang.Closure;
6+
7+
public class CreateJniCrossCompileOptions extends Closure<JniCrossCompileOptions> {
8+
9+
public CreateJniCrossCompileOptions() {
10+
super(null);
11+
}
12+
13+
private static final long serialVersionUID = -2465995793739686728L;
14+
15+
public JniCrossCompileOptions doCall(String a) {
16+
return new JniCrossCompileOptions(a, null);
17+
}
18+
19+
public JniCrossCompileOptions doCall(String a, String b) {
20+
return new JniCrossCompileOptions(a, b, null);
21+
}
22+
23+
public JniCrossCompileOptions doCall(String a, List<String> b) {
24+
return new JniCrossCompileOptions(a, b);
25+
}
26+
27+
public JniCrossCompileOptions doCall(String a, String b, List<String> c) {
28+
return new JniCrossCompileOptions(a, b, c);
29+
}
30+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package edu.wpi.first.jni;
2+
3+
import org.gradle.api.tasks.compile.JavaCompile;
4+
import org.gradle.api.file.DirectoryProperty;
5+
import org.gradle.nativeplatform.internal.DefaultNativeLibrarySpec;
6+
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
public class DefaultJniNativeExecutable extends DefaultNativeLibrarySpec
13+
implements JniNativeExecutableSpec {
14+
private List<JavaCompile> javaCompile = new ArrayList<>();
15+
private List<JniCrossCompileOptions> crossCompileOptions = new ArrayList<>();
16+
private Map<JavaCompile, DirectoryProperty> jniHeaderLocation = new HashMap<>();
17+
private boolean enableCheckTask = false;
18+
private List<String> checkSkipSymbols = new ArrayList<>();
19+
20+
@Override
21+
public void setCheckSkipSymbols(List<String> checkSkipSymbols) {
22+
this.checkSkipSymbols = checkSkipSymbols;
23+
}
24+
25+
@Override
26+
public List<String> getCheckSkipSymbols() {
27+
return checkSkipSymbols;
28+
}
29+
30+
public DefaultJniNativeExecutable() {
31+
super();
32+
}
33+
34+
@Override
35+
public List<JavaCompile> getJavaCompileTasks() {
36+
return javaCompile;
37+
}
38+
39+
@Override
40+
public void setJavaCompileTasks(List<JavaCompile> compile) {
41+
javaCompile = compile;
42+
}
43+
44+
@Override
45+
public List<JniCrossCompileOptions> getJniCrossCompileOptions() {
46+
return crossCompileOptions;
47+
}
48+
49+
@Override
50+
public void setJniCrossCompileOptions(List<JniCrossCompileOptions> options) {
51+
crossCompileOptions = options;
52+
}
53+
54+
@Override
55+
public Map<JavaCompile, DirectoryProperty> getJniHeaderLocations() {
56+
return jniHeaderLocation;
57+
}
58+
59+
@Override
60+
public void setJniHeaderLocations(Map<JavaCompile, DirectoryProperty> location) {
61+
jniHeaderLocation = location;
62+
}
63+
64+
@Override
65+
public boolean getEnableCheckTask() {
66+
return enableCheckTask;
67+
}
68+
69+
@Override
70+
public void setEnableCheckTask(boolean val) {
71+
enableCheckTask = val;
72+
}
73+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package edu.wpi.first.jni;
2+
3+
import org.gradle.api.tasks.compile.JavaCompile;
4+
import org.gradle.api.file.DirectoryProperty;
5+
import org.gradle.nativeplatform.internal.DefaultNativeLibrarySpec;
6+
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
public class DefaultJniNativeLibrary extends DefaultNativeLibrarySpec
13+
implements JniNativeLibrarySpec {
14+
private List<JavaCompile> javaCompile = new ArrayList<>();
15+
private List<JniCrossCompileOptions> crossCompileOptions = new ArrayList<>();
16+
private Map<JavaCompile, DirectoryProperty> jniHeaderLocation = new HashMap<>();
17+
private boolean enableCheckTask = false;
18+
private List<String> checkSkipSymbols = new ArrayList<>();
19+
20+
@Override
21+
public void setCheckSkipSymbols(List<String> checkSkipSymbols) {
22+
this.checkSkipSymbols = checkSkipSymbols;
23+
}
24+
25+
@Override
26+
public List<String> getCheckSkipSymbols() {
27+
return checkSkipSymbols;
28+
}
29+
30+
public DefaultJniNativeLibrary() {
31+
super();
32+
}
33+
34+
@Override
35+
public List<JavaCompile> getJavaCompileTasks() {
36+
return javaCompile;
37+
}
38+
39+
@Override
40+
public void setJavaCompileTasks(List<JavaCompile> compile) {
41+
javaCompile = compile;
42+
}
43+
44+
@Override
45+
public List<JniCrossCompileOptions> getJniCrossCompileOptions() {
46+
return crossCompileOptions;
47+
}
48+
49+
@Override
50+
public void setJniCrossCompileOptions(List<JniCrossCompileOptions> options) {
51+
crossCompileOptions = options;
52+
}
53+
54+
@Override
55+
public Map<JavaCompile, DirectoryProperty> getJniHeaderLocations() {
56+
return jniHeaderLocation;
57+
}
58+
59+
@Override
60+
public void setJniHeaderLocations(Map<JavaCompile, DirectoryProperty> location) {
61+
jniHeaderLocation = location;
62+
}
63+
64+
@Override
65+
public boolean getEnableCheckTask() {
66+
return enableCheckTask;
67+
}
68+
69+
@Override
70+
public void setEnableCheckTask(boolean val) {
71+
enableCheckTask = val;
72+
}
73+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package edu.wpi.first.jni;
2+
3+
import java.io.File;
4+
import java.io.FileOutputStream;
5+
import java.io.IOException;
6+
import java.io.InputStream;
7+
import java.io.OutputStream;
8+
9+
import javax.inject.Inject;
10+
11+
import org.gradle.api.DefaultTask;
12+
import org.gradle.api.file.DirectoryProperty;
13+
import org.gradle.api.model.ObjectFactory;
14+
import org.gradle.api.tasks.OutputDirectory;
15+
import org.gradle.api.tasks.TaskAction;
16+
17+
public class ExtractJniFilesTask extends DefaultTask {
18+
19+
private final DirectoryProperty outputDirectory;
20+
21+
@OutputDirectory
22+
public DirectoryProperty getOutputDirectory() {
23+
return outputDirectory;
24+
}
25+
26+
@Inject
27+
public ExtractJniFilesTask(ObjectFactory factory) {
28+
outputDirectory = factory.directoryProperty();
29+
getOutputs().dir(outputDirectory);
30+
outputDirectory.set(getProject().getLayout().getBuildDirectory().dir("embeddedJniHeaders"));
31+
setGroup("JNI");
32+
setDescription("Extracts the embedded JNI headers");
33+
}
34+
35+
@TaskAction
36+
public void extract() {
37+
File mainDir = outputDirectory.getAsFile().get();
38+
mainDir = new File(mainDir, "arm-linux-jni");
39+
File linuxDir = new File(mainDir, "linux");
40+
linuxDir.mkdirs();
41+
42+
InputStream is = ExtractJniFilesTask.class.getResourceAsStream("/arm-linux-jni/jni.h");
43+
OutputStream os = null;
44+
45+
byte[] buffer = new byte[1024];
46+
int readBytes = 0;
47+
try {
48+
os = new FileOutputStream(new File(mainDir, "jni.h"));
49+
while ((readBytes = is.read(buffer)) != -1) {
50+
os.write(buffer, 0, readBytes);
51+
}
52+
} catch (IOException ex) {
53+
} finally {
54+
try {
55+
if (os != null) {
56+
os.close();
57+
}
58+
is.close();
59+
} catch (IOException ex) {
60+
}
61+
}
62+
63+
is = ExtractJniFilesTask.class.getResourceAsStream("/arm-linux-jni/linux/jni_md.h");
64+
os = null;
65+
66+
buffer = new byte[1024];
67+
readBytes = 0;
68+
try {
69+
os = new FileOutputStream(new File(linuxDir, "jni_md.h"));
70+
while ((readBytes = is.read(buffer)) != -1) {
71+
os.write(buffer, 0, readBytes);
72+
}
73+
} catch (IOException ex) {
74+
} finally {
75+
try {
76+
if (os != null) {
77+
os.close();
78+
}
79+
is.close();
80+
} catch (IOException ex) {
81+
}
82+
}
83+
84+
}
85+
}

0 commit comments

Comments
 (0)