Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build shared library for Apple Silicon #51

Merged
merged 12 commits into from
Aug 4, 2023
30 changes: 25 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ on:
branches: [ master ]
jobs:
build:
name: Build JNI lib for ${{ matrix.build }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, macos-latest, windows-latest]
include:
- build: x86_64-linux
os: ubuntu-latest
- build: x86_64-macos
os: macos-latest
- build: aarch64-macos
os: macos-latest
target: aarch64-apple-darwin
- build: x86_64-windows
os: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
Expand All @@ -31,16 +41,26 @@ jobs:
- name: Binary compatibility settings (Windows)
if: ${{ startsWith(matrix.os, 'windows') }}
run: echo 'RUSTFLAGS=-Ctarget-feature=+crt-static' >> $GITHUB_ENV
# Run gradle normally to build the JNI lib
- name: Build with Gradle
if: ${{ !startsWith(matrix.os, 'ubuntu') }}
run: ./gradlew build copyJniLib
- name: Set build target for cross-compiling
if: matrix.target != ''
run: |
echo CARGO_BUILD_TARGET=${{ matrix.target }} >> $GITHUB_ENV
echo JNILIB_RUST_TARGET=${{ matrix.target }} >> $GITHUB_ENV
echo GRADLE_ARGS="${GRADLE_ARGS} -x test">> $GITHUB_ENV
rustup target add ${{ matrix.target }}
# Run gradle in a docker container to build the JNI lib on Linux for old glibc compatibility
- name: Build with Gradle (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }}
run: |
docker build -t build-image ./ci/docker/x86_64-linux
docker run --rm --volume $PWD:/build --workdir /build build-image ./gradlew build copyJniLib -x javadoc
# Otherwise, run gradle normally to build the JNI lib
- name: Build with Gradle
if: ${{ !startsWith(matrix.os, 'ubuntu') }}
run: ./gradlew build copyJniLib ${GRADLE_ARGS}
- name: List shared library files
run:
ls build/jni-libs
- name: Save JNI lib output
if: startsWith(github.ref, 'refs/tags/')
rob-odwyer marked this conversation as resolved.
Show resolved Hide resolved
uses: actions/upload-artifact@v2
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ dependencies {

An artifact (JAR) of `wasmtime-java` ships along with prebuilt JNI libraries for some major platforms, so just adding the above dependency provides you a self-contained `wasmtime` runtime on supported platforms:

| OS | Arch |
| ---- | ---- |
| Linux (ELF) | x86_64 |
| Mac OS | x86_64 |
| Windows | x86_64 |
| OS | Arch |
| ---- | ---- |
| Linux (ELF) | x86_64 |
| Mac OS | x86_64 |
| Mac OS | aarch64 |
| Windows | x86_64 |

# Example

Expand Down
9 changes: 8 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ test {

static def jniLibOsClassifier() {
def os = System.getProperty("os.name").toLowerCase()

if (os.contains("linux")) {
return "linux"
}
Expand All @@ -71,6 +72,12 @@ static def jniLibOsClassifier() {
throw new RuntimeException("platform not supported: " + System.getProperty("os.name"))
}

static def jniLibArchClassifier() {
def target = rustTargetTriple() ?: ""
// Use the first part of the rust target triple as the arch classifier if set, otherwise assume "x86_64"
return target ? target.split("-")[0] : "x86_64"
}

static def rustTargetTriple() {
System.getenv("JNILIB_RUST_TARGET")
}
Expand Down Expand Up @@ -170,7 +177,7 @@ task copyJniLib(type: Copy) {
def targetDir = rustTargetTriple() ?: ""
from "wasmtime-jni/target/$targetDir/release"
include '*.so', '*.dylib', "*.dll"
rename "^(lib)?wasmtime_jni", "\$1wasmtime_jni_${project.version}_${jniLibOsClassifier()}"
rename "^(lib)?wasmtime_jni", "\$1wasmtime_jni_${project.version}_${jniLibOsClassifier()}_${jniLibArchClassifier()}"
into new File(project.buildDir, "jni-libs")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private static String libraryPath() throws IOException {
Platform platform = detectPlatform();
String version = libVersion();
String ext = platform.ext;
String fileName = platform.prefix + NATIVE_LIBRARY_NAME + '_' + version + '_' + platform.classifier;
String fileName = platform.prefix + NATIVE_LIBRARY_NAME + '_' + version + '_' + platform.os.value + '_' + platform.arch.value;
Path tempFile = Files.createTempFile(fileName, ext);
try (InputStream in = NativeLibraryLoader.class.getResourceAsStream('/' + fileName + ext)) {
Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING);
Expand All @@ -70,34 +70,56 @@ private static String libraryPath() throws IOException {

private static String libVersion() throws IOException {
final Properties props;
try (InputStream in = NativeLibraryLoader.class.getResourceAsStream( '/' + META_PROPS_FILE)) {
try (InputStream in = NativeLibraryLoader.class.getResourceAsStream('/' + META_PROPS_FILE)) {
props = new Properties();
props.load(in);
}
return props.getProperty(JNI_LIB_VERSION_PROP);
}

@AllArgsConstructor
private enum Os {
LINUX("linux"),
MACOS("macos"),
WINDOWS("windows");

final String value;
}

@AllArgsConstructor
private enum Arch {
X86_64("x86_64"),
AARCH64("aarch64");

final String value;
}

@AllArgsConstructor
private enum Platform {
LINUX("linux","lib" , ".so"),
MACOS("macos","lib", ".dylib"),
WINDOWS("windows","",".dll")
;
LINUX(Os.LINUX, Arch.X86_64, "lib", ".so"),
MACOS(Os.MACOS, Arch.X86_64, "lib", ".dylib"),
MACOS_AARCH64(Os.MACOS, Arch.AARCH64, "lib", ".dylib"),
WINDOWS(Os.WINDOWS, Arch.X86_64, "", ".dll");

final String classifier;
final Os os;
final Arch arch;
final String prefix;
final String ext;
}

private static Platform detectPlatform() {
String os = System.getProperty("os.name").toLowerCase();
String arch = System.getProperty("os.arch").toLowerCase();
if (os.contains("linux")) {
return Platform.LINUX;
}
if (os.contains("mac os") || os.contains("darwin")) {
if (arch.equals("aarch64")) {
return Platform.MACOS_AARCH64;
}
return Platform.MACOS;
}
if(os.toLowerCase().contains("windows")){
if (os.toLowerCase().contains("windows")) {
return Platform.WINDOWS;
}
throw new RuntimeException("platform not supported: " + os);
Expand Down