Introduction to OpenJDK and IcedTea
IcedTea provides a build harness
for the OpenJDK package, Oracle's
open-sourced Java development
environment. In order to provide a completely free runtime
environment, similar to Oracle's closed distribution, the
IcedTea build harness also
provides free, and arguably better versions of parts of the JDK
which have not been open-sourced to date. OpenJDK is useful for developing Java programs and provides a complete runtime
environment to run Java programs.
This package is known to build and work properly using an LFS-7.6
platform.
Note
The browser plugin and webstart implementation have been split
off into a separate project. To provide a complete
implementation, you will need to later install IcedTea-Web-1.5.1.
OpenJDK is GPL'd code, however, it should be explained that there
has been a special exception made for non-free projects to use
these classes in their proprietary products. In similar fashion to
the LGPL, which allows non-free programs to link to libraries
provided by free software, the GNU General Public
License, version 2, with the Classpath Exception allows third
party programs to use classes provided by free software without the
requirement that the third party software also be free. As with the
LGPL, any modifications made to the free software portions of a
third party application, must also be made freely available.
Note
The IcedTea build environment includes a very thorough, open
source test suite titled JTreg.
JTreg is intended to test the
just built JDK for reasonable compatibility with the closed
Oracle JDK. However, in order for an independent implementation
to claim compatibility, including the Oracle sponsored
OpenJDK project, it must pass a
closed JCK/TCK test suite. No
claims of compatibility, even partial compatibility, may be made
without passing an approved test suite.
Oracle does provide free community access, on a case by case
basis, to a closed toolkit to ensure 100% compatibility with its
proprietary JDK. The binary version provided here has not been
tested against the
TCK. Any version that is built using the instructions given,
cannot claim to be compatible with the proprietary JDK, without
the user applying for, and completing the compatibility tests
themselves.
With that in mind, the binaries produced using this build method
are regularly tested against the TCK by the members listed on the
site above. In addition to the community license above, an
educational, non-commercial license for the TCK can be obtained
from here.
Source Package Information
The following may be downladed separately or be done as a part of
the make process. For
convenience the BLFS editors have made the files available in an
LFS website. The files are not distributed with versions, but
extracted from the OpenJDK version control system at specified
(tagged) points.
Additional Downloads
Required Patches
Required JAR
Optional package (to obtain an icon for the openjdk-7-policytool.desktop
file)
OpenJDK Dependencies
Required Dependencies
An existing binary ( Java-1.7.0.65 or an earlier built version of
this package), alsa-lib-1.0.28, apache-ant-1.9.4,
Certificate Authority
Certificates, cpio-2.11, Cups-1.7.5, GTK+-2.24.24, giflib-5.1.0,
UnZip-6.0,
Wget-1.15, Which-2.20, Xorg Libraries, and
Zip-3.0
Recommended
JUnit-4.11
and NSS-3.17
Optional
libxslt-1.1.28, lsb_release-1.4, Mercurial-3.1.1,
MIT Kerberos V5-1.12.2, and Xorg-Server-1.16.0 (for the tests)
User Notes: http://wiki.linuxfromscratch.org/blfs/wiki/openjdk
Installation of OpenJDK
Note
The source build of OpenJDK requires apache-ant-1.9.4.
You'll need to build that first to satisfy the circular
dependency, and return to this section to continue building
OpenJDK.
Unlike other packages in BLFS, the OpenJDK source packages are distributed in
multiple downloads. Since the IcedTea build harness will be used to
build OpenJDK, begin by extracting
the IcedTea package and changing into the extracted directory.
The IcedTea OpenJDK distribution
requires that js.jar
(from the Rhino
package) be in place in order to provide a java-script
implementation for the free JDK. If you have not installed the
js.jar file in another way, do so with the following commands as
the root
user:
unzip ../rhino1_7R4.zip &&
install -v -d -m755 /usr/share/java &&
install -v -m755 rhino1_7R4/*.jar /usr/share/java
As mentioned previously, OpenJDK
is composed of several individual projects of the proprietary
JDK that have been relicensed
under an open source license. If you have already downloaded all of
the individual components, place them into the source tree with the
following commands:
cp -v ../corba.tar.bz2 . &&
cp -v ../hotspot.tar.bz2 . &&
cp -v ../jaxp.tar.bz2 . &&
cp -v ../jaxws.tar.bz2 . &&
cp -v ../jdk.tar.bz2 . &&
cp -v ../langtools.tar.bz2 . &&
cp -v ../openjdk.tar.bz2 .
Apply a patch to generate a valid cacerts file using the system CA
certificates:
patch -Np1 -i ../icedtea-2.5.2-add_cacerts-1.patch
Apply a patch to replace fixed paths with ones appropriate for
BLFS:
patch -Np1 -i ../icedtea-2.5.2-fixed_paths-1.patch
Apply a patch to adapt the code to the new giflib API:
patch -Np1 -i ../icedtea-2.5.2-fix_new_giflib-1.patch
Apply a patch to exclude known broken tests from the test suite:
patch -Np1 -i ../icedtea-2.5.2-fix_tests-1.patch
Note
Before proceeding, you should ensure that your environment is
properly set for building OpenJDK. First, review the content of the
ANT_HOME
variable. Second, the
PATH
variable should contain the paths
to the java and
ant executables.
Last, the CLASSPATH
variable should be
set as explained on the Java-1.7.0.65 and JUnit-4.11 pages.
Configure and build the package with the following commands
(--with-pkgversion and --with-version-suffix values can be modified
to fit user preferences):
unset JAVA_HOME &&
./autogen.sh &&
./configure --with-jdk-home=/opt/OpenJDK-1.7.0.65-bin \
--with-version-suffix=BLFS \
--enable-nss \
--disable-system-kerberos \
--with-parallel-jobs &&
make
Note
If you have not installed the tarballs specified above, they will
be automatically downloaded here.
To test the results, issue: make
jtregcheck. The included version of jtreg is old, and the test suite is also very
dependent on the host system and the environment that it is run in.
You should expect to see anywhere between 40 and 100 failures in
jdk with up to 10 errors in the tests themselves. The majority of
the 6000+ tests should pass. The reason for the greatly varying
results is due to how stringent the testing environment must be.
Varying architectures, different versions of dependent libraries,
unexpected X Window environment and window managers, the CA
certificates used to generate the cacerts
file, and even any user input or power
management or screen saver interruptions during the testing can
lead to various failures. While the known broken tests have been
removed, with the fix_tests patch above, the graphics tests
failures cannot be pre-determined (short of removing them all). The
best bet for the minimal number of failures is to run the test
suite in a framebuffer on a different screen (Xvfb). Even still,
disk I/O can cause failures.
export DISPLAY=:20 &&
Xvfb :20 -screen 0 1x1x24 -ac&
echo $!> Xvfb.pid &&
make -k jtregcheck &&
kill -9 `cat Xvfb.pid` &&
unset DISPLAY &&
rm -f Xvfb.pid
Install the package with the following commands as the root
user:
chmod 0644 openjdk.build/j2sdk-image/lib/sa-jdi.jar &&
cp -R openjdk.build/j2sdk-image /opt/OpenJDK-1.7.0.65 &&
chown -R root:root /opt/OpenJDK-1.7.0.65
If desired, you may install a .desktop file corresponding to an
entry in a desktop menu for policytool. First, you need to
obtain an icon from IcedTea-Web-1.5.1:
tar -xf ../icedtea-web-1.5.1.tar.gz \
icedtea-web-1.5.1/javaws.png \
--strip-components=1
Now, as root
user:
mkdir -pv /usr/share/applications &&
cat > /usr/share/applications/openjdk-7-policytool.desktop << "EOF" &&
[Desktop Entry]
Name=OpenJDK Java 7 Policy Tool
Name[pt_BR]=OpenJDK Java 7 - Ferramenta de Política
Comment=OpenJDK Java 7 Policy Tool
Comment[pt_BR]=OpenJDK Java 7 - Ferramenta de Política
Exec=/opt/jdk/bin/policytool
Terminal=false
Type=Application
Icon=javaws
Categories=Settings;
EOF
install -v -Dm0644 javaws.png /usr/share/pixmaps/javaws.png
The choice of pt_BR is just an example. You can add any translation
by adding lines corresponding to your locale, e.g. for fr_FR,
“Name[fr_FR]=” and
“Comment[fr_FR]=” with the
appropriate text as values.
Command Explanations
./autogen.sh: This
command forces rebuilding of auto-generated files to account for
new options added to configure
.
--with-jdk-home
: This
switch provides the location of the temporary JDK.
--with-pkgversion
: This switch can be
used to modify the version string in addition to "IcedTea".
--with-version-suffix
: This
switch appends the given text to the JDK version string.
--enable-nss
: Enable
inclusion of NSS security provider.
--disable-system-kerberos
:
Remove this switch, if MIT
Kerberos V5-1.12.2 is installed.
--with-parallel-jobs
:
Allows to set the number of jobs for make equal to the number of
processors plus one. Note that the default is 2 if this option is
not specified. You have to explicitely set --with-parallel-jobs=1
to disable parallel jobs.
The SBU given above are with parallel jobs disabled.
chmod -v 0644
...sa-jdi.jar: Fix permissions in a generated file
so all users can access it.
Configuring
OpenJDK
Configuration Information
There are now two OpenJDK SDKs
installed in /opt
. You should
decide on which one you would like to use as the default. For
example if you decide to use the precompiled OpenJDK, do the following as the
root
user:
ln -v -nsf OpenJDK-1.7.0.65-bin /opt/jdk
The information below assumes your system is set up using the
instructions found in “The Bash Shell Startup
Files”. You may need to extract the relevant
information below and incorporate it into your system's startup
files if your system is set up differently.
Add the following openjdk.sh
shell
startup file to the /etc/profile.d
directory with the following commands as the root
user:
cat > /etc/profile.d/openjdk.sh << "EOF"
# Begin /etc/profile.d/openjdk.sh
# Set JAVA_HOME directory
JAVA_HOME=/opt/jdk
# Set ANT_HOME directory
ANT_HOME=/opt/ant
# Adjust PATH
pathappend $JAVA_HOME/bin PATH
pathappend $ANT_HOME/bin PATH
# Auto Java CLASSPATH
# Copy jar files to, or create symlinks in this directory
AUTO_CLASSPATH_DIR=/usr/share/java
pathprepend . CLASSPATH
for dir in `find ${AUTO_CLASSPATH_DIR} -type d 2>/dev/null`; do
pathappend $dir CLASSPATH
done
for jar in `find ${AUTO_CLASSPATH_DIR} -name "*.jar" 2>/dev/null`; do
pathappend $jar CLASSPATH
done
export JAVA_HOME ANT_HOME CLASSPATH
unset AUTO_CLASSPATH_DIR dir jar
# End /etc/profile.d/openjdk.sh
EOF
Finally, add the man pages to man_db's configuration. As the root
user:
cat >> /etc/profile.d/extrapaths.sh << "EOF" &&
# Begin Java addition
pathappend /opt/jdk/man MANPATH
# End Java addition
EOF
cat >> /etc/man_db.conf << "EOF" &&
# Begin Java addition
MANDATORY_MANPATH /opt/jdk/man
MANPATH_MAP /opt/jdk/bin /opt/jdk/man
MANDB_MAP /opt/jdk/man /var/cache/man/jdk
# End Java addition
EOF
mandb -c /opt/jdk/man
To test if the man pages are correctly installed, issue
source /etc/profile
and man java to
display the respective man page.
Install or update the
JRE Certificate Authority Certificates (cacerts) file
Use the following procedure to check if the cacerts
file was successfully installed during
the OpenJDK build. Also, if the Certificate Authority
Certificates have been updated, the following instructions
will generate a new JRE cacerts
file. First, check if the cacerts
have been successfully installed:
cd /opt/jdk
bin/keytool -list -keystore jre/lib/security/cacerts
At the prompt "Enter keystore password:", press the "Enter" key
if there is no keystore password defined. If the cacerts
were installed correctly, you will see
a list of the certificates with related information for each one.
If not, you need to manually install them. First, generate the
mkcacerts script as
the root
user:
cat > /opt/jdk/bin/mkcacerts << "EOF"
#!/bin/sh
# Simple script to extract x509 certificates and create a JRE cacerts file.
function get_args()
{
if test -z "${1}" ; then
showhelp
exit 1
fi
while test -n "${1}" ; do
case "${1}" in
-f | --cafile)
check_arg $1 $2
CAFILE="${2}"
shift 2
;;
-d | --cadir)
check_arg $1 $2
CADIR="${2}"
shift 2
;;
-o | --outfile)
check_arg $1 $2
OUTFILE="${2}"
shift 2
;;
-k | --keytool)
check_arg $1 $2
KEYTOOL="${2}"
shift 2
;;
-s | --openssl)
check_arg $1 $2
OPENSSL="${2}"
shift 2
;;
-h | --help)
showhelp
exit 0
;;
*)
showhelp
exit 1
;;
esac
done
}
function check_arg()
{
echo "${2}" | grep -v "^-" > /dev/null
if [ -z "$?" -o ! -n "$2" ]; then
echo "Error: $1 requires a valid argument."
exit 1
fi
}
# The date binary is not reliable on 32bit systems for dates after 2038
function mydate()
{
local y=$( echo $1 | cut -d" " -f4 )
local M=$( echo $1 | cut -d" " -f1 )
local d=$( echo $1 | cut -d" " -f2 )
local m
if [ ${d} -lt 10 ]; then d="0${d}"; fi
case $M in
Jan) m="01";;
Feb) m="02";;
Mar) m="03";;
Apr) m="04";;
May) m="05";;
Jun) m="06";;
Jul) m="07";;
Aug) m="08";;
Sep) m="09";;
Oct) m="10";;
Nov) m="11";;
Dec) m="12";;
esac
certdate="${y}${m}${d}"
}
function showhelp()
{
echo "`basename ${0}` creates a valid cacerts file for use with IcedTea."
echo ""
echo " -f --cafile The path to a file containing PEM"
echo " formated CA certificates. May not be"
echo " used with -d/--cadir."
echo ""
echo " -d --cadir The path to a directory of PEM formatted"
echo " CA certificates. May not be used with"
echo " -f/--cafile."
echo ""
echo " -o --outfile The path to the output file."
echo ""
echo " -k --keytool The path to the java keytool utility."
echo ""
echo " -s --openssl The path to the openssl utility."
echo ""
echo " -h --help Show this help message and exit."
echo ""
echo ""
}
# Initialize empty variables so that the shell does not pollute the script
CAFILE=""
CADIR=""
OUTFILE=""
OPENSSL=""
KEYTOOL=""
certdate=""
date=""
today=$( date +%Y%m%d )
# Process command line arguments
get_args ${@}
# Handle common errors
if test "${CAFILE}x" == "x" -a "${CADIR}x" == "x" ; then
echo "ERROR! You must provide an x509 certificate store!"
echo "\'$(basename ${0}) --help\' for more info."
echo ""
exit 1
fi
if test "${CAFILE}x" != "x" -a "${CADIR}x" != "x" ; then
echo "ERROR! You cannot provide two x509 certificate stores!"
echo "\'$(basename ${0}) --help\' for more info."
echo ""
exit 1
fi
if test "${KEYTOOL}x" == "x" ; then
echo "ERROR! You must provide a valid keytool program!"
echo "\'$(basename ${0}) --help\' for more info."
echo ""
exit 1
fi
if test "${OPENSSL}x" == "x" ; then
echo "ERROR! You must provide a valid path to openssl!"
echo "\'$(basename ${0}) --help\' for more info."
echo ""
exit 1
fi
if test "${OUTFILE}x" == "x" ; then
echo "ERROR! You must provide a valid output file!"
echo "\'$(basename ${0}) --help\' for more info."
echo ""
exit 1
fi
# Get on with the work
# If using a CAFILE, split it into individual files in a temp directory
if test "${CAFILE}x" != "x" ; then
TEMPDIR=`mktemp -d`
CADIR="${TEMPDIR}"
# Get a list of staring lines for each cert
CERTLIST=`grep -n "^-----BEGIN" "${CAFILE}" | cut -d ":" -f 1`
# Get a list of ending lines for each cert
ENDCERTLIST=`grep -n "^-----END" "${CAFILE}" | cut -d ":" -f 1`
# Start a loop
for certbegin in `echo "${CERTLIST}"` ; do
for certend in `echo "${ENDCERTLIST}"` ; do
if test "${certend}" -gt "${certbegin}"; then
break
fi
done
sed -n "${certbegin},${certend}p" "${CAFILE}" > "${CADIR}/${certbegin}.pem"
keyhash=`${OPENSSL} x509 -noout -in "${CADIR}/${certbegin}.pem" -hash`
echo "Generated PEM file with hash: ${keyhash}."
done
fi
# Write the output file
for cert in `find "${CADIR}" -type f -name "*.pem" -o -name "*.crt"`
do
# Make sure the certificate date is valid...
date=$( ${OPENSSL} x509 -enddate -in "${cert}" -noout | sed 's/^notAfter=//' )
mydate "${date}"
if test "${certdate}" -lt "${today}" ; then
echo "${cert} expired on ${certdate}! Skipping..."
unset date certdate
continue
fi
unset date certdate
ls "${cert}"
tempfile=`mktemp`
certbegin=`grep -n "^-----BEGIN" "${cert}" | cut -d ":" -f 1`
certend=`grep -n "^-----END" "${cert}" | cut -d ":" -f 1`
sed -n "${certbegin},${certend}p" "${cert}" > "${tempfile}"
echo yes | env LC_ALL=C "${KEYTOOL}" -import \
-alias `basename "${cert}"` \
-keystore "${OUTFILE}" \
-storepass 'changeit' \
-file "${tempfile}"
rm "${tempfile}"
done
if test "${TEMPDIR}x" != "x" ; then
rm -rf "${TEMPDIR}"
fi
exit 0
EOF
chmod -c 0755 /opt/jdk/bin/mkcacerts
Note
Doing a very large copy/paste directly to a terminal may result
in a corrupted file. Copying to an editor may overcome this
issue.
If you need to generate a cacerts
file, and there is already one in /opt/jdk/jre/lib/security
, it is better to make
a backup. Then, you can create a new one, as the root
user:
/opt/jdk/bin/mkcacerts \
-d "/etc/ssl/certs/" \
-k "/opt/jdk/bin/keytool" \
-s "/usr/bin/openssl" \
-o "/opt/jdk/jre/lib/security/cacerts"