package/openjdk: fix installation with merged usr directories
authorAdam Duskett <Aduskett@gmail.com>
Sat, 18 Apr 2020 19:06:59 +0000 (12:06 -0700)
committerYann E. MORIN <yann.morin.1998@free.fr>
Tue, 21 Apr 2020 21:17:18 +0000 (23:17 +0200)
commit3edb915709dec21158542b15e62f1560b8dc2fa2
tree812fc18ffc5cf4c5b6193e6635fc7252dbe7b257
parent1e5723ee589e8d205883c15ca863c01f94b8854f
package/openjdk: fix installation with merged usr directories

Currently, Buildroot installs the jre libraries using
cp -dprf /build/linux-*-release/images/jre/lib/* $(TARGET_DIR)/usr/lib/

However, if a system has a merged /usr directory, and there is a built kernel
before installing OpenJDK, the installation fails because jre/lib has binary
modules file, which causes the following error: cp: cannot overwrite directory
'/usr/lib/modules with non-directory

The obvious fix is to install the modules to /usr/lib/jvm/ and set the
appropriate rpaths via the --with-extra-ldflags conf option. However, this fix
does not work because the built binaries themselves do not link against
libjava.so

Indeed, running readelf on the built java binary reports the following:
"(RUNPATH) Library runpath: [/usr/lib/jvm]" and /usr/lib/jvm/libjava.so exists.
However, when running the Java binary on the target, the following error
occurs: "Error: could not find libjava.so."

The following is the result of "strace java" ran on the target:
faccessat(AT_FDCWD, "/usr/lib/libjava.so", F_OK) = -1 ENOENT
faccessat(AT_FDCWD, "/usr/jre/lib/libjava.so", F_OK) = -1 ENOENT
newfstatat(AT_FDCWD, "/usr/lib/libjava.so", 0x7ffe7b4af8, 0) = -1 ENOENT
newfstatat(AT_FDCWD, "/usr/lib/jvm/libjli.so", [sic] AT_SYMLINK_NOFOLLOW) = 0

As seen above, the java binary searches for libjli.so in /usr/lib/jvm,
which demonstrates that the java binary searches for some of the
DT_NEEDED libraries using the correct rpath. But libjava.so is not
searched from the rpath; it is instead dl-opened manually, looked for in
the search paths hardcoded to the following directories:
  - /usr/lib/
  - /usr/jre/lib/
  - $(dirname $0)/../lib/

The reason behind the hardcoded paths given by the maintainers is due to
historical purposes for the need to support several java versions at the
same time on a single system, and that changing the above behavior is not
likely to ever happen.

As such, most distributions such as Redhat do the following:
  - Create the directory /usr/lib/jvm/java-$(JAVA_VERSION)/
  - Install all directories and files found in images/jre to that directory.
  - Symlink the binaries to in /usr/lib/jvm/java-$(JAVA_VERSION)/bin to
    /usr/bin.

However, because Buildroot does not need to support multiple versions of java
concurrently, there is no need for the additional java-$(JAVA_VERSION)
directory.

To fix the above issue, the following changes are performed:
  - Introduce the variable "OPENJDK_INSTALL_BASE" which points to /usr/lib/jvm
  - Set the --with-extra-ldflags conf_opt to
      "-Wl,-rpath,$(OPENJDK_INSTALL_BASE)/lib,-rpath,
      $(OPENJDK_INSTALL_BASE)/lib/$(OPENJDK_JVM_VARIANT)"
  - Run "mkdir -p $(TARGET_DIR)/usr/lib/jvm/" in the INSTALL_TARGET_CMDS step.
  - Copy both the lib and bin directories to /usr/lib/jvm/
  - Symlink the binaries in /usr/lib/jvm/bin/ to /usr/bin.

Fixes: https://bugs.busybox.net/show_bug.cgi?id=12751
Signed-off-by: Adam Duskett <Aduskett@gmail.com>
Reviewed-by: Ryan Barnett <ryan.barnett@rockwellcollins.com>
Tested-by: Ryan Barnett <ryan.barnett@rockwellcollins.com>
[yann.morin.1998@free.fr: fix two remaining mis-placed '/']
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
package/openjdk/openjdk.mk