86

In my CMake script I want to see if I have a file on my system, and if it is there do something with it, otherwise do something with a default file. Here is the code:

find_file(
          ${project_name}_${customer}_config 
          ${ROOT}/configuration/${customer}/configuration.${project_name}.xml
)

if(NOT ${${project_name}_${customer}_config} STREQUAL
   ${project_name}_${customer}_config-NOTFOUND )
        configure_file(${ROOT}/configuration/${customer}/configuration.${project_name}.xml
                       ${CMAKE_CURRENT_BINARY_DIR}/conf/configuration.xml)
else()
    configure_file(${FAPP_ROOT}/configuration/Default/configuration.${project_name}.xml
                   ${CMAKE_CURRENT_BINARY_DIR}/conf/configuration.xml)
endif()

But it seems, this is not working.

What is the proper way of checking if a file exists in CMake?

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167

4 Answers4

189

The proper way to check if a file exists, if you already know the full path name to the file is simply:

if(EXISTS "${ROOT}/configuration/${customer}/configuration.${project_name}.xml")
   ...
else()
   ...
endif()
DLRdave
  • 13,876
  • 4
  • 53
  • 70
  • 2
    [documentation is here](https://cmake.org/cmake/help/v3.5/command/if.html?highlight=EXISTS) – Teivaz Feb 19 '18 at 08:48
  • 6
    Unfortunally, `EXISTS` does not what it claims to do. If the checked file can't be read or written, it return false, although the file is visible. This is a sad bug, because this sometimes can be useful, like the existence of a certain device file. – Philippos Apr 10 '18 at 11:45
  • 1
    oddly this simple command does not work for any file i create :/ – Jimmy Pettersson Dec 06 '18 at 12:58
  • Can you provide an example that does not work? Is there some sort of race condition where the file is possibly created shortly after you try to use the EXISTS test? – DLRdave Dec 06 '18 at 16:49
  • 2
    For the latest cmake (at least 3.14+) this is incomplete answer. You have to additionally test on not a directory path: `if (EXISTS "..." AND NOT IS_DIRECTORY "...")` as long as `EXISTS` returns true on directories too! – Andry May 07 '19 at 20:03
  • @Andry This is a valid point. It has been the case going back to at least CMake 3.0, `if (EXISTS "...")` will return true if the file OR directory exists. Here are the [docs](https://cmake.org/cmake/help/v3.0/command/if.html). – Kevin May 09 '19 at 13:00
11

You should be able to just use

if(NOT ${project_name}_${customer}_config)

From the docs:

if(<constant>)

True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number. False if the constant is 0, OFF, NO, FALSE, N, IGNORE, "", or ends in the suffix '-NOTFOUND'.

However, if the file is found using find_file, the value is cached, and subsequent runs of CMake will not try to find it again. To force a recheck on every run, before the find_file call do:

unset(${project_name}_${customer}_config CACHE)
Fraser
  • 74,704
  • 20
  • 238
  • 215
8

I believe the if (EXISTS <path>) is a good solution. I'd like to share a scenario I recently encountered, though you probably won't care about this scenario in most cases.

Please note, this solution will not return true if the file is not accessible by the effective user. The file does exist, but it's just not readable.

A workaround for this scenario if you do care about whether the file really exists or not, is to call execute_process(COMMAND ls /dev/fb0 RESULT_VARIABLE result OUTPUT_QUIET ERROR_QUIET) and then check the result like this:

if (result)
    message("/dev/fb0 doesn't exist.")
endif()

edit: add ERROR_QUIET in execute_process or you will get error messages from ls when the file does not exist.

ZHANG Zikai
  • 560
  • 6
  • 15
7

From Condition Syntax docs:

if(EXISTS path-to-file-or-directory)

True if the named file or directory exists. Behavior is well-defined only for full paths. Resolves symbolic links, i.e. if the named file or directory is a symbolic link, returns true if the target of the symbolic link exists.

If the file you are looking for is located within the current cmakelist-file, then one solution could be:

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE_WORKING_ON}) ...

Community
  • 1
  • 1
Mujtaba Aldebes
  • 123
  • 1
  • 7