User:Aslantis/Cross compiling openjdk

From Gentoo Wiki
Jump to:navigation Jump to:search
Important
I really recommend you to read the following pages before proceeding: Official OpenJDK building documentation & Arthurzam's guide to boostrapping OpenJDK

This is a guide to cross compile openjdk to a new architecture or libc. First, make sure your architecture/OS combo is supported by openjdk and by the specific version of openjdk you're building (TODO: more on that). This guide will use openjdk-11 for sparc64/linux as an example. In fact, if you copy this guide verbatim, you should have a working sparc64 build \o/. You can follow this guide on any gentoo install that has easy access to a pre built jdk, but for this example I used a fresh amd64 stage3.

New guide

I have gotten wise since I first did this. I have a revised guide here. This guide makes heavy 100% use of gentoo-specific tools: If you found this somehow and aren't using gentoo, follow the old guide below, it uses less gentoo-isms. This new guide is also practically step by step instructions to reproduce the sparc64/linux build, so the old guide might be more helpful if you're not doing that :)

Basic setup

We will be using crossdev to install our cross compilation toolchains.

root #emerge dev-java/openjdk-bin:11 sys-devel/crossdev
root #crossdev -S -t sparc64-unknown-linux-gnu

This will install our cross compilation toolchains. Note that when building java normally, you can build with one lower version, but when cross compiling, try to have the build and target versions as close as possible. Note that you cannot compile a lower JDK, i.e, if you have JDK11, you cannot build JDK10.

Modifying the ebuild

The way the openjdk ebuild is written right now will require minor manual edits to the ebuild to work with crossdev's emerge tool.

Add to configure flags:

FILE ebuild
--openjdk-target=sparc64-unknown-linux-gnu
--disable-warnings-as-errors

I remembered having to remove a flag last time that caused it to attempt to rebuild itself, but as of right now I don't see it. Note I am on a machine without the storage required to build openjdk, so I can't ensure this works :[

Important
If it errors on is big endian... no(will be something else if your target and host are same endianness), there could be two causes. 1) you specified the wrong target. Supply the exact same tuple to --openjdk-target that you did to crossdev. 2) for some arcane reason, for JDK8, I have to set and export CC and CXX to the cross GCC and G++ respectively.

Compiling

root #sparc64-unknown-linux-gnu-emerge openjdk:11


Old guide

Basic setup

We will be using crossdev to install our cross compilation toolchains.

root #emerge dev-java/openjdk-bin:11 sys-devel/crossdev
root #crossdev -S -t sparc64-unknown-linux-gnu

This will install our cross compilation toolchains. Note that when building java normally, you can build with one lower version, but when cross compiling, try to have the build and target versions as close as possible. Note that you cannot compile a lower JDK, i.e, if you have JDK11, you cannot build JDK10.

Next, we clone the source. The most convenient way to get the same source gentoo's ebuilds use (including our patches!) is with the `ebuild` command.

root #ebuild /var/db/repos/gentoo/dev-java/openjdk/openjdk-11.0.15_p10-r1.ebuild prepare
root #cd /var/tmp/portage/dev-java/openjdk-11.0.15_p10-r1/work/jdk11u-jdk-11.0.15-ga/

TODO: use the proper env vars instead of default path

Another way to get the source is to clone the u repositories from github. For example, github.com/openjdk/jdk11u. However, it will save you from (potential!) hair loss if you just use ebuild prepare.

Starting the build

Like I said in the banner above, read the official documentation on cross compiling. I won't explain what I'm doing here, as you should take a look at that anyways. And remember, for your 'tuple', use the exact same string that you gave to crossdev above ;p

root #bash configure --openjdk-target=sparc64-unknown-linux-gnu --disable-warnings-as-errors
Important
If it errors on is big endian... no(will be something else if your target and host are same endianness), there could be two causes. 1) you specified the wrong target. Supply the exact same tuple to --openjdk-target that you did to crossdev. 2) for some arcane reason, for JDK8, I have to set and export CC and CXX to the cross GCC and G++ respectively.

I also recommend you to read the help page for additional options. For example, you can change c/c++ flags, or you can build a more bare bones JDK if you like. The less code you have to compile, the less chance to run into a build error ;). Not kidding btw: for example on JDK8 doing --disable-jfr resulted in a successful build!

