Issue No. 12 - August 09, 2002
|
Version lu3.5 was released on June 14, 2002 for all Tier 1 and Tier 2 platforms. For a full list of fixes and enhancements see the release notes. The more significant new features and enhancements include the following:
:: assertion operator can now be
used to build shared libraries. Many users find this easier to use
than :LIBRARY:.
-I- for referencing include files in the viewpath.
See the quoteinclude article below for more
discussion about this feature.
.SCAN.idl scan rule is now defined in the base rules.
-I-
support. The .INCLUDE. function can now generate
-I command line flags which include the -I-
(or similar) flag.
-I-
but not prefixinclude, nmake will add the necessary prefix
directories to the -I search list on the compile command
line to allow the native preprocessor to locate the headers in these
directories. There are some caveats when using this feature.
See the prefixinclude FAQ
for a detailed discussion on this feature.
Release lu3.5 includes a new feature which allows Java developers to launch builds from inside a package. This feature was mentioned in the previous newsletter outlining the motivation for the feature. In this article we will take a closer look at building inside a Java package using lu3.5. For detailed information about the Java options and features see the lu3.5 :JAVA: man page.
The inside-package builds are intended to make it easier for development; a developer can make code changes and launch nmake in the same directory. A makefile is still required at the package root for the full builds, and in fact, the package root makefile is also used for the inside-package builds.
Let's use the following directory tree as an example:
/home/richb/n12/ <---- build root; VPATH=/home/richb/n12
src/
java/ <---- package root
Makefile
com/
lucent/
stc/
|
----------------------------------------------------
| | | |
pkg1/ pkg2/ pkg3/ pkg4/
B.java D.java M.java P.java
C.java E.java N.java Makefile
A.java Makefile Makefile
F.java
G.java
Makefile
The package root makefile, located at src/java/Makefile, is responsible for building the all the Java code underneath it. The makefile looks like this:
/* -- src/java/Makefile -- package root Java makefile */ JAVAPACKAGEROOT = $(VROOT)/src/java JAVACLASSDEST = $(JAVAPACKAGEROOT)/class :JAVA: com
JAVAPACKAGEROOT variable is mandatory as of lu3.5.
If it is not defined nmake will issue an error and exit.
JAVAPACKAGEROOT defines the Java package root directory
and is needed so the inside-package build can find the root.
We advise against using JAVAPACKAGEROOT=$(VROOT)/$(VOFFSET)
or JAVAPACKAGEROOT=$(PWD) because it will be incorrect
when the Makefile is copied and used for an inside-package build.
The recommended form, shown above, will also be correct when put in a
global makefile for projects which use a single common Java root directory.
JAVACLASSDEST variable defines the destination
directory for the compiled classes. If the directory does not
exist it will be created. Sub-directories will be created as
necessary to reflect the package structure of the classes.
:JAVA: assertion builds all the *.java
files under the com sub-directory.
First we will build our Java code from the package root as will
typically be done in full builds. In this example we will run
nmake in directory /home/richb/n12/src/java/.
Since VROOT is used in the Makefile we must set the
viewpath correctly.
$ cd /home/richb/n12/src/java $ export VPATH=/home/richb/n12 $ ls -l total 40 -rwxr-xr-x 1 richb richb 149 Aug 1 13:00 Makefile drwxr-xr-x 3 richb richb 4096 Jul 24 13:46 com $ nmake + /tools/nmake/javadeps/jdeps /tools/nmake/javadeps/jdeps.jar -C JAVACLASSE S -n --vpath=/home/richb/n12/src/java --silent -s /tools/nmake/javadeps/syn config -o localjavadeps -d ../../src/java/class --classpath= com/lucent/stc /pkg1/A.java com/lucent/stc/pkg1/B.java com/lucent/stc/pkg1/C.java com/luce nt/stc/pkg1/F.java com/lucent/stc/pkg1/G.java com/lucent/stc/pkg2/D.java co m/lucent/stc/pkg2/E.java com/lucent/stc/pkg3/M.java com/lucent/stc/pkg3/N.j ava com/lucent/stc/pkg4/P.java + mkdir -p ../../src/java/class/com/lucent/stc/pkg2 + mkdir -p ../../src/java/class/com/lucent/stc/pkg1 + mkdir -p ../../src/java/class/com/lucent/stc/pkg3 + mkdir -p ../../src/java/class/com/lucent/stc/pkg4 + javac -O -d ../../src/java/class -classpath . com/lucent/stc/pkg2/D.java com/lucent/stc/pkg2/E.java com/lucent/stc/pkg1/G.java com/lucent/stc/pkg1/C .java com/lucent/stc/pkg1/B.java com/lucent/stc/pkg1/F.java com/lucent/stc/ pkg3/M.java com/lucent/stc/pkg3/N.java com/lucent/stc/pkg4/P.java com/lucen t/stc/pkg1/A.java
Javadeps was run first to generate the Java dependencies. These are
stored in files globaljavadeps and localjavadeps.
Next, the destination class directories were created. And finally,
javac was run to compile all the Java code.
A directory listing shows the following:
$ ls -l total 136 -rwxr-xr-x 1 richb richb 149 Aug 1 13:00 Makefile -rw-r--r-- 1 richb richb 20066 Aug 1 14:16 Makefile.mo -rw-r--r-- 1 richb richb 19308 Aug 1 14:18 Makefile.ms drwxr-xr-x 3 richb richb 4096 Aug 1 14:16 class drwxr-xr-x 3 richb richb 4096 Jul 24 13:46 com -rw-r--r-- 1 richb richb 2642 Aug 1 14:16 globaljavadeps -rw-r--r-- 1 richb richb 3371 Aug 1 14:16 localjavadeps
Running nmake again does nothing because all our classes are up-to-date.
$ nmake
Now we are ready for an inside-package build. Say we are doing development
work and making changes to pkg1. We can sit in the pkg1/
directory, edit code and rebuild without going back to the package root.
We will need to copy the package-root makefile to the package directory
we are working on and make a small modification to the makefile.
$ cd com/lucent/stc/pkg1 $ cp ../../../../Makefile . $ vi Makefile [ edit Makefile and save ] $ cat Makefile /* -- src/java/com/lucent/stc/pkg1/Makefile -- */ JAVAPACKAGEROOT = $(VROOT)/src/java JAVACLASSDEST = $(JAVAPACKAGEROOT)/class :JAVA: *.java
The :JAVA: assertion has been changed because com
on the RHS is no longer valid for this directory. Instead we specify
*.java to bring all the .java files in this directory up to date.
We can now edit some Java files and rebuild. Running nmake inside the package causes a recursive nmake call to the package root directory which bring our classes up-to-date. Recursing to the package root allows nmake to use the original dependency and state information to determine what to rebuild.
$ vi C.java [ edit C.java and save ] $ nmake + cd /home/richb/n12/src/java + nmake javasdir=com/lucent/stc/pkg1 javarhs=*.java javaclassdest=../../../ ../../../src/java/class javadeps=0 + javac -O -d ../../src/java/class -classpath .:class com/lucent/stc/pkg1/C .java com/lucent/stc/pkg1/B.java
The variable JAVAMAKEFILE is used to specify the makefile
name when the package root makefile does not use the default name.
For example, say the package root makefile is named "java.mk".
JAVAMAKEFILE can be specified in the local makefile or on
the nmake command line. It is easiest to define it in the local makefile
and not worry about it.
$ cat Makefile /* -- src/java/com/lucent/stc/pkg1/Makefile -- */ JAVAPACKAGEROOT = $(VROOT)/src/java JAVACLASSDEST = $(JAVAPACKAGEROOT)/class JAVAMAKEFILE = java.mk :JAVA: *.java $ touch C.java $ nmake + cd /home/richb/n12/src/java + nmake -f java.mk javasdir=com/lucent/stc/pkg1 javarhs=*.java javaclassdes t=../../../../../../src/java/class javadeps=0 + javac -O -d ../../src/java/class -classpath .:class com/lucent/stc/pkg1/C .java com/lucent/stc/pkg1/B.java
Targets and variable assignments are currently ignored when specified on the
inside-package, nmake command line. In the future these command line
parameters will be passed up in the recursion to the package root. Additional
future enhancements include issuing the standard recurse message rather than
showing the explicit cd and nmake calls.
The quoteinclude feature was introduced in
Release lu3.5.
Using quoteinclude, a project can make full use of viewpathing using
compilation tools which do not support -I-.
This is done by enforcing the exclusive use of
#include <...> directives, which do not require
-I- for viewpath support.
In many cases #include "..." is not necessary since nmake
searches the current directory even for files included with
<...>.
Another motivation for quoteinclude is the elimination of nmake cpp
which simplifies the build process thereby increasing its robustness, and
may speed up builds a bit by eliminating a compilation step.
With quoteinclude
enabled, nmake will emit a warning or error when a #include "..."
directive is detected inside the viewpath when the viewpath contains more than
one node. Developers can then change their code to use
#include <...>.
The value of $(quoteinclude) defines the severity level
of the error, where the severity level matches the level specified for
the nmake error statement. Setting quoteinclude=1
or 2 will cause nmake to issue a warning. Setting
quoteinclude=3 will cause nmake to exit with an error.
For the following example say our project must use a C compiler which
does not support -I- and which is incompatible with nmake cpp.
In order to safely use a viewpathing build environment we will use a
strict quoteinclude policy. The global makefile defines the following:
/* -- src/global.mk -- project global rules -- */ /* use the native preprocessor of our special compiler */ CC = zcc nativepp = -1 /* issue an error for #include "..." directives in the vpath */ quoteinclude = 3
Now we have some code to build. Here is the makefile:
/* -- src/lib/Makefile -- */ include $(VROOT)/src/global.mk .SOURCE.c : /home/richb/3rd-party/v1.7 libabc.a :: abc.c xyz.c
We have one local file being developed, abc.c. We are also
using a 3rd-party source file, xyz.c, which is installed
outside of the build node. We'll reference the 3rd-party file by
.SOURCE.c. Both source files include a user supplied
header, abc.h.
/* -- src/lib/abc.c -- */
#include "abc.h"
#include <stdio.h>
int abc(){
printf("abc\n");
return(0);
}
/* -- 3rd-party xyz.c -- */
#include "abc.h"
#include <stdio.h>
int main(){
printf("xyz\n");
return(0);
}
Now let's try to build it.
$ echo $VPATH /home/richb/n12:/home/richb/n11 $ pwd /home/richb/n12/src/lib $ ls -l total 16 -rw-r--r-- 1 richb richb 93 Aug 8 17:38 Makefile -rw-r--r-- 1 richb richb 111 Aug 8 17:34 abc.c -rw-r--r-- 1 richb richb 38 Aug 8 17:35 abc.h $ nmake make: *** error abc.c uses quoted include for abc.h $ echo $? 1
Oops. We need to change the include directive in abc.c:
/* -- src/lib/abc.c -- */
#include <abc.h>
#include <stdio.h>
int abc(){
printf("abc\n");
return(0);
}
Ok, let's try building again.
$ nmake + zcc -O -I. -c abc.c + zcc -O -I. -c /home/richb/3rd-party/v1.7/xyz.c + ar r libabc.a abc.o xyz.o ar: creating libabc.a + rm -f abc.o xyz.o
Success! Notice xyz.c still includes "abc.h"
with quotes, but it does not generate an error because xyz.c
is not in the viewpath.
One drawback of quoteinclude is the requirement to manually edit source files to change the type of include directives used. This can be particularly serious for large projects. We would like to gauge interest in the development of a tool to automatically convert files and verify correctness of the conversion. If you would be interested in such a tool please contact us.
Sometimes we run into tools which provide no means to pickup files through the viewpath. For such tools it is often necessary to copy the input files that are not in the current viewpath node to the current directory before running the tool. The following example illustrates a simple technique to accomplish this.
1 /* -- src/cf/Makefile -- **/ 2 3 rainbow : red orange yellow green blue indigo violet 4 $(*:N=/*:@Y?cp $(*:N=/*) .??) 5 myapp $(*:B:S) > $(<) 6 $(*:N=/*:@Y?rm $(*:N=/*:B:S)??)
Line 3 defines the assertion. The target rainbow will be made from the prerequisite files red, orange, yellow, green, blue, indigo and violet.
Line 4 copies the needed files to the current directory. Variable
$(*) expands to all the file prerequisites, including their
paths. Files not in the current node will be referenced using their absolute
path. :N=/* returns the files that start with "/".
This will give us the files down the viewpath since files in the local node
are referenced with their relative paths. The :@Y edit
operator will return the string between the first two question marks
if the previous string is not null, and the string between the second
and third question marks if the previous string is null. In other words,
if $(*:N=/*) lists any files then the :@Y
operator will expand "cp $(*:N=/*) .", otherwise it will
expand null. (The actual edit operator is :Y (yield).
The "@" is added so the previous string is treated as one token,
otherwise the :Y operation will expand once for each file in
the list.) The result is, if
any files are down the viewpath, then the entire variable will expand
to the copy command to copy those files to the current directory. If
all the files are in the local node then the variable will expand to null
and no operation will be performed.
Line 5 runs our application on the prerequisite files. Notice here we
use the :B:S edit operators to remove the directory path
from the files so they will be referenced in the current directory.
Finally, Line 6 removes the files we copied to the current node in line 4.
It is very similar to line 4. We check if any of the prerequisite files
are down the viewpath. Note, even though we copied the files up
$(*) will still expand to their original bound path.
Instead of copying the files up, now we remove the same files from the
current directory by expanding the variable to
"rm $(*:N=/*:B:S)".
Here is how it looks when we build it.
$ ls -l total 8 -rw-r--r-- 1 richb richb 171 Aug 6 14:23 Makefile -rw-r--r-- 1 richb richb 6 Aug 6 14:20 green -rw-r--r-- 1 richb richb 7 Aug 6 14:20 indigo -rw-r--r-- 1 richb richb 7 Aug 6 14:20 orange $ nmake + cp /home/richb/n11/src/cf/red /home/richb/n11/src/cf/yellow /home/richb/n 11/src/cf/blue /home/richb/n11/src/cf/violet . + myapp red orange yellow green blue indigo violet + 1> rainbow + rm red yellow blue violet $ ls -l total 48 -rw-r--r-- 1 richb richb 171 Aug 6 14:23 Makefile -rw-r--r-- 1 richb richb 3069 Aug 6 14:55 Makefile.mo -rw-r--r-- 1 richb richb 13100 Aug 6 14:55 Makefile.ms -rw-r--r-- 1 richb richb 6 Aug 6 14:20 green -rw-r--r-- 1 richb richb 7 Aug 6 14:20 indigo -rw-r--r-- 1 richb richb 7 Aug 6 14:20 orange -rw-r--r-- 1 richb richb 43 Aug 6 14:55 rainbow
A small modification can be made to handle the case where files scattered
in a viewpath node need to be copied to the current directory for processing.
In this case, the files could be down the viewpath or simply in another
directory in local node. Checking $(*:N=/*) will not be
sufficient because some of the files to copy will not start with
"/". But we can use $(*:N=*/*) to test if
there is any path information associated with the file. This will return
files that are referenced with a relative path in another directory as
well as files down the viewpath, but not files in the current directory.
rainbow : red orange yellow green blue indigo violet $(*:N=*/*:@Y?cp $(*:N=*/*) .??) myapp $(*:B:S) > $(<) $(*:N=*/*:@Y?rm $(*:N=*/*:B:S)??)
We are always interested in feedback! Let us know what you think of the newsletter, how we may improve, or ideas you have for future issues. Send us a note at nmake@alcatel-lucent.com. All ideas, suggestions, and comments are welcome.
<<home / newsletters