Nokia Networks Home

Nokia nmake Product Builder

Quick Links

Related Products

Tutorial: A Little Help With Nokia nmake

[Table of Contents] [Previous Section] [Next Section]

7. Programming nmake

nmake recognizes some standard programming constructs that are described in chapter 5 of the manual. Programmers usually pick the important points up quickly, so we won't spend time showing you how to use if statements or write for loops. Instead, we'll say a few words about print, introduce two other important commands, and then show you how to write action blocks designed for nmake rather than the shell.

7.1 print

We've already used print in an example, and it wasn't difficult. When nmake finds a print statement it takes the rest of the line, expands variable references, and copies the result to standard output. The syntax is:

     print [ options ] message ...

Options were introduced in 3.1's implementation of print. We're not going to describe them here, except to say that -- (i.e., two minus signs) marks the end of the options. In other words, if you're using a new version of nmake

     print --  message

prints your message, even if it starts with a minus sign.

7.2 error

When nmake finds an error statement it takes the rest of the line, expands variable references, and usually copies the result to standard error. The syntax is:

     error [ level ] message ...

level is an optional integer [16] that controls the format of the message and determines what happens after nmake prints the message. Setting level to 0 is the same as leaving it out, as long as your message doesn't begin with a number. A level greater than 2 means abort after printing the message. We can experiment with different error levels by putting

     error $(LEVEL) this message comes from error
                                              
     hello :
        silent echo "hello, world"

in a file named error.mk. For example, if we type

     nmake -f error.mk LEVEL=3

we get the message from error

     make: this message comes from error

and nothing else, because a level of 3 (or higher) means abort. Increase level and nothing obvious changes, but check nmake's exit status after it aborts and you'll see it depends on level.

7.3 include

Cooperating makefiles usually need to share information, and that's why a mechanism for including files is so important. When nmake finds an include statement it takes the rest of the line, expands variable references, and reads the files named in the result. The syntax is:

     include [ - ] file ...

The optional minus sign disables the warning about a file that can't be found. Individual files are space separated and optionally quoted, so you'll often see

     include "file"

even though the quotes are unnecessary. nmake complains when it can't find an include file, but it's just a warning that usually disappears when nmake reads the objectfile. For example, put

     include global.mk
                                    
     hello :
        silent echo "$(<), $(AUDIENCE)"

in include.mk and type

     nmake -f include.mk hello

and we get:

     make: "include.mk", line 1: global.mk: cannot read include file
     hello,

nmake couldn't find global.mk and told us so, but run it again and the warning goes away. The message from hello is still incomplete, because AUDIENCE isn't defined, but put

     AUDIENCE = world

in a file named global.mk and both problems are fixed.

7.4 .MAKE

Action blocks are usually handed to the shell, but adding .MAKE to a prerequisite list means reading the action block (just like it's another makefile) whenever it builds the target. It's not hard to figure out who should get an action block. You let the shell do the work when you want to run Unix commands (e.g., a compiler) or do things in the file system, and you let nmake handle the action block when you want to define variables or assertions that can be used later on.

7.4.1 Sometimes You Have A Choice ...

Most of our examples have been so simple that we could easily rewrite the action blocks and hand them to nmake. For example,

     AUDIENCE = world
                            
     goodbye hello : .MAKE
        print $(<), $(AUDIENCE)

and message.mk seem to be equivalent, even though the shell handles one action block and nmake handles the other. But even these two simple makefiles can behave differently. Add things to AUDIENCE that mean something special to the shell, print, or echo and you may notice a difference. For example, save the last makefile in make.mk and we get different results from

     nmake -f message.mk AUDIENCE='$LOGNAME'

and

     nmake -f make.mk AUDIENCE='$LOGNAME'

because the shell understands $LOGNAME, but nmake doesn't.

We haven't talked much about environment variables, but put parentheses around LOGNAME and we get the same thing from both makefiles. nmake reads your environment when it starts, so it recognizes LOGNAME, and that's why we get the right answer when nmake expands $(LOGNAME). Collisions aren't a problem, because variables defined on the command line or in a makefile override environment variables.

7.4.2 ... But Usually You Won't

Even though the shell is usually the right choice, there may be times when we need to exercise some control over nmake using an action block. Here's an example that we'll save in setup.mk - it's contrived, but it's also easy and will help you understand what happens when nmake handles an action block:

     setup : .MAKE
        AUDIENCE = world
                                       
        goodbye hello :
           silent echo "$(<), $(AUDIENCE)"

We started with a target named setup, added .MAKE as a prerequisite, and copied message.mk into setup's action block. You deserve an explanation if you're wondering why we didn't use

     setup : .MAKE
        include message.mk

as our example: we wanted to make you look at a variable definition, a blank line, and an assertion in an action block. Even though we can see the assertion that defines hello, it's hidden in an action block, so when we type

     nmake -f setup.mk hello

we get,

     make: don't know how to make hello

because nmake won't find it, but add setup to the command line

     nmake -f setup.mk setup hello

and we get:

     hello, world

Building setup defined AUDIENCE, hello, and goodbye, and that allowed nmake to build hello. By the way, you should have no trouble understanding what happens when we type:

     nmake -f setup.mk AUDIENCE='New Jersey' setup hello

The command line assignment defined AUDIENCE, but building setup replaced the definition, and that's why the message doesn't change.

FOOTNOTES:

[16]
Negative numbers work with nmake's debugging option, but won't be described here.

[Table of Contents] [Previous Section] [Next Section]

Last Update: Friday,12-Aug-2016 12:19:28 EDT