Nokia nmake 15 JAVA(1)


:JAVA: − Java source dependency operator


:JAVA: files-or-directories


Java files to be built are specified by the right hand side arguments. There must be at least one right hand side (rhs) argument. Each rhs argument specifies a pathname and may be one of the following types:


Pathname of a Java source file. Shell pathname expansion patterns such as *.java work as expected. This is typically, but not necessarily, a relative pathname.


Pathname of a directory. This is equivalent to specifying the relative pathnames of all .java files which exist in the tree rooted at the specified directory. Shell pathname expansion is not supported for directories.

The :JAVA: operator uses dependencies among .java and .class files to insure that build steps run in the proper order, and that only necessary build steps get run. These dependencies are automatically derived from Java source files; furthermore, complex requirements of Java builds, such as dependency cycles and implicit targets, are correctly handled. However, to speed the development cycle this version of :JAVA: does not by default automatically update the dependencies themselves each time a build is run. If javadeps=1 or no $(LOCALJAVADEPS) file exists in the viewpath the dependencies are automatically updated from source, otherwise the dependencies in $(LOCALJAVADEPS) are used. The user is responsible for updating the dependencies whenever Java source is changed in a way that modifies the dependencies among .java and .class files.

For proper and consistent :JAVA: operation, Java source files must be arranged in a package hierarchy that mirrors their directory hierarchy. This is as recommended on the javac(1) manual page. For example, if $(JAVAPACKAGEROOT) is $(VROOT)/javapkg, Java source in $(VROOT)/javapkg/com/alcatel_lucent/src/pkg1/ must be declared as package com.alcatel_lucent.src.pkg1, typically through a declaration like:

package com.alcatel_lucent.src.pkg1;

:JAVA: checks for missing or inconsistent package statements and issues a fatal error if any are found.

In order to speed up dependency maintenance, this version of :JAVA: updates dependencies incrementally if possible. This means that only source files whose modification time is changed since the last run are rescanned for dependencies. Dependency information for other files is reused from the last run.

Since commonly used Java compilers have a high startup overhead, :JAVA: provides an optional feature (enabled by default) which reduces the number of Java compiler invocations by batching calls to the compiler. That is, instead of compiling Java files one by one as is normally the case in nmake based builds, :JAVA: arranges for Java compilations to be queued, and only runs the compiler when the queue length exceeds a threshold. This approach can dramatically reduce build times. The maxjavac variable provides user control over this feature.

Removing a File from the Build
Since Java source files are not typically listed in the makefile they cannot simply be removed from the makefile to be removed from the build. Deleting a Java source file will eliminate that file from a build. However, in a viewpathing situation where versions of the deleted file remain in other viewpathed nodes, those unwanted versions will still be picked up. The #empty feature provides a way to remove a Java file from a build and also mask out viewpathed files in other nodes.

Java source files containing the string ‘‘#empty’’ outside of comment sections and as the first item on a line are not built. The contents of a source file can be changed to ‘‘#empty’’, masking out old versions of the file in the viewpath, when it should no longer be built.

Source files changed to ‘‘#empty’’ in an incremental build will have the contents of their class files changed to ‘‘#empty’’ effectively removing the class and masking out old versions in the viewpath.

Files that were ‘‘#empty’’ in the initial build and have ‘‘#empty’’ removed in an incremental build will be compiled only if javadeps=1 is set, just like when adding new code to a build. Note, the user is responsible for setting javadeps=1.

Filtering can be turned off by including the following in the makefiles: : .CLEAR

Global and Local Java Builds
Due to cross-package dependencies, Java builds are best managed using a single top-level Makefile in the Java package root directory. This Makefile contains a global set of Java dependencies in all subpackages, ensuring that class files get rebuilt when necessary no matter which package they reside in. As a consequence, global and package local Java builds are organized differently from traditional C/C++ builds.

A global build is run from the package root directory and brings all subordinate packages (as specified on the rhs of :JAVA:) up to date. The top-level Makefile knows all dependencies among Java and class files in subordinate packages, detects out-of-date targets, and initiates all compilations directly from the top level directory. This is unlike traditional C/C++ builds, where the top-level Makefile merely recurses to lower level directories, and actual compilations are performed by local Makefiles located within each source directory. In the case of Java global builds, local Makefiles are not used, and not needed.

The use of the top-level Makefile provides correct dependency management, however, when developing inside a package, local Makefiles have some advantages: they allow a build to be conveniently started without leaving the local directory, and they allow specification of a subset of local targets for update. To provide these conveniences while retaining the benefits of global dependency management, :JAVA: provides support for the safe use of local inside-package Makefiles. These local Makefiles also use the :JAVA: assertion to specify a local set of Java source files to build. To actually perform a build, :JAVA: collects the build targets (whether explicitly specified or defaulted), changes to the package root directory (by default), and builds the specified targets in the context of the global package dependencies. This ensures that the minimal work will be performed to bring the specified local targets up to date, but that other targets, including possibly files in other packages, will be updated if required to bring the specified local targets up to date. An example of a local package build is shown below. A locally issued clobber will only remove generated files that are within the local package.

