Using Nmake

NMake is a make utility provided by Microsoft and available in Visual Studio. It is a handy tool for creating automated builds.

Simple Example

 "makefile"
 foo.exe:foo.cs
        csc foo.cs
To execute the above makefile use the following command
 nmake foo.exe
What the makefile says is that foo.exe depends on foo.cs and that if foo.cs has changed more recently than foo.exe execute the command "csc foo.cs"

 <target>: <dependency> [<dependency>]
 <tab><command>
Where <target> is the name of a file to be generated or acted upon. <dependency> is a file that <target> depends on. [<dependency>] means that optional additional dependencies can be listed on the line. <tab> is a literal tab character NOTE: using spaces will cause the command to fail to execute. <command> is a command line that you would like to execute which usually creates the target from the dependencies.

Another Example

 "makefile"
 TARGET = foo.exe

SOURCES = \ foo.cs \ bar.cs

all: $(TARGET)

$(TARGET):$(SOURCES) csc /out:$@ $**
This makefile does a little more. There is an all which is a psudotarget. A psudotarget represents a missing file and thus will always be out of date. Executing nmake without any parameters will cause nmake to open the file in the local directory called makefile, find the first target defined in it (the all target in our example), and begin evaluating dependencies. Use the following to build the all target in the example makefile

 nmake
or optionally

 nmake all

There is a TARGET macro that evaluates to the string "foo.exe" and a SOURCES macro that evaluates to the string "foo.cs bar.cs" the "\" character indicates that the line is continued and must be the last character in the line. To dereference a macro it must be wrapped with $(<macroname>) where <macroname> is the name of the macro to dereference. Preprocessing the makefile will result in the following substitutions

 all:foo.exe

foo.exe:foo.cs bar.cs csc /out:foo.exe foo.cs bar.cs
The $@ macro evaluates to the target to be built on the left of the : and $** evaluates to the dependencies to the right of the :

Traversing Directories

 "makefile"
 DIRS = \ 
         dir1 \ 
         dir2 \ 
         dir3

all: $(DIRS)

$(DIRS): pushd $@ & nmake & popd
This example creates a macro called DIRS that evaluates to the string "dir1 dir2 dir3". Preprocessing the makefile will result in the following

 dir1:
         pushd dir1 & nmake & popd

dir2: pushd dir2 & nmake & popd

dir3: pushd dir3 & nmake & popd
NOTE: that the targets were split onto separate lines for you. Something to keep in mind is that a command executes in its own shell thus the reason for &ing together the commands. Running them on separate lines like this:

 dir1:
         pushd dir1
         nmake
         popd
would not have the desired result because each command would run in its own shell environment and the change directory would not execute in the same shell as the nmake.

Including Defaults

 "default.mk"
 BUILDROOT = C:\Build
 PROJECT = MyProject

O = $(BUILDROOT)\$(PROJECT)\bin

RECURSE_DIR = \ pushd $@ & nmake & popd

COMPILE_EXE = \ csc /out:$@ $(REFERENCES) $(SOURCES)

"makefile" !include $(DEFAULT)

DIRS = bam

TARGET = $(O)\foo.exe

SOURCES = \ foo.cs \ bar.cs

REFERENCES = \ /r:$(O)\bam.dll

all: $(DIRS) $(TARGET)

$(DIRS): $(RECURSE_DIR)

$(TARGET): $(SOURCES) $(COMPILE_EXE)
In this example I have two files a default.mk and makefile. As you can see in the makefile, I am making reference to a macro DEFAULT that doesn't appear to be set. The assumption is that this macro is defined in the environment as follows:

 set DEFAULT=C:\Build\default.mk
You can dereference environment variables with the same syntax as macros. If you define a macro that is also an environment variable the macro wins. As you can see the all target is going to process DIRS then the TARGET. Preprocessing this makefile will result in the following:

 all: bam C:\Build\MyProject\bin\foo.exe

bam: pushd bam & nmake & popd

C:\Build\MyProject\bin\foo.exe: foo.cs bar.cs csc /out:C:\Build\MyProject\bin\foo.exe /r:C:\Build\MyProject\bin\bam.dll foo.cs bar.cs
After all the substitutions are made you can see that nmake will traverse the bam directory then build foo.exe to the appropriate target location. NOTE: macros can contain references to other macros but avoid creating circular macro references or nmake will complain.

-- JeremyEmerson


CategorySoftwareTool


EditText of this page (last edited January 9, 2014) or FindPage with title or text search