Changes in Nmake 8.0: Answer

In my previous post, I described two issues encountered after updating our build system to Nmake 8.0 (the version from Visual Studio 2005) from earlier versions. Both issues turned out to have essentially the same root cause.

Nmake's job is to execute a sequence of commands to bring targets up-to-date. Some of those commands do real work, such as "cl -c MyProgram.cpp" to run the compiler. Other commands just set things up, such as "set TARGETDIR=c:\obj". Some commands just output status information, such as "echo Starting compile".

In order to improve build speed (as well as to supply certain semantics expected by the developer), Nmake emulates some commands instead of actually executing them. For example, if Nmake were to run "cmd /c set TARGETDIR=c:\obj", nothing would happen (the environment of the new cmd.exe process would be modified, but then the process would exit and the change to the environment would be lost).

It seems that between Nmake 7.1 and Nmake 8.0, the mechanism for executing some of cmd.exe's internal commands was changed. Previously, "echo", "type" and other built-in commands were always executed with predictable semantics. (I'm guessing this is because they were emulated by Nmake instead of being passed to cmd.exe.) In Nmake 8.0, the "echo" and "type" commands are apparently executed exactly as if you typed them into the cmd.exe command line.

On the surface, this isn't such a big deal. Most of the time, this change is completely transparent. Once in a while...

In the first case described in the previous blog post, it turned out that "echo.exe" was a program on the user's path. This is a tool written to make the "echo" command in cmd.exe behave more like the "echo" command in Unix. Nmake was simply calling the user's echo.exe instead of using cmd.exe's built-in echo command.

In the second case, "type.exe" was a program on the user's path.