By default, all builds (even builds initiated from local package Makefiles) are performed at package root level. Builds at package root are termed global builds since they can ‘‘see’’ all packages rooted at $(JAVAPACKAGEROOT) and can take into account all dependencies across packages, even when updating only a local subset of project class files. In some circumstances, it may be desirable to actually perform the build at a lower package level. This truly local build can only manage class files dependencies within the package level or below, but may be more efficient since fewer class files are involved. Use the JAVABUILDDIR variable to specify a local build execution directory. To build within the current directory only, set JAVABUILDDIR=.. Setting JAVABUILDIR to intermediate directory levels between . and JAVAPACKAGEROOT is also possible. The build execution directory must have a Makefile. Use JAVABUILDDIR with caution.

Variables and Atoms
Several user-settable nmake variables influence the behavior of the :JAVA: operator. The JAVAPACKAGEROOT variable has no default and must be defined:

Package root directory for Java source files. Typically specified in a global Makefile in the form $(VROOT)/java-root-offset. As discussed previously, each Java source file offset relative to JAVAPACKAGEROOT must be consistent with its Java package name. The top-level global build is performed at JAVAPACKAGEROOT.

All other variables are optional. The following variables specify the locations of files and commands used:

Java class search path, as used by $(JAVAC). Within a Makefile, .SOURCE.class is preferred.


Location of file containing Java dependency data. Used for merging incremental dependency scans. Defaults to globaljavadeps. This file is generated automatically by $(JDEPS).


Build execution directory for inside-package local builds. Default is $(JAVAPACKAGEROOT), meaning that builds are performed at package root level. This is the safest setting since it accounts for cross-package dependencies. To force build execution to be strictly local, set JAVABUILDDIR to ‘.’. Use with caution, since with this setting prerequisite files in other packages will not be updated.


Java compiler. Defaults to javac.


Java compiler flags. Defaults to null.


Destination directory for class files, typically $(VROOT)/java-class-offset. This sets the $(JAVAC) -d option. Default is $(JAVAPACKAGEROOT).


Makefile name in build execution directory, if that directory is different from the current directory. Defaults to [Mm]akefile.


Java source dependency scanner. This is an external tool used to extract dependency information from Java source files. Defaults to an external scanner which is known to produce dependency information in a format usable by nmake. Default is $(JDEPSDIR)/jdeps.


Pathname of directory where javadeps package may be found. Defaults to first directory that exists of nmake_install_root/../jdeps and nmake_install_root/../../jdeps.


Location of jdeps jar file. This file is required in order to run $(JDEPS), and defaults appropriately to properly run the external scanner. Default is $(JDEPSDIR)/jdeps.jar.


Location of file containing Java dependencies. Defaults to localjavadeps. This file is generated automatically by $(JDEPS).


Syntax configuration file for $(JDEPS). Default is $(JDEPSDIR)/synconfig.

The following variables provide fine control over the behavior of the :JAVA: operator:

Maximum number of Java files to be compiled in a single call to javac(1).


javadeps=1 triggers an incremental update of the Java file dependencies (out-of-date source files are rescanned for dependency information). For performance reasons the user is responsible for setting javadeps=1 whenever Java source is changed in a way that modifies the dependencies.

recurse_begin_message, recurse_end_message

Specify overrides for the messages emitted when recursing to the package root directory.


Allow a convenient shorthand for target paths specified on the command line. java_warp_target specifies an edit operation that selects local targets to be ‘‘warped’’ to their corresponding location under JAVACLASSDEST. For example, if java_warp_target=N=*.class and we are in the source directory of package com/stc/pkg1, saying ‘nmake A.class’ will actually build $(JAVACLASSDEST)/com/stc/pkg1/A.class.

The following special atoms are used:

javac -classpath command line option. Note that the meaning of this option changed between JDK1.1 and JDK1.2. One consequence is that the system library must be included in the .SOURCE.class atom for JDK1.1, but not for JDK1.2.

Directories to search for Java files.


Directory Structure

<viewpath_root_dir>/    # $(VROOT)
  java/                 # $(JAVAPACKAGEROOT)            # global Makefile
    Makefile            # top level Makefile
            Makefile    # local Makefile
    class/              # $(JAVACLASSDEST)

Global Build Example
Contents of viewpath_root_dir/java/ Note that JAVAPACKAGEROOT has no default and must be specified:


Contents of top level Makefile viewpath_root_dir/java/Makefile:

include $(VROOT)/java/
:JAVA: com/alcatel_lucent/stc/pkg1 com/alcatel_lucent/stc/pkg2

Then a global build from directory viewpath_root_dir/java generates all dependencies and compiles all Java source files in packages 1 and 2:

