(道歉:从CMake邮件列表交叉发布)
我正试图了解CMake的正则表达式实现;我有一个包含4个文件夹和2个文本文件的文件夹,如下所示:
build/
projectA/
CMakeLists.txt
extrafiles/
README
temp/
一行CMakeLists.txt是:
set(CPACK_SOURCE_IGNORE_FILES "[^projectA]$")
在我的源包中随后生成,build/
,projectA/
和extrafiles
存在,但temp/
和2个文本文件不存在。我正试图进入一个阶段,正则表达式将忽略文件夹中除projectA/
,README
和CMakeLists.txt
之外的所有内容,但目前无法解决正则表达式我有
提供的是给出这些结果。
我想这归结为如何使用正则表达式匹配整个字符串。我意识到文档说Matches any character(s) not inside the brackets
这就是我猜我错了...
进一步探索
在试图理解CMake的正则表达式实现时,我认为我从第一原则开始并做一些简单的事情。
如果我这样做
set(CPACK_SOURCE_IGNORE_FILES projectA)
然后文件夹projectA
没有出现在我的源包中(如预期的那样);但是,如果我这样做
set(CPACK_SOURCE_IGNORE_FILES ^projectA$)
或
set(CPACK_SOURCE_IGNORE_FILES ^/projectA/$)
然后显示projectA
。关于^
(行首)和$
(行尾)我不理解的是什么?
更多
很明显,projectA
实际上并不是我项目的名称,但是当我将项目文件夹物理重命名为projectA
时,上述所有内容都成立。但是,当我替换
set(CPACK_SOURCE_IGNORE_FILES projectA)
与
set(CPACK_SOURCE_IGNORE_FILES <name of my project>)
并将我的实际项目文件夹从projectA
重命名为其实际名称,我最终得到了一个空 tarball!哎呀!我绝对没有想法CMake在我身上玩什么奇怪的技巧,但我只是想哭。
非常感谢任何见解!
自包含示例
弗雷泽的As requested,一个自成一体的例子,展示了我所描述的两个“特征”。但是,我确实知道我正在以一种略微非标准的方式运行CMake,以便将所有内容与各个版本保持在一起,所以如果有任何证据以更标准的方式运行CMake消除了这些问题我会成为有兴趣看到它们。
第1步:创建文件
创建树:
cd ~
mkdir
cd projectA
mkdir projectA
创建C文件,并将其另存为~/projectA/projectA/helloworld.c
:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("!!!Hello World!!!\n"); /* prints !!!Hello World!!! */
printf("!!!Hello CMake!!!\n"); /* prints !!!Hello CMake!!! */
return 0;
}
创建一个不需要编译的文件,并将其另存为~/projectA/test.sh
:
#A non compiled program
echo "Hello world!"
创建~/projectA/CMakeLists.txt
:
cmake_minimum_required (VERSION 2.6)
project (HelloWorld)
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/projectAinstall")
add_executable(helloworld projectA/helloworld.c)
install(TARGETS helloworld DESTINATION .)
include(InstallRequiredSystemLibraries)
set(CPACK_GENERATOR "TGZ")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)
第2步:编译
在~/projectA
中,运行:
chris@chris:~/projectA$ cmake -H. -Bbuild
然后:
make -C build && make -C build package && make -C build package_source
这导致build
文件夹中有2个tarball。将这些移动到其他地方并解开它们会在二进制tarball中显示helloworld
(如预期的那样),并在源tarball中显示{{1>}的所有,包括~/projectA/projectA
不会被编译(弗雷泽似乎感到惊讶)
第3步:随机测试
修改test.sh
以包含
CMakeLists.txt
并重新运行上面的CMake / Make命令会产生一个空的源tarball,但具有与上面相同的二进制tarball。我现在已经意识到更改目录树以使顶级目录为set(CPACK_SOURCE_IGNORE_FILES "projectA")
(与其子文件夹不同)不会导致空的源tarball,并且只做删除testproject
答案 0 :(得分:2)
我认为你在使用 [在编辑结束时查看更新的答案。] CPACK_SOURCE_IGNORE_FILES
之后无法实现目标(虽然我不确定)。正如你正确指出的那样,CMake的正则表达式处理允许排除字符组,但我不认为它允许否定整个模式。
话虽这么说,我想你可以在install
命令中列出你想要排除的所有文件夹。不像排除“projectA”之外的所有内容那样强大,但仍然是语法:
install(DIRECTORY .
DESTINATION the_install_subdir
REGEX "build|extrafiles|temp+" EXCLUDE)
关于空的tarball,我想你可能有<name of my project>
作为项目的根目录和子目录?因此,在您的示例中,如果您将项目称为“projectA”,那么您将拥有“projectA / build”,“projectA / projectA”等。
如果是这样,正则表达式将在完整路径上工作,因此项目中的所有文件将在其路径中包含projectA/
。
至于哭......好吧,我只能建议你抓紧把自己拉到一起! : - )
编辑:在回复评论时,以下是使用install
命令实现目标的快速示例:
install(DIRECTORY projectA
DESTINATION the_install_subdir)
install(FILES CMakeLists.txt README DESTINATION the_install_subdir)
进一步修改:
好的,你的例子很有帮助 - 我确实误解了你在做什么。我没有意识到你实际上在制作2个不同的目标(“package”和“package_source”)。我以为你是通过做类似
的东西来创建二进制包的cpack -G DEB
并且你正在通过
创建另一个包cpack -G TGZ
这些都构建了二进制包。我的错 - 我应该多加注意。遗憾!
至于你的具体问题:
问题1
在我看来,安装未编译但与包含所有已编译文件(即bin)的文件夹处于同一级别的文件/目录,然后使用CPACK_SOURCE_IGNORE_FILES忽略bin文件夹会导致空的tarball - 这是对的吗?
我认为这意味着:“应该set(CPACK_SOURCE_IGNORE_FILES "${CMAKE_BINARY_DIR}")
导致空的tarball吗?”答案可能不是。
因为CPACK_SOURCE_IGNORE_FILES
表示正则表达式,我确信在某些情况下,结果正则表达式可以匹配项目中的每个文件,这会导致空的tarball。但是我想这不太可能。
如果不是通过变量${CMAKE_BINARY_DIR}
使用bin目录的完整路径,而是只提供文件夹名称,那么空的tarball就有更大的可能性。假设您调用bin目录“build”并拥有set(CPACK_SOURCE_IGNORE_FILES "build")
。如果您的项目位于~/test_builds/projectA
,那么正则表达式“build”将匹配项目中的每个文件,因为每个文件都包含“test_builds”;导致空的tarball。
我认为每次生成空的tarball时,这都是问题的关键。无论正则表达式试图实现什么,它实际上最终匹配并排除所有文件。
问题2
CMAKE_SOURCE_DIR
中未安装的文件似乎不会在二进制tarball中结束但最终会在源tarball中结束
是的,“package_source”确实是二进制包的不同目标。它默认包含${CMAKE_SOURCE_DIR}
中的所有文件,而“package”目标仅包含通过install
命令添加的项目。在这里,术语“源文件”可能有点用词不当,因为它意味着源树中的所有文件 - 不仅仅是.c,.cc,.cxx等。
原始问题
我认为毕竟有一种合理安全的方式来实现你的原始目标!如果您使用file(GLOB ...)
生成根目录中所有文件/文件夹的非递归列表,然后删除您希望保留在源包中的那些文件/文件夹,您应该能够使用剩余列表作为正则表达式的值CPACK_SOURCE_IGNORE_FILES
:
file(GLOB SourceIgnoreFiles "${CMAKE_SOURCE_DIR}/*")
set(SourceKeepFiles "${CMAKE_SOURCE_DIR}/projectA"
"${CMAKE_SOURCE_DIR}/CMakeLists.txt"
"${CMAKE_SOURCE_DIR}/README")
list(REMOVE_ITEM SourceIgnoreFiles ${SourceKeepFiles})
# Escape any '.' characters
string(REPLACE "." "\\\\." SourceIgnoreFiles "${SourceIgnoreFiles}")
set(CPACK_SOURCE_IGNORE_FILES "${SourceIgnoreFiles}")
希望这应该适合你。再次抱歉误导。