Skip to content

Commit

Permalink
Build shared library for Apple Silicon (#51)
Browse files Browse the repository at this point in the history
* aarch64 build with cargo

* turn off tests for aarch64-macos

* use an env var to avoid more than 2 gradle build variants

* support macos_aarch64 shared library

* always upload artifact after build step

* fix gradle log

* fix debug command on windows

* use arch from rust target triple when set in gradle

* fix platform + arch in shared library filename

* add arch into shared lib filename for other platforms

* restore conditional check for uploading artifacts

* add note to README about aarch64
  • Loading branch information
rob-odwyer authored Aug 4, 2023
1 parent 844fb90 commit d662872
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 19 deletions.
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/')
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

0 comments on commit d662872

Please sign in to comment.