root #bash configure --help

If it fails on configure, figure out why. Crossdev should have installed a full toolchain prefixed by your specified tuple. Try compiling a hello world with it, and see if it runs on the target.

Next, we're on to the exciting part! :D

root #make -j1

Debugging

Chances are, you are going to run into build failures. These should be minimized using the source provided by ebuild prepare: you will be working with a branch that gets backports upstream, in addition to any gentoo specific patches. But regardless, errors happen. Google is your friend. For this example of building openjdk-11 to sparc64, I did need to apply a patch from this bug: https://bugs.openjdk.org/browse/JDK-8230708

root #mv 9fba708740d6 sparcy.patch
root #patch -p1 <sparcy.patch

Both openjdk and other distributions likely have patches attached to their bugtrackers. If you need help, feel free to hop onto our IRC and we'll try our best :)

Installing

Ngl, I have no idea, but if you copy over the whole build/linux-sparcv9-normal-server-release folder to your target, everything seemed to work for JDK11. JDK8 has been a whole different beast. It would probably be smartest to run make install DESTDIR=/tmp/jdk and copy that to the target. I again need sleep.

For JDK8, I also needed rt.jar.

Using this to emerge the real deal

You can add the jdk/bin folder into your $PATH (make SURE to add it to the beginning of PATH). Set $JAVA_HOME to the location of jdk. Then, accept the keywords for openjdk (and its deps!). Note that this worked for me: your mileage may vary. For JDK8, I had to fiddle with the ebuild for a while.

Steps:

  • Install all the deps of openjdk EXCEPT eselect-java with --onlydeps
  • Run ebuild /path/of/openjdk/ebuild prepare
  • Re apply any patches you had to apply for the original bootstrap
  • Run ebuild /path/of/openjdk/ebuild install


That does not install it to the system, just a prefix. Check it out and see if it has any problems, before running ebuild merge :D

If it worked, emerge eselect-java.

Sending patches upstream

You have no idea how annoying this was. TLDR: to submit a patch, it has to be tied to a bug on the JBS (Jdk Bug System). You cannot open a bug on the JBS: Only registered java developers can. Want to report a bug?? Your best chance is in the OpenJDK mailing lists. To actually submit a patch for an unresolved bug, or backport a patch for a resolved bug to an earlier version of the JDK, here are the steps:

  • The right repo to send a PR in is <https://github.com/openjdk/jdk11u-dev/>. Replace the '11' with the JDK version you want.
  • You have to sign the OCA (Oracle Contributor Agreement). Yes, even if you're backporting an existing patch. This requires an Oracle account and can be done (here)[1].
  • They will make you re-send your PR if your PR is based off of the 'master' branch in your fork. Create a new branch named whatever you like.
  • The name of your bug must be the name of your bug number suffixed by the name of the bug in the JBS. Example: " 8230708: Hotspot fails to build on linux-sparc with gcc-9"
  • If backporting an existing patch, find the sha1 of the commit for that patch. What I did was clone openjdk/jdk and use this command: git log --all --grep='8230708'. Then rename your PR Backport then the sha1 of that commit.
  • You will need to sign an additional terms of service to comment on a PR (including your own).
  • Follow the instructions from the bot. You will need a sponsor to look-over your PR and merge it.

Hopefully everything goes well, I know this can be an irritating process, but keep with it!

//TODO: someone sent me a link I can't find that actually outlines this process. It is strangely hard to find.

Creating a bootstrap tarball

Now it should be easy to create a bootstrap tarball. If the bootstrap tarball is created before your patch is included in a new version of openjdk, you will have to replace the SRC_URI in the ebuild to one that has your patch applied. With github you can get a tarball for almost every commit, so this isn't too difficult.

Note
Make sure to change your C/C++ flags to remove -march/-mcpu! It is also probably a good idea to stick with -O2.

A full guide is located here. I will just outline the exact commands I used:

Final thoughts

I may have forgotten to document some steps I took, or link some resources I used. Regardless, I need sleep, will update eta soon. Ping me on IRC if you need any help :D