Add shared library for musl-libc (#3143)

Summary:
Add the jni library for musl-libc, specifically for incorporating into Alpine based docker images. The classifier is `musl64`.

I have signed the CLA electronically.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/3143

Differential Revision: D18719372

fbshipit-source-id: 6189d149310b6436d6def7d808566b0234b23313
main
Patrick Double 5 years ago committed by Facebook Github Bot
parent d9314a9214
commit 8ae149eba1
  1. 39
      Makefile
  2. 25
      java/RELEASE.md
  3. 26
      java/crossbuild/Vagrantfile
  4. 70
      java/crossbuild/build-linux-alpine.sh
  5. 18
      java/crossbuild/docker-build-linux-alpine.sh
  6. 10
      java/crossbuild/docker-build-linux-centos.sh
  7. 2
      java/rocksjni.pom
  8. 43
      java/src/main/java/org/rocksdb/util/Environment.java
  9. 74
      java/src/test/java/org/rocksdb/util/EnvironmentTest.java

@ -1731,12 +1731,23 @@ else
ARCH := $(shell getconf LONG_BIT) ARCH := $(shell getconf LONG_BIT)
endif endif
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
ifneq ($(origin JNI_LIBC), undefined)
JNI_LIBC_POSTFIX = -$(JNI_LIBC)
endif
ifneq (,$(filter ppc% arm64 aarch64 sparc64, $(MACHINE))) ifneq (,$(filter ppc% arm64 aarch64 sparc64, $(MACHINE)))
ROCKSDBJNILIB = librocksdbjni-linux-$(MACHINE).so ROCKSDBJNILIB = librocksdbjni-linux-$(MACHINE)$(JNI_LIBC_POSTFIX).so
else else
ROCKSDBJNILIB = librocksdbjni-linux$(ARCH).so ROCKSDBJNILIB = librocksdbjni-linux$(ARCH)$(JNI_LIBC_POSTFIX).so
endif endif
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux$(ARCH).jar 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_JAR_ALL = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH).jar
ROCKSDB_JAVADOCS_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-javadoc.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 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 cd java/src/main/java;jar -cf ../../../target/$(ROCKSDB_SOURCES_JAR) org
rocksdbjavastaticrelease: rocksdbjavastatic 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;jar -cf target/$(ROCKSDB_JAR_ALL) HISTORY*.md
cd java/target;jar -uf $(ROCKSDB_JAR_ALL) librocksdbjni-*.so librocksdbjni-*.jnilib 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 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;jar -cf target/$(ROCKSDB_JAR_ALL) HISTORY*.md
cd java/target;jar -uf $(ROCKSDB_JAR_ALL) librocksdbjni-*.so librocksdbjni-*.jnilib 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 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 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 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 rocksdbjavastaticpublish: rocksdbjavastaticrelease rocksdbjavastaticpublishcentral
rocksdbjavastaticpublishdocker: rocksdbjavastaticreleasedocker 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)-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)-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)-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)-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)-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 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

@ -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: Building a cross-platform JAR requires:
* [Vagrant](https://www.vagrantup.com/) * [Docker](https://www.docker.com/docker-community)
* [Virtualbox](https://www.virtualbox.org/)
* A Mac OSX machine that can compile RocksDB. * A Mac OSX machine that can compile RocksDB.
* Java 7 set as JAVA_HOME. * Java 7 set as JAVA_HOME.
Once you have these items, run this make command from RocksDB's root source directory: 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: You can find all native binaries and JARs in the java/target directory upon completion:
librocksdbjni-linux32.so librocksdbjni-linux32.so
librocksdbjni-linux64.so librocksdbjni-linux64.so
librocksdbjni-linux64-musl.so
librocksdbjni-linux32-musl.so
librocksdbjni-osx.jnilib librocksdbjni-osx.jnilib
rocksdbjni-3.5.0-javadoc.jar rocksdbjni-x.y.z-javadoc.jar
rocksdbjni-3.5.0-linux32.jar rocksdbjni-x.y.z-linux32.jar
rocksdbjni-3.5.0-linux64.jar rocksdbjni-x.y.z-linux64.jar
rocksdbjni-3.5.0-osx.jar rocksdbjni-x.y.z-linux64-musl.jar
rocksdbjni-3.5.0-sources.jar rocksdbjni-x.y.z-linux32-musl.jar
rocksdbjni-3.5.0.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 ## Maven publication

@ -8,10 +8,28 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define "linux32" do |linux32| config.vm.define "linux32" do |linux32|
linux32.vm.box = "bento/centos-6.10-i386" linux32.vm.box = "bento/centos-6.10-i386"
linux32.vm.provision :shell, path: "build-linux-centos.sh"
end end
config.vm.define "linux64" do |linux64| config.vm.define "linux64" do |linux64|
linux64.vm.box = "bento/centos-6.10" 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 end
config.vm.provider "virtualbox" do |v| config.vm.provider "virtualbox" do |v|
@ -20,7 +38,13 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
v.customize ["modifyvm", :id, "--nictype1", "virtio" ] v.customize ["modifyvm", :id, "--nictype1", "virtio" ]
end 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 "../target", "/rocksdb-build"
config.vm.synced_folder "../..", "/rocksdb", type: "rsync" config.vm.synced_folder "../..", "/rocksdb", type: "rsync"
config.vm.boot_timeout = 1200 config.vm.boot_timeout = 1200

@ -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

@ -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

@ -14,19 +14,19 @@ cd /rocksdb-local-build
# Use scl devtoolset if available # Use scl devtoolset if available
if hash scl 2>/dev/null; then if hash scl 2>/dev/null; then
if scl --list | grep -q 'devtoolset-7'; then if scl --list | grep -q 'devtoolset-7'; then
# CentOS 7+ # CentOS 7+
scl enable devtoolset-7 'make clean-not-downloaded' scl enable devtoolset-7 'make clean-not-downloaded'
scl enable devtoolset-7 'PORTABLE=1 make -j2 rocksdbjavastatic' scl enable devtoolset-7 'PORTABLE=1 make -j2 rocksdbjavastatic'
elif scl --list | grep -q 'devtoolset-2'; then elif scl --list | grep -q 'devtoolset-2'; then
# CentOS 5 or 6 # CentOS 5 or 6
scl enable devtoolset-2 'make clean-not-downloaded' scl enable devtoolset-2 'make clean-not-downloaded'
scl enable devtoolset-2 'PORTABLE=1 make -j2 rocksdbjavastatic' scl enable devtoolset-2 'PORTABLE=1 make -j2 rocksdbjavastatic'
else else
echo "Could not find devtoolset" echo "Could not find devtoolset"
exit 1; exit 1;
fi fi
else else
make clean-not-downloaded make clean-not-downloaded
PORTABLE=1 make -j2 rocksdbjavastatic PORTABLE=1 make -j2 rocksdbjavastatic
fi fi

@ -10,7 +10,7 @@
<artifactId>rocksdbjni</artifactId> <artifactId>rocksdbjni</artifactId>
<!-- Version will be automatically replaced --> <!-- Version will be automatically replaced -->
<version>-</version> <version>-</version>
<description>RocksDB fat jar that contains .so files for linux32 and linux64, jnilib files <description>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. for Mac OSX, and a .dll for Windows x64.
</description> </description>
<licenses> <licenses>

@ -1,9 +1,22 @@
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
package org.rocksdb.util; package org.rocksdb.util;
import java.io.File;
import java.io.IOException;
public class Environment { public class Environment {
private static String OS = System.getProperty("os.name").toLowerCase(); private static String OS = System.getProperty("os.name").toLowerCase();
private static String ARCH = System.getProperty("os.arch").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() { public static boolean isAarch64() {
return ARCH.contains("aarch64"); return ARCH.contains("aarch64");
@ -38,6 +51,10 @@ public class Environment {
OS.contains("nux"); OS.contains("nux");
} }
public static boolean isMuslLibc() {
return MUSL_LIBC;
}
public static boolean isSolaris() { public static boolean isSolaris() {
return OS.contains("sunos"); return OS.contains("sunos");
} }
@ -61,15 +78,37 @@ public class Environment {
return appendLibOsSuffix("lib" + getSharedLibraryName(name), true); 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) { public static String getJniLibraryName(final String name) {
if (isUnix()) { if (isUnix()) {
final String arch = is64Bit() ? "64" : "32"; final String arch = is64Bit() ? "64" : "32";
if (isPowerPC() || isAarch64()) { if (isPowerPC() || isAarch64()) {
return String.format("%sjni-linux-%s", name, ARCH); return String.format("%sjni-linux-%s%s", name, ARCH, getLibcPostfix());
} else if (isS390x()) { } else if (isS390x()) {
return String.format("%sjni-linux%s", name, ARCH); return String.format("%sjni-linux%s", name, ARCH);
} else { } else {
return String.format("%sjni-linux%s", name, arch); return String.format("%sjni-linux%s%s", name, arch, getLibcPostfix());
} }
} else if (isMac()) { } else if (isMac()) {
return String.format("%sjni-osx", name); return String.format("%sjni-osx", name);

@ -16,14 +16,17 @@ import static org.assertj.core.api.Assertions.assertThat;
public class EnvironmentTest { public class EnvironmentTest {
private final static String ARCH_FIELD_NAME = "ARCH"; private final static String ARCH_FIELD_NAME = "ARCH";
private final static String OS_FIELD_NAME = "OS"; 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_OS;
private static String INITIAL_ARCH; private static String INITIAL_ARCH;
private static boolean INITIAL_MUSL_LIBC;
@BeforeClass @BeforeClass
public static void saveState() { public static void saveState() {
INITIAL_ARCH = getEnvironmentClassField(ARCH_FIELD_NAME); INITIAL_ARCH = getEnvironmentClassField(ARCH_FIELD_NAME);
INITIAL_OS = getEnvironmentClassField(OS_FIELD_NAME); INITIAL_OS = getEnvironmentClassField(OS_FIELD_NAME);
INITIAL_MUSL_LIBC = getEnvironmentClassField(MUSL_LIBC_FIELD_NAME);
} }
@Test @Test
@ -53,6 +56,7 @@ public class EnvironmentTest {
@Test @Test
public void nix32() { public void nix32() {
// Linux // Linux
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
setEnvironmentClassFields("Linux", "32"); setEnvironmentClassFields("Linux", "32");
assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.isWindows()).isFalse();
assertThat(Environment.getJniLibraryExtension()). assertThat(Environment.getJniLibraryExtension()).
@ -61,7 +65,17 @@ public class EnvironmentTest {
isEqualTo("librocksdbjni-linux32.so"); isEqualTo("librocksdbjni-linux32.so");
assertThat(Environment.getSharedLibraryFileName("rocksdb")). assertThat(Environment.getSharedLibraryFileName("rocksdb")).
isEqualTo("librocksdbjni.so"); 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 // UNIX
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
setEnvironmentClassFields("Unix", "32"); setEnvironmentClassFields("Unix", "32");
assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.isWindows()).isFalse();
assertThat(Environment.getJniLibraryExtension()). assertThat(Environment.getJniLibraryExtension()).
@ -84,6 +98,7 @@ public class EnvironmentTest {
@Test @Test
public void nix64() { public void nix64() {
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
setEnvironmentClassFields("Linux", "x64"); setEnvironmentClassFields("Linux", "x64");
assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.isWindows()).isFalse();
assertThat(Environment.getJniLibraryExtension()). assertThat(Environment.getJniLibraryExtension()).
@ -92,7 +107,17 @@ public class EnvironmentTest {
isEqualTo("librocksdbjni-linux64.so"); isEqualTo("librocksdbjni-linux64.so");
assertThat(Environment.getSharedLibraryFileName("rocksdb")). assertThat(Environment.getSharedLibraryFileName("rocksdb")).
isEqualTo("librocksdbjni.so"); 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 // UNIX
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
setEnvironmentClassFields("Unix", "x64"); setEnvironmentClassFields("Unix", "x64");
assertThat(Environment.isWindows()).isFalse(); assertThat(Environment.isWindows()).isFalse();
assertThat(Environment.getJniLibraryExtension()). assertThat(Environment.getJniLibraryExtension()).
@ -130,8 +155,37 @@ public class EnvironmentTest {
isEqualTo("librocksdbjni.dll"); 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 @Test
public void aarch64() { public void aarch64() {
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
setEnvironmentClassFields("Linux", "aarch64"); setEnvironmentClassFields("Linux", "aarch64");
assertThat(Environment.isUnix()).isTrue(); assertThat(Environment.isUnix()).isTrue();
assertThat(Environment.isAarch64()).isTrue(); assertThat(Environment.isAarch64()).isTrue();
@ -142,6 +196,19 @@ public class EnvironmentTest {
assertThat(Environment.getJniLibraryFileName("rocksdb")) assertThat(Environment.getJniLibraryFileName("rocksdb"))
.isEqualTo("librocksdbjni-linux-aarch64.so"); .isEqualTo("librocksdbjni-linux-aarch64.so");
assertThat(Environment.getSharedLibraryFileName("rocksdb")).isEqualTo("librocksdbjni.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, private void setEnvironmentClassFields(String osName,
@ -154,9 +221,10 @@ public class EnvironmentTest {
public static void restoreState() { public static void restoreState() {
setEnvironmentClassField(OS_FIELD_NAME, INITIAL_OS); setEnvironmentClassField(OS_FIELD_NAME, INITIAL_OS);
setEnvironmentClassField(ARCH_FIELD_NAME, INITIAL_ARCH); setEnvironmentClassField(ARCH_FIELD_NAME, INITIAL_ARCH);
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, INITIAL_MUSL_LIBC);
} }
private static String getEnvironmentClassField(String fieldName) { private static <T> T getEnvironmentClassField(String fieldName) {
final Field field; final Field field;
try { try {
field = Environment.class.getDeclaredField(fieldName); field = Environment.class.getDeclaredField(fieldName);
@ -164,13 +232,13 @@ public class EnvironmentTest {
final Field modifiersField = Field.class.getDeclaredField("modifiers"); final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true); modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
return (String)field.get(null); return (T)field.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) { } catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private static void setEnvironmentClassField(String fieldName, String value) { private static void setEnvironmentClassField(String fieldName, Object value) {
final Field field; final Field field;
try { try {
field = Environment.class.getDeclaredField(fieldName); field = Environment.class.getDeclaredField(fieldName);

Loading…
Cancel
Save