Testing file existence in NMake

Alexey Romanov picture Alexey Romanov · Dec 17, 2010 · Viewed 11.3k times · Source

In a makefile for GNU Make I use this idiom to test whether a file exists:

static:
ifeq ($(wildcard $(FileName)),)
    # do something when the file doesn't exist
else
    # do something different when it does
endif

But it doesn't work in NMake (fatal error U1000: syntax error : ')' missing in macro invocation). How can I replace it? It would be perfect if the replacement works in both build systems.

Answer

Cheeso picture Cheeso · Dec 22, 2010

Just to add to Jack Kelly's suggestion, you can do the test for existence in a CMD.EXE shell. NMake also includes the ability to create a temporary .cmd file, and execute it.

Here's an example of the (n)makefile syntax, that I use for a "check-syntax" target. It checks the syntax in a single C# source file, in a multi-file project, by doing a compile.

check-syntax :
    <<flymake-build.cmd  $(CS_SOURCE)
SETLOCAL ENABLEDELAYEDEXPANSION
set errorlevel=
for %%I in (%*) do if NOT x%%I == x$(FLYMAKE_ORIGINAL) (
   set filesToBuild=!filesToBuild! %%I
)
$(_CSC) /t:module $(LIBSREF) $(FLYMAKE_CHECK) !filesToBuild!
ENDLOCAL && exit /b %errorlevel%
<<

The "flymake-build.cmd" is the name of the temporary cmd file that gets created. The double angle brackets (<<) denote the beginning and end of the content that goes into the temp file, before the file is executed.

The stuff after the filename on that first line are arguments passed to the .cmd file. In this example, the arguments are the contents of a makefile variable called CS_SOURCE. In my case this is just a list of filenames in the project. Makefile variables will be expanded within the text for the temporary file, as well. You can see I refer to a compiler (_CSC) and some other symbols.

Inside the .cmd code, you can do for loops, if statements, anything you like. It's a regular .cmd file.

If you want nmake to respond to errors (eg, terminate the build) generated by commands within the .cmd file, then you need to use the exit /b approach to end the cmd.

I found the documentation for this in a dark corner somewhere, so I thought I'd share it here for general elucidation. (EDIT: here's the link.)