How do I check if file exists in Makefile?


It's strange to see so many people using shell scripting for this. I was looking for a way to use native makefile syntax, because I'm writing this outside of any target. You can use the wildcard function to check if file exists:

 ifeq ($(UNAME),Darwin)
     SHELL := /opt/local/bin/bash
     OS_X  := true
 else ifeq (,$(wildcard /etc/redhat-release))
     OS_RHEL := true
     OS_DEB  := true
     SHELL := /bin/bash


I found a way which is really working for me:

ifneq ("$(wildcard $(PATH_TO_FILE))","")

In the clean section of my makefle I am trying to check if the file exists before deleting permanently. I use this code but I receive errors.

What's wrong with it?

 if [ -a myApp ]
     rm myApp

I get this error message

 f [ -a myApp ]
 /bin/sh: Syntax error: end of file unexpected (expecting "then")
 make: *** [clean] Error 2

Simply define OUTLIB_CACHE_EXISTS as follows

OUTLIB_CACHE_EXISTS := $(shell if ls $(OUTLIB_CACHE_LIST) >/dev/null 2>&1; then echo "1"; fi)

make: Error in ifneq: word unexpected (expecting “)”)

In the meanwhile, I could solve it on the shell side:

IDX = ""
%.pdf: %.tex $(TEX:=.tex)
    @if test -f $(IDX); then \
        echo "foo"; \
    $(TEXI) $<

test ! -a always succeeds whether file exists or not

From the bash man page for [ with three arguments (note my emphasis):

The following conditions are applied in the order listed.

  • If the second argument is one of the binary conditional operators listed above under CONDITIONAL EXPRESSIONS, the result of the expression is the result of the binary test using the first and third arguments as operands. The '-a' and '-o' operators are considered binary operators when there are three arguments.

  • If the first argument is '!', the value is the negation of the two-argument test using the second and third arguments.

  • If the first argument is exactly '(' and the third argument is exactly ')', the result is the one-argument test of the second argument.

  • Otherwise, the expression is false.

In other words, -a is not acting as you expect it to in this case. It's actually being treated as the logical-and operator and, since both ! and bar are considered true, the result of anding them is also true:

pax> if [ ! ] ; then echo yes ; fi
pax> if [ bar ] ; then echo yes ; fi

The foibles of [ are many and varied, which is why sensible bash coders will use [[ instead :-)

try this :

$ touch bar
$ if [[ -a bar ]]; then echo "Yes"; fi
$ if [[ ! -a bar ]]; then echo "Yes"; fi

Ref :

Special primitives that [[ is defined to have, but [ may be lacking (depending on the implementation):

entry (file or directory) exists
[[ -e $config ]] && echo "config file exists: $config"
file is newer/older than other file
-nt / -ot
[[ $file0 -nt $file1 ]] && echo "$file0 is newer than $file1"
two files are the same
[[ $input -ef $output ]] && { echo "will not overwrite input file: $input"; exit 1; } 
[[ ! -u $file ]] && echo "$file is not a setuid file"