diff --git a/Makefile b/Makefile index 1b72e947b..3b0ddffee 100644 --- a/Makefile +++ b/Makefile @@ -1731,12 +1731,23 @@ else ARCH := $(shell getconf LONG_BIT) endif -ifneq (,$(filter ppc% arm64 aarch64 sparc64, $(MACHINE))) - ROCKSDBJNILIB = librocksdbjni-linux-$(MACHINE).so -else - ROCKSDBJNILIB = librocksdbjni-linux$(ARCH).so +ifeq ($(shell ldd /usr/bin/env 2>/dev/null | grep -q musl; echo $$?),0) + JNI_LIBC = musl +# GNU LibC (or glibc) is so pervasive we can assume it is the default +# else +# JNI_LIBC = glibc endif -ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux$(ARCH).jar + +ifneq ($(origin JNI_LIBC), undefined) + JNI_LIBC_POSTFIX = -$(JNI_LIBC) +endif + +ifneq (,$(filter ppc% arm64 aarch64 sparc64, $(MACHINE))) + ROCKSDBJNILIB = librocksdbjni-linux-$(MACHINE)$(JNI_LIBC_POSTFIX).so +else + ROCKSDBJNILIB = librocksdbjni-linux$(ARCH)$(JNI_LIBC_POSTFIX).so +endif +ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux$(ARCH)$(JNI_LIBC_POSTFIX).jar ROCKSDB_JAR_ALL = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH).jar ROCKSDB_JAVADOCS_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-javadoc.jar ROCKSDB_SOURCES_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-sources.jar @@ -1910,12 +1921,12 @@ rocksdbjavastatic: $(java_static_all_libobjects) cd java/src/main/java;jar -cf ../../../target/$(ROCKSDB_SOURCES_JAR) org rocksdbjavastaticrelease: rocksdbjavastatic - cd java/crossbuild && vagrant destroy -f && vagrant up linux32 && vagrant halt linux32 && vagrant up linux64 && vagrant halt linux64 + cd java/crossbuild && (vagrant destroy -f || true) && vagrant up linux32 && vagrant halt linux32 && vagrant up linux64 && vagrant halt linux64 && vagrant up linux64-musl && vagrant halt linux64-musl cd java;jar -cf target/$(ROCKSDB_JAR_ALL) HISTORY*.md cd java/target;jar -uf $(ROCKSDB_JAR_ALL) librocksdbjni-*.so librocksdbjni-*.jnilib cd java/target/classes;jar -uf ../$(ROCKSDB_JAR_ALL) org/rocksdb/*.class org/rocksdb/util/*.class -rocksdbjavastaticreleasedocker: rocksdbjavastatic rocksdbjavastaticdockerx86 rocksdbjavastaticdockerx86_64 +rocksdbjavastaticreleasedocker: rocksdbjavastatic rocksdbjavastaticdockerx86 rocksdbjavastaticdockerx86_64 rocksdbjavastaticdockerx86musl rocksdbjavastaticdockerx86_64musl cd java;jar -cf target/$(ROCKSDB_JAR_ALL) HISTORY*.md cd java/target;jar -uf $(ROCKSDB_JAR_ALL) librocksdbjni-*.so librocksdbjni-*.jnilib cd java/target/classes;jar -uf ../$(ROCKSDB_JAR_ALL) org/rocksdb/*.class org/rocksdb/util/*.class @@ -1936,6 +1947,22 @@ rocksdbjavastaticdockerarm64v8: mkdir -p java/target docker run --rm --name rocksdb_linux_arm64v8-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos7_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh +rocksdbjavastaticdockerx86musl: + mkdir -p java/target + docker run --rm --name rocksdb_linux_x86-musl-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_x86-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh + +rocksdbjavastaticdockerx86_64musl: + mkdir -p java/target + docker run --rm --name rocksdb_linux_x64-musl-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_x64-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh + +rocksdbjavastaticdockerppc64lemusl: + mkdir -p java/target + docker run --rm --name rocksdb_linux_ppc64le-musl-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh + +rocksdbjavastaticdockerarm64v8musl: + mkdir -p java/target + docker run --rm --name rocksdb_linux_arm64v8-musl-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh + rocksdbjavastaticpublish: rocksdbjavastaticrelease rocksdbjavastaticpublishcentral rocksdbjavastaticpublishdocker: rocksdbjavastaticreleasedocker rocksdbjavastaticpublishcentral @@ -1945,6 +1972,8 @@ rocksdbjavastaticpublishcentral: mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-sources.jar -Dclassifier=sources mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux64.jar -Dclassifier=linux64 mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux32.jar -Dclassifier=linux32 + mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux64-musl.jar -Dclassifier=linux64-musl + mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux32-musl.jar -Dclassifier=linux32-musl mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-osx.jar -Dclassifier=osx mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-win64.jar -Dclassifier=win64 mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH).jar diff --git a/java/RELEASE.md b/java/RELEASE.md index 65da3d83a..dda19455f 100644 --- a/java/RELEASE.md +++ b/java/RELEASE.md @@ -4,28 +4,33 @@ RocksDB can be built as a single self contained cross-platform JAR. The cross-pl Building a cross-platform JAR requires: - * [Vagrant](https://www.vagrantup.com/) - * [Virtualbox](https://www.virtualbox.org/) + * [Docker](https://www.docker.com/docker-community) * A Mac OSX machine that can compile RocksDB. * Java 7 set as JAVA_HOME. Once you have these items, run this make command from RocksDB's root source directory: - make jclean clean rocksdbjavastaticrelease + make jclean clean rocksdbjavastaticreleasedocker -This command will build RocksDB natively on OSX, and will then spin up two Vagrant Virtualbox Ubuntu images to build RocksDB for both 32-bit and 64-bit Linux. +This command will build RocksDB natively on OSX, and will then spin up docker containers to build RocksDB for 32-bit and 64-bit Linux with glibc, and 32-bit and 64-bit Linux with musl libc. You can find all native binaries and JARs in the java/target directory upon completion: librocksdbjni-linux32.so librocksdbjni-linux64.so + librocksdbjni-linux64-musl.so + librocksdbjni-linux32-musl.so librocksdbjni-osx.jnilib - rocksdbjni-3.5.0-javadoc.jar - rocksdbjni-3.5.0-linux32.jar - rocksdbjni-3.5.0-linux64.jar - rocksdbjni-3.5.0-osx.jar - rocksdbjni-3.5.0-sources.jar - rocksdbjni-3.5.0.jar + rocksdbjni-x.y.z-javadoc.jar + rocksdbjni-x.y.z-linux32.jar + rocksdbjni-x.y.z-linux64.jar + rocksdbjni-x.y.z-linux64-musl.jar + rocksdbjni-x.y.z-linux32-musl.jar + rocksdbjni-x.y.z-osx.jar + rocksdbjni-x.y.z-sources.jar + rocksdbjni-x.y.z.jar + +Where x.y.z is the built version number of RocksDB. ## Maven publication diff --git a/java/crossbuild/Vagrantfile b/java/crossbuild/Vagrantfile index 48ab03f80..0ee50de2c 100644 --- a/java/crossbuild/Vagrantfile +++ b/java/crossbuild/Vagrantfile @@ -8,10 +8,28 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define "linux32" do |linux32| linux32.vm.box = "bento/centos-6.10-i386" + linux32.vm.provision :shell, path: "build-linux-centos.sh" end config.vm.define "linux64" do |linux64| linux64.vm.box = "bento/centos-6.10" + linux64.vm.provision :shell, path: "build-linux-centos.sh" + end + + config.vm.define "linux32-musl" do |musl32| + musl32.vm.box = "alpine/alpine32" + musl32.vm.box_version = "3.6.0" + musl32.vm.provision :shell, path: "build-linux-alpine.sh" + end + + config.vm.define "linux64-musl" do |musl64| + musl64.vm.box = "generic/alpine36" + + ## Should use the alpine/alpine64 box, but this issue needs to be fixed first - https://github.com/hashicorp/vagrant/issues/11218 + # musl64.vm.box = "alpine/alpine64" + # musl64.vm.box_version = "3.6.0" + + musl64.vm.provision :shell, path: "build-linux-alpine.sh" end config.vm.provider "virtualbox" do |v| @@ -20,7 +38,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| v.customize ["modifyvm", :id, "--nictype1", "virtio" ] end - config.vm.provision :shell, path: "build-linux-centos.sh" + if Vagrant.has_plugin?("vagrant-cachier") + config.cache.scope = :box + end + if Vagrant.has_plugin?("vagrant-vbguest") + config.vbguest.no_install = true + end + config.vm.synced_folder "../target", "/rocksdb-build" config.vm.synced_folder "../..", "/rocksdb", type: "rsync" config.vm.boot_timeout = 1200 diff --git a/java/crossbuild/build-linux-alpine.sh b/java/crossbuild/build-linux-alpine.sh new file mode 100755 index 000000000..561d34141 --- /dev/null +++ b/java/crossbuild/build-linux-alpine.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + +set -e + +# update Alpine with latest versions +echo '@edge http://nl.alpinelinux.org/alpine/edge/main' >> /etc/apk/repositories +echo '@community http://nl.alpinelinux.org/alpine/edge/community' >> /etc/apk/repositories +apk update +apk upgrade + +# install CA certificates +apk add ca-certificates + +# install build tools +apk add \ + build-base \ + coreutils \ + file \ + git \ + perl \ + automake \ + autoconf \ + cmake + +# install tool dependencies for building RocksDB static library +apk add \ + curl \ + bash \ + wget \ + tar \ + openssl + +# install RocksDB dependencies +apk add \ + snappy snappy-dev \ + zlib zlib-dev \ + bzip2 bzip2-dev \ + lz4 lz4-dev \ + zstd zstd-dev \ + linux-headers \ + jemalloc jemalloc-dev + +# install OpenJDK7 +apk add openjdk7 \ + && apk add java-cacerts \ + && rm /usr/lib/jvm/java-1.7-openjdk/jre/lib/security/cacerts \ + && ln -s /etc/ssl/certs/java/cacerts /usr/lib/jvm/java-1.7-openjdk/jre/lib/security/cacerts + +# cleanup +rm -rf /var/cache/apk/* + +# puts javac in the PATH +export JAVA_HOME=/usr/lib/jvm/java-1.7-openjdk +export PATH=/usr/lib/jvm/java-1.7-openjdk/bin:$PATH + +# gflags from source +cd /tmp &&\ + git clone -b v2.0 --single-branch https://github.com/gflags/gflags.git &&\ + cd gflags &&\ + ./configure --prefix=/usr && make && make install &&\ + rm -rf /tmp/* + + +# build rocksdb +cd /rocksdb +make jclean clean +PORTABLE=1 make -j8 rocksdbjavastatic +cp /rocksdb/java/target/librocksdbjni-* /rocksdb-build +cp /rocksdb/java/target/rocksdbjni-* /rocksdb-build diff --git a/java/crossbuild/docker-build-linux-alpine.sh b/java/crossbuild/docker-build-linux-alpine.sh new file mode 100755 index 000000000..e605c7716 --- /dev/null +++ b/java/crossbuild/docker-build-linux-alpine.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + +set -e +#set -x + +# just in-case this is run outside Docker +mkdir -p /rocksdb-local-build + +rm -rf /rocksdb-local-build/* +cp -r /rocksdb-host/* /rocksdb-local-build +cd /rocksdb-local-build + +make clean-not-downloaded +PORTABLE=1 make rocksdbjavastatic + +cp java/target/librocksdbjni-linux*.so java/target/rocksdbjni-*-linux*.jar /rocksdb-java-target + diff --git a/java/crossbuild/docker-build-linux-centos.sh b/java/crossbuild/docker-build-linux-centos.sh index 33fcff955..c4217785f 100755 --- a/java/crossbuild/docker-build-linux-centos.sh +++ b/java/crossbuild/docker-build-linux-centos.sh @@ -14,19 +14,19 @@ cd /rocksdb-local-build # Use scl devtoolset if available if hash scl 2>/dev/null; then if scl --list | grep -q 'devtoolset-7'; then - # CentOS 7+ - scl enable devtoolset-7 'make clean-not-downloaded' + # CentOS 7+ + scl enable devtoolset-7 'make clean-not-downloaded' scl enable devtoolset-7 'PORTABLE=1 make -j2 rocksdbjavastatic' elif scl --list | grep -q 'devtoolset-2'; then - # CentOS 5 or 6 - scl enable devtoolset-2 'make clean-not-downloaded' + # CentOS 5 or 6 + scl enable devtoolset-2 'make clean-not-downloaded' scl enable devtoolset-2 'PORTABLE=1 make -j2 rocksdbjavastatic' else echo "Could not find devtoolset" exit 1; fi else - make clean-not-downloaded + make clean-not-downloaded PORTABLE=1 make -j2 rocksdbjavastatic fi diff --git a/java/rocksjni.pom b/java/rocksjni.pom index 94f07551c..5defdca7d 100644 --- a/java/rocksjni.pom +++ b/java/rocksjni.pom @@ -10,7 +10,7 @@ rocksdbjni - - RocksDB fat jar that contains .so files for linux32 and linux64, jnilib files + RocksDB fat jar that contains .so files for linux32 and linux64 (glibc and musl-libc), jnilib files for Mac OSX, and a .dll for Windows x64. diff --git a/java/src/main/java/org/rocksdb/util/Environment.java b/java/src/main/java/org/rocksdb/util/Environment.java index bac1c559a..b5de34b75 100644 --- a/java/src/main/java/org/rocksdb/util/Environment.java +++ b/java/src/main/java/org/rocksdb/util/Environment.java @@ -1,9 +1,22 @@ // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. package org.rocksdb.util; +import java.io.File; +import java.io.IOException; + public class Environment { private static String OS = System.getProperty("os.name").toLowerCase(); private static String ARCH = System.getProperty("os.arch").toLowerCase(); + private static boolean MUSL_LIBC; + + static { + try { + final Process p = new ProcessBuilder("/usr/bin/env", "sh", "-c", "ldd /usr/bin/env | grep -q musl").start(); + MUSL_LIBC = p.waitFor() == 0; + } catch (final IOException | InterruptedException e) { + MUSL_LIBC = false; + } + } public static boolean isAarch64() { return ARCH.contains("aarch64"); @@ -38,6 +51,10 @@ public class Environment { OS.contains("nux"); } + public static boolean isMuslLibc() { + return MUSL_LIBC; + } + public static boolean isSolaris() { return OS.contains("sunos"); } @@ -61,15 +78,37 @@ public class Environment { return appendLibOsSuffix("lib" + getSharedLibraryName(name), true); } + /** + * Get the name of the libc implementation + * + * @return the name of the implementation, + * or null if the default for that platform (e.g. glibc on Linux). + */ + public static /* @Nullable */ String getLibcName() { + if (isMuslLibc()) { + return "musl"; + } else { + return null; + } + } + + private static String getLibcPostfix() { + final String libcName = getLibcName(); + if (libcName == null) { + return ""; + } + return "-" + libcName; + } + public static String getJniLibraryName(final String name) { if (isUnix()) { final String arch = is64Bit() ? "64" : "32"; if (isPowerPC() || isAarch64()) { - return String.format("%sjni-linux-%s", name, ARCH); + return String.format("%sjni-linux-%s%s", name, ARCH, getLibcPostfix()); } else if (isS390x()) { return String.format("%sjni-linux%s", name, ARCH); } else { - return String.format("%sjni-linux%s", name, arch); + return String.format("%sjni-linux%s%s", name, arch, getLibcPostfix()); } } else if (isMac()) { return String.format("%sjni-osx", name); diff --git a/java/src/test/java/org/rocksdb/util/EnvironmentTest.java b/java/src/test/java/org/rocksdb/util/EnvironmentTest.java index ff13ddb5d..ab0ff2027 100644 --- a/java/src/test/java/org/rocksdb/util/EnvironmentTest.java +++ b/java/src/test/java/org/rocksdb/util/EnvironmentTest.java @@ -16,14 +16,17 @@ import static org.assertj.core.api.Assertions.assertThat; public class EnvironmentTest { private final static String ARCH_FIELD_NAME = "ARCH"; private final static String OS_FIELD_NAME = "OS"; + private final static String MUSL_LIBC_FIELD_NAME = "MUSL_LIBC"; private static String INITIAL_OS; private static String INITIAL_ARCH; + private static boolean INITIAL_MUSL_LIBC; @BeforeClass public static void saveState() { INITIAL_ARCH = getEnvironmentClassField(ARCH_FIELD_NAME); INITIAL_OS = getEnvironmentClassField(OS_FIELD_NAME); + INITIAL_MUSL_LIBC = getEnvironmentClassField(MUSL_LIBC_FIELD_NAME); } @Test @@ -53,6 +56,7 @@ public class EnvironmentTest { @Test public void nix32() { // Linux + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); setEnvironmentClassFields("Linux", "32"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). @@ -61,7 +65,17 @@ public class EnvironmentTest { isEqualTo("librocksdbjni-linux32.so"); assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); + // Linux musl-libc (Alpine) + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true); + assertThat(Environment.isWindows()).isFalse(); + assertThat(Environment.getJniLibraryExtension()). + isEqualTo(".so"); + assertThat(Environment.getJniLibraryFileName("rocksdb")). + isEqualTo("librocksdbjni-linux32-musl.so"); + assertThat(Environment.getSharedLibraryFileName("rocksdb")). + isEqualTo("librocksdbjni.so"); // UNIX + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); setEnvironmentClassFields("Unix", "32"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). @@ -84,6 +98,7 @@ public class EnvironmentTest { @Test public void nix64() { + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); setEnvironmentClassFields("Linux", "x64"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). @@ -92,7 +107,17 @@ public class EnvironmentTest { isEqualTo("librocksdbjni-linux64.so"); assertThat(Environment.getSharedLibraryFileName("rocksdb")). isEqualTo("librocksdbjni.so"); + // Linux musl-libc (Alpine) + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true); + assertThat(Environment.isWindows()).isFalse(); + assertThat(Environment.getJniLibraryExtension()). + isEqualTo(".so"); + assertThat(Environment.getJniLibraryFileName("rocksdb")). + isEqualTo("librocksdbjni-linux64-musl.so"); + assertThat(Environment.getSharedLibraryFileName("rocksdb")). + isEqualTo("librocksdbjni.so"); // UNIX + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); setEnvironmentClassFields("Unix", "x64"); assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.getJniLibraryExtension()). @@ -130,8 +155,37 @@ public class EnvironmentTest { isEqualTo("librocksdbjni.dll"); } + @Test + public void ppc64le() { + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); + setEnvironmentClassFields("Linux", "ppc64le"); + assertThat(Environment.isUnix()).isTrue(); + assertThat(Environment.isPowerPC()).isTrue(); + assertThat(Environment.is64Bit()).isTrue(); + assertThat(Environment.getJniLibraryExtension()).isEqualTo(".so"); + assertThat(Environment.getSharedLibraryName("rocksdb")).isEqualTo("rocksdbjni"); + assertThat(Environment.getJniLibraryName("rocksdb")).isEqualTo("rocksdbjni-linux-ppc64le"); + assertThat(Environment.getJniLibraryFileName("rocksdb")) + .isEqualTo("librocksdbjni-linux-ppc64le.so"); + assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so"); + // Linux musl-libc (Alpine) + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true); + setEnvironmentClassFields("Linux", "ppc64le"); + assertThat(Environment.isUnix()).isTrue(); + assertThat(Environment.isPowerPC()).isTrue(); + assertThat(Environment.is64Bit()).isTrue(); + assertThat(Environment.getJniLibraryExtension()).isEqualTo(".so"); + assertThat(Environment.getSharedLibraryName("rocksdb")).isEqualTo("rocksdbjni"); + assertThat(Environment.getJniLibraryName("rocksdb")).isEqualTo("rocksdbjni-linux-ppc64le-musl"); + assertThat(Environment.getJniLibraryFileName("rocksdb")) + .isEqualTo("librocksdbjni-linux-ppc64le-musl.so"); + assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so"); + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); + } + @Test public void aarch64() { + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); setEnvironmentClassFields("Linux", "aarch64"); assertThat(Environment.isUnix()).isTrue(); assertThat(Environment.isAarch64()).isTrue(); @@ -142,6 +196,19 @@ public class EnvironmentTest { assertThat(Environment.getJniLibraryFileName("rocksdb")) .isEqualTo("librocksdbjni-linux-aarch64.so"); assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so"); + // Linux musl-libc (Alpine) + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, true); + setEnvironmentClassFields("Linux", "aarch64"); + assertThat(Environment.isUnix()).isTrue(); + assertThat(Environment.isAarch64()).isTrue(); + assertThat(Environment.is64Bit()).isTrue(); + assertThat(Environment.getJniLibraryExtension()).isEqualTo(".so"); + assertThat(Environment.getSharedLibraryName("rocksdb")).isEqualTo("rocksdbjni"); + assertThat(Environment.getJniLibraryName("rocksdb")).isEqualTo("rocksdbjni-linux-aarch64-musl"); + assertThat(Environment.getJniLibraryFileName("rocksdb")) + .isEqualTo("librocksdbjni-linux-aarch64-musl.so"); + assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.so"); + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); } private void setEnvironmentClassFields(String osName, @@ -154,9 +221,10 @@ public class EnvironmentTest { public static void restoreState() { setEnvironmentClassField(OS_FIELD_NAME, INITIAL_OS); setEnvironmentClassField(ARCH_FIELD_NAME, INITIAL_ARCH); + setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, INITIAL_MUSL_LIBC); } - private static String getEnvironmentClassField(String fieldName) { + private static T getEnvironmentClassField(String fieldName) { final Field field; try { field = Environment.class.getDeclaredField(fieldName); @@ -164,13 +232,13 @@ public class EnvironmentTest { final Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); - return (String)field.get(null); + return (T)field.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } } - private static void setEnvironmentClassField(String fieldName, String value) { + private static void setEnvironmentClassField(String fieldName, Object value) { final Field field; try { field = Environment.class.getDeclaredField(fieldName);