cmake – CPack:使用正则表达式忽略文件

(道歉:从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之外的所有内容,但目前无法解决我的正则表达式如何
提供的是给出这些结果.

我想这归结为如何使用正则表达式匹配整个字符串.我意识到文档说匹配任何不在括号内的字符,我猜我错了…

进一步探索

在试图理解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 by Fraser,一个自包含的例子,展示了我描述过的两个“特征”.但是,我确实知道我正在以一种略微非标准的方式运行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!"

create~ / 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中〜/ projectA / projectA的所有内容,包括不会被编译的test.sh(Fraser似乎感到惊讶)

第3步:随机测试

修改CMakeLists.txt以包含

set(CPACK_SOURCE_IGNORE_FILES "projectA")

并重新运行上面的CMake / Make命令会产生一个空的源tarball,但具有与上面相同的二进制tarball.我现在已经意识到更改目录树以使顶级目录是testproject(与其子文件夹不同)不会导致空的源tarball,并且只删除CPACK_SOURCE_IGNORE_FILES中列出的文件

最佳答案 我不认为你可以在使用CPACK_SOURCE_IGNORE_FILES之后实现你的目标(虽然我不确定).正如你正确指出的那样,CMake的正则表达式处理允许排除字符组,但我不认为它允许否定整个模式. [请参阅编辑结尾处的更新答案.]

话虽这么说,我想你可以在安装命令中列出你想要排除的所有文件夹.不像排除“projectA”之外的所有东西那样强大,但仍然是这里的语法:

install(DIRECTORY .
        DESTINATION the_install_subdir
        REGEX "build|extrafiles|temp+" EXCLUDE)

关于空的tarball,我想你可能有 既作为项目的根目录又作为子目录?因此,在您的示例中,如果您将项目称为“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

It seems to me that installing files / directories that aren’t compiled but are at the same level as the folder containing all the compiled files (i.e. bin), and then ignoring the bin folder using CPACK_SOURCE_IGNORE_FILES results in an empty tarball – is this correct?

我的意思是:“应该设置(CPACK_SOURCE_IGNORE_FILES”${CMAKE_BINARY_DIR}“)导致空的tarball?”答案可能不是.

因为CPACK_SOURCE_IGNORE_FILES代表一个正则表达式,我确信在某些情况下,结果正则表达式可以匹配项目中的每个文件,这会导致空的tarball.但是我想这不太可能.

如果,而不是通过变量${CMAKE_BINARY_DIR}使用bin目录的完整路径,你只需要给出文件夹名称,那么空的tarball就有更大的可能性.假设您调用bin目录“build”并设置(CPACK_SOURCE_IGNORE_FILES“build”).如果您的项目位于〜/ test_builds / projectA中,那么正则表达式“build”将匹配项目中的每个文件,因为每个文件都包含“test_builds”;导致空的tarball.

我认为每次你生成一个空的tarball时,这都是问题的关键.无论正则表达式试图实现什么,它实际上最终匹配并排除所有文件.

问题2

It also seems that files in the CMAKE_SOURCE_DIR which aren’t ‘installed’ don’t end up in the binary tarball but do end up in the source tarball

是的,“package_source”确实是二进制包的不同目标.它默认包含${CMAKE_SOURCE_DIR}中的所有文件,而“package”目标仅包含通过安装命令添加的项目.在这里,术语“源文件”可能有点用词不当,因为它表示源树中的所有文件 – 不仅仅是.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}")

希望这应该适合你.再次抱歉误导.

点赞