ayaports/unmaintained/openjdk14/build.patch

515 lines
18 KiB
Diff
Raw Permalink Normal View History

2021-07-14 03:56:39 +00:00
Subject: Fix compilation issues with musl libc
Upstream: No
Author: The portola team at https://openjdk.java.net/projects/portola/
With modifications by Simon Frankenberger <simon-alpine@fraho.eu>
This giant patch makes it possible to compile openjdk with musl libc.
The base was taken from a diff with the portola project and adjusted for latest musl libc.
--- old/make/ReleaseFile.gmk
+++ new/make/ReleaseFile.gmk
@@ -53,6 +53,7 @@
$(call info-file-item, "JAVA_VERSION_DATE", "$(VERSION_DATE)")
$(call info-file-item, "OS_NAME", "$(RELEASE_FILE_OS_NAME)")
$(call info-file-item, "OS_ARCH", "$(RELEASE_FILE_OS_ARCH)")
+ $(call info-file-item, "LIBC", "musl")
endef
# Param 1 - The file containing the MODULES list
--- old/make/hotspot/lib/CompileJvm.gmk
+++ new/make/hotspot/lib/CompileJvm.gmk
@@ -73,6 +73,7 @@
-DHOTSPOT_BUILD_USER='"$(USERNAME)"' \
-DHOTSPOT_VM_DISTRO='"$(HOTSPOT_VM_DISTRO)"' \
-DCPU='"$(OPENJDK_TARGET_CPU_VM_VERSION)"' \
+ -DLIBC='"musl"' \
#
################################################################################
--- old/make/lib/CoreLibraries.gmk
+++ new/make/lib/CoreLibraries.gmk
@@ -190,6 +190,7 @@
endif
LIBJLI_CFLAGS += $(LIBZ_CFLAGS)
+LIBJLI_CFLAGS += -DLIBC=\"musl\"
ifneq ($(USE_EXTERNAL_LIBZ), true)
LIBJLI_EXTRA_FILES += \
--- old/src/hotspot/os/linux/os_linux.cpp
+++ new/src/hotspot/os/linux/os_linux.cpp
@@ -102,7 +102,6 @@
# include <string.h>
# include <syscall.h>
# include <sys/sysinfo.h>
-# include <gnu/libc-version.h>
# include <sys/ipc.h>
# include <sys/shm.h>
# include <link.h>
@@ -597,6 +596,11 @@
// detecting pthread library
void os::Linux::libpthread_init() {
+#if !defined(__GLIBC__) && !defined(__UCLIBC__)
+ // Hard code Alpine Linux supported musl compatible settings
+ os::Linux::set_glibc_version("glibc 2.9");
+ os::Linux::set_libpthread_version("NPTL");
+#else
// Save glibc and pthread version strings.
#if !defined(_CS_GNU_LIBC_VERSION) || \
!defined(_CS_GNU_LIBPTHREAD_VERSION)
@@ -614,6 +618,7 @@
str = (char *)malloc(n, mtInternal);
confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
os::Linux::set_libpthread_version(str);
+#endif
}
/////////////////////////////////////////////////////////////////////////////
@@ -3117,20 +3122,36 @@
extern "C" JNIEXPORT void numa_warn(int number, char *where, ...) { }
extern "C" JNIEXPORT void numa_error(char *where) { }
+static void* dlvsym_if_available(void* handle, const char* name, const char* version) {
+ typedef void* (*dlvsym_func_type)(void* handle, const char* name, const char* version);
+ static dlvsym_func_type dlvsym_func;
+ static bool initialized = false;
+
+ if (!initialized) {
+ dlvsym_func = (dlvsym_func_type)dlsym(RTLD_NEXT, "dlvsym");
+ initialized = true;
+ }
+
+ if (dlvsym_func != NULL) {
+ void *f = dlvsym_func(handle, name, version);
+ if (f != NULL) {
+ return f;
+ }
+ }
+
+ return dlsym(handle, name);
+}
+
// Handle request to load libnuma symbol version 1.1 (API v1). If it fails
// load symbol from base version instead.
void* os::Linux::libnuma_dlsym(void* handle, const char *name) {
- void *f = dlvsym(handle, name, "libnuma_1.1");
- if (f == NULL) {
- f = dlsym(handle, name);
- }
- return f;
+ return dlvsym_if_available(handle, name, "libnuma_1.1");
}
// Handle request to load libnuma symbol version 1.2 (API v2) only.
// Return NULL if the symbol is not defined in this particular version.
void* os::Linux::libnuma_v2_dlsym(void* handle, const char* name) {
- return dlvsym(handle, name, "libnuma_1.2");
+ return dlvsym_if_available(handle, name, "libnuma_1.2");
}
bool os::Linux::libnuma_init() {
--- old/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
+++ new/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
@@ -75,9 +75,6 @@
# include <pwd.h>
# include <poll.h>
# include <ucontext.h>
-#ifndef AMD64
-# include <fpu_control.h>
-#endif
#ifdef AMD64
#define REG_SP REG_RSP
--- old/src/hotspot/share/gc/shared/genCollectedHeap.cpp
+++ new/src/hotspot/share/gc/shared/genCollectedHeap.cpp
@@ -1116,7 +1116,7 @@
static ScratchBlock *removeSmallestScratch(ScratchBlock **prev_ptr) {
bool first = true;
size_t min_size = 0; // "first" makes this conceptually infinite.
- ScratchBlock **smallest_ptr, *smallest;
+ ScratchBlock **smallest_ptr = NULL, *smallest;
ScratchBlock *cur = *prev_ptr;
while (cur) {
assert(*prev_ptr == cur, "just checking");
--- old/src/hotspot/share/utilities/globalDefinitions_gcc.hpp
+++ new/src/hotspot/share/utilities/globalDefinitions_gcc.hpp
@@ -204,7 +204,7 @@
#elif defined(__APPLE__)
inline int g_isnan(double f) { return isnan(f); }
#elif defined(LINUX) || defined(_ALLBSD_SOURCE)
-inline int g_isnan(float f) { return isnanf(f); }
+inline int g_isnan(float f) { return isnan(f); }
inline int g_isnan(double f) { return isnan(f); }
#else
#error "missing platform-specific definition here"
--- old/src/java.base/linux/native/libnet/linux_close.c
+++ new/src/java.base/linux/native/libnet/linux_close.c
@@ -60,7 +60,7 @@
/*
* Signal to unblock thread
*/
-static int sigWakeup = (__SIGRTMAX - 2);
+static int sigWakeup;
/*
* fdTable holds one entry per file descriptor, up to a certain
@@ -149,6 +149,7 @@
/*
* Setup the signal handler
*/
+ sigWakeup = SIGRTMAX - 2;
sa.sa_handler = sig_wakeup;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
--- old/src/java.base/unix/native/libjava/childproc.c
+++ new/src/java.base/unix/native/libjava/childproc.c
@@ -235,7 +235,13 @@
{
if (envp == NULL || (char **) envp == environ) {
execvp(file, (char **) argv);
- return;
+ // ENOEXEC indicates that the file header was not recognized. The musl C
+ // library does not implement the fallback to /bin/sh for that case, so fall
+ // through to the code below which implements that fallback using
+ // execve_with_shell_fallback.
+ if (errno != ENOEXEC) {
+ return;
+ }
}
if (*file == '\0') {
--- old/src/java.base/unix/native/libjava/jdk_util_md.h
+++ new/src/java.base/unix/native/libjava/jdk_util_md.h
@@ -37,7 +37,7 @@
#define ISNAND(d) isnan(d)
#elif defined(__linux__) || defined(_ALLBSD_SOURCE)
#include <math.h>
-#define ISNANF(f) isnanf(f)
+#define ISNANF(f) isnan(f)
#define ISNAND(d) isnan(d)
#elif defined(_AIX)
#include <math.h>
--- old/src/java.base/unix/native/libjli/java_md_solinux.c
+++ new/src/java.base/unix/native/libjli/java_md_solinux.c
@@ -236,6 +236,39 @@
char *dmllp = NULL;
char *p; /* a utility pointer */
+#ifdef __linux
+#ifndef LIBC
+#error "LIBC not set"
+#endif
+
+ if (strcmp(LIBC, "musl") == 0) {
+ /*
+ * The musl library loader requires LD_LIBRARY_PATH to be set in
+ * order to correctly resolve the dependency libjava.so has on libjvm.so.
+ *
+ * Specifically, it differs from glibc in the sense that even if
+ * libjvm.so has already been loaded it will not be considered a
+ * candidate for resolving the dependency unless the *full* path
+ * of the already loaded library matches the dependency being loaded.
+ *
+ * libjvm.so is being loaded by the launcher using a long path to
+ * dlopen, not just the basename of the library. Typically this
+ * is something like "../lib/server/libjvm.so". However, if/when
+ * libjvm.so later tries to dlopen libjava.so (which it does in
+ * order to get access to a few functions implemented in
+ * libjava.so) the musl loader will, as part of loading
+ * dependent libraries, try to load libjvm.so using only its
+ * basename "libjvm.so". Since this does not match the longer
+ * path path it was first loaded with, the already loaded
+ * library is not considered a candidate, and the loader will
+ * instead look for libjvm.so elsewhere. If it's not in
+ * LD_LIBRARY_PATH the dependency load will fail, and libjava.so
+ * will therefore fail as well.
+ */
+ return JNI_TRUE;
+ }
+#endif
+
#ifdef AIX
/* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */
return JNI_TRUE;
--- old/src/java.base/unix/native/libnio/ch/NativeThread.c
+++ new/src/java.base/unix/native/libnio/ch/NativeThread.c
@@ -36,7 +36,7 @@
#ifdef __linux__
#include <pthread.h>
/* Also defined in net/linux_close.c */
- #define INTERRUPT_SIGNAL (__SIGRTMAX - 2)
+ #define INTERRUPT_SIGNAL (SIGRTMAX - 2)
#elif defined(_AIX)
#include <pthread.h>
/* Also defined in net/aix_close.c */
--- old/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c
+++ new/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c
@@ -27,9 +27,6 @@
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
-#ifdef __linux__
-#include <execinfo.h>
-#endif
#include <jvm.h>
#include <jni.h>
@@ -779,26 +776,6 @@
}
return ret;
}
-
-#ifdef __linux__
-void print_stack(void)
-{
- void *array[10];
- size_t size;
- char **strings;
- size_t i;
-
- size = backtrace (array, 10);
- strings = backtrace_symbols (array, size);
-
- fprintf (stderr, "Obtained %zd stack frames.\n", size);
-
- for (i = 0; i < size; i++)
- fprintf (stderr, "%s\n", strings[i]);
-
- free (strings);
-}
-#endif
Window get_xawt_root_shell(JNIEnv *env) {
static jclass classXRootWindow = NULL;
--- old/src/jdk.jdwp.agent/share/native/libjdwp/util.h
+++ new/src/jdk.jdwp.agent/share/native/libjdwp/util.h
@@ -35,15 +35,15 @@
#ifdef DEBUG
/* Just to make sure these interfaces are not used here. */
#undef free
- #define free(p) Do not use this interface.
+ #define free do_not_use_this_interface_free
#undef malloc
- #define malloc(p) Do not use this interface.
+ #define malloc do_not_use_this_interface_malloc
#undef calloc
- #define calloc(p) Do not use this interface.
+ #define calloc do_not_use_this_interface_calloc
#undef realloc
- #define realloc(p) Do not use this interface.
+ #define realloc do_not_use_this_interface_realloc
#undef strdup
- #define strdup(p) Do not use this interface.
+ #define strdup do_not_use_this_interface_strdup
#endif
#include "log_messages.h"
--- old/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c
+++ new/test/hotspot/jtreg/runtime/StackGuardPages/exeinvoke.c
@@ -33,6 +33,7 @@
#include <assert.h>
#include <jni.h>
+#include <jvm.h>
#include <alloca.h>
#include <signal.h>
#include <string.h>
@@ -91,6 +92,20 @@
}
}
+int get_java_stacksize () {
+ size_t stacksize;
+ pthread_attr_t attr;
+ JDK1_1InitArgs jdk_args;
+
+ jdk_args.version = JNI_VERSION_1_1;
+ JNI_GetDefaultJavaVMInitArgs(&jdk_args);
+ if (jdk_args.javaStackSize <= 0) {
+ fprintf(stderr, "Test ERROR. Can't get a valid value for the default stacksize.\n");
+ exit(7);
+ }
+ return jdk_args.javaStackSize;
+}
+
void *run_java_overflow (void *p) {
JNIEnv *env;
jclass class_id;
@@ -258,13 +273,19 @@
exit(7);
}
+ int stack_size = get_java_stacksize();
pthread_t thr;
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setstacksize(&thread_attr, stack_size);
+
if (argc > 1 && strcmp(argv[1], "test_java_overflow") == 0) {
printf("\nTesting JAVA_OVERFLOW\n");
printf("Testing stack guard page behaviour for other thread\n");
- pthread_create (&thr, NULL, run_java_overflow, NULL);
+
+ pthread_create (&thr, &thread_attr, run_java_overflow, NULL);
pthread_join (thr, NULL);
printf("Testing stack guard page behaviour for initial thread\n");
@@ -277,7 +298,7 @@
printf("\nTesting NATIVE_OVERFLOW\n");
printf("Testing stack guard page behaviour for other thread\n");
- pthread_create (&thr, NULL, run_native_overflow, NULL);
+ pthread_create (&thr, &thread_attr, run_native_overflow, NULL);
pthread_join (thr, NULL);
printf("Testing stack guard page behaviour for initial thread\n");
--- old/test/jdk/java/lang/ProcessBuilder/Basic.java
+++ new/test/jdk/java/lang/ProcessBuilder/Basic.java
@@ -396,8 +396,8 @@
if (failed != 0) throw new Error("null PATH");
} else if (action.equals("PATH search algorithm")) {
equal(System.getenv("PATH"), "dir1:dir2:");
- check(new File("/bin/true").exists());
- check(new File("/bin/false").exists());
+ check(new File(TrueExe.path()).exists());
+ check(new File(FalseExe.path()).exists());
String[] cmd = {"prog"};
ProcessBuilder pb1 = new ProcessBuilder(cmd);
ProcessBuilder pb2 = new ProcessBuilder(cmd);
@@ -438,13 +438,13 @@
checkPermissionDenied(pb);
// continue searching if EACCES
- copy("/bin/true", "dir2/prog");
+ copy(TrueExe.path(), "dir2/prog");
equal(run(pb).exitValue(), True.exitValue());
new File("dir1/prog").delete();
new File("dir2/prog").delete();
new File("dir2/prog").mkdirs();
- copy("/bin/true", "dir1/prog");
+ copy(TrueExe.path(), "dir1/prog");
equal(run(pb).exitValue(), True.exitValue());
// Check empty PATH component means current directory.
@@ -460,10 +460,10 @@
pb.command(command);
File prog = new File("./prog");
// "Normal" binaries
- copy("/bin/true", "./prog");
+ copy(TrueExe.path(), "./prog");
equal(run(pb).exitValue(),
True.exitValue());
- copy("/bin/false", "./prog");
+ copy(FalseExe.path(), "./prog");
equal(run(pb).exitValue(),
False.exitValue());
prog.delete();
@@ -518,12 +518,12 @@
new File("dir2/prog").delete();
new File("prog").delete();
new File("dir3").mkdirs();
- copy("/bin/true", "dir1/prog");
- copy("/bin/false", "dir3/prog");
+ copy(TrueExe.path(), "dir1/prog");
+ copy(FalseExe.path(), "dir3/prog");
pb.environment().put("PATH","dir3");
equal(run(pb).exitValue(), True.exitValue());
- copy("/bin/true", "dir3/prog");
- copy("/bin/false", "dir1/prog");
+ copy(TrueExe.path(), "dir3/prog");
+ copy(FalseExe.path(), "dir1/prog");
equal(run(pb).exitValue(), False.exitValue());
} finally {
@@ -620,6 +620,13 @@
new File("/bin/false").exists());
}
+ static class BusyBox {
+ public static boolean is() { return is; }
+ private static final boolean is =
+ (! Windows.is() &&
+ new File("/bin/busybox").exists());
+ }
+
static class UnicodeOS {
public static boolean is() { return is; }
private static final String osName = System.getProperty("os.name");
@@ -658,6 +665,45 @@
}
}
+ // On alpine linux, /bin/true and /bin/false are just links to /bin/busybox.
+ // Some tests copy /bin/true and /bin/false to files with a different filename.
+ // However, copying the busbox executable into a file with a different name
+ // won't result in the expected return codes. As workaround, we create
+ // executable files that can be copied and produce the exepected return
+ // values. We use this workaround, if we find the busybox executable.
+
+ private static class TrueExe {
+ public static String path() { return path; }
+ private static final String path = path0();
+ private static String path0(){
+ if (!BusyBox.is()) {
+ return "/bin/true";
+ }
+ else {
+ File trueExe = new File("true");
+ setFileContents(trueExe, "#!/bin/true\n");
+ trueExe.setExecutable(true);
+ return trueExe.getAbsolutePath();
+ }
+ }
+ }
+
+ private static class FalseExe {
+ public static String path() { return path; }
+ private static final String path = path0();
+ private static String path0(){
+ if (!BusyBox.is()) {
+ return "/bin/false";
+ }
+ else {
+ File falseExe = new File("false");
+ setFileContents(falseExe, "#!/bin/false\n");
+ falseExe.setExecutable(true);
+ return falseExe.getAbsolutePath();
+ }
+ }
+ }
+
static class EnglishUnix {
private static final Boolean is =
(! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
@@ -1961,7 +2007,7 @@
//----------------------------------------------------------------
try {
new File("suBdiR").mkdirs();
- copy("/bin/true", "suBdiR/unliKely");
+ copy(TrueExe.path(), "suBdiR/unliKely");
final ProcessBuilder pb =
new ProcessBuilder(new String[]{"unliKely"});
pb.environment().put("PATH", "suBdiR");
--- old/test/jdk/java/lang/ProcessHandle/InfoTest.java
+++ new/test/jdk/java/lang/ProcessHandle/InfoTest.java
@@ -298,7 +298,14 @@
}
if (info.command().isPresent()) {
String command = info.command().get();
- String expected = Platform.isWindows() ? "sleep.exe" : "sleep";
+ String expected = "sleep";
+ if (Platform.isWindows()) {
+ expected = "sleep.exe";
+ } else if (new File("/bin/busybox").exists()) {
+ // With busybox sleep is just a sym link to busybox.
+ // The busbox executable is seen as ProcessHandle.Info command.
+ expected = "busybox";
+ }
Assert.assertTrue(command.endsWith(expected), "Command: expected: \'" +
expected + "\', actual: " + command);