使用CMake检查本地文件是否存在

87

在我的CMake脚本中,我想检查系统上是否有一个文件,如果有,就对它执行某些操作,否则使用默认文件执行某些操作。以下是代码:

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()

但是看起来,这并不起作用。

在CMake中检查文件是否存在的正确方法是什么?

4个回答

192

如果您已经知道文件的完整路径名,检查该文件是否存在的正确方法是:

if(EXISTS "${ROOT}/configuration/${customer}/configuration.${project_name}.xml")
   ...
else()
   ...
endif()

2
文档在此:https://cmake.org/cmake/help/v3.5/command/if.html?highlight=EXISTS - Teivaz
6
遗憾的是,EXISTS并不能像它所声称的那样正常工作。如果所检查的文件无法读取或写入,则会返回false,即使该文件可见。这是一个令人沮丧的错误,因为有时候这可能非常有用,例如确定某个设备文件是否存在。 - Philippos
1
奇怪的是,这个简单的命令对我创建的任何文件都不起作用 :/ - Jimmy Pettersson
你能提供一个不起作用的例子吗?是否存在某种竞争条件,使得文件可能在你尝试使用EXISTS测试后不久被创建? - DLRdave
3
对于最新的cmake(至少3.14+),这是不完整的答案。您还必须在非目录路径上进行额外的测试:if (EXISTS "..." AND NOT IS_DIRECTORY "..."),因为EXISTS也会在目录上返回true! - Andry
@Andry,你说的很有道理。至少从CMake 3.0开始,如果文件或目录存在,if (EXISTS "...")会返回true。这里是文档 - Kevin

11

你应该可以直接使用

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

根据文档

if(<constant>)

如果常量为1、ON、YES、TRUE、Y或非零数字,则为真。如果常量为0、OFF、NO、FALSE、N、IGNORE、""或以“-NOTFOUND”结尾,则为假。

然而,如果使用find_file找到了文件,该值将被缓存,并且CMake的后续运行不会再次查找它。要在每次运行时强制重新检查,请在find_file之前执行以下操作:

unset(${project_name}_${customer}_config CACHE)

8

我认为 if (EXISTS <path>) 是一个不错的解决方案。我想分享最近遇到的一个场景,虽然在大多数情况下您可能不会关心这个场景。

请注意,如果文件对有效用户不可访问,则此解决方案将不返回 true。该文件确实存在,但只是不可读。

如果您确实关心文件是否真正存在,那么可以通过调用 execute_process(COMMAND ls /dev/fb0 RESULT_VARIABLE result OUTPUT_QUIET ERROR_QUIET) 然后像这样检查 result 来解决此场景的问题:

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

编辑:在execute_process中添加ERROR_QUIET,否则当文件不存在时,您将会收到来自ls的错误消息。


谢谢!这里提供的解决方法是我情况下唯一可行的解决方案。 - MartinBG

7

从条件语法的文档中:

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

如果指定的文件或目录存在则为真。 仅对全路径定义的行为有明确规定。解析符号链接,即如果指定的文件或目录是符号链接,则返回true表示符号链接的目标存在。

如果您要查找的文件位于当前cmakelist文件中,则一种解决方案可能是:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接