|
| 1 | +## Building OpenJDK |
| 2 | + |
| 3 | +### Intro |
| 4 | + |
| 5 | +The goal of this project is to provide a small enough Java runtime that |
| 6 | +would run on ev3dev on EV3. Currently OpenJDK is used for this. |
| 7 | +The reason is simple - it contains an Oracle-developed and then |
| 8 | +opensourced fast ARM32 JIT from JDK9 onwards. The second reason is that |
| 9 | +leJOS EV3 had used a similar JDK (Embedded JDK 7/8), but it was a |
| 10 | +proprietary offering prepared and not later updated by Oracle. |
| 11 | + |
| 12 | +### Build system |
| 13 | + |
| 14 | + |
| 15 | + |
| 16 | +To build the OpenJDK binaries in an environment suitable for |
| 17 | +cross-compilation for EV3, the repository is using a couple of Docker |
| 18 | +containers. They have two variants: `native` (ARM host -> ARM target) and |
| 19 | +`cross` (x86 host -> ARM target). The native builders have an advantage |
| 20 | +in that the JDK can be partially tested right on the build machine. |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | +The layers of the build environment are shown on the picture above. |
| 25 | +The lower docker container/image contains the target OS (Debian/ev3dev) |
| 26 | +with its libraries and compilers. This is done to ensure that the API |
| 27 | +provided by the system and its libraries are compatible between the build |
| 28 | +and target machines. |
| 29 | + |
| 30 | +On top of that, there resides a set of shell scripts which control the build. |
| 31 | +Their task is to download JDK and source-level dependencies and to build |
| 32 | +the JDK binaries with its build system. |
| 33 | + |
| 34 | +These two containers have to be built before the build of OpenJDK itself. |
| 35 | +Afterwards, the scripts in the upper container take over the rest of |
| 36 | +the build process. |
| 37 | + |
| 38 | +It should be notes that as the builds run in a container, it is |
| 39 | +necessary to mount a directory from the host to the container as |
| 40 | +a build workspace. This makes it possible to access the built binaries. |
| 41 | + |
| 42 | +### Build scripts |
| 43 | + |
| 44 | +Let's return back to the scripts. There are six build scripts in total: |
| 45 | + * `autobuild.sh` - This is the entrypoint for the build. |
| 46 | + It calls the last four scripts in succession |
| 47 | + if autobuild is enabled. Otherwise it just exits |
| 48 | + into shell. |
| 49 | + * `config.sh` |
| 50 | + - This script is `source`'d from the last four scripts. |
| 51 | + - It takes in the JDK version and other parameters from environment |
| 52 | + variables passed to the container and in turn it exports different |
| 53 | + environment variables to be used by other build scripts |
| 54 | + (like the JDK source URL). |
| 55 | + * `prepare.sh` - This script contains the *Prepare* phase. |
| 56 | + 1. It downloads and unpacks the Host JDK (needed for OpenJDK build) |
| 57 | + to a directory in the build workspace. This is then used to build |
| 58 | + the Java classes of the resulting JDK. |
| 59 | + 2. It also downloads JTreg, which is used when building included |
| 60 | + test cases (not currently run on Jenkins; but they can be run manually). |
| 61 | + * `fetch.sh` - This scripts contains the *Fetch* phase. |
| 62 | + 1. It determines the SCM parameters (commit hash, real version). |
| 63 | + From them, it generates a metadata file used to identify the build. |
| 64 | + Usually the latest GA release is picked. |
| 65 | + 2. It then has to download the OpenJDK source code. |
| 66 | + 3. It applies the patches stored in this repository. |
| 67 | + 4. It clones one extra repository - the AdoptOpenJDK |
| 68 | + [openjdk-build][bld] repository used for the CA certificates. |
| 69 | + * `build.sh` - This script is doing the *Build* phase. |
| 70 | + 1. It configures the JDK build using the `configure` script. |
| 71 | + 2. It runs the JDK build using `make`. |
| 72 | + - If the build is running on native (ARM) hardware, it also runs a |
| 73 | + bootcycle build, which uses the newly built JDK to build itself |
| 74 | + once more. This provides a basic level of testing. |
| 75 | + * `zip.sh` - This script finishes the build with the *Archiving* stage. |
| 76 | + 1. It generates the JRI (Java Runtime Image) for the EV3, |
| 77 | + which is basically a reduced Java runtime. |
| 78 | + 1. It then packs that and remaining build outputs (such as JMOD |
| 79 | + packages and the full JDK) into a tarball which is then uploaded |
| 80 | + as a build artifact. |
| 81 | + |
| 82 | +[bld]: https://github.com/adoptopenjdk/openjdk-build |
| 83 | + |
| 84 | + |
| 85 | + |
| 86 | +### Build parameters |
| 87 | + |
| 88 | +The build scripts accept a predefined set of environment variables |
| 89 | +describing the build. The parameters need to be passed in via Docker |
| 90 | +environment variables; see [Manual build](#manual-build) for an example. |
| 91 | + |
| 92 | + * `JDKVER` - sets the JDK version to build. |
| 93 | + - One of `11`, `12`, `13`, `tip`, `loom`. |
| 94 | + Numeric versions will usually build the latest tagged |
| 95 | + General-Availability releases; `tip` will build the latest commit. |
| 96 | + - *Note.* When a new JDK version is branched out for stabilization, |
| 97 | + then the latest non-GA tag must used, as there are no GA tags yet. |
| 98 | + * `JDKVM` - sets the JVM JIT to use. One of: |
| 99 | + - `zero`: portable non-assembler JIT/interpreter. |
| 100 | + It's quite slow, but it should always work. |
| 101 | + - `client`: fast ARM assembler-assisted JIT. |
| 102 | + - `minimal`: similar to `client`, but should be a bit smaller. |
| 103 | + Unfortunately, this configuration does not build |
| 104 | + successfully (the linking process will fail). |
| 105 | + * `JDKPLATFORM` - sets the platform for the build scripts. Only `ev3` is allowed. |
| 106 | + * `JDKDEBUG` - sets the JVM debug level. Optional. One of (from JDK source): |
| 107 | + - `release`: no debug information, all optimizations, no asserts. |
| 108 | + - `optimized`: no debug information, all optim., no asserts, HS tgt is 'optimized'. |
| 109 | + - `fastdebug`: debug information (-g), all optimizations, all asserts |
| 110 | + - `slowdebug`: debug information (-g), no optimizations, all asserts |
| 111 | + * `AUTOBUILD` - when set to `1` or `yes`, it runs the autorun.sh script |
| 112 | + directly instead of the shell. |
| 113 | + |
| 114 | +### Build outputs |
| 115 | + |
| 116 | +The output of the build process are three different archives: |
| 117 | + * `jmods-ev3.tar.gz` - contains Java JMODs. |
| 118 | + These are pieces of the JDK that can be assembled into a proper and |
| 119 | + useful JRE/JDK/JRI; see [here][jmod]. They are intended to be |
| 120 | + processed with the jlink tool provided with host-native Java JDK. |
| 121 | + * `jri-ev3.tar.gz` - EV3 JRI. |
| 122 | + This is a smaller version of traditional JRE. It is intended to be |
| 123 | + used as a Java runtime for the brick. It contains only a few Java |
| 124 | + modules in order to reduce its size. |
| 125 | + * `jdk-ev3.tar.gz` - Full EV3 JDK. This directory comes from the JDK |
| 126 | + build process; however, it is likely also built internally using jlink. |
| 127 | + This could be useful for someone who wants to do full Java |
| 128 | + development on the brick. |
| 129 | + |
| 130 | +[jmod]: https://www.developer.com/java/data/how-modules-are-packaged-in-java-9.html |
| 131 | + |
| 132 | +### Manual build |
| 133 | +You can run the build OpenJDK on your own computer too. This script should do that: |
| 134 | + |
| 135 | +```sh |
| 136 | +# define parameters |
| 137 | +TARGET_WORKSPACE="$(pwd)/build" # 10 GB of free space should be sufficient |
| 138 | +TARGET_DEBIAN_VERSION="stretch" # stretch or buster |
| 139 | +TARGET_OPENJDK_VERSION="11" # 11, 12, 13, tip, loom are on Jenkins |
| 140 | + |
| 141 | +# clone repository |
| 142 | +git clone https://github.com/ev3dev-lang-java/openjdk-ev3.git |
| 143 | +cd openjdk-ev3 |
| 144 | + |
| 145 | +# prepare working directory |
| 146 | +mkdir -p "$TARGET_WORKSPACE" |
| 147 | +chmod -R 777 "$TARGET_WORKSPACE" # docker may not share UID with the current user |
| 148 | + |
| 149 | +# build base system container |
| 150 | +docker build --build-arg DEBIAN_RELEASE="$TARGET_DEBIAN_VERSION" \ |
| 151 | + --build-arg ARCH="armel" \ |
| 152 | + --tag "ev3dev-lang-java:jdk-cross-$TARGET_DEBIAN_VERSION" \ |
| 153 | + --file ./system/Dockerfile.cross \ |
| 154 | + ./system |
| 155 | + |
| 156 | +# on top of that, create a build scripts container |
| 157 | +docker build --build-arg commit="$(git rev-parse HEAD)" \ |
| 158 | + --build-arg extra="Manual build #1 by $(whoami)" \ |
| 159 | + --build-arg DEBIAN_RELEASE="$TARGET_DEBIAN_VERSION" \ |
| 160 | + --build-arg BUILD_TYPE="cross" \ |
| 161 | + --tag "ev3dev-lang-java:jdk-cross-build" \ |
| 162 | + ./scripts |
| 163 | + |
| 164 | +# now run the build |
| 165 | +docker run --rm \ |
| 166 | + --interactive \ |
| 167 | + --tty \ |
| 168 | + --volume "$TARGET_WORKSPACE:/build" \ |
| 169 | + --env JDKVER="$TARGET_OPENJDK_VERSION" \ |
| 170 | + --env JDKVM="client" \ |
| 171 | + --env JDKPLATFORM="ev3" \ |
| 172 | + --env JDKDEBUG="release" \ |
| 173 | + --env AUTOBUILD="1" \ |
| 174 | + ev3dev-lang-java:jdk-cross-build |
| 175 | + |
| 176 | +# finally, make workspace accessible for all users (i.e. current one too) |
| 177 | +chmod -R 777 "$TARGET_WORKSPACE" |
| 178 | +# and list the output directory (now it should contain three *-ev3.tar.gz files) |
| 179 | +ls "$TARGET_WORKSPACE" |
| 180 | +``` |
| 181 | + |
| 182 | +See [issue #34][manual_build]. |
| 183 | + |
| 184 | +[manual_build]: https://github.com/ev3dev-lang-java/openjdk-ev3/issues/34 |
0 commit comments