Building and Running OpenJFX
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.
Working with OpenJFX and JavaFX
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:
- JDK1.8 Snapshot release
- Ant 1.8.2
- Mercurial 1.8.2
- Cygwin (for Linux commands on Windows)
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):
- mkdir -p ~/open-jfx
- cd ~/open-jfx
- hg clone http://hg.openjdk.java.net/openjfx/8/master
- cd master
- mkdir -p artifacts/sdk/rt/lib/ext
- cp <PATH TO JDK>jre/lib/ext/jfxrt.jar artifacts/sdk/rt/lib/ext
- hg clone http://hg.openjdk.java.net/openjfx/8/master/rt
- cd rt
- Edit build-defs.xml (comment out '<propertycopy name="javac.debuglevel" from="${ant.project.name}.javac.debuglevel" silent="true" override="true"/>' if not already commented)
- ant
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":
- antlr-3.1.3.jar
- antlr-runtime-3.1.3.jar
- stringtemplate-3.2.jar
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):
- java -Xbootclasspath/a:<PATH TO HOME DIR>/open-jfx/master/rt/javafx-ui-controls/dist/javafx-ui-controls.jar:<PATH TO JDK>/rt/lib/jfxrt.jar" test.HelloButton
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.
Coming Soon: Gradle Build for OpenJFX
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.
Once you are setup and ready to go, the first thing you should do is generate the project files for your preferred IDE.
gradle netBeans
gradle idea
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!
Unique Challenges of Working on the JDK
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.