Improve musl libc detection and provide an option for the user to override (#10889)

Summary:
The user may override the detection of whether to use GNU libc (the default) or musl libc by setting the environment variable: `ROCKSDB_MUSL_LIBC=true`.

Builds upon and supersedes: https://github.com/facebook/rocksdb/pull/9977

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10889

Reviewed By: akankshamahajan15

Differential Revision: D40788431

Pulled By: ajkr

fbshipit-source-id: ef594d973fc14cbadf28bfb38434231a18a2107c
main
Adam Retter 2 years ago committed by Facebook GitHub Bot
parent 4a6906e28c
commit 781a387488
  1. 87
      java/src/main/java/org/rocksdb/util/Environment.java
  2. 30
      java/src/test/java/org/rocksdb/util/EnvironmentTest.java

@ -1,21 +1,20 @@
// 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; 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; private static String MUSL_ENVIRONMENT = System.getenv("ROCKSDB_MUSL_LIBC");
static { /**
try { * Will be lazily initialised by {@link #isMuslLibc()} instead of the previous static
final Process p = new ProcessBuilder("/usr/bin/env", "sh", "-c", "ldd /usr/bin/env | grep -q musl").start(); * initialisation. The lazy initialisation prevents Windows from reporting suspicious behaviour of
MUSL_LIBC = p.waitFor() == 0; * the JVM attempting IO on Unix paths.
} catch (final IOException | InterruptedException e) { */
MUSL_LIBC = false; private static Boolean MUSL_LIBC = null;
}
}
public static boolean isAarch64() { public static boolean isAarch64() {
return ARCH.contains("aarch64"); return ARCH.contains("aarch64");
@ -50,10 +49,80 @@ public class Environment {
OS.contains("nux"); OS.contains("nux");
} }
/**
* Determine if the environment has a musl libc.
*
* @return true if the environment has a musl libc, false otherwise.
*/
public static boolean isMuslLibc() { public static boolean isMuslLibc() {
if (MUSL_LIBC == null) {
MUSL_LIBC = initIsMuslLibc();
}
return MUSL_LIBC; return MUSL_LIBC;
} }
/**
* Determine if the environment has a musl libc.
*
* The initialisation counterpart of {@link #isMuslLibc()}.
*
* Intentionally package-private for testing.
*
* @return true if the environment has a musl libc, false otherwise.
*/
static boolean initIsMuslLibc() {
// consider explicit user setting from environment first
if ("true".equalsIgnoreCase(MUSL_ENVIRONMENT)) {
return true;
}
if ("false".equalsIgnoreCase(MUSL_ENVIRONMENT)) {
return false;
}
// check if ldd indicates a muslc lib
try {
final Process p =
new ProcessBuilder("/usr/bin/env", "sh", "-c", "ldd /usr/bin/env | grep -q musl").start();
if (p.waitFor() == 0) {
return true;
}
} catch (final IOException | InterruptedException e) {
// do nothing, and move on to the next check
}
final File lib = new File("/lib");
if (lib.exists() && lib.isDirectory() && lib.canRead()) {
// attempt the most likely musl libc name first
final String possibleMuslcLibName;
if (isPowerPC()) {
possibleMuslcLibName = "libc.musl-ppc64le.so.1";
} else if (isAarch64()) {
possibleMuslcLibName = "libc.musl-aarch64.so.1";
} else if (isS390x()) {
possibleMuslcLibName = "libc.musl-s390x.so.1";
} else {
possibleMuslcLibName = "libc.musl-x86_64.so.1";
}
final File possibleMuslcLib = new File(lib, possibleMuslcLibName);
if (possibleMuslcLib.exists() && possibleMuslcLib.canRead()) {
return true;
}
// fallback to scanning for a musl libc
final File[] libFiles = lib.listFiles();
if (libFiles == null) {
return false;
}
for (final File f : libFiles) {
if (f.getName().startsWith("libc.musl")) {
return true;
}
}
}
return false;
}
public static boolean isSolaris() { public static boolean isSolaris() {
return OS.contains("sunos"); return OS.contains("sunos");
} }

@ -4,28 +4,32 @@
// (found in the LICENSE.Apache file in the root directory). // (found in the LICENSE.Apache file in the root directory).
package org.rocksdb.util; package org.rocksdb.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.is;
import java.lang.reflect.Field;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.lang.reflect.Field;
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_ENVIRONMENT_FIELD_NAME = "MUSL_ENVIRONMENT";
private final static String MUSL_LIBC_FIELD_NAME = "MUSL_LIBC"; 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; private static String INITIAL_MUSL_ENVIRONMENT;
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); INITIAL_MUSL_LIBC = getEnvironmentClassField(MUSL_LIBC_FIELD_NAME);
INITIAL_MUSL_ENVIRONMENT = getEnvironmentClassField(MUSL_ENVIRONMENT_FIELD_NAME);
} }
@Test @Test
@ -236,6 +240,21 @@ public class EnvironmentTest {
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false); setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, false);
} }
@Test
public void resolveIsMuslLibc() {
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, null);
setEnvironmentClassFields("win", "anyarch");
assertThat(Environment.isUnix()).isFalse();
// with user input, will resolve to true if set as true. Even on OSs that appear absurd for
// musl. Users choice
assertThat(Environment.initIsMuslLibc()).isFalse();
setEnvironmentClassField(MUSL_ENVIRONMENT_FIELD_NAME, "true");
assertThat(Environment.initIsMuslLibc()).isTrue();
setEnvironmentClassField(MUSL_ENVIRONMENT_FIELD_NAME, "false");
assertThat(Environment.initIsMuslLibc()).isFalse();
}
private void setEnvironmentClassFields(String osName, private void setEnvironmentClassFields(String osName,
String osArch) { String osArch) {
setEnvironmentClassField(OS_FIELD_NAME, osName); setEnvironmentClassField(OS_FIELD_NAME, osName);
@ -246,6 +265,7 @@ 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_ENVIRONMENT_FIELD_NAME, INITIAL_MUSL_ENVIRONMENT);
setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, INITIAL_MUSL_LIBC); setEnvironmentClassField(MUSL_LIBC_FIELD_NAME, INITIAL_MUSL_LIBC);
} }

Loading…
Cancel
Save