Nokia nmake Product Builder
Customer Support Newsletter

http://www.bell-labs.com/project/nmake/newsletters/

Issue No. 12 - August 09, 2002
Highlights
  1. Release lu3.5
Technical Notes
  1. Java Inside-package Local Builds
  2. Quoteinclude
Tidbits
  1. Copying files to current directory
  2. Newsletter Feedback
Contacts
email: nmake@alcatel-lucent.com (tech support)
email: software@alcatel-lucent.com (licenses/orders)
web: http://www.bell-labs.com/project/nmake/


Highlights

Alcatel-Lucent nmake lu3.5 Released

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:

Java inside-package local build
Allows developers to launch Java builds from within a package rather than only at the package root. See the article, Java inside-package local build, below for more discussion about this feature.
:: operator support for building shared libraries
The :: assertion operator can now be used to build shared libraries. Many users find this easier to use than :LIBRARY:.
quoteinclude
The quoteinclude feature allows the integration of tools that do not support -I- for referencing include files in the viewpath. See the quoteinclude article below for more discussion about this feature.
IDL scan rule
A .SCAN.idl scan rule is now defined in the base rules.
Multiple language support for -I-
Support for scanning multiple languages requiring -I- support. The .INCLUDE. function can now generate -I command line flags which include the -I- (or similar) flag.
Prefixinclude for native preprocessors
When using a native preprocessor which supports -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.

index


Technical Notes

Java Inside-package Local Builds

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
The 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
The 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: com
The :JAVA: assertion builds all the *.java files under the com sub-directory.

A Typical Package-root Build

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   

An Inside-package Build

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                                            

Specifying a Makefile

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                                            

Limitations and the Future

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.

index

Quoteinclude

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.

index


Tidbits

Copying files to current directory

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)??)                

index


Newsletter Feedback

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.

index

<<home / newsletters