(抱歉:从 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作者:Fraser,这是一个独立的示例,显示了我所描述的 2 个“功能”。但是,我确实知道我正在以稍微不标准的方式运行 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
(如预期),以及来自 ~/projectA/projectA
的所有内容源 tarball,包括 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 的正则表达式处理允许排除字符组,但我认为它不允许否定整个模式。
话虽如此,我想您可以在 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)
<小时/>
进一步编辑:
好吧,你的例子很有帮助 - 我确实误解了你在做什么。我没有意识到你实际上正在制作两个不同的目标(“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?
我认为这意味着:“执行 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
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”目标仅包含通过 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}")
希望这现在对您有用。再次抱歉误导了您。
关于cmake - CPack : Ignoring files using regex,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17935748/