$ nmake
+ /tools/nmake/javadeps-lu2.0.2/jdeps /tools/nmake/javadeps-lu2.0.2/jd
eps.jar -C JAVACLASSES -n --vpath=/home/gms/wrk/nmake/java/phase2/user
man/java --silent -s /tools/nmake/javadeps-lu2.0.2/synconfig -o localj
avadeps -d ../class --classpath=../class:/opt/exp/java/lib/
 com/alcatel_lucent/stc/pkg1/ com/alcatel_lucent/stc/pkg1/
 com/alcatel_lucent/stc/pkg2/ com/alcatel_lucent/stc/pkg2/
+ /opt/exp/bin/javac -O -d ../class -classpath .:../class:/opt/exp/jav
a/lib/ com/alcatel_lucent/stc/pkg2/ com/alcatel_lucen
t/stc/pkg1/ com/alcatel_lucent/stc/pkg2/ com/alcatel_lucen
t/stc/pkg2/ com/alcatel_lucent/stc/pkg1/

In this case, the following :JAVA: assertion has the same effect:

:JAVA: com

To incrementally update the dependencies in addition to updating the .class files, run:

$ nmake javadeps=1

As described previously, the global build is totally managed by viewpath_root_dir/java/Makefile, no recursive makes are done.

Local Package Build Example
Continuing the above example, suppose we now want to work within a package. viewpath_root_dir/java/com/alcatel_lucent/stc/pkg2/Makefile is an example of a package local Makefile:

include $(VROOT)/java/

The local package working directory is viewpath_root_dir/java/com/alcatel_lucent/stc/pkg2. From this directory, a developer may edit the local Java files, and BR , and then run nmake:

$ cd viewpath_root_dir/java/com/alcatel_lucent/stc/pkg2
$ touch
$ nmake
+ cd
+ nmake javasdir=com/alcatel_lucent/stc/pkg2 E.j
ava javaclassdest=../../../../../class javadeps=0
+ /opt/exp/bin/javac -O -d ../class -classpath .:../class:/opt/exp/jav
a/lib/ com/alcatel_lucent/stc/pkg2/ com/alcatel_lucen
t/stc/pkg1/ com/alcatel_lucent/stc/pkg2/ com/alcatel_lucen

As described previously, the specified targets are passed up the top level Makefile, and the build is actually performed in $(JAVAPACKAGEROOT). Note that due to the complex dependencies of this example, a Java file from another package is brought up to date in addition to files in the local package.


:JAVA: uses a Java-based scanner to extract dependencies from Java source. This scanner requires JDK version 1.2.1 or higher to run.

assert and enum are treated as Java keywords, so may not be used for other purposes in Java source. This is in accordance with recent JDK releases ( assert was introduced in JDK 1.4, enum in JDK 1.5/J2SE 5.0).

Operation on Windows® Systems

Setup and use of the Interix and UWIN-based versions of Nokia nmake is similar to usage on the UNIX® version. There are several rules to keep in mind:

In Nokia nmake Makefiles, absolute paths must be in UNIX format.

VPATH must also be in UNIX format. ‘:’ is the path separator.

CLASSPATH must be in Windows format because it is directly used by Java SDK for Windows. ‘;’ is the path separator.

On UWIN with the case insensitive setting, user Makefiles must not have names,, or any variant of these names differing only in case (, etc). Due to case insensitive filename conventions on Windows systems, these files will mask the system files that define :JAVA: and :JAR: leading to undefined operator errors. On UWIN with the case sensitive setting, and are valid Makefile names.

Interix supports full case sensitivity for files on locally mounted NTFS file systems, so problems due to case insensitivity do not apply in this case. Under Interix, file names on Windows file shares still exhibit case insensitive behavior.

$JAVAHOME/bin should be before /win on the PATH. Otherwise, nmake can not find java.exe.

Several of these rules arise because the UWIN and Interix-based nmake engines use UNIX file paths while the Windows-based Java JDK uses Windows file paths. The implementation uses a wrapper program called npwj(1) which converts file paths from UNIX to Windows format. npwj is also useful as an convenient helper utility for running Windows-based Java SDK tools from the UWIN command line. See the npwj(1) manual page for more information.

There are several implementation issues:

On UWIN, a typical default home directory is /home/username. /home/username often maps to ‘‘C:\Program Files\UWIN3.x\home\username’’ on Windows. Because the current Java support on UWIN does not support space in Windows pathnames, users are asked to work under directories that do not contain space in either the UNIX pathname or Windows pathname. /home/username is usually not a valid choice. For the same reason, javadeps should also be installed in a directory which does not contain space in either UNIX or Windows pathnames. Directories containing spaces should also be avoided under Interix.

Occasionally, the absolute path to java.exe needs to be specified in the jdeps shell script. For an unknown reason, UWIN may fail to locate java.exe even when $JAVAHOME/bin is at the beginning of $PATH.

Under Interix, depending on the shell used, the .exe suffix may be required in order to find executables. For example, specify javac.exe rather than just javac.


JAR(1), npwj(1), nmake(1)
nmake User’s Guide
nmake Reference Manual
nmake Web Site

nmake 15 June 2013 JAVA(1)