如何从cmake的“file(GLOB ...)”模式中排除单个文件?

124

我的CMakeLists.txt文件包含这一行:

file(GLOB lib_srcs Half/half.cpp Iex/*.cpp IlmThread/*.cpp Imath/*.cpp IlmImf/*.cpp)

IlmImf文件夹中包含b44ExpLogTable.cpp,我需要在构建过程中排除它。

如何实现呢?

4个回答

133
你可以使用list函数来操作列表,例如:
list(REMOVE_ITEM <list> <value> [<value> ...])

在你的情况下,也许这样做会有用:

list(REMOVE_ITEM lib_srcs "IlmImf/b44ExpLogTable.cpp")

1
除了lib_src,改成lib_srcs,而不是IlmThread,改成IlmImf,问题得以解决!非常感谢! - berak
25
注意:在移除列表项时,请确保您搜索的值与列表中的完全匹配。我试图混合使用 ${CMAKE_SOURCE_DIR}/src/file_to_remove.cpp 和 ${CMAKE_CURRENT_SOURCE_DIR}/../file_to_remove.cpp,但它们虽然指向同一位置,但不是相同的字符串。使用 message("${VARIABLE_NAME}") 命令可以帮助您调试这些内容。 - hbobenicio
1
如果您正在使用CONFIGURE_DEPENDS并且需要排除构建生成的文件,则此方法无法帮助您。在file调用之后对列表进行过滤仍会触发重建,而我正试图避免这种情况。 - simon.watts
1
最好使用 list(FILTER) - hukeping
7
上述解决方案在我的camke版本3.10.2上不起作用,但是下面的解决方案:list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)对我很有效。 - MH Yip
@MHYip,这个方法应该是可行的,但是只有在你输入要删除的项目与列表中完全一致时才有效。然而,使用正则表达式的解决方案可以给你更多的灵活性,所以如果它对你有用,那就太好了。 - Lindydancer

80

FILTER是另一个选项,有些情况下可能更方便:

list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)

这行代码排除了每个以所需文件名结尾的项目:

list(FILTER lib_srcs EXCLUDE REGEX ".*b44ExpLogTable\\.cpp$")

这里是cmake的正则表达式规范

The following characters have special meaning in regular expressions:

^         Matches at the beginning of input
$         Matches at the end of input
.         Matches any single character
[ ]       Matches any character(s) inside the brackets
[^ ]      Matches any character(s) not inside the brackets
 -        Inside brackets, specifies an inclusive range between
          characters on either side e.g. [a-f] is [abcdef]
          To match a literal - using brackets, make it the first
          or the last character e.g. [+*/-] matches basic
          mathematical operators.
*         Matches preceding pattern zero or more times
+         Matches preceding pattern one or more times
?         Matches preceding pattern zero or once only
|         Matches a pattern on either side of the |
()        Saves a matched subexpression, which can be referenced
          in the REGEX REPLACE operation. Additionally it is saved
          by all regular expression-related commands, including
          e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).

2
可以比折腾绝对/相对路径更可靠。 - EFraim
2
list(REMOVE_ITEM 好得多 - ceztko
2
请注意,list(FILTER ...)是在cmake v3.6中引入的:https://dev59.com/dFgQ5IYBdhLWcg3w0HSW#42167646 - yano
1
你忘记转义文件名和扩展名之间的点了。因此,它将匹配到在文件名和扩展名之间的任何字符,例如 b44ExpLogTableacpp - Mustafa Kemal GILOR
1
修正后的表达式应为:list(FILTER lib_srcs EXCLUDE REGEX ".*b44ExpLogTable\\.cpp$") - Mustafa Kemal GILOR
显示剩余2条评论

4

尝试这个:CMakeLists.txt

install(DIRECTORY   ${CMAKE_SOURCE_DIR}/ 
            DESTINATION ${CMAKE_INSTALL_PREFIX}
            COMPONENT   copy-files
            PATTERN     ".git*"   EXCLUDE
            PATTERN     "*.in"    EXCLUDE
            PATTERN     "*/build" EXCLUDE)

add_custom_target(copy-files
            COMMAND ${CMAKE_COMMAND} -D COMPONENT=copy-files
            -P cmake_install.cmake)

$cmake <src_path> -DCMAKE_INSTALL_PREFIX=<install_path>
$cmake --build . --target copy-files

它并没有回答OP的问题,因为问题相当具体。但我仍然认为这个答案是最合适的。如果真正的问题是在安装构建中不包括什么,那么这是一个优雅的解决方案。特别是如果有多个特殊的构建目标(add_custom_target)进入一个共同的构建目录,这更容易维护。注意:对于“覆盖所有”情况,不需要使用COMPONENT。与CPack完美配合(已测试DEB生成器,cmake版本3.18.4)。 - Michael Ambrus

0
我有一个值得注意的替代方案:将源代码标记为头文件。 这样它就不会成为构建过程的一部分,但在IDE中可见(在Visual Studio和Xcode上验证)。
set_source_files_properties(b44ExpLogTable.cpp,
                            PROPERTIES HEADER_FILE_ONLY TRUE)

当某些源文件是特定于平台时,我使用这个。它非常好,因为如果某个符号必须在许多地方进行修改并且在一个平台上工作,则其他特定于平台的源代码也可以被看到并更新。

为此,我创建了一个辅助函数,在我的当前项目中运行良好。

我还没有使用文件GLOB这种方法。


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