- Loading...
Building
...
(Note: These instructions are being revised for our new project layout & Gradle build. On June 28, 2013 we will have switch from ant to gradle as our build system, and these instructions will NO LONGER WORK. This page is being revised with the new instructions, and should be updated the first week of July)
JFX consists of a forest of mercurial repositories. These repositories contain NetBeans, Eclipse and IntelliJ projects with the Java source, native projects and the scripts needed to build JavaFX components. A JavaFX component is a large and obvious unit of functionality, such as the user interface controls or the embedded web browser.
As you can imagine, building a UI toolkit for many different platforms is quite complex. It requires platform specific tools such as C compilers as well as portable tools like ant. The build and project structure of JavaFX like most large projects has evolved over time and is constantly being revised.
Building OpenJFX requires that you have the binary porition of OpenJFX. As of JDK7, JavaFX is co-bundled with Java so you will need the version of Java that matches the mercurial repositories you cloned. The rest of this document assumes that you are developing against JavaFX 8 (co-bundled with JDK8) and uses paths and naming accordingly.
Widget Connector | ||
---|---|---|
|
Over the course of time, various components, projects and build structures will be contributed to OpenJFX until all of JavaFX is open source. In the meantime, you will need to download the JavaFX binary that matches OpenJFX for your platform and place your compiled code first on the class path. First though, you will need to download and install the tools needed to build OpenJFX and place them on your the command line path for your operating system.
Here are the tools required to build OpenJFX:
On Ubuntu Linux (tested on 12.04), the following command can be used to satisfy the prerequisites for this build:
sudo apt-get install mercurial ant libgtk2.0-dev libxtst-dev
You will need to ensure that the command path is set up correctly. The java and javac commands should come from the JDK8 bundle by preference (current build minimum is JDK7). On some Linux systems, OpenJDK6 may be the system default. Use the '-version' switch to check each of java, javac and ant to verify the versions in your path, for example
# ant -version
Apache Ant(TM) version 1.8.2 compiled on December 3 2011
Here is the recipe for building OpenJFX (use a Cygwin shell on Windows):
Note: JDK1.8 and the JFX contained within are are moving target, so you may need to refresh your snapshot periodically to match the items you are building.
In addition, the following files need to be downloaded and placed in "open-jfx/lib":
Certain parts of JFX, e.g. JavaFX/SWT classes in rt/javafx-embed-swt, depend on SWT being available at compile time. Environmental variable SWT_DIR or ant property swt.path can be used to specify a directory with swt.jar. If neither SWT_DIR nor swt.path are specified, no classes that depend on SWT are built. TODO: does it make sense to look for swt.jar in open-jfx/lib as well?
Here is the command line needed to run OpenJFX (using the controls jar from OpenJFX):
The above command assumes that you have a class test.HelloButton and that your OpenJFX directory is /Users/someone/open-jfx. If you have multiple versions of java installed on your machine, make sure you use the java that matches jfxrt.jar.
Configuring your system to be able to build native code is a bit of a black art. Hopefully we will have captured here steps that are both correct and comprehensive, but it has been our experience that lots of little things don't get documented than could trip you up (especially on Windows).
Setting up a linux build configuration is fairly straightforward. These build instructions were used for the "official" build platform of Ubuntu 10.04, but also on the latest Ubuntu 12.10. First, run the following command to install all the required development packages:
sudo apt-get update
sudo apt-get install bison flex gperf libasound2-dev libgl1-mesa-dev \
libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libjpeg-dev \
libpng-dev libx11-dev libxml2-dev libxslt1-dev libxt-dev \
libxxf86vm-dev pkg-config qt4-qmake x11proto-core-dev \
x11proto-xf86vidmode-dev libavcodec-dev mercurial libgtk2.0-dev \
ksh libxtst-dev libudev-dev
To configure your Mac, make sure you have at least version 10.7 installed. Install the latest version of Xcode and that you have the developer tools installed. You can install them by using the menus within Xcode: XCode -> Preferences -> Downloads -> Components. Install the latest JDK 8 build. At present that should be sufficient, but when WebKit is open sourced you will also need to install QT (because WebKit uses QTMake and some other such tools).
You need to have the following tools installed:
The OpenJFX team is working on a replacement for our current build and test system. We have chosen Gradle as the basis for this new system based on its IDE support, community support, flexibility, and great command line support. This new system is now far enough along to start testing. The documentation included here below is preliminary, but should provide enough guidance to give our gradle build system a good test.
Gradle is a build system which might be defined as a cross between Ant, Maven, and Rake. Like Ant, Gradle is designed primarily as a declarative means to build Java projects. In fact, Gradle has the ability to call into any Ant tasks. Like Maven, Gradle can automatically download and manage dependencies between projects and with library dependencies. In Fact, it can be configured to download from maven central and handle dependency management transparently. Like Rake, Gradle is a DSL. It is not XML based. In fact, Gradle is based on Groovy, which is a dynamic language for the JDK which shares its syntax with Java. In fact, a Groovy script can be written completely using valid Java code, or you can "groovify it" by, for example, removing semi-colons.
Our build is based on Gradle Version 1.4. This page is not a guide on using Groovy, nor is it a Gradle DSL reference. Rather, it is simply going to walk through using our new build system. If you already know Gradle, much of this will be self-explanatory. A different page will go into detail regarding how the build system works, so that anybody so (un)fortunate as to have to work on build files can get up to speed quickly
The prerequisites for using this document is to make sure you have downloaded Gradle 1.4 and installed it on your path. You must have successfully cloned openjfx, and must have already run the 'gradle -b generator.gradle' command in the rt repo. This will create a new sibling of rt called "javafx". All of the following assumes you are in this directory. In the next few months we will convert from our current project layout to the new one in the "javafx" directory, and these instructions will be modified accordingly.
Also, you need to have the native tools installed for native compilation.
And, proxies. If you're like us at Oracle and cursed to work behind a proxy, when using gradle you'll find it hangs while trying to download dependencies. What you need to do is create / edit your ~/.gradle/gradle.properties file:
Code Block |
---|
systemProp.http.proxyHost=<your proxy host here>
systemProp.http.proxyPort=<your proxy port here> |
Once you are setup and ready to tom you are can build by typing gradle in the 'javafx' directory:
Code Block |
---|
gradle |
Thats's all there is to it. You can now begin editing source files and doing command line development. If you are like us, you'll want to develop using your IDE of choice.
Despite the fact that most of the major IDE's support gradle directly, we have decided to provide pre-generated IDE configuration files in order to make using an IDE smooth and painless.
IMPORTANT: Ensure that you do not have gradle plugins for NetBeans or Eclipse installed. They will conflict with the pre-generated IDE files. In furture, we may move to gradle builds within the IDE's as support becomes better.
If you are building and running native libraries, the current native build produces 32-bit libraries. If you attempt to use them in a 64-bit JVM, they will fail to load and presently do not provide much indication about what went wrong. The easiest thing to do is to use a 32-bit JVM. This is not necessary on platforms like Mac that only support 64-bit JVM's.
OpenJFX is based on JDK1.8 and IDE support for lambdas and defender methods currently requires that you get a pre-release version. IntelliJ supports this out of the box. Eclipse and NetBeans do not.
IntelliJ: http://www.jetbrains.com/idea/download/
Eclipse: http://downloads.efxclipse.org/eclipse-java8/
NetBeans: http://bits.netbeans.org/dev/nightly/
- this version works on Mac: netbeans-trunk-nightly-201305192300-javase-macosx.dmg
- this version works on Windows: netbeans-trunk-nightly-201305192300-javase-windows.exe
- this versions works on Linux: netbeans-trunk-nightly-201306252301-javase-linux.sh
- other versions are likely to work but these are the ones that have been tested
Once you have downloaded and installed an IDE that is JDK8 aware, you will need to configure it to accept JDK8 syntax and generate the right byte codes. This will be explained later on for each particular IDE.
JavaFX is bundled with the JDK as an extension. The jfxrt.jar is located in the extension directory called 'ext' where Java is installed. You must remove it from this directory for the IDE's to work properly. You can make a copy of your current JDK, remove the jar and tell your IDE to use this JDK instead. Another strategy is to keep the jar around but move it into a sibling 'ext2' directly so that paths can easily be changed manually to use it and you can restore it when necessary. Regardless, if you do not remove jfxrt.jar, you will get strange errors.
//TODO - document support
//TODO - document support
We have found the nightly versions of NetBeans to be unstable under JDK8, but fine otherwise. Further, NetBeans needs to be told not to report errors when private JDK classes referenced. The netbeans.conf file is located in the etc directory of your NetBeans install. You will edit netbeans_default_options and netbeans_jdkhome.
Here is a sample file from the Mac. The Windows and Linux default options might be a bit different.
Code Block |
---|
# Options used by NetBeans launcher by default:
# (can be overridden by explicit command line switches)
#
# Note that default -Xmx and -XX:MaxPermSize are selected for you automatically.
# You can find these values in var/log/messages.log file in your userdir.
# The automatically selected value can be overridden by specifying -J-Xmx or
# -J-XX:MaxPermSize= here or on the command line.
#
# If you specify the heap size explicitly, you may also want to enable
# Concurrent Mark & Sweep garbage collector.
# (see http://wiki.netbeans.org/FaqGCPauses)
#
netbeans_default_options="-J-client -J-Xss2m -J-Xms32m -J-XX:PermSize=32m -J-Xmx1024m -J-da -J-DCachingArchiveProvider.disableCtSym=true -J-Dnetbeans.logger.console=true -J-Dapple.laf.useScreenMenuBar=true -J-Dapple.awt.graphics.UseQuartz=true -J-Dsun.java2d.noddraw=true -J-Dsun.java2d.dpiaware=true -J-Dsun.zip.disableMemoryMapping=true -J-Dplugin.manager.check.updates=false -J-Dnetbeans.extbrowser.manual_chrome_plugin_install=yes"
# Default location of JDK:
# (set by installer or commented out if launcher should decide)
#
# It can be overridden on command line by using --jdkhome <dir>
# Be careful when changing jdkhome.
# There are two NetBeans launchers for Windows (32-bit and 64-bit) and
# installer points to one of those in the NetBeans application shortcut
# based on the Java version selected at installation time.
#
netbeans_jdkhome="/Library/Java/JavaVirtualMachines/jdk1.7.0_11.jdk/Contents/Home"
|
Invoke NetBeans
...
a UI toolkit for many different platforms is a complex and challenging endeavor. It requires platform specific tools such as C compilers as well as portable tools like Gradle and the JDK. Which tools must be installed differs from platform to platform. While the OpenJFX build system was designed to remove as many build hurdles as possible, it is necessary to build native code and have the requisite compilers and toolchains installed. On Mac and Linux this is fairly easy, but setting up Windows is more difficult.
If you are looking for instructions to build FX for JDK 8uNNN, they have been archived here.
Table of Contents |
---|
Do you really want to build OpenJFX? We would like you to, but the latest stable build is already available on the JavaFX website, and JavaFX 8 is bundled by default in Oracle JDK 8 (9 and 10 also included JavaFX, but were superseded by 11, which does not). There are also some great community builds that may work for you.
We are exploring making this easier, by enabling a developer to build a set of javafx.* modules that can be used with a clean OpenJDK build (without the javafx.* modules). Stay tuned.
Building WebKit as part of building JavaFX is optional and requires additional steps; these are detailed per operating system below. If you do not build WebKit, you can use pre-built libraries as detailed here.
You will need Windows 10 or later (Windows 10 is recommended) 64-bit OS.
You need to have the following tools installed:
openssh
zip
unzip
make
(needed to compile media)makedepend
(needed for media)git
Desktop development with C++
workload is required at most, but it may be possible to install individual components to satisfy the requirements.If you build WebKit (it is not built by default) you will need the following additional tools:
bison
flex
gperf
perl (5.10 or later)
python3
ruby (2.5 or later)
All commands on this page are run inside Cygwin (and not in Windows CMD).
The JavaFX build will automatically locate your Visual Studio installation, as long as you installed it in the default location. You no longer need to set any env variables to point to your VS 2022 installation, unless you installed Visual Studio in a non-standard location, for example, the D:
drive instead of the default C:
drive.
The initial build process that generates the needed resources is done by the buildSrc
folder. On Windows, it tries to locate all the needed tools and write their paths to the build\windows_tools.properties
file. If it fails, the file is left blank, which results in a fatal error. In this case, define the VSCOMNTOOLS
variable (older versions of JavaFX used VS150COMNTOOLS
) to point to the VC\Auxiliary\Build
directory in your Visual studio Installation. For example, use the following if you installed Visual Studio 2022 on the D:
drive.
Code Block |
---|
export VSCOMNTOOLS="D:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build" |
Note the use of the double backslash in the VSCOMNTOOLS
env var. This is needed because the cygwin shell uses the '\' as an escape character.
If these definitions aren't persisted between launches of Cygwin, you can either set them in the Windows Environment Variables UI or in the /home/$user$/.bash_profile
file (these are ran on startup). Use export -p
to verify that the env variables are set correctly.
You will need macOS 12 (Monterey) or later.
Install the following software:
If you build WebKit (it is not built by default) you will need the following additional tools:
Anchor | ||||
---|---|---|---|---|
|
Setting up a Linux build configuration is fairly straightforward. These build instructions were used for Ubuntu 18.04.
First, run the following command to install all the required development packages:
sudo apt-get update sudo apt-get install libavformat-ffmpeg57 libgl1-mesa-dev \ libx11-dev pkg-config x11proto-core-dev git \
libgtk2.0-dev libgtk-3-dev
If you build WebKit (it is not built by default) you will need the following additional tools:
perl (5.10 or later)
python3
ruby (2.5 or later)
The following should satisfy the requirements (but check the version of cmake) :
sudo apt-get install cmake bison flex gperf ruby
Same as Ubuntu 18.04 with the following changes for sudo apt-get install
:
libavformat-ffmpeg57
to libavformat58
libxxf86vm-dev
We use Oracle Linux 7 to build the javafx.* modules that we ship with the Oracle JDK releases. Here are the packages you will need:
yum install mercurial git bison flex gperf pkgconfig \
gtk2-devel gtk3-devel pango-devel freetype-devel
Run the following commands (using Java 11 here as an example):
sudo yum update
sudo yum install git bison flex pkgconfig gtk2-devel gtk3-devel \
pango-devel freetype-devel libXtst-devel java-11-openjdk-devel ant gcc-c++
sudo yum install epel-release
sudo yum config-manager --set-enabled PowerTools
sudo yum update
sudo yum install libstdc++-static
sudo alternatives --config java
(specify Java 11)
OpenJFX N is formally compatible with JDK N and N-1. For OpenJFX 22, download OpenJDK 21 or later to use as the boot JDK to build and test OpenJFX. We recommend to use the latest version, however, Gradle might not support that version, so a version that Gradle supports might also be required to run Gradle itself (though it will use the latest version of the JDK through toolchain support).
OpenJFX (and OpenJDK) transitioned to Git as part of Project Skara. The OpenJFX repo is hosted on GitHub at openjdk/jfx. We encourage developers to become familiar with Git and GitHub.
Many (if not all) IDEs include built in support. For example, Eclipse uses EGit, which can be downloaded through the built-in update site http://download.eclipse.org/releases/latest/ under Collaboration > Java implementation of Git.
For Linux, the git
package is included in the list of required packaged that were installed. On Windows, you can also install git as a Cygwin package.
Popular GUI options include SourceTree for Windows or Mac from Atlassian and TortoiseGit for Windows.
Gradle is the primary build tool for building OpenJFX. Since the repository includes a Gradle wrapper that will download the correct Gradle version when needed, you do not need to manually install Gradle. The current and minimum Gradle versions are defined in the source code. If you want to generate a wrapper yourself (for example, you want to build OpenJFX with a different Gradle version), then you will need to install Gradle.
The sh gradlew
command used throughout this document can be replaced with gradle
when not using the wrapper.
Note: gradle is available as an Ubuntu package, but check the version. This command should work after you set JAVA_HOME:
gradle -version
You will need Apache Ant 1.10.5 to build the OpenJFX apps (IMPORTANT: there are known issues with ant 1.9.x, so use either version 1.10.5 or 1.8.2).
Set the following environment variables:
JAVA_HOME
and JDK_HOME
to point to the root of your jdk-N release$JAVA_HOME/bin
to your PATH
gradle-x.y/bin
to your PATH
where x.y
is the versionapache-ant-1.10.5/bin
to your PATH
Note: on windows, the JAVA_HOME and JDK_HOME variables must be in DOS format (e.g., "C:/Program Files/..." rather than "/cygdrive/c/Program Files/..."), although you can use forward slashes ('/'). Test your settings with:
Code Block |
---|
"$JAVA_HOME/bin/java" -version
gradle -version
ant -version |
IMPORTANT: Any time you change env settings or install new software after a failed build of JavaFX you should execute the following three commands:
Code Block |
---|
sh gradlew --stop
rm -rf build
sh gradlew clean |
The first is needed to stop any gradle daemons that might be running (by default gradle starts a daemon that is used to speed up subsequent builds). There was a bug in the gradle daemon that causes gradle to ignore any env variables set after the daemon is started (see JDK-8193288). Additionally, on Windows platforms, the gradle daemon can sometimes interfere with your ability to delete files that it keeps open. If you run into problems you can stop the gradle daemon with "gradle --stop" (or disable the gradle daemon altogether).
The second is needed because the OpenJFX build caches the results of a previous configuration, in such a way that it can cause gradle clean to fail.
All OpenJFX sources are held in https://github.com/openjdk/jfx (see Repositories and Releases). To clone the repo from the command line, use:
Code Block | ||
---|---|---|
| ||
# for the active development stream, currently targeted for JDK 14
git clone https://github.com/openjdk/jfx.git |
Other tools will have a clone option.
Before diving directly into building OpenJFX, lets get our feet wet by learning what kinds of things we can call from the command line, and how to get help when we need it. The first command you should execute is tasks:
Code Block |
---|
$ sh gradlew tasks
...
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Default tasks: sdk
Basic tasks
-----------
buildModuleBaseWin - creates javafx.base property files
buildModuleGraphicsWin - copies javafx.graphics native libraries
buildModuleLibsWin
buildModuleMediaWin - copies javafx.media native libraries
buildModuleSWTWin - copies SWT JAR
buildModuleWebWin - copies javafx.web native libraries
clean - Deletes the build directory and the build directory of all sub projects
cleanAll - Scrubs the repo of build artifacts
javadoc - Generates the JavaDoc for all the public API
javafxSwtWin - Creates the javafx-swt.jar for the win target
sdkWin
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildModulesWin
buildModuleWin
buildModuleZipWin
buildNeeded - Assembles and tests this project and all projects it depends on.
buildRunArgsWin
ccWinFont - Compiles native sources for font for win
ccWinGlass - Compiles native sources for glass for win
ccWinIio - Compiles native sources for iio for win
ccWinPrism - Compiles native sources for prism for win
ccWinPrismD3D - Compiles native sources for prismD3D for win
ccWinPrismES2 - Compiles native sources for prismES2 for win
ccWinPrismSW - Compiles native sources for prismSW for win
classes - Assembles main classes.
clean - Deletes the build directory.
cleanNative - Clean all native libraries and objects for Graphics
cleanNativeDecora - Clean native objects for Decora
cleanNativeFont - Clean native objects for font
cleanNativeGlass - Clean native objects for glass
cleanNativeIio - Clean native objects for iio
cleanNativePrism - Clean native objects for prism
cleanNativePrismD3D - Clean native objects for prismD3D
cleanNativePrismES2 - Clean native objects for prismES2
cleanNativePrismSW - Clean native objects for prismSW
createMSPfile
generateD3DHeaders - Generate headers by compiling hlsl files
jar - Assembles a jar archive containing the main classes.
jslcClasses - Assembles jslc classes.
linkWinFont - Creates native dynamic library for font for win
linkWinGlass - Creates native dynamic library for glass for win
linkWinIio - Creates native dynamic library for iio for win
linkWinPrism - Creates native dynamic library for prism for win
linkWinPrismD3D - Creates native dynamic library for prismD3D for win
linkWinPrismES2 - Creates native dynamic library for prismES2 for win
linkWinPrismSW - Creates native dynamic library for prismSW for win
native - Compiles and Builds all native libraries for Graphics
nativeDecora - Generates JNI headers, compiles, and builds native dynamic library for Decora
nativeFont - Generates JNI headers, compiles, and builds native dynamic library for font for all compile targets
nativeGlass - Generates JNI headers, compiles, and builds native dynamic library for glass for all compile targets
nativeIio - Generates JNI headers, compiles, and builds native dynamic library for iio for all compile targets
nativePrism - Generates JNI headers, compiles, and builds native dynamic library for prism for all compile targets
nativePrismD3D - Generates JNI headers, compiles, and builds native dynamic library for prismD3D for all compile targets
nativePrismES2 - Generates JNI headers, compiles, and builds native dynamic library for prismES2 for all compile targets
nativePrismSW - Generates JNI headers, compiles, and builds native dynamic library for prismSW for all compile targets
rcFont - Compiles native sources for font
rcGlass - Compiles native sources for glass
rcIio - Compiles native sources for iio
rcPrism - Compiles native sources for prism
rcPrismD3D - Compiles native sources for prismD3D
rcPrismES2 - Compiles native sources for prismES2
rcPrismSW - Compiles native sources for prismSW
shadersClasses - Assembles shaders classes.
shimsClasses - Assembles shims classes.
stubClasses - Assembles stub classes.
testapp1Classes - Assembles testapp1 classes.
testapp2Classes - Assembles testapp2 classes.
testapp3Classes - Assembles testapp3 classes.
testapp4Classes - Assembles testapp4 classes.
testapp5Classes - Assembles testapp5 classes.
testapp6Classes - Assembles testapp6 classes.
testClasses - Assembles test classes.
toolsClasses - Assembles tools classes.
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'rt'.
components - Displays the components produced by root project 'rt'. [incubating]
dependencies - Displays all dependencies declared in root project 'rt'.
dependencyInsight - Displays the insight into a specific dependency in root project 'rt'.
dependentComponents - Displays the dependent components of components in root project 'rt'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'rt'. [incubating]
projects - Displays the sub-projects of root project 'rt'.
properties - Displays the properties of root project 'rt'.
tasks - Displays the tasks runnable from root project 'rt' (some of the displayed tasks may belong to subprojects).
Publishing |
Once you are setup and ready to go, the first thing you should do is generate the project files for your preferred IDE.
Code Block |
---|
gradle netBeans |
Code Block |
---|
gradle idea |
Code Block |
---|
gradle eclipse |
You can then leave the command line (hopefully forever!) and do all the rest of your work from within your IDE. No, really!
The "Gradle Support" module for NetBeans 7.3 was previously installed in my NetBeans instance. After running 'gradle netBeans', I then opened the javafx project with NetBeans and all of JavaFX is available for me and ready to go, even including native code. Its all there.
In order to perform a build from NetBeans, you simply have to hit the build button. To run a specific file (such as a sample), find the sample in the source tree (NOTE: Samples not setup yet as of 3/23/2013), right click and choose "run".
The experience in IDEA is similar. After running 'gradle idea', you open the "javafx" project. We will have already generated the project, workspace, and module settings for you. Many settings will have already been configured to be shared across all developers working on the project, such as the number of spaces per indent and the use of spaces instead of tabs.
IDEA and Eclipse differ from NetBeans in that they maintain their own compiled classes and maintain their own build. That is, while you can (and need to at times) run the Gradle build script in order to build, for example an SDK or the JavaDoc for the entire project or run all of the tests in the right way, most of the time you will end up just working in IDEA like you would for any other project. There are caveats though (such as making sure the JDK you have configured for the project does not have jfxrt.jar on its classpath!). This will all be documented separately.
You can setup a run configuration for any gradle tasks you want to. In this screenshot above, IDEA has been configured to execute the top-level clean run target. You can specify any environment variables or Gradle properties to feed to the build. This can be very convenient when you have different configurations you want to build for (for example, you might have a configuration for building normally and another for building iOS or ARM).
Most of the time you will be able to just work from within your IDE, doing building and testing. Even when you need to execute actually tasks in the OpenJFX Gradle build script, you can do it easily from within the IDE. However, for the sake of understanding the nuts and bolts (and to avoid having to take screenshots from all three IDEs for the rest of this document), I will switch to executing all commands from the command line. In fact, one of the advantages to Gradle over Ant is the fantastic command line interface it provides.
*END OF STUFF THAT IS NO LONGER TRUE*
Before diving directly into building OpenJFX, lets get our feet wet by learning what kinds of things we can call from the command line, and how to get help when we need it. The first command you should execute is tasks:
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle tasks The CompileOptions.useAnt property has been deprecated and is scheduled to be removed in Gradle 2.0. There is no replacement for this property. :tasks ------------------------------------------------------------ All tasks runnable from root project ------------------------------------------------------------ Default tasks: assemble Basic tasks ----------- clean - Deletes the build directory and the build directory of all sub projects javadoc - Generates the JavaDoc for all the public API jfxrt - Creates the jfxrt.jar sdk - Creates an SDK Build tasks ---------------- assemblegenerateMetadataFileForJavafxPublication - AssemblesGenerates the outputs of this project. build - Assembles and tests this project. buildDependents - Assembles and tests this project and all projects that depend on it. buildNeeded - Assembles and tests this project and all projects it depends on. ccDecora - Compiles native sources for Decora ccGlass - Compiles native sources for Glass ccPrism - Compiles native sources for Prism ccPrismSW - Compiles native sources for PrismSW classes - Assembles the main classes. clean - Deletes the build directory. jar - Assembles a jar archive containing the main classes. javahDecora - Generates JNI Headers for Decora javahGlass - Generates JNI Headers for Glass javahPrism - Generates JNI Headers for Prism javahPrismSW - Generates JNI Headers for PrismSW linkDecora - Creates native dynamic library for Decora linkGlass - Creates native dynamic library for Glass linkPrism - Creates native dynamic library for Prism linkPrismSW - Creates native dynamic library for PrismSW native - Compiles and Builds all native libraries for Graphics nativeDecora - Generates JNI headers, compiles, and builds native dynamic library for Decora nativeGlass - Generates JNI headers, compiles, and builds native dynamic library for Glass nativePrism - Generates JNI headers, compiles, and builds native dynamic library for Prism nativePrismSW - Generates JNI headers, compiles, and builds native dynamic library for PrismSW stubClasses - Assembles the stub classes. testClasses - Assembles the test classes. Documentation tasks ------------------- javadoc - Generates Javadoc API documentation for the main source code. Help tasks ---------- dependencies - Displays all dependencies declared in root project 'javafx'. dependencyInsight - Displays the insight into a specific dependency in root project 'javafx'. help - Displays a help message projects - Displays the sub-projects of root project 'javafx'. properties - Displays the properties of root project 'javafx'. tasks - Displays the tasks runnable from root project 'javafx' (some of the displayed tasks may belong to subprojects). IDE tasks Gradle metadata file for publication 'javafx'. generateMetadataFileForMavenPublication - Generates the Gradle metadata file for publication 'maven'. generatePomFileForJavafxPublication - Generates the Maven POM file for publication 'javafx'. generatePomFileForMavenPublication - Generates the Maven POM file for publication 'maven'. publish - Publishes all publications produced by this project. publishJavafxPublicationToMavenLocal - Publishes Maven publication 'javafx' to the local Maven repository. publishJavafxPublicationToMavenRepository - Publishes Maven publication 'javafx' to Maven repository 'maven'. publishMavenPublicationToMavenLocal - Publishes Maven publication 'maven' to the local Maven repository. publishMavenPublicationToMavenRepository - Publishes Maven publication 'maven' to Maven repository 'maven'. publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache. Verification tasks ------------------ check - Runs all checks. test - Runs the unit tests. To see all tasks and more detail, run gradle tasks --all To see more detail about a task, run gradle help --task <task> BUILD SUCCESSFUL in 19s 1 actionable task: 1 executed |
The tasks task is extremely helpful. You use it to discover all the other things you can do with this build file. You notice at the top of the output the phrase "All tasks runnable from root project". The "root" project is "rt". That is, we are in the root project. Below the root project are a series of sub projects, some of which are referred to as modules or "components". But more about those later.
Gradle then tells us what the default tasks are. In this case, our default task is the 'sdk' task. This is the task that will be executed if you just call 'gradle' alone without providing any additional arguments. After this comes a listing of different tasks, broken out by group. The first group is the "Basic" group which contains the tasks you may find yourself using most often. These are all named and have a description provided. For example, executing the 'clean' task would be done like this:
Code Block |
---|
$ sh gradlew clean |
Finally, the tasks task gives us a useful hint that we can pass the --all argument in order to see all of the tasks in more detail. This produces a lot more output, but really gives an in depth look at what tasks are available for you to call.
As mentioned above, the root project is called "rt", and that we have sub-projects in the gradle build. To see all of the projects available to you, execute the projects task (which you will notice was in the "Help tasks" group produced by the tasks task). This lists not just what projects are available, but what their name is, and what the project hierarchy is.
Code Block |
---|
$ sh gradlew projects ... :projects --------------------------- cleanIdea - Cleans IDEA project files (IML, IPR) cleanIdeaWorkspace - Deletes the javafx.ipw file cleanNetBeans - Deletes generated NetBeans files idea - Generates IDEA project files (IML, IPR, IWS) netBeans - Creates the NetBeans project files for JavaFX Verification tasks -------------------------- check - Runs all checks. test - Runs the unit tests. To see all tasks and more detail, run with --all. BUILDRoot SUCCESSFUL Total time: 4.883 secs |
The tasks task is extremely helpful. You use it to discover all the other things you can do with this build file. You notice at the top of the output the phrase "All tasks runnable from root project". The "root" project is "javafx". That is, we are in the root project. Below the root project are a series of sub projects, some of which are referred to as modules or "components". But more about those later.
Gradle then tells us what the default tasks are. In this case, our default task is the 'assembly' task. This is the task that will be executed if you just call 'gradle' alone without providing any additional arguments. After this comes a listing of different tasks, broken out by group. The first group is the "Basic" group which contains the tasks you may find yourself using most often. These are all named and have a description provided. For example, if I wanted to execute the 'clean' task, then I would do so like this:
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle clean |
Finally, the tasks task gives us a useful hint that we can pass the --all argument in order to see all of the tasks in more detail. This produces a lot more output, but really gives an in depth look at what tasks are available for you to call.
I mentioned above that our root project is called "javafx", and that we have sub-projects in the gradle build. To see all of the projects available to you, execute the projects task (which you will notice was in the "Help tasks" group produced by the tasks task). This lists not just what projects are available, but what their name is, and what the project hierarchy is.
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle projects
The CompileOptions.useAnt property has been deprecated and is scheduled to be removed in Gradle 2.0. There is no replacement for this property.
:projects
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'javafx'
+--- Project ':base'
+--- Project ':build-tools'
+--- Project ':controls'
+--- Project ':designTime'
+--- Project ':fxml'
+--- Project ':graphics'
| +--- Project ':graphics:effects-jsl'
| \--- Project ':graphics:prism-jsl'
+--- Project ':swing'
\--- Project ':swt'
To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :base:tasks
BUILD SUCCESSFUL
Total time: 4.194 secs |
Projects in gradle are named according to their depth. So the root project is simply named "javafx". The immediate subprojects are all prefixed with a ":". Sub-subprojects have their parents in their name, for example, ":graphics:effects-jsl". When you execute a command such as gradle assemble what actually happens is that Gradle locates the assemble task on all projects and executes them. (TODO Is this entirely accurate?)
There are a couple other tricks-of-the-trade that you should be aware of. You can execute any gradle command with --info or --debug in order to get more output. Running in --info mode provides some additional debugging output that is very useful when things go wrong. In particular, our build system will output certain crucial variables that are being used to perform the build:
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle projects Starting Build Settings evaluated using settings file '/Users/rbair/Projects/JavaFX/graphics-8.0/javafx/settings.gradle'. Projects loaded. Root project using build file '/Users/rbair/Projects/JavaFX/graphics-8.0/javafx/build.gradle'. Included projects: [root project 'javafx', project ':base', project ':build-tools', project ':controls', project ':designTime', project ':fxml', project ':graphics', project ':swing', project ':swt', project ':graphics:effects-jsl', project ':graphics:prism-jsl'] Evaluating root project 'javafx' using build file '/Users/rbair/Projects/JavaFX/graphics-8.0/javafx/build.gradle'. OS_NAME: mac os x JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk_b81/Contents/Home/jre JDK_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk_b81/Contents/Home BINARY_STUB: file:///Library/Java/JavaVirtualMachines/jdk1.8.0.jdk_b81/Contents/Home/jre/lib/ext/jfxrt.jar HUDSON_JOB_NAME: not_hudson HUDSON_BUILD_NUMBER: 0000 PROMOTED_BUILD_NUMBER: 00 PRODUCT_NAME: OpenJFX RAW_VERSION: 8.0.0 RELEASE_NAME: 8.0 RELEASE_MILESTONE: ea The CompileOptions.useAnt property has been deprecated and is scheduled to be removed in Gradle 2.0. There is no replacement for this property. Evaluating project ':base' using empty build file. Evaluating project ':build-tools' using empty build file. Evaluating project ':controls' using empty build file. Evaluating project ':designTime' using empty build file. Evaluating project ':fxml' using empty build file. Evaluating project ':graphics' using empty build file. Evaluating project ':swing' using empty build file. Evaluating project ':swt' using empty build file. Evaluating project ':graphics:effects-jsl' using empty build file. Evaluating project ':graphics:prism-jsl' using empty build file. All projects evaluated. Selected primary task 'projects' Tasks to be executed: [task ':projects'] :projects ------------------------------------------------------------ Root project ------------------------------------------------------------ Root project 'javafxproject ------------------------------------------------------------ Root project 'rt' +--- Project ':apps' +--- Project ':base' +--- Project ':controls' +--- Project ':fxml' +--- Project ':graphics' +--- Project ':media' +--- Project ':baseswing' +--- Project ':build-toolsswt' +--- Project ':controlssystemTests' +\--- Project ':designTime' +--- Project ':fxml' +--- Project ':graphics' | +--- Project ':graphics:effects-jsl' | \--- Project ':graphics:prism-jsl' +--- Project ':swing' \--- Project ':swt' To see a list of the tasks of a project, run gradle <project-path>:tasks For example, try running gradle :base:tasks BUILD SUCCESSFUL Total time: 4.194 secs |
Among all this output is a list of several important properties, such as JDK_HOME and BINARY_STUB. These properties are essential to the behavior of the build system, so if something goes wrong, you can check that you are building with the right binary stub and the right JDK (hint: nearly everything is based on JDK_HOME – if you have that set right, the rest of the Java build should just work).
One more trick is the --profile argument. You can perform any gradle task and use the --profile argument. This will cause gradle to keep track of how long various parts of the build took, and will produce an HTML report in build/reports/profile. The report breaks down how much time was spent in configuration, dependency resolution, and task execution. It further breaks it down by project. This gives useful metrics for tracking down which parts of the build take the longest and hopefully tighten up the build times.
There are three main things you may want to do on a regular basis when working on JavaFX: building, testing, and creating documentation. Lets look at each of these in turn.
The simplest basic task to build is the sdk task. The sdk task will compile all Java sources and all native sources for your target platform. It will create the appropriate sdk directory and populate it with the native dynamic libraries and the jfxrt.jar. Because the SDK is not distributed with documentation, the javadocs are not created as part of the sdk task. Once the sdk task has completed, you will have and SDK distribution which you could run against (modulo any closed-bits) or give to somebody else to run.
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle sdk
The CompileOptions.useAnt property has been deprecated and is scheduled to be removed in Gradle 2.0. There is no replacement for this property.
:base:processVersion
:build-tools:generateGrammarSource
:build-tools:compileJava
:build-tools:processResources
:build-tools:classes
:build-tools:jar
:base:compileJava
[snip out a whole bunch of stuff]
:jfxrt
:sdk
BUILD SUCCESSFUL
Total time: 1 mins 45.184 secs
|
You can find the built SDK in the build directory:
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ pwd
/Users/rbair/open-jfx/graphics/javafx
rbair$ ls -l build/
drwxr-xr-x 3 rbair staff 102 Mar 23 17:39 mac-sdk
drwxr-xr-x 3 rbair staff 102 Mar 23 17:39 tmp
rbair$ ls build/mac-sdk/rt/lib/
ext/ libdecora-sse.dylib libprism-common.dylib
javafx.properties libglass.dylib libprism-sw.dylib |
The build is setup to support multiple different SDK builds. However, it is not possible to produce all SDKs from all platforms. For example, the win-sdk cannot be created from a Mac. However, on the Mac, you can compile the mac-sdk, ios-sdk, and android-sdk. On Linux you can compile linux-sdk, android-sdk, armhf-sdk, and armvpf-sdk. On Windows you can compile win-sdk and android-sdk. An attempt to build for a platform that is not supported will result in an error.
To compile for a specific target, set the COMPILE_TARGET property. This is usually done via a -P flag, such as:
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle -PCOMPILE_TARGET=ios sdk |
If you do not specify the COMPILE_TARGET property, then the target will be picked based on what platform you are compiling from. At the present time only Linux x86, Windows, and Mac are platforms that you can compile from, but we would like to add support for compiling from Linux ARM as well (so that you can build the SDK on a Raspberry PI for example, which would be great for educational environments). At this time the following COMPILE_TARGET values are supported or planned:
Note* Right now you cannot specify whether you want 32 or 64, but that option is coming
web'
To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :apps:tasks
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
|
Projects in gradle are named according to their depth. So the root project is simply named "rt" (or whatever your top directory is named). The immediate subprojects are all prefixed with a ":". Sub-subprojects have their parents in their name, for example, ":graphics:effects-jsl". When you execute a command such as gradle assemble what actually happens is that Gradle locates the assemble task on all projects and executes them. (TODO Is this entirely accurate?)
There are a couple other tricks-of-the-trade that you should be aware of. You can execute any gradle command with --info
or --debug
in order to get more output. Running in --info
mode provides some additional debugging output that is very useful when things go wrong.
One more trick is the --profile
argument. You can perform any gradle task and use the --profile
argument. This will cause gradle to keep track of how long various parts of the build took, and will produce an HTML report in build/reports/profile. The report breaks down how much time was spent in configuration, dependency resolution, and task execution. It further breaks it down by project. This gives useful metrics for tracking down which parts of the build take the longest and hopefully tighten up the build times.
There are three main things you may want to do on a regular basis when working on JavaFX: building, testing, and creating documentation. Lets look at each of these in turn.
The simplest basic task to build is the sdk task. The sdk task will compile all Java sources and all native sources for your target platform. It is the default task which is executed if you do not supply a specific task to run. It will create the appropriate sdk directory and populate it with the native dynamic libraries and the jfxrt.jar. Because the SDK is not distributed with documentation, the javadocs are not created as part of the sdk task by default. Once the sdk task has completed, you will have and SDK distribution which you could run against or give to somebody else to run.
Code Block |
---|
$ sh gradlew
...
:buildModulesLinux
:buildRunArgsLinux
:buildModules
:createTestArgfilesLinux
:sdkLinux
:sdk
BUILD SUCCESSFUL in 1m 48s
127 actionable tasks: 127 executed
|
You can find the built SDK in the build/modular-sdk directory:
Code Block |
---|
$ pwd
/Users/kcr/jfx-dev/rt
$ ls -l build/
-rw-r--r-- 1 kcr kcr 1621 Dec 22 09:54 compile.args
drwxr-xr-x 2 kcr kcr 4096 Dec 22 09:54 libs/
-rw-r--r-- 1 kcr kcr 47 Dec 22 09:54 linux_freetype_tools.properties
-rw-r--r-- 1 kcr kcr 681 Dec 22 09:54 linux_gtk2.properties
-rw-r--r-- 1 kcr kcr 799 Dec 22 09:54 linux_gtk3.properties
-rw-r--r-- 1 kcr kcr 255 Dec 22 09:54 linux_pango_tools.properties
drwxr-xr-x 9 kcr kcr 4096 Dec 22 09:54 modular-sdk/
-rw-r--r-- 1 kcr kcr 1916 Dec 22 09:54 run.args
-rw-r--r-- 1 kcr kcr 1379 Dec 22 09:54 run.java.policy
-rw-r--r-- 1 kcr kcr 1304 Dec 22 09:54 test.java.policy
-rw-r--r-- 1 kcr kcr 1551 Dec 22 09:54 testcompile.args
-rw-r--r-- 1 kcr kcr 1846 Dec 22 09:54 testrun.args
drwxr-xr-x 3 kcr kcr 4096 Dec 22 09:54 tmp/ |
The sdk task will build an OpenJFX SDK for your particular platform. Gradle automatically handles the downloading of all dependencies (such as Antlr and SWT located under \rt\build\libs
).
For more information on build properties, see Customizing the Build.
The build is configured to support cross builds, that is, the ability to build an SDK for a platform other than the one you are building from. There are multiple gradle files located in buildSrc which represent specific compile targets. These include:
Each of these have specific prerequisites that must be met before they can be built. win.gradle can only be used on Windows, mac.gradle on Mac, and linux.gradle on Linux. Android can be cross built from Mac, Windows, or Linux so long as the Android SDK and NDK are installed and the build knows where to find them. iOS can be cross built on Mac. ARM (soft float and hard float) can be cross built from Linux.
By default, the OpenJFX build system will only build the SDK for the desktop platform you are building from. To ask it to build for a specific compile target, you must pass a COMPILE_TARGETS property to the build system, instructing it which to build. This is a comma separated list. Assuming you have already setup the prerequisites for building ARM (for example, when targeting the Raspberry PI), you would invoke gradle like this:
Code Block |
---|
$ sh gradlew -PCOMPILE_TARGETS=armv6hf |
Anchor | ||||
---|---|---|---|---|
|
The build can be customized fairly extensively through the use of Gradle properties. Gradle provides many ways to supply properties to the build system. However the most common approach will be to use a gradle.properties file located in the rt directory. Simply make a copy of gradle.properties.template and then edit the resulting gradle.properties file to customize your build.
Code Block |
---|
$ cp gradle.properties.template gradle.properties
|
The gradle.properties file that you have just created is heavily documented and contains information on all the different configuration options at your disposal.
Arguably the most important property in the build is the JDK_HOME property, which will be set to the value of $JAVA_HOME if you haven't explicitly set itArguably the most important flag in the build is the JDK_HOME flag. Almost all other properties are derived automatically from this flagone. THe The JDK_HOME is by default based on the java.home System property, which is set automatically by the JVM based on which version of Java is executed. Typically, then, the version of Java you will be using to compile with will be the version of Java you have setup on your path. You can of course specify the JDK_HOME yourself (but be sure to include the file:// prefix or it will be treated as a relative path):
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle projects --info
...
JDK_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk_b81/Contents/Home
...
rbair$ gradle -PJDK_HOME=file:///Library/Java/JavaVirtualMachines/projects --info
...
JDK_HOME: file:///Library/Java/JavaVirtualMachines/jdk1.8.0.jdk_b78/Contents/Home
... |
The BINARY_STUB (see below), JAVA, JAVAC, and JAVAH properties are all derived from JDK_HOME, but can be specified directly if so needed (not likely). Another property, JDK_DOCS, is used to specify the URL to the JDK javadocs so that when the JavaFX javadocs are generated, any references to JDK classes will be hyperlinked.
There is also a COMPILE_FLAGS_FILE property. This flag is used to load a gradle file which is responsible for setting up the CC_PARAMS, LINK_PARAMS, CC, and LINK properties (and in the case of windows the RC property). For example, on Mac this property defaults to "mac.gradle", while on window it defaults to "win.gradle", and so forth. These supplemental gradle files contain all of the setup unique to those platforms for the sake of native compilation. But this property can be overridden such that a build for some custom system or to use some custom compiler could be made without modifying the core build script or requiring the build file to be stored in the open project. A third party might have some custom compiler or environment for an embedded system, for instance, and would need to customize the compilation flags.
Finally there are a number of properties which are used to define the values in the VersionInfo class. Typically these are set only from Hudson and include:
The next basic task which you may want to perform is test. The test task will execute the unit tests. You generally will execute the top level test because unlike with Ant, Gradle will only re-execute those tests which have changed (or were dependent on code that was changed) on subsequent runs. You can of course execute gradle cleanTest in order to clean all the test results so they will run fresh. Or, if you want to execute only those tests related to a single project, you can do so in the normal fashion:
Code Block | ||||
---|---|---|---|---|
| ||||
rbair$ gradle :base:test
The CompileOptions.useAnt property has been deprecated and is scheduled to be removed in Gradle 2.0. There is no replacement for this property.
:base:processVersion UP-TO-DATE
:build-tools:generateGrammarSource UP-TO-DATE
:build-tools:compileJava UP-TO-DATE
:build-tools:processResources UP-TO-DATE
:build-tools:classes UP-TO-DATE
:build-tools:jar UP-TO-DATE
:base:compileJava UP-TO-DATE
:base:processResources UP-TO-DATE
:base:classes UP-TO-DATE
:base:compileTestJava UP-TO-DATE
:base:processTestResources UP-TO-DATE
:base:testClasses UP-TO-DATE
> Building > :base:test > 3411 tests completed, 45 skipped |
Gradle gives helpful output during execution of the number of tests completed and the number skipped without dumping out lots of output to the console (unless you opt for --info). Also, once the tests complete, an HTML report is dumped to the project's build/reports/test directory (for example, modules/base/build/reports/test):
For the sake of performance, most of the tests are configured to run in the same VM. However some tests by design cannot be run in the same VM, and others cannot yet run in the same VM due to bugs or issues in the test. In order to improve the quality of the project we need to run as many tests as possible in the same VM. The more tests we can run on pre-integration the less likely we are to see failures leak into master. Being able to run 20,000 tests in a minute is extremely useful, but not possible, unless they run in the same VM. Something to keep in mind.
The last of the basic tasks you might want to accomplish is the generation of javadoc. This is done by invoking the javadoc task. NOTE: At present there is a bug where gradle javadoc will fail, but gradle :javadoc succeeds. There really isn't much to say about the generation of javadoc, other than it works .
It is important to understand some unique challenges that come with building for the JDK. All Java developers have experience in building applications which rely on a specific JDK, but very few have attempted to build code for the JDK itself. Welcome to an elite band . As you know, when the JVM starts up, it locates classes on a class path. By default, all JDK classes are first on the class path, before any application code. Normally this is not a problem, because application code is not redefining java.lang.String, for example. However when building JDK code, that is exactly what you are doing. In the case of JavaFX, your version of javafx.scene.Node needs to take precedence over the version of javafx.scene.Node provided by the JDK. Further, since you need a version of the JDK available to build against, you have to deal with the problem of having two versions of most classes on your class path – those provided by the JDK you are building with and those you are providing yourself.
Over the years JDK engineers have developed various techniques for dealing with this problem. The issue manifests itself at two times: when you attempt to build, and when you attempt to run code. For now this document will cover the build part of the problem only. The good news is that the OpenJFX Gradle build handles this for you.
The main contributions of JavaFX to the JDK are the jfxrt.jar file and several native libraries. jfxrt.jar is located on the extension class path. This path comes before application code but after code on the boot class path. Because of this, the jfxrt.jar file is located in JDK_HOME/jre/lib/ext/ (ext here stands for 'extension'). Java allows developers to override the location of the ext directory by means of the -Djava.ext.dirs= command line argument. Setting the value of this argument to empty (i.e.: a dangling = sign with nothing after it) effectively clears the ext path. This means that the jfxrt.jar file shipped with the JDK won't be included on the class path by default.
This is how the OpenJFX Gradle build works. Whenever anything needs to be compiled (whether compiling java sources, or running javadoc) we always set the -Djavafx.ext.dirs flag to be empty. This way the code we're building isn't confused by the presence of another nearly identical set of classes on the ext class path (that is, our locally built jfxrt.jar and associated files take precedence over what is supplied by the JDK).
But, there is a wrinkle. Because OpenJFX is not yet completely buildable based on open software, we need to have the jfxrt.jar supplied by the most recent JDK available to us so that any classes or native libraries that we need for compiling and running (so-called 'closed bits' or 'binary stub') is available. But because JDK_HOME/jre/lib/ext/jfxrt.jar has duplicate classes to those we have built locally, we need to make sure that it is placed last on the class path – after all our own code. This way when the JVM is looking for javafx.scene.Node, it will find our version of javafx.scene.Node first, before the one supplied by the JDK. This, again, is handled for you by the Gradle build.
The OpenJFX Gradle build defines a property called BINARY_STUB, which is a path to a jar file containing the closed bits. This file is then added to the end of the class path when building. Ultimately this will not be needed anymore when the rest of the OpenJFX code is open sourced and a fully open build can be done. However for the moment, this is a requirement to get the build to succeed.
When running gradle normally, minimal output is produced. However if you run your gradle command with --info, additional information is printed at the head of the output, including the value of the BINARY_STUB variable. This must be a path to a copy of jfxrt.jar containing the closed bits. Most often this will be the jfxrt.jar file contained in your JDK_HOME/jre/lib/ext/ directory. Again, our build automatically figures this all out based on the value of your JDK_HOME (which by default is the version of Java you used to run the build).
Each week we produce a published "promoted" build of the JDK which includes the week's worth of changes to JavaFX. Generally speaking if you are building from the "master" OpenJFX forest, then you should always use the same corresponding version of the JDK. For example, on Mar 22 2013 we published b82 of the JDK. When building from OpenJFX master for the following week, use b82. This way the open bits and the closed bits are "matched" and your build will succeed.
During the week many changes go into the "graphics" or "controls" forests. It is possible that some corresponding changes are made to the closed bits during the week. This means when you try to build the "graphics" or "controls" forest, you will not have the corresponding "matched" closed bits available to you, and your build may fail. This situation is temporary and will last only until we have finished open sourcing all of the code.
So 9 paragraphs later, we get to the conclusion. You shouldn't have to do anything special to build OpenJFX for the "master" forest – just run gradle. However if you have a problem, the first step to debugging is to run the command with --info and look at the values of JDK_HOME and BINARY_STUB. If these are correct, make sure you have the right "matched" version of the JDK. You will most likely resolve any build problems by taking those steps. If you have additional build issues, let us know on the openjfx-dev mailing list.
. Note also that on Windows, the version of the JDK you have set as JDK_HOME will determine whether you build 32 or 64 bit binaries.
The next basic task which you may want to perform is test. The test task will execute the unit tests for all projects (all modules). If you want to execute only those tests related to a single project, you can do so in the normal fashion:
Code Block |
---|
$ sh gradlew :base:test
The CompileOptions.useAnt property has been deprecated and is scheduled to be removed in Gradle 2.0. There is no replacement for this property.
:base:processVersion UP-TO-DATE
:build-tools:generateGrammarSource UP-TO-DATE
:build-tools:compileJava UP-TO-DATE
:build-tools:processResources UP-TO-DATE
:build-tools:classes UP-TO-DATE
:build-tools:jar UP-TO-DATE
:base:compileJava UP-TO-DATE
:base:processResources UP-TO-DATE
:base:classes UP-TO-DATE
:base:compileTestJava UP-TO-DATE
:base:processTestResources UP-TO-DATE
:base:testClasses UP-TO-DATE
> Building > :base:test > 3411 tests completed, 45 skipped |
Gradle gives helpful output during execution of the number of tests completed and the number skipped without dumping out lots of output to the console (unless you opt for --info
). Also, once the tests complete, an HTML report is dumped to the project's build/reports/test directory (for example, modules/base/build/reports/test):
For the sake of performance, most of the tests are configured to run in the same VM. However some tests by design cannot be run in the same VM, and others cannot yet run in the same VM due to bugs or issues in the test. In order to improve the quality of the project we need to run as many tests as possible in the same VM. The more tests we can run on pre-integration the less likely we are to see failures leak into master. Being able to run 20,000 tests in a minute is extremely useful, but not possible, unless they run in the same VM. Something to keep in mind.
When running a system test that requires the Robot API, additional flags need to be passed:
Code Block |
---|
sh gradlew -PFULL_TEST=true -PUSE_ROBOT=true :systemTests:test --tests TestClassName |
Using the results of a modular OpenJFX build is quite simple. A "run" args file can be used to point to the overriding modules that are in your build. (args file support for java was added in JDK 9) The file build/run.args and build/compile.args are created during the FX build process. The run.args file contains full paths to the overriding modules and shared libraries, and so must be recreated if you are using a copied or downloaded module set (for example from a nightly build). A script is provided that will recreate the xpatch.args file in the current directory:
bash tools/scripts/make_runargs.sh /absolute_path_to/modular-sdk
The following can be used to set up an alias that can be used to launch a JFX application, but using the FX binaries from your development tree. This alias will override the modules built into JDK9.
export JAVA_HOME="path_to_top_of_JDK"
export JFX_BUILD="path_to_top_of_your_repo"
export JFX_PATCH=$JFX_BUILD/build/run.args (or the path to one created by make_runargs.sh)
alias javafx='$JAVA_HOME/bin/java @$JFX_PATCH'
This alias uses the @argfile mechanism to include all that Xpatch/java.library.path verbosity to create a single command to run FX backed by your recently built binaries.
In Windows, the paths for the alias can be a bit tricky to get right, as the JDK wants native Windows paths, and cygwin often works better with a Unix path. Here is an example that works with Cygwin:
export JAVA_HOME=`cygpath -m "/cygdrive/c/Program Files/Java/jdk-9/"`
export JFX_PATCH=`cygpath -m "$JFX_BUILD/build/run.args"`
alias javafx='"$JAVA_HOME/bin/java" @$JFX_PATCH'
With the module system in JDK 9 and later, it is not possible to easily overlay an OpenJFX build over an existing JDK as was possible with JDK 8. It is possible to build an OpenJDK that included the updated OpenJFX modules.
To create an integrated OpenJDK with OpenJFX requires two builds:
See the following instructions for building OpenJDK. Use the following repository path: http://hg.openjdk.java.net/jdk/jdk.
Build OpenJFX first.
Configure the JDK with the following addition:
--with-import-modules=_path_to_jfx-dev_/rt/build/modular-sdk
Then build the JDK as normal.
The export of module packages is governed by two sets of files:
During the build process, we generate some files for use by the build, and also by developers working in the sandbox.
Each of these files has a "test" variant, for example "testrun.args". These files are altered to add in the "shims" version of the module. Note that the build/shims is not populated by the "sdk" task. Use the "copyGeneratedShims" or "test" task.
When dealing primarily with unit tests, additional arguments are needed to access non public API from within the unit tests. These additional arguments have been placed in "addExports" that are local to the tests that need them. For example, "modules/javafx.graphics/src/test/addExports" contains all of the "--add-exports" clauses required to compile and run all of the graphics module junit tests. Care should be taken when modifying these files, as additions may mean that package module-info may need updates too. Keep in mind - if you are adding an "--add-exports" to ALL-UNNAMED so that a junit test can see the API, then the addExports the right place. If you are trying to fix access by another module, it likely is the wrong place.
The JDK Module System adds complexity to the development chain, but particularly when adding new API and especially packages. Adding a new package or changing package visibility will be a multi step task that will require at least two change sets to implement.
Our developer sandbox build uses several items to work around module export during build and testing that you should be familiar with.
Create a "followup JBS" to cover the cleanup/removal of module access workarounds. Be sure to link this new followup JBS to the one you started with.
Modify affected modules module-info to reflect the proposed changes. These changes will only directly affect the current build java compile process. It is key to remember that the java runtime will ignore any changes to module-info, even while it uses "--patch-module".
The next modify buildSrc/addExport files to mirror changes that were made in the module-info files. Mark any additions with a comment containing the "Completion JBS" number, like this:
# to be removed by 81XXXXX
--add-exports=javafx.graphics/com.sun.javafx.newpackage=javafx.controls
--add-exports=javafx.graphics/com.sun.javafx.newpackage=ALL-UNNAMED
Note, if you add a junit test that for the new package, you will likely also need an export to ALL-UNNAMED (which the junit jar is a member of). The result may be two exports in buildSrc/addExport to add the temporary workarounds required for both development and test. If you are not modifying unit tests - do not add the ALL-UNNAMED line.
Complete development of your new package and adding unit test coverage, and all of the other process we normally do.
Your complete change set will now contain all of the delta required for the nightly build and test your changes. The promotion process will soon merge your module-info changes into the JDK. Once there is a promoted JDK that has the new module-info changes, it is possible to move to the second step.
One consideration - building a local development copy of the JDK is not difficult. In some cases, it may be useful to create a local developer JDK that incorporates the module-info changes, even before development of the changeset it complete. This developer JDK will honor the new package exports without the need of the changes to the addExport files. Note however, your change set may break the build if it has not be tested with the current minimum promoted JDK build.
Once the changes are promoted into a JDK, the second step to remove the addExports workarounds can be scheduled with the team lead.
As both the build machine and the other developers will need to update to the newer JDK build, this step will need to be coordinated.
Create a change set with:
Test, review and commit as normal.