Ant and Platform Specific macrodefs

Ant works great for any pure Java project, very simple to deal with, might get a little tricky when dealing with jar manifests, but not bad, and very efficient in terms of limiting the Java VM startup overhead. But what about platform specific tasks? I myself find the "<exec>" ant task so painful to use that I avoid it at all costs, or at least isolate each use to a "<macrodef>". And this macrodef isolation actually works pretty well when you are dealing with many different platforms that you need to build on.

There are many solutions to the issue of platform specific builds, including the ant cpptasks and I am sure many more. So what I am saying here is not new and not the end all to this issue. Just some ideas for people to consider when up against this problem. Please, add your comments if you have some good references and ideas. It's very obvious to me that I am no where near an ant expert, so take all this with a grain of salt. I also want to give credit to the many JavaFX teams and individuals you wrote the various ant scripts in all the repositories, most of this is a consolidation of other peoples ideas and techniques.

So how did the JavaFX SDK deal with multiple platform issues in ant? This project was composed of many sub repositories, each with different system needs and often using slightly different techniques for building. The top repository (or setup repository or root repository) we have allows for this independence as much as possible, but at the same time trys to create some kind of structure to the build process. From the Mercurial file view of the openjfx-compiler setup repository, I will try and explain what is happening.

  • Basic OS arch detection is done in the file build-os-arch.xml:

    People unfamiliar with xml or ant might find the syntax a bit convoluted, it takes time to get used to it. Key here is the property os_name (which will contain one of: solaris, windows, linux, or macosx), and will be used in the build-defs.xml file to import the right platform specific file build-${os_name}-defs.xml. Keep in mind this is unique to this project, but the basics should work for any multi-platform build project.

  • The platform specific macrodefs are in the build-${os_name}-defs.xml files, customized for each OS, and each defines the -init-platform-defs task. Consider the macosx file:

    Special to this file is the ability to run the xcodebuild utility, this macrodef should probably be turned into some kind of generic do-project-build macrodef, someday. Note that with the JavaFX SDK project we have allowed teams to work in sparse Mercurial forests, this repository we are looking at is the top repository but it could have many sub repositories. Depending on the sub repositories present, there are different needs. We try and check them in these build-${os_name}-defs.xml files, via the -init-platform-defs target.

  • Pull it all together with the file build-defs.xml which we ask all sub repositories to import early in their own build.xml

    This file is imported by each subrepository. Note that this file imports build-os-arch.xml, build-${os_name}-defs.xml, and many other files to provide lots of macrodefs and property settings for a sub repository.

  • Then we established an ant target contract between each sub repository and the top repository by requiring certain jfx-\* targets to be available in the sub repository, for example in the openjfx-compiler repository build.xml file (somewhere in the first 100 lines you should see jfx-\* targets defined):

    Note that it imports in ../build-defs.xml and has defined a set of jfx-\* targets for use by the top repository build.xml file.

  • The forest build script then uses some macrodefs to cycle through the various sub repositories (sometimes called components) in the file build-components.xml, look for the do-all-\* targets:

    Which you will see imported in the top level build.xml file:

    We have a cached area where a previous SDK build is used in the case of a partial forest, allowing a developer to concentrate on the work in a single repository and not have to build the entire forest. The OpenJDK builds uses a similar concept with the Import JDK, where the pieces you aren't building can come from. Effectively, we will cycle over the sub repositories present, in a particular order, and request each one to perform a certain action as defined by the jfx-\* target contract. Look for the use of the do-all-components macrodef for where we will cycle over the sub repositories. (It's a shame that ant doesn't have some kind of applyant task, but you use the tools you are given.)

    You can read more about all this in the JavaFX SDK Build README.

The JavaFX SDK project is a bit unique, and the techniques used in it's build process may not suit many projects, but I thought some of this might be of interest to anyone considering putting their hand into any large ant nest someday. :\^)

Hope someone has found this helpful, as always, comments on better ideas is always welcome.



Post a Comment:
Comments are closed for this entry.

Various blogs on JDK development procedures, including building, build infrastructure, testing, and source maintenance.


« July 2016