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.csTo execute the above makefile use the following command
nmake foo.exeWhat 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
nmakeor optionally
nmake allThere 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.csThe $@ 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 & popdThis 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 & popdNOTE: 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 popdwould 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.mkYou 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.csAfter 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.