8.4 Building Java Applications Successfully

The following alternatives allow you to successfully build Java applications with clearmake or omake:

The following sections describe each option in detail.

Writing Correct Makefiles

A correctly written makefile results in a correct set of configuration records, which gives you the full power of ClearCase configuration records and winkin without unnecessary rebuilding and without missing rebuilds. You can restructure a makefile to avoid javac's automatic building behavior by enforcing that files on which other files depend are built before their dependents.

NOTE: clearmake and omake detect implicit dependencies but cannot determine build order dependencies. If you want files to build in a certain order, you must declare that order in the makefile by adding additional dependencies.

You must take extra care when handling mutually dependent files, because there is not necessarily a correct order for building them. One possibility is to always generate all mutually dependent files as one unit, that is, in one configuration record. You can write the build script for a set of mutually dependent files to delete all class files that correspond to those files before building any of them. This ensures that they are not overwritten individually and makes them available as a unit for winkin.

The advantage of writing your makefile correctly is that it does not cause extra compilations or rebuilds. No special makefile directives are required, the configuration records have no unusual properties, and winkins will work fully. The disadvantage is that the makefile must always be synchronized with the structure and dependencies of the application.

The following sections are makefile examples for applications with particular dependency characteristics.

No Mutually Dependent Files

In this application, classes x, y, and z have a hierarchical dependency graph:

The makefile for such a dependency structure is very simple:

.SUFFIXES: .java .class

.java.class:
javac $<
x.class: y.class
y.class: z.class

Mutually Dependent Files

This application consists of classes top, a, b, c, and d, which have a more complex dependency structure:

The makefile for this dependency structure is somewhat longer, but correct:

top.class: a.class b.class
javac top.java

a.class: b.class

b.class:
rm -f a.class b.class
javac a.java b.java

b.class: c.class

c.class: d.class

d.class:
rm -f c.class d.class
javac c.java d.java

Allowing Rebuilds

If you continue to invoke clearmake or omake until it determines that all files are up to date, the other ClearCase features work correctly. The configuration records record all class files as implicit dependencies rather than siblings, which allows winkin to work.

However, the number of rebuilds can become very large if the makefile is written incorrectly. It is possible to map out a correct set of dependencies as described in Writing Correct Makefiles; it is also possible to request (however inadvertently) that clearmake or omake build the files in exactly the reverse, and most inefficient, order.

In addition, clearmake and omake's default behavior is to ignore modifications to siblings for the purposes of rebuilding. For winkin to work correctly, you must reenable that behavior by using a command-line option or special makefile directive.

Another drawback to this method is that the builds of mutually dependent source files do not fit well, because the files are never up to date. The makefile for these must be written carefully, as described in Writing Correct Makefiles.

Configuring Makefiles to Behave Like make

By using special targets (called directives in omake), you can configure your clearmake or omake makefile so that clearmake or omake behaves as make does with regard to Java builds. The following targets eliminate the extra rebuilding described in Allowing Rebuilds:

.NOCMP_SCRIPT: %.class

(omake only)

.NO_CMP_SCRIPT: %.class

(clearmake only)

.DEPENDENCY_IGNORED_FOR_REUSE: %.class

.NOCMP_SCRIPT and .NO_CMP_SCRIPT disable build script checking. However, relevant build-script changes are ignored. In addition, .NOCMP_SCRIPT and .NO_CMP_SCRIPT have no effect during winkin, so even when they are in use, winkins are prevented because of build script differences. Therefore, you must use manual winkins (see the winkin reference page) or forego them entirely.

.DEPENDENCY_IGNORED_FOR_REUSE disables the version checking of implicit dependencies when clearmake or omake is looking for DOs to reuse. This can cause desired rebuilds to be missed, however. One benefit of using clearmake or omake is automatic dependency detection (for example, of .h files in a C build), so it is not desirable to give this up.

To improve the missed implicit dependency checking caused by .DEPENDENCY_IGNORED_FOR_REUSE, you can add the missing dependencies as explicit dependencies in the makefile. However, this is a manual process, and you still lose build script checking and winkin. The remaining benefit of using clearmake or omake is configuration records (though the catcr output for them may be confusing).