When we stopped working on message.mk in section 2.7.6 we told you something was wrong. It's time to show you the problem and the fix, and in the process introduce some magic tokens, called special atoms, that give you extra control over nmake.
There are about a hundred special atoms, but we'll only need a few, and we're not going to classify them. Special atoms have the same look - a period followed by some upper case letters. A few of the more complicated ones include several periods and occasionally a percent sign as a pattern-matching character. The names are wired into nmake. Special atoms won't often collide with Unix file names, so it's not hard to understand nmake's choice of names.
Flip through the manual and you may decide that targets, like hello and goodbye in message.mk, are labels. The official definition of a label, taken from manual's glossary, looks something like:
If an assertion has no prerequisites but has an update action block, or if an assertion has prerequisites but no actions and the target is not a file, the target represents a label in the makefile. The time stamps of the labels are stored in the statefiles but are ignored by nmake; therefore, they are made on subsequent invocations of nmake.
If you don't read carefully you might assume that targets that don't have prerequisites are automatically labels and are always built. It's easy to overlook, "and the target is not a file," but the words explain why message.mk, and most of our other makefiles, aren't quite right. We can show you the problem by creating a file that has the same name as one of our targets
nmake -f message.mk hello
We get the usual message the first time, but try it again and nothing happens. This time it's easy to blame the statefile - remove message.ms or tell nmake to ignore the statefile using the -S option
nmake -f message.mk -S hello
and the message reappears.
The explanation isn't difficult, but you'll probably need some help. nmake looked around after it finished building hello, found a file named hello, and decided the target was responsible for the file. Information about the connection was saved in the statefile, and after that nmake refused to build hello, because everything available from the statefile and file system indicated it was up to date.
So how do we make sure a target is always built, even if it appears to be up to date? Adding a special atom named .FORCE to the prerequisite list does it:
AUDIENCE = world goodbye hello : .FORCE silent echo "$(<), $(AUDIENCE)"
When nmake finds .FORCE it marks the targets, in this case hello and goodbye, with a flag that says they're supposed to be built whenever we ask. Save the example in a file named force.mk and now something happens whenever we type,
nmake -f force.mk hello
and it doesn't matter if the dummy hello file is there or not.
Something's still wrong with force.mk, and we'll show you the problem using clobber. We'll talk about more clobber later in section 11.2 when we talk about the common actions you get for free with nmake. It's what you do when you're really finished and want to clean everything up. Even though force.mk doesn't leave much lying around, when we type
touch hello nmake -f force.mk clobber
+ ignore rm -f hello force.mo force.ms
Look carefully at what happened - you should be concerned. Deleting the objectfile and statefile is normal, but nmake also removed hello, because it believed the file was built by the target named hello. So how do we protect innocent files, like hello, that just happen to have the same name as a makefile target? Start with force.mk, add .VIRTUAL to the prerequisite list,
AUDIENCE = world goodbye hello : .VIRTUAL .FORCE silent echo "$(<), $(AUDIENCE)"
and save the result in virtual.mk. Now when we type
touch hello nmake -f virtual.mk clobber
+ ignore rm -f virtual.mo
so hello was spared. The .VIRTUAL special atom breaks the connection between targets and files. Adding it to the prerequisite list means nmake won't associate hello and goodbye with files, and that's what protected the file when we ran clobber. By the way, .FORCE is still needed. Take it out of the prerequisite list in virtual.mk and you only get one message, because nmake uses the statefile to remember when targets marked by .VIRTUAL